Tile-based collision detection
A Flash Developer Resource Site

Results 1 to 4 of 4

Thread: Tile-based collision detection

  1. #1
    Junior Member
    Join Date
    Dec 2003
    Location
    Netherlands
    Posts
    6

    Lightbulb Tile-based collision detection

    Hello guys,

    I've been working on a little game project of mine where I have a tile-based engine.
    I've got a lot so far... But the collision detection is not working for me.
    As far as I can see, it should work, but it just doesn't somehow.

    I've got a demo here:
    http://murtada.nl/experiments/tiles/

    Move with WASD keys.

    The edge function for collidable tiles:
    Code:
    function get_edges(object):Array
    {
    	var r = Math.floor(Math.round(object.x+object.speedX+object.width*0.5)/WORLD.tileWidth);
    	var l = Math.floor(Math.round(object.x+object.speedX-object.width*0.5)/WORLD.tileWidth);
    	var b = Math.floor(Math.round(object.y+object.speedY+object.height*0.5)/WORLD.tileHeight);
    	var t = Math.floor(Math.round(object.y+object.speedY-object.height*0.5)/WORLD.tileHeight);
    	
    	var tr = currentLevel[t][r];
    	var tl = currentLevel[t][l];
    	var bl = currentLevel[b][l];
    	var br = currentLevel[b][r];
    	
    	var finalArray:Array = new Array();
    	finalArray["tr"] = tr;
    	finalArray["br"] = br;
    	finalArray["bl"] = bl;
    	finalArray["tl"] = tl;
    	finalArray["b"] = b;
    	finalArray["t"] = t;
    	finalArray["l"] = l;
    	finalArray["r"] = r;
    	return finalArray;
    }
    and here's the code for the actual collision detection and collision resolving:

    Code:
    function CollisionObjectTile(object)
    {
    	var edges:Array = get_edges(object);
    
    	// GOING DOWN
    	if (object.speedY > 0)
    	{
    		if (in_array(edges["br"],collidables) || in_array(edges["bl"],collidables))
    		{
    			object.speedY = 0;
    			object.y = edges["b"] * WORLD.tileHeight - object.height * 0.5;
    			object.onGround = true;
    
    			if (! object.walking)
    			{
    				object.speedX *=  WORLD.groundFriction;
    			}
    		}
    	}
    	// GOING UP
    	else if (object.speedY < 0)
    	{
    		if (in_array(edges["tr"],collidables) || in_array(edges["tl"],collidables))
    		{
    			object.speedY = 0;
    			object.y = (edges["t"]+1) * WORLD.tileHeight + object.height * 0.5;
    			if (! object.walking)
    			{
    				object.speedX *=  WORLD.groundFriction;
    			}
    		}
    	}
    
    	edges = get_edges(object);
    	// GOING LEFT
    	if (object.speedX < 0)
    	{
    		if (in_array(edges["tl"],collidables) || in_array(edges["bl"],collidables))
    		{
    			object.x = (edges["l"]+1) * WORLD.tileWidth + object.width * 0.5;
    			object.speedX = 0;
    		}
    
    		
    	}
    	// GOING RIGHT
    	else if (object.speedX > 0)
    	{
    		if (in_array(edges["tr"],collidables) || in_array(edges["br"],collidables))
    		{
    			object.x = edges["r"] * WORLD.tileWidth - object.width * 0.5;
    			object.speedX = 0;
    
    		}
    	}
    }
    I'd greatly appreciate it if someone could point me in the right direction or figure out what exactly I am doing wrong.

    Thanks!
    Last edited by Murtada-King; 08-12-2011 at 09:49 PM.
    -

  2. #2
    Bacon-wrapped closures Nialsh's Avatar
    Join Date
    Dec 2003
    Location
    Houston!
    Posts
    338
    You're checking the vertical cases before the horizontal cases, so they're winning every time.

    Try making them weaker.

    Code:
    function CollisionObjectTile(object)
    {
    	var BOUNCE = 0.5;
    	var edges:Array = get_edges(object);
    
    	// GOING DOWN
    	if (object.speedY > 0)
    	{
    		if (in_array(edges["br"],collidables) || in_array(edges["bl"],collidables))
    		{
    			object.speedY = -Math.abs(object.speedY) * BOUNCE;
    			object.y += object.speedY;
    			object.onGround = true;
    
    			if (! object.walking)
    			{
    				object.speedX *=  WORLD.groundFriction;
    			}
    		}
    	}
    	// GOING UP
    	else if (object.speedY < 0)
    	{
    		if (in_array(edges["tr"],collidables) || in_array(edges["tl"],collidables))
    		{
    			object.speedY = Math.abs(object.speedY) * BOUNCE;
    			object.y += object.speedY;
    			if (! object.walking)
    			{
    				object.speedX *=  WORLD.groundFriction;
    			}
    		}
    	}
    
    	edges = get_edges(object);
    	// GOING LEFT
    	if (object.speedX < 0)
    	{
    		if (in_array(edges["tl"],collidables) || in_array(edges["bl"],collidables))
    		{
    			object.speedX = Math.abs(object.speedX) * BOUNCE;
    			object.x += object.speedX;
    		}
    
    		
    	}
    	// GOING RIGHT
    	else if (object.speedX > 0)
    	{
    		if (in_array(edges["tr"],collidables) || in_array(edges["br"],collidables))
    		{
    			object.speedX = -Math.abs(object.speedX) * BOUNCE;
    			object.x += object.speedX;
    
    		}
    	}
    }
    Setting the position directly can be a jarring thing. Unless you can get your conditions perfect, it looks more natural to manipulate the velocity.

  3. #3
    Junior Member
    Join Date
    Dec 2003
    Location
    Netherlands
    Posts
    6
    Thank you for your response Nialsh,

    I always did it that way before, adjusting velocity instead of directly change the position of the object. But it's really not what I want for this project. A player is not supposed to bounce, he has to just stop when he reaches the ground.
    Besides, the ground is like quicksand now, I still need to move the player above/below the tile directly through the x/y coordinates so it won't slowly "fall" inside the tile. And then we have another problem: the bounce will have the player "blink" for 1 vertical coordinate all the time.

    I just don't understand why it's not working correctly. When you move left/right, object.speedX becomes greater or less than zero. Then I check for the edges top left or bottom left if object.speedX < 0 (because the player is moving to the left) and top right or bottom right if object.speedX > 0 (because player is moving to the right).

    So what I noticed is that the bottom edges seem to be inside a tile, causing the player to move very abruptly to the edge of a tile horizontally. But this shouldn't happen since I first check the vertical collisions (top left, top right and bottom left, bottom right) - meaning I put the object above the tiles so it won't collide with the tiles at the bottom at all (for at least one frame).

    But still even after I update the edges, they seem to be inside the tiles below.
    What am I not seeing?

    Edit: so I just changed this line:
    Code:
    object.y = edges["b"] * WORLD.tileHeight - object.height * 0.5;
    to
    Code:
    object.y = (edges["b"] * WORLD.tileHeight - object.height * 0.5)-1;
    and it fixed a lot of problems. But still, I have some issues with jumping against vertically stacked tiles. So for example, if you hold down left/right and want to jump on a tile, it notices that the top edge of the object sticks inside the tile (because of holding the left/right key, you are adding horizontal velocity to the object).

    Any thoughts?
    Demo here: http://murtada.nl/experiments/tiles/v4/
    Last edited by Murtada-King; 08-24-2011 at 12:54 PM.
    -

  4. #4
    Bacon-wrapped closures Nialsh's Avatar
    Join Date
    Dec 2003
    Location
    Houston!
    Posts
    338
    If you're pretty certain that you won't change your mind about representing the player's shape as a non-rotating rectangle, you can keep the math simple. Just check to see which dimension has the least overlap, and correct that one.

    Code:
    function CollisionObjectTile(object)
    {
    	var edges:Array = get_edges(object);
    
    	yOverlap = 0;
    	// GOING DOWN
    	if (object.speedY > 0)
    	{
    		if (in_array(edges["br"],collidables) || in_array(edges["bl"],collidables))
    		{
    			yOverlap = Math.abs(edges["b"] * WORLD.tileHeight - object.height * 0.5 - object.y);
    		}
    	}
    	// GOING UP
    	else if (object.speedY < 0)
    	{
    		if (in_array(edges["tr"],collidables) || in_array(edges["tl"],collidables))
    		{
    			yOverlap = Math.abs((edges["t"]+1) * WORLD.tileHeight + object.height * 0.5 - object.y);
    		}
    	}
    
    	edges = get_edges(object);
    	xOverlap = 0;
    	// GOING LEFT
    	if (object.speedX < 0)
    	{
    		if (in_array(edges["tl"],collidables) || in_array(edges["bl"],collidables))
    		{
    			xOverlap = Math.abs((edges["l"]+1) * WORLD.tileWidth + object.width * 0.5 - object.x);
    		}
    
    		
    	}
    	// GOING RIGHT
    	else if (object.speedX > 0)
    	{
    		if (in_array(edges["tr"],collidables) || in_array(edges["br"],collidables))
    		{
    			xOverlap = Math.abs(edges["r"] * WORLD.tileWidth - object.width * 0.5 - object.x);
    		}
    	}
    
    	if (xOverlap < yOverlap && xOverlap != 0) { // handle X collision
    		
    	} else if (yOverlap != 0) { // handle Y collision
    		
    	}
    }

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center

Poll by Flashkit.com