-
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 08:49 PM.
-
-
Bacon-wrapped closures
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.
-
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 11:54 AM.
-
-
Bacon-wrapped closures
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|