这几天我一直在为此烦恼。更新实体时,我会检查是否存在碰撞,如果它们根据下面的代码发生碰撞,则它们的相应运动值将设置为0.除了某些原因,此代码不能用于检查右侧的碰撞。如果实体前面有2个高墙,它将忽略它。但是,如果我在下面检查它似乎正常,但它会完全停止。
碰撞代码:
public static bool CollidesRight(Level level, Vector2 position, Vector2 motion, int width, int height)
{
Vector2 result = position + motion;
int x1 = (int)(result.X / (float)Tile.TILE_WIDTH);
int x2 = (int)((result.X + (float)width) / (float)Tile.TILE_WIDTH) + 1;
int y1 = (int)(result.Y / (float)Tile.TILE_HEIGHT);
int y2 = (int)((result.Y + (float)height) / (float)Tile.TILE_HEIGHT);
AABB resultBB = new AABB(result, width, height);
for (int i = x1; i < x2; i++)
{
for (int j = y1; j < y2; j++)
{
if (level.GetTileAt(i, j) != 0 && (Tile.TileList[level.GetTileAt(i, j)].IsSolid() || Tile.TileList[level.GetTileAt(i, j)].HasSolidTop()))
{
AABB tile = new AABB(new Vector2(i * 64f, j * 64f), 64, 64);
Console.WriteLine(tile);
return resultBB.Intersects(tile);
}
}
}
return false;
}
这是我的实体的更新代码:
public virtual void Tick()
{
lastMotion = motion;
lastPosition = position;
if (Collision.CollidesBottom(level, position, motion, width, height))
{
onGround = true;
}
else if(!Collision.CollidesBottom(level, position, motion, width, height))
{
onGround = false;
}
if (onGround && !isJumping)
{
motion.Y = 0f;
fallDistance = 0;
}
else if(!onGround)
{
fallDistance++;
motion.Y += gravity * (fallDistance * 0.005f);
}
if (isJumping)
{
timeJumping++;
if (timeJumping > 32)
{
timeJumping = 0;
isJumping = false;
}
else
{
motion.Y = -2.25f;
}
}
position.Y += motion.Y;
if (motion.X != 0)
{
if (motion.X < 0)
{
motion.X += friction;
}
if (motion.X > 0)
{
motion.X -= friction;
}
}
if ((motion.X > 0 && Collision.CollidesRight(level, position, motion, width, height)) || (motion.X < 0 && Collision.CollidesLeft(level, position, motion, width, height)))
{
motion.X = 0f;
}
position.X += motion.X;
//MoveEntity(motion);
}
答案 0 :(得分:0)
我有3个选项。
首先,编辑 - 没关系这个,我误读了你的代码我认为你应该在进行碰撞检查之前添加你的X动作,因为碰撞检查使用它来工作。如果您不想将其添加到实际的玩家动作中,请至少将潜在动作传递给该功能。仅此一点就可以解决所有问但还有另一个问题。
其次,我很确定这是,我怀疑你的位置。当你的OnGround bool设置时,你的位置经常被截断为Int。这意味着它的最小值将是一个整体,下一个单位将是一个整体。在您的来自pastebin的AABB代码中:
if (bb.max.Y <= min.Y || bb.min.Y >= max.Y)
{
return false;
}
即使X坐标相关代码检测到碰撞,此代码也将返回false。您应该修改此处的逻辑,以便在发生冲突时函数返回true,而不是在两次独立检查时返回false 。
第三,假设你的宽度是1个单位,你的瓷砖也是1个单位宽,一个块在x = 2和position.x = 0.5,还有一个非常小的xMotion(或者一个尚未添加的,见答案1):
(占据第0区块和部分第1区块,如此)
[.][ ][X]
当你达到x = 1时你想要停止,因为那样你就会遇到障碍。但是:
x1 =(int)(0.5)= 0
x2 =(int)(0.5 + 1)+ 1 = 2
所以你的循环:
for (int i = x1; i < x2; i++)
检查块0(它是空的,然后检查块1(它是空的)然后停止(因为i == x2)并且从不检查块2.所以你关心的块永远不会得到它的碰撞检查。我认为如果你把它改成
for (int i = x1; i <= x2; i++)
然后一切都会更好地检测到即将发生的碰撞。您可能应该为将来的CollidesTop函数执行类似的操作。
P.S。当然,一次尝试这些答案。 :)