Tile-based 2D collision detection problems
I'm trying to follow this tutorial http://www.tonypa.pri.ee/tbw/tut05.html to implement real-time collisions in a tile-based world.
I find the cente开发者_Python百科r coordinates of my entities thanks to these properties:
public float CenterX
{
get { return X + Width / 2f; }
set { X = value - Width / 2f; }
}
public float CenterY
{
get { return Y + Height / 2f; }
set { Y = value - Height / 2f; }
}
Then in my update method, in the player class, which is called every frame, I have this code:
public override void Update()
{
base.Update();
int downY = (int)Math.Floor((CenterY + Height / 2f - 1) / 16f);
int upY = (int)Math.Floor((CenterY - Height / 2f) / 16f);
int leftX = (int)Math.Floor((CenterX + Speed * NextX - Width / 2f) / 16f);
int rightX = (int)Math.Floor((CenterX + Speed * NextX + Width / 2f - 1) / 16f);
bool upleft = Game.CurrentMap[leftX, upY] != 1;
bool downleft = Game.CurrentMap[leftX, downY] != 1;
bool upright = Game.CurrentMap[rightX, upY] != 1;
bool downright = Game.CurrentMap[rightX, downY] != 1;
if(NextX == 1)
{
if (upright && downright)
CenterX += Speed;
else
CenterX = (Game.GetCellX(CenterX) + 1)*16 - Width / 2f;
}
}
downY, upY, leftX and rightX should respectively find the lowest Y position, the highest Y position, the leftmost X position and the rightmost X position. I add + Speed * NextX because in the tutorial the getMyCorners function is called with these parameters:
getMyCorners (ob.x+ob.speed*dirx, ob.y, ob);
The GetCellX and GetCellY methods:
public int GetCellX(float mX)
{
return (int)Math.Floor(mX / SGame.Camera.TileSize);
}
public int GetCellY(float mY)
{
return (int)Math.Floor(mY / SGame.Camera.TileSize);
}
The problem is that the player "flickers" while hitting a wall, and the corner detection doesn't even work correctly since it can overlap walls that only hit one of the corners. I do not understand what is wrong. In the tutorial the ob.x and ob.y fields should be the same as my CenterX and CenterY properties, and the ob.width and ob.height should be the same as Width / 2f and Height / 2f. However it still doesn't work.
Thanks for your help.
EDIT - Oops, you're right. CenterX is a pixel coordinate, which GetCellX converts to a tile coordinate, so the code is equivalent. It really is particularly hard to follow.
At this point I am beginning to think we do not have enough information to answer your question. Here are some ideas:
Is Speed a whole number? Are your coordinates whole numbers? It looks like it's possible to pass 0.5 pixels into a wall without colliding, but when you pass in 1.0 pixels you'll be snapped back. If the speed and coordinates are whole numbers that won't happen, which is how I assume the tutorial works, but if any fractions get in then you might see some jittering.
Does anything significant happen in base.Update()? When does rendering happen? Does anything else move the player between calls to Update()?
How are the map and player rendered? Is it possible that they are accidentally being rendered in the wrong place relative to each other? I don't think that would cause your flickering problem, but it might contribute to your problem of the collision detection sometimes letting you through.
Old answer:
The tutorial isn't particularly clear itself: it's pretty hard to understand what it's supposed to be doing. Where you have (Game.GetCellX(CenterX) + 1)*16 - Width / 2f
the tutorial has (ob.xtile+1)*game.tileW-ob.width
. These are different. The tutorial takes a tile index, adds one to get the next tile over, then converts to an x coordinate. Your code takes a tile index, converts to an x coordinate, and then adds one pixel. That is probably at least partially responsible for your flickering.
Its hard to tell what's going on here. You might try to narrow down the problem a bit more if possible, and tell us what some of your magic numbers and variables mean. But from my own experience with collision detection, you're player might be flickering because the code is moving his position into the wall and the resetting it back because its not allowed. The collision check needs to be done after getting input and before you update the position.
Something like: (pseudocodish..)
if(input == "right" && !(Tile.right.collidable))
{
//vector.speed = {1, 0, 0};
}
else
{
//vector.speed = {0, 0, 0};
}
Perhaps not exactly like this, but I hope it helps. Cheers~
精彩评论