 A Flash Developer Resource Site

1. ## 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:

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!  Reply With Quote

2. 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.  Reply With Quote

3. 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?  Reply With Quote

4. 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

}
}```  Reply With Quote

collision, engine, game, physics, tiles #### Posting Permissions

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

 » Home » Movies » Tutorials » Submissions » Board » Links » Reviews » Feedback » Gallery » Fonts » The Lounge » Sound Loops » Sound FX » About FK » Sitemap 