2d Tile map collision help
BlitzMax Forums/BlitzMax Beginners Area/2d Tile map collision help
| ||
Hi, Can someone please explain how collisions work using a simple map array and a collision map. I have been told that this is the best way to do collision, but if someone has a simple example of how to do this, it would really help me out. Thanks |
| ||
Usually you have a `visible tilemap` comprising images which you draw on-screen, and an `invisible collision map` which is often at a higher resolution, against which you do collision tests. At its simplest, all you are doing is finding the bounding rectagles around the player/enemy - which is a simple matter of taking their x,y coordinates in map-space and deciding how many collision tiles they cover and checking all of those tiles to see if it is `solid` or `pass through`. Then when you've found out which tiles around the player/enemy are blocking it from moving in a certain direction, you can take action or not allow movement in that direction. You could also simply get the tile in the collision map which the character/enemy is close to, treat it like a bounding rectangle, and see if the two overlap. So as a real basic example, maybe you check the tile which would be immediate below the feet of your game character. If that tile is considered solid, you do not allow the player to move down the screen - ie he `lands on` the tile. He can walk left and right on the tiles or jump up but he can't go down. Then you also check to the left, right, and above, to see if he can move left, right, or whether he's bumping his head. If it helps, instead of thinking of your game world as 2d viewed from the side, imagine it as viewed from above, where you are navigating around a maze of walls and you keep bumping into some. You simply are trying to only allow movement if the tile in the direction of your movement is not solid. |
| ||
Here's my plat code. Using tiles. Tiles can be read in via data statements or via a tile map editor. Thanks go to jesse and a few other peeps for helping me to get it to work. Jesse being the guy that provided the "mod" based landing on tile code. :) Enjoy! :) Also after this code I'll also post the code to a simple Single Screen Tilemap editor which reads and saves files. Hopefully it should get you on your way to making that next great platform game or tilebased game. :) http://www.lunaticninja.com/storage/plat_tiles.rar SuperStrict Graphics 800 , 600 Global Tiles:TImage = LoadImage("tile.png") Global Player:TImage = LoadImage("player1632.png") Const MAPWIDTH:Int = 800/32 Const MAPHEIGHT:Int = 600/32 Global Map:Int[MAPWIDTH , MAPHEIGHT] Global PlayerX:Float Global PlayerY:Float Global Player_Width:Int = 16 Global Player_Height:Int = 32 Global CheckPlayerPosition:Int = 0 Global Direction:Int = -1 Global Jump:Int = 0 Const Gravity:Float = 0.2 Global JumpHeight:Float = 5.3 Global CanJump:Int = 1 Global Falling:Int = 0 ReadLevelData() ' We Read the level data While Not KeyHit(KEY_ESCAPE) Cls DrawMap() CheckIfPlayerCollideWithTile() DrawPlayer() MovePLayer() DoJump() Flip Wend '###################################################### '#### Function DrawPLayer() # '#### Draws Player to Screen and gets Player Position # '###################################################### Function DrawPlayer() If CheckPlayerPosition = 0 For Local x:Int = 0 Until MAPWIDTH For Local y:Int = 0 Until MAPHEIGHT Select Map[x, y] Case 2 PlayerX = getX(x) PlayerY = getY(y) CheckPlayerPosition = 1 End Select Next Next EndIf DrawText "PlayerX = " +PlayerX , 0 , 20 DrawImage Player, PlayerX , PlayerY , 0 End Function '################################################# '### Function MovePLayer() # '## Moves Player and checks outer boundaries # '################################################# Function MovePLayer() If KeyDown(KEY_LEFT) And Not KeyDown(KEY_RIGHT) Direction = 0 PlayerX:-2 ElseIf KeyDown(KEY_RIGHT) And Not KeyDown(KEY_LEFT) Direction = 1 PlayerX:+2 End If If PlayerX - 32 <= 0 PlayerX:+2 ElseIf PlayerX >= 800 - 32 PlayerX:-2 End If End Function '########################################################## '### Function CheckIfPlayerCollideWithTile() # '### Checks to see if the player has collided with a tile # '### Checks also if the Player is falling # '########################################################## Function CheckIfPlayerCollideWithTile() '#Region Select Direction Case 1 If Jump = 0 If Map[(PlayerX - Player_Width) / 32 + 1, PlayerY / 32]= 1 PlayerX:-2 EndIf EndIf If Jump = 1 and PlayerX >= 784 - 32 If Map[(PlayerX - Player_Width) / 32 + 1, PlayerY / 32]= 1 PlayerX:-2 EndIf End If Case 0 If Jump = 0 If Map[(PlayerX + Player_Width) / 32, PlayerY / 32]= 1 PlayerX:+2 End If EndIf End Select '#End Region If Falling = 1 PlayerY:+3.2 If Map[(PlayerX + Player_Width) / 32, PlayerY / 32 + 1]= 1 or Map[(PlayerX - Player_Width * 2) / 32 + 1, PlayerY / 32 + 1]= 1 If (PlayerY mod 32.0) <= 6.4 PlayerY = PlayerY - (PlayerY mod 32) Jump = 0 Falling = 0 CanJump = 1 JumpHeight = 5.5 EndIf EndIf End If If not Map[(PlayerX + Player_Width) / 32, PlayerY / 32 + 1]and not Map[(PlayerX - Player_Width * 2) / 32 + 1, PlayerY / 32 + 1] If Jump = 0 Falling = 1 End If End If End Function '############################################## '### Function DoJump() # '### Makes our player jump # '############################################## Function DoJump() If KeyHit(KEY_SPACE) and CanJump = 1 Jump = 1 CanJump = 0 End If If Jump = 1 PlayerY:-JumpHeight JumpHeight:-Gravity If JumpHeight <= - 1.0 or PlayerY < 32 Falling = 1 EndIf End If End Function '######################################## '### Function DrawMap() # '### We Draw the Map to screen # '######################################## Function DrawMap() For Local x:Int = 0 Until MAPWIDTH For Local y:Int = 0 Until MAPHEIGHT Select Map[x, y] Case 1 DrawImage Tiles, x * 32, y * 32, 0 End Select Next Next End Function '####################################################### '### Function ReadLevelData() # '### We read the data stored in the defdata statements # '####################################################### Function ReadLevelData() For Local y:Int = 0 Until MAPHEIGHT For Local x:Int = 0 Until MAPWIDTH Local Data:Int ReadData Data Map[x, y]= Data Next Next End Function Function getX:Int(x:Int) Return 32 * x '+ offsetX End Function Function getY:Int(y:Int) Return 32 * y '+ offsetX End Function DefData 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1 DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1 DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 0, 0, 0, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 DefData 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 Here is the very simple Single Screen Tilemap Editor. http://www.lunaticninja.com/storage/TileMapEditor.zip '// A simple TileMap Editor which saves and Loads Maps. '// Programmed Amon '// v1.0 SuperStrict '// We setup our Graphics Mode Graphics 800, 600 '// We Load our images, 6 frames in an AnimImage Global Tiles:TImage = LoadAnimImage("tiles.png", 32, 32, 0, 6) '// We setup 2 Constants to hold our MapWidth and MapHeight. Const MAPWIDTH:Int = 25 '// 800/32 = 25 tiles going across the screen Const MAPHEIGHT:Int = 18 ' 600/32 = 18 tiles going down the screen Const TILESIZE:Int = 32 '// Our tiles are 32x32 pixels square '// We setup an Array to hold our map data Global MapArray:Int[MAPWIDTH, MAPHEIGHT] '// We init and prefill the MapArray with a value For Local x:Int = 0 Until MAPWIDTH For Local y:Int = 0 Until MAPHEIGHT MapArray[x, y] = - 1 Next Next '// We set a Global to store the current tile number Global TileSelected:Int = 0 '// We create another variable for holding the mapfile number we save with '// This will increase by 1 everytime we save a map. Global iter:Int = 0 '// We setup our loop While Not KeyHit(KEY_ESCAPE) Cls DrawMap() SelectTile() Place_Tile() SaveMap() LoadMap() Flip Wend '// Our DrawMap Function Function DrawMap() For Local y:Int = 0 Until MAPHEIGHT For Local x:Int = 0 Until MAPWIDTH '//There are 2 ways we can draw the map to screen '// We can use the array data to to select which frame we draw '// or we can write if or case statements for the individual tile. '// I'll show both below. '// Method 1 - Draw with frame data from array. Comment out the line below and comment '// The second method to see how each works 'DrawImage Tiles, x * TILESIZE, y * TILESIZE, MapArray[x, y] '// above we do x*Tilesize, y * Tilesize because as the for loop loops it goes from '// 0 to MAPWIDTH/MAPHEIGHT which is 25 and 18. So , 0 * Tilesize(32) is 0, 1*32 = 32 and so on and it will draw '// the tiles according to where they are in the array. '// Method 2 - If statements If MapArray[x, y] = 0 DrawImage Tiles, x * TILESIZE, y * TILESIZE, 0 ElseIf MapArray[x, y] = 1 DrawImage Tiles, x * TILESIZE, y * TILESIZE, 1 ElseIf MapArray[x, y] = 2 DrawImage Tiles, x * TILESIZE, y * TILESIZE, 2 ElseIf MapArray[x, y] = 3 DrawImage Tiles, x * TILESIZE, y * TILESIZE, 3 ElseIf MapArray[x, y] = 4 DrawImage Tiles, x * TILESIZE, y * TILESIZE, 4 ElseIf MapArray[x, y] = 5 DrawImage Tiles, x * TILESIZE, y * TILESIZE, 5 EndIf Next Next End Function '// Our SelectTile Function Function SelectTile() '// If we hit the space bar we increase the tileSelected variable by 1 '// if Tileselected = 2 then we know we will be drawing image frame 2 to the screen. '// if Tileselected is Greater than 5 (how many images we have in our animimage) then '// we set it to 0. If KeyHit(KEY_SPACE) TileSelected:+1 If TileSelected > 5 Then TileSelected = 0 End If End Function '// Our Place_Tile Function Function Place_Tile() If MouseX() > 0 And MouseX() < 800 '// if the mouse in the screen boundaries If MouseY() > 0 And MouseY() < 600 - 50 '// if the mouse is within the screen and array boundaries If MouseDown(MOUSE_LEFT) '// If we hit or hold MouseLeft '// What this next line does is find what position we are within the MapArray '// and places a tile in that cell. For example if mousex() position = 64 and MouseY() position = 64 '// and we divide by our TileSize then we know that 64/32 = 2 so our mouse will place a tile '// in the place in the MapArray and that screen location. MapArray[MouseX() / TILESIZE, MouseY() / TILESIZE] = TileSelected End If End If End If End Function '// Our LoadMap Function Function LoadMap() If KeyHit(KEY_F5) Local MapFile:String = RequestFile("MapFile", "map") '//We load the map file Local FileToRead:TStream = ReadFile(MapFile) If FileToRead '// if the mapfile has loaded For Local y:Int = 0 Until MAPHEIGHT For Local x:Int = 0 Until MAPWIDTH MapArray[x, y] = ReadInt(FileToRead) Next Next End If End If End Function '// Our SaveMap Function Function SaveMap() '// Below we save our Map when we press F6 If KeyHit(KEY_F6) Local Mapfile:String = "Map" + "_" + iter + ".map" '// Create a MapFile name add an underscore and what '// iter equals to the end of it Local Filewrite:TStream = WriteFile(MapFile) '// We tell max that we want to write a stream called If Filewrite ' if the stream exists For Local y:Int = 0 Until MAPHEIGHT '// Loop through our array For Local x:Int = 0 Until MAPWIDTH'// and save the map data to the file WriteInt FileWrite, MapArray[x, y] '// by writing ints to file Next Next EndIf CloseFile FileWrite '// We close the file when we've finished with it iter:+1 '// add 1 to iter Cls DrawText "MapSaved", 380, 585 '// Display a map save text Flip Delay 1000 End If End Function Hope it helps. :) |
| ||
and here is a really simplified version in case you need more help: edited - been messing with this: it will work even if you change the tilesize. I have a better example in the code archives: http://www.blitzbasic.com/codearcs/codearcs.php?code=2235 |