Alright, let me just say it. I'm a complete noob to making games without the aid of a visual editor. Love2D is one of my first, uhh, frameworks? Or engine, whatever it wants to call itself. Up until now, I've just been using Unity, actually thinking I'm good at programming.
Anyways, I really want to make a simple top down game similar to The Binding of Isaac, just without all of the procedurally generated maps and such. I followed Kikito's tile map editor tutorial up until it, well, just decided to stop. And I'd love to make a game with the code they provided! Only problem is that I'm not sure how to handle collisions with it. Anyways, I'm hoping someone here can help me out with my noobly problems. Here's a .love file of my project.
Top Down Game Collision Help
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
Top Down Game Collision Help
- Attachments
-
- Attempt2.love
- (4.14 KiB) Downloaded 173 times
Re: Top Down Game Collision Help
I'm a newby myself, but I happen to be making the exact same kind of game (only with the random dungeons). Here's what I do:
First I check which tile the player is standing on. This is simple to figure out, since you know what the x-location of the player is, and what the offset is of the map and the camera. So, since you know how big a tile is, and what the size is of your map, you can calculate the exact tile that the player is on. Its simply a matter of unleashing some good old math on the x and y location of the player.
Most of the newb tutorials write the tiles in a table, with an x and y value. What I did was create a second table, where I write all the collision. I created a reference file that the game loads, which basically instructs the game what the collision type is for any tile on my sprite sheet. Then as I create the initial sprite batch, I also look up the collision, and write the collision to a separate table of the exact same size as the map. So each tile in the map-table, also has an entry in my collision-table.
This is what the collision file looks like for my spritesheet:
An "X" is a wall, and a "." is a floor. I load this file, and then all this information is saved to a variable. So I only need to know what sprite the tile is using, and then check this table to know if there's an "X" (a collision).
And whenever I change the tiles in the spritebatch, I run this script to also update the collisions-table accordingly. The collisions-table must always be updated along with the map-table.
So since I now know what tile the player is standing on, I can check the collision table to see if the tile is considered a wall or a floor. I can also check this for any adjacent tiles. For example, if the player is moving right, I check tile: playertileX+1,playertileY
Or if the player is moving up, I check tile: playertileX,playertileY-1
To make sure that the player doesn't cheat by walking between two tiles, I check 3 tiles in a row in front of the player. Lastly, I make sure that the sprite of the player is actually overlapping with the location of the tile. Because maybe the player is still a few pixels away from the wall. I also auto correct the location of the player, so that he is no longer overlapping with the wall. Because I don't want the player to push himself through the wall.
Example picture of checking 3 tiles ahead of the player
One important tip I can give you, is to debug the collision by drawing a rectangle on the location you are checking, like I did in the picture. This allows you to check if the location is updated correctly as the map is scrolling. I use this code to draw the debug info:
"collisionTile" is a table that contains the number of the tile, and a boolean that either indicates a collision or not. I have another script that checks the actual collision. I then run this script over all those tiles when drawing the game. The script automatically draws the rectangle as red, if the player is colliding, or green if there is no collision.
If all of this sounds a bit overwhelming, then start by figuring out what tile the player is on, and drawing a rectangle on that tile. That is step one, and you can slowly figure out the rest from there.
First I check which tile the player is standing on. This is simple to figure out, since you know what the x-location of the player is, and what the offset is of the map and the camera. So, since you know how big a tile is, and what the size is of your map, you can calculate the exact tile that the player is on. Its simply a matter of unleashing some good old math on the x and y location of the player.
Code: Select all
camOffset = { (zoomX*(mapX%1)*tileSize),(zoomY*(mapY%1)*tileSize) }
player.tile = { math.floor((player.x + camOffset[1]) / tileSize) , math.floor((player.y + camOffset[2]+(player.size/5)+math.floor(player.size/5)) / tileSize) }
This is what the collision file looks like for my spritesheet:
Code: Select all
-- Collision reference sheet for the tilesheet
--"X"=wall--"."=floor--"W"=water--"L"=lava--"F"=firepit--"E"=emptyfirepit
--"P"=pit--"T"=spiketrap--"S"=stairs--"U"=hammerblockup--"C"=chest
--"D"=hammerblockdown--"I"=blockup--"O"=blockdown--"B"=blockswitch--"Q"=pressurepad
local collisionsheet={
{ "X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X"},
{ "X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X"},
{ "X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","."},
{ "X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","."},
{ "X","X","X",".",".",".",".",".",".",".","X","X","X","X","X","X","."},
{ "X","X","X",".",".",".",".",".",".",".","X","X","X","X","X","X","Q"},
{ "X","X","X","X","X","X","X","X","X","X","X","X","X",".",".",".","."},
{ "X","X","X","X","X","X","X","X","X","X","X","X",".",".",".","X","P"},
{ "X","X","X","X","X","X","X","X","X","X","X","X","S","S","S","S","X"},
{ "X","X","X","X","X","X","X","X","X","X","X","X","S","S","S","S","X"},
{ "X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X"},
{ "X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","."},
{ "X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","."},
{ "X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","."},
{ "X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","."},
{ "X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","X","."},
{ "X","X","X","X","X","X","X","X","X","X","X","X","S","S","S","S","."},
{ "X","X","X","X","X","X","X","X","X","X","X","X","S","S","S","S","."},
{ ".",".",".",".",".",".","X","X","X","X",".",".",".",".",".",".","X"},
{ ".",".",".",".",".",".","X","X","X","X",".",".",".",".",".",".","."},
{ ".","X","X","X","X","X","X","E","F","F","F","X","X","X","T","T","T"},
{ ".","X","X","X","X","X","X","O","I","I","O","I","I",".",".","X","X"},
{ "L","W","W","W","X",".",".",".","X",".",".","X",".","B","B","X","."},
{ "L","X","X","X","X",".","X","X","X",".","X","X","X",".",".",".","."},
{ "L","X","X","X",".",".",".","X","X","X","X","X","X",".",".",".","."},
{ "X","X","X","X","X",".",".","X","X","X","X","X",".",".",".",".","."},
{ "X","X","X","X","X",".",".","X","X","X",".",".",".","D","U","U","U"},
{ ".",".",".",".","X",".",".",".",".",".",".",".","S","S","S","S","C"},
{ ".",".",".",".",".",".",".",".",".",".",".",".","S","S","S","S","X"},
{ ".",".",".",".","S","S","S","S","S","S","S","S","X","X","X","X","C"},
{ "C","C","X","X","S","S","S","S","S","S","S","S","X","X","X","X","X"}
}
return collisionsheet
Code: Select all
---------------------------------------------------------------------------
--Put this code in the startup
collisionReference = {}
collisionReference = loadCollision("/tiles/dungeontiles.lua") --This is the path to the above collision file
----------------------------------------------------------------------------
function loadCollision(path)
newcollision = love.filesystem.load(path)() -- attention! extra parenthesis
local collisiondata = newcollision -- execute the chunk
return collisiondata
end
Code: Select all
collisions[x+((roomX*roomWidth)-roomWidth)][y+((roomY*roomHeight)-roomHeight)] = collisionReference[math.ceil(newroom[1][y][x] / (tilesetImage:getWidth()/tileSize))][(newroom[1][y][x] - (math.floor(newroom[1][y][x] / (tilesetImage:getWidth()/tileSize))*(tilesetImage:getWidth()/tileSize)))]
Or if the player is moving up, I check tile: playertileX,playertileY-1
To make sure that the player doesn't cheat by walking between two tiles, I check 3 tiles in a row in front of the player. Lastly, I make sure that the sprite of the player is actually overlapping with the location of the tile. Because maybe the player is still a few pixels away from the wall. I also auto correct the location of the player, so that he is no longer overlapping with the wall. Because I don't want the player to push himself through the wall.
Example picture of checking 3 tiles ahead of the player
One important tip I can give you, is to debug the collision by drawing a rectangle on the location you are checking, like I did in the picture. This allows you to check if the location is updated correctly as the map is scrolling. I use this code to draw the debug info:
Code: Select all
for i=1,#collisionTile do
--Collision tile
if (collisionTile[i][2]) then
love.graphics.setColor( 255, 0, 0, 255 )
else
love.graphics.setColor( 0, 255, 0, 255 )
end
love.graphics.rectangle("line", collisionTile[i][1][1],collisionTile[i][1][2],tileSize,tileSize)
love.graphics.setColor( 255, 255, 255, 255 )
end
If all of this sounds a bit overwhelming, then start by figuring out what tile the player is on, and drawing a rectangle on that tile. That is step one, and you can slowly figure out the rest from there.
Re: Top Down Game Collision Help
Hey, thanks for all of the info and tips! I'll be sure to try all of this out myself.Imaculata wrote:I'm a newby myself, but I happen to be making the exact same kind of game (only with the random dungeons). Here's what I do...
Re: Top Down Game Collision Help
My pleasure, and good luck. This is all new stuff to me as well, but so far it seems to be running smoothly.
Who is online
Users browsing this forum: Bing [Bot], Google [Bot] and 3 guests