我在碰撞检测方面遇到了一些问题,除了自己的玩家外,还有2种类型的物体。 Tiles和我称之为MapObjects。
瓷砖都是16x16,其中MapObjects可以是任何一个,但我的问题是它们也是16x16。
当我的播放器运行时,mapobjects或者tile会让它变得非常麻烦。玩家无法向右移动,向左移动时会向前弯曲。
我发现了问题,那就是我的碰撞检测会在侧面碰撞物体时向左/向右移动,如果从上/下碰撞,则向上/向下移动。
现在想象我的玩家在2,12个牌上,在10,12和11,12,并且玩家主要站在11,12牌上。碰撞检测将首先在10,12瓦上运行,它计算碰撞深度,并发现它是侧面的碰撞,因此更多的是右侧的物体。之后它会用11,12进行碰撞检测,这样它会移动角色。因此,玩家不会摔倒,但无法向右移动。当向左移动时,同样的问题会让玩家变形。
这个问题一直困扰着我几天,而我却找不到解决方案!
这是我的代码,用于检测碰撞。
public void ApplyObjectCollision(IPhysicsObject obj, List<IComponent> mapObjects, TileMap map)
{
PhysicsVaraibales physicsVars = GetPhysicsVariables();
Rectangle bounds = ((IComponent)obj).GetBound();
int leftTile = (int)Math.Floor((float)bounds.Left / map.GetTileSize());
int rightTile = (int)Math.Ceiling(((float)bounds.Right / map.GetTileSize())) - 1;
int topTile = (int)Math.Floor((float)bounds.Top / map.GetTileSize());
int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / map.GetTileSize())) - 1;
// Reset flag to search for ground collision.
obj.IsOnGround = false;
// For each potentially colliding tile,
for (int y = topTile; y <= bottomTile; ++y)
{
for (int x = leftTile; x <= rightTile; ++x)
{
IComponent tile = map.Get(x, y);
if (tile != null)
{
bounds = HandelCollision(obj, tile, bounds, physicsVars);
}
}
}
// Handel collision for all Moving objects
foreach (IComponent mo in mapObjects)
{
if (mo == obj)
continue;
if (mo.GetBound().Intersects(((IComponent)obj).GetBound()))
{
bounds = HandelCollision(obj, mo, bounds, physicsVars);
}
}
}
private Rectangle HandelCollision(IPhysicsObject obj, IComponent objb, Rectangle bounds, PhysicsVaraibales physicsVars)
{
// If this tile is collidable,
SpriteCollision collision = ((IComponent)objb).GetCollisionType();
if (collision != SpriteCollision.Passable)
{
// Determine collision depth (with direction) and magnitude.
Rectangle tileBounds = ((IComponent)objb).GetBound();
Vector2 depth = bounds.GetIntersectionDepth(tileBounds);
if (depth != Vector2.Zero)
{
float absDepthX = Math.Abs(depth.X);
float absDepthY = Math.Abs(depth.Y);
// Resolve the collision along the shallow axis.
if (absDepthY <= absDepthX || collision == SpriteCollision.Platform)
{
// If we crossed the top of a tile, we are on the ground.
if (obj.PreviousBound.Bottom <= tileBounds.Top)
obj.IsOnGround = true;
// Ignore platforms, unless we are on the ground.
if (collision == SpriteCollision.Impassable || obj.IsOnGround)
{
// Resolve the collision along the Y axis.
((IComponent)obj).Position = new Vector2(((IComponent)obj).Position.X, ((IComponent)obj).Position.Y + depth.Y);
// If we hit something about us, remove all velosity upwards
if (depth.Y > 0 && obj.IsJumping)
{
obj.Velocity = new Vector2(obj.Velocity.X, 0);
obj.JumpTime = physicsVars.MaxJumpTime;
}
// Perform further collisions with the new bounds.
return ((IComponent)obj).GetBound();
}
}
else if (collision == SpriteCollision.Impassable) // Ignore platforms.
{
// Resolve the collision along the X axis.
((IComponent)obj).Position = new Vector2(((IComponent)obj).Position.X + depth.X, ((IComponent)obj).Position.Y);
// Perform further collisions with the new bounds.
return ((IComponent)obj).GetBound();
}
}
}
return bounds;
}