Tile based collisions

BlitzMax Forums/BlitzMax Beginners Area/Tile based collisions

spraycanmansam(Posted 2011) [#1]
Ok so I've been messing with a little tile based platformer and I have two questions...

1/ How do people usually handle collisions? On a tile basis or pixel basis. Or a mix of both?

2/ How do people set the handles for their images? All midhandled?

The reason I ask is my map of tiles are all sized at 16x16 px and my player is 24x24 px ...or would it be better to resize my player to multiples of 16?


Czar Flavius(Posted 2011) [#2]
You can do image collides but I suggest you do the square one. Unless the shape is very irregular, it gives good enough results and is very fast. By irregular I mean oblong. If your player is 24x24, but you collide him as 16x16 it could give an interesting effect. It means he could overlap slightly with an enemy but wouldn't be considered to touch it unless he ran right into it. Could look cool.

Last edited 2011


Jesse(Posted 2011) [#3]
1. it all depends on what you want to do, there is no absolute right or wrong. if you are doing something that is simple and works than that is good enough. Don't complicate your life if you don't need to. the main thing is to get it done. if it's is not working try something different and if none of your ideas solve the problem than ask specific questions and someone might be able to help you.

2. normally you won't need to change the handle from 0,0 to anything else but than again it all depends on what you are doing. You can try it different ways and if changing the handle works for you than stick with it no one will tell you that is wrong.

using a different player size than the tile size is not a problem as long as you know how to deal with collision. Just be logical and if you can't figure it just ask.


Foppy(Posted 2011) [#4]
1. If the tile-graphics are simple squares (filling up all of the tile) you can check whether the a tile is solid the moment he is moving into the tile. (Movement of the player would include automatic vertical movement due to gravity.) You wouldn't need pixel-level collisions because you know that the tile-graphics are like blocks that correspond exactly to the tile system underneath, you can use just numbers to decide where the player can go.

If the tile-graphics include slopes, simple move-into-tiles check are not enough. You then need to work with collisions on pixel level (collisions between the player and the visible tile graphics, or between the player and some kind of silhouette version of the visible tile) or use a kind of height map to determine by numbers what the Y of the player should be given the X of the player on a given tile.

2. I would almost always leave it at 0,0. If you set it as the center of objects I think you would need to subtract and add half the width and height of the image every time you want to do collisions detection. (If you leave it at 0,0 you already know the left and top side of the image, and only have to add height and width to get bottom and right hand sides.)

There can be exceptions, for instance if you never need to do collision checks and/or the image is to be rotated around its center.


ima747(Posted 2011) [#5]
Regarding mid-handling I try to avoid it as it generally simplifies a lot of the position logic and some collision detection (like foppy mentioned) however if you plan on using live changes to the image (such as scaling and rotation) then mid handling makes that MUCH easier. It's a matter of tradeoffs in complexity in one place or another, just depends on where the mental savings make sense.

The "right" way is almost always what makes the most sense to you as the developer. If it's confusing it's hard to maintain and troubleshoot and you're asking for more problems. There's always a "better" way (e.g. faster code, more optimized, etc.) so you just stop when it doesn't make sense to go further (e.g. your code is easy to understand and plenty fast enough for your needs, optimizing past this point just complicates things for you later.)


jalih(Posted 2011) [#6]
For testing players vs level collision, a simple collision map for level and a couple of collision points for the player sprite will do just fine.

For sprite vs sprite collision detection, a combination of simple rectangle based approach and a pixel perfect collision detection works good enough.


Some old platformer test for Windows written in Hollywood using the above mentioned methods: http://xob.kapsi.fi/~ljl/peli/mario.zip

(You need to rename the file: mario.e -> mario.exe to test it.)


Kryzon(Posted 2011) [#7]
For characters I strongly recommend putting the handle at bottom-middle, between their feet - makes the collision logic easier to visualize, if we're talking about a side-scroller. You'd be actually testing their feet.

Last edited 2011


Czar Flavius(Posted 2011) [#8]
Good idea Kryzon!


spraycanmansam(Posted 2011) [#9]
Well thanks for all the replies!

I'm still having a bit of trouble refining my collision code :(
I think it's a combination of where I'm testing for collisions and maybe what order I'm testing.

I'm using Mappy for the Map drawing and collisions. Mappy's collisions by default only test for a collision on the top left corner of a tile.

The problem I'm having is only on the corner tiles. Sometimes when you make the player run and jump into the corner of a platform tile, it's as if the collision logic cant decide if the player has ran into the tile or bumped their head and by the time it does the players head appears to move into the block AND THEN the bump logic works and they fall back down. Run the program and try to recreate the above scenario and you'll see what I mean pretty soon.


Here's a link to the game file:
http://www.mediafire.com/file/8ry715xs4i5vkgy/main.exe

Also a screenshot of the problem:




I've included most of the player movement/collision code for reference as well:


			
		Local 	accel:Float			= 0.2
		Local	friction:Float		= 0.1
		Local	topSpeed:Float		= 2.0
		
		
		'Left and right movement
		
		If KeyDown( KEY_RIGHT )
		
			image = lImage
			direction = DIR_RIGHT

			speed:+ accel
	
		Else If KeyDown( KEY_LEFT ) 
		
			image = rImage
			direction = DIR_LEFT

			speed:- accel		
		
		End If
		
		
		If speed > friction   speed:- friction
		If speed < -friction  speed:+ friction
		
		If speed > topSpeed   speed = topSpeed
		If speed < -topSpeed  speed = -topSpeed
		
		If speed < friction And speed > -friction  speed = 0

		
		'If player isn't in front of blocks, move.
		
		If wall = False
		
			If worldX > 0 And direction = DIR_LEFT
				worldX:+ speed
			Else If X > viewW / 2 And direction = DIR_RIGHT					'If player past half screen, start scrolling.
				worldX:+ speed	
			End If	
				
			X:+ speed
		
		End If
		
		If X < 0  X = 0														'Makes sure player can't walk off screen.

		
		If speed > 0 Or speed < 0											'If player is moving, animate frames.
				
			frame:+ frameSpeed
			If frame >= 4  frame = 0
				
		Else 
			frame = 0	
		End If		
				
		
		
		
		'Jump				
		MAP.mapcurlyr = 0													'Important: Set current layer to test collisions on that layer.		
		
		
		If( KeyHit( KEY_UP ) )  
		
			If( jump = False )												'Only allow jump sound to play once when jumping.
				'If( falling = False )  PlaySound( jumpSnd )
			End If				
			
			jump = True
		
		End If

		If( jump = True )
		
			frame = 4
		
			Y:- jumpHeight
			jumpHeight:- gravity
			
			If( jumpHeight <= 0 )  falling = True							'If player reaches peak of jump, they're falling.

		Else
		
			If( Not MAP.MapCollision( X, Y + MAP.mapblockheight ) )
				If jumpHeight > 0   jumpHeight = 0							'Need to set jumpHeight to 0 so player falls.
				falling = True
			End If
		
		End If
			
					
		'Is player onscreen?
		
		If( Y => 0 )
		
			'Is player falling?
	
			If( falling = True )
				
				jump = 0
				frame = 4
				
				Y:- jumpHeight
				jumpHeight:- gravity
			
			
				If MAP.MapCollision( X, Y + 16 )

					If safeMod( Y, MAP.mapblockheight ) > 0
						Y:- safeMod( Y, MAP.mapblockheight )
					End If
				
					
					'Reset variables.
					
					frame = 0			
					falling = False		
					jumpHeight = 5.2
				
				End If
				
			End If

			
			'Has player walked into block?
			'Checks tiles on either side to see if its a block.
			'X -+ 8 lets the player walk into the block a bit.		
			'Y + 15 fixes the jumping up to the next block glitch by collision checking at bottom of tile.
			'Changing the Y value seems to alter the glitch with afterfects.
			
			If( MAP.MapCollision( X - 8, Y + 15 ) And direction = DIR_LEFT ) Or..
			  ( MAP.MapCollision( X + 8, Y + 15 ) And direction = DIR_RIGHT )
	
			   	speed = 0
			   	accel = 0
				wall = True
			
			Else
	
				wall = False
				
			End If

			
			lastY = Y
					
			If ( MAP.MapCollision( X, Y - 8 ) And jump = True )					'Problem with bump collision/walking collisions affecting ea other.
				
				jumpHeight = 0
				Y = lastY
				
				'PlaySound( bumpSnd )
					
				falling = True
								
			End If


Last edited 2011