碰撞检测有问题
我遇到了这个问题,每当我接触地面时,我的速度就会设置为 0。发生这种情况是因为我的函数将我推出去,恰好将我推到了边缘。因此,当我除以该块的高度时,它仍然认为我在该块上。当我跳到最右边的墙上时也会发生这种情况。
例子 : 坐标 0,720 上有一个块,我的 y = 723
723 / 5 = 144(向下舍入)
然后我被推出到 720。但是当我除以块高度时,它仍然认为我正在触摸该块720 直到 725
720 / 5 = 144
我该如何解决这个问题,我的意思是我知道问题是什么,但我看不到任何方法来解决它。
另外,当我不跳跃并且恰好在关卡的右边缘时,我可以通过向右行走来穿过墙壁,但是一旦我跳跃,碰撞检测就会跳入。
我不知道最后一个问题的原因和方式任何人都可以看看会发生什么。
代码 :
void DoCollisions()
{
onGround = false;
Position.Y += Velocity.Y;
Vector2 tileCollision = GetTileCollision();
if (tileCollision.X != -1 || tileCollision.Y != -1)
{
onGround = true;
Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
new Rectangle(
tileCollision.X * World.tileEngine.TileWidth,
tileCollision.Y * World.tileEngine.TileHeight,
World.tileEngine.TileWidth,
World.tileEngine.TileHeight
)
);
Velocity.Y = 0;
Position.Y += collisionDepth.Y;
}
Position.X += Velocity.X;
tileCollision = GetTileCollision();
if (tileCollision.X != -1 || tileCollision.Y != -1)
{
Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
new Rectangle(
tileCollision.X * World.tileEngine.TileWidth,
tileCollision.Y * World.tileEngine.TileHeight,
World.tileEngine.TileWidth,
World.tileEngine.TileHeight
)
);
Velocity.X = 0;
Position.X += collisionDepth.X;
}
}
Vector2 GetTileCollision()
{
int topLeftTileX = (int)(CollisionRectangle.TopLeft.X / World.tileEngine.TileWidth);
int topLeftTileY = (int)(CollisionRectangle.TopLeft.Y / World.tileEngine.TileHeight);
int BottomRightTileX = (int)(CollisionRectangle.DownRight.X / World.tileEngine.TileWidth);
int BottomRightTileY = (int)(CollisionRectangle.DownRight.Y / World.tileEngine.TileHeight);
for (int i = topLeftTileX; i <= BottomRightTileX; i++)
{
for (int j = topLeftTileY; j <= BottomRightTileY; j++)
{
if (World.tileEngine.TileIsSolid(i, j))
{
return new Vector2(i,j);
}
}
}
return new Vector2(-1,-1);
}
I got this problem that whenever I touch the ground my speed is set to 0. It happens because my function that pushes me out pushes me precisely to the edge. So when I then divide by the height of the block it still thinks i'm on that block. This also happens when I jump against the right most wall.
example :
there is a block on coordinates 0,720 and my y = 723
723 / 5 = 144(rounded down)
then I get pushed out to 720. but then when I then divide by the block height it still thinks i'm touching the block thats on 720 till lets say 725
720 / 5 = 144
How can I fix this, I mean I know what the problem is but I can't see any way to fix it.
Also when I am not jumping and precisely at the right edge of the level I can go through the wall by walking to the right, but as soon as I jump the collisions detection jumps in.
I have no idea why and how this last problem is occurring could anyone take a look and see what happens.
Code :
void DoCollisions()
{
onGround = false;
Position.Y += Velocity.Y;
Vector2 tileCollision = GetTileCollision();
if (tileCollision.X != -1 || tileCollision.Y != -1)
{
onGround = true;
Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
new Rectangle(
tileCollision.X * World.tileEngine.TileWidth,
tileCollision.Y * World.tileEngine.TileHeight,
World.tileEngine.TileWidth,
World.tileEngine.TileHeight
)
);
Velocity.Y = 0;
Position.Y += collisionDepth.Y;
}
Position.X += Velocity.X;
tileCollision = GetTileCollision();
if (tileCollision.X != -1 || tileCollision.Y != -1)
{
Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
new Rectangle(
tileCollision.X * World.tileEngine.TileWidth,
tileCollision.Y * World.tileEngine.TileHeight,
World.tileEngine.TileWidth,
World.tileEngine.TileHeight
)
);
Velocity.X = 0;
Position.X += collisionDepth.X;
}
}
Vector2 GetTileCollision()
{
int topLeftTileX = (int)(CollisionRectangle.TopLeft.X / World.tileEngine.TileWidth);
int topLeftTileY = (int)(CollisionRectangle.TopLeft.Y / World.tileEngine.TileHeight);
int BottomRightTileX = (int)(CollisionRectangle.DownRight.X / World.tileEngine.TileWidth);
int BottomRightTileY = (int)(CollisionRectangle.DownRight.Y / World.tileEngine.TileHeight);
for (int i = topLeftTileX; i <= BottomRightTileX; i++)
{
for (int j = topLeftTileY; j <= BottomRightTileY; j++)
{
if (World.tileEngine.TileIsSolid(i, j))
{
return new Vector2(i,j);
}
}
}
return new Vector2(-1,-1);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
一路移动,发生碰撞则弹出的实现策略几乎肯定会出现错误,因为没有简单的方法可以确保弹出代码将您弹回到应该发生碰撞的位置。通常它会向其他方向弹出,因此会出现错误。
不仅仅是您:专业人士也会遇到这个问题。请参阅 tasvideos.org,了解《超级马里奥兄弟》中的碰撞错误集合 由这种移动然后弹出策略引起的游戏。
所以,不要这样做。计算出确切的碰撞点并仅移动到该位置。现在的计算机已经足够快了。
您询问了一种将角色与瓷砖碰撞的推荐方法。好吧,首先考虑角色的单步运动,例如(dx,dy):
我夸大了距离以使示例变得有趣:通常您会期望运动步骤与图块大小相比相当小。
角色可能会接触到与角色命中框的扫描路径相交的所有图块,如下图阴影所示。使用Wu 的直线算法的方法来查找这些图块。
按点击时间对图块进行排序:
角色与编号最小的实心图块发生碰撞。
Your implementation strategy of move all the way, then eject if colliding is pretty much guaranteed to be buggy, because there's no easy way to ensure that the ejection code ejects you back to the point where you should have collided. Often it ejects in some other direction, hence bugs.
It's not just you: professionals encounter this problem too. See tasvideos.org for a collection of collision bugs in the Super Mario Bros games that are caused by this move-then-eject strategy.
So, don't do that. Work out the exact point of collision and move only as far as that. Computers are plenty fast enough these days.
You asked for a recommended method for colliding a character with tiles. Well, start by considering a single step of motion of your character, say (dx, dy):
I've exaggerated the distance to make the example interesting: normally you'd expect the motion steps to be fairly small compared with the tile size.
The character potentially touches all the tiles that intersect the swept path of the character's hit box, shown shaded below. Use an approach along the lines of Wu's line algorithm to find these tiles.
Sort the tiles into order by when they are hit:
The character collides with the lowest-numbered tile that's solid.
您是否尝试过使用调整后的 y 坐标?上移一位仅用于计算。
Have you tried to use an adjusted y coordinate? Move one up for the calculation only.
对于任何与我遇到同样问题的人,我设法解决了它,并认为带有我的代码的pastebin链接会很方便: http:// /pastebin.com/t8PdtDEK
将其添加到我的代码中:
并将其添加到我的获取碰撞方法中:
它的作用是,如果它恰好在边缘上,则减去 1,因此它不会添加该图块。
另外,pastebin 上的链接不包含插值以确保对象不会移动得太快。
感谢大家的帮助!
For anyone coping with the same problem as me I managed to fix it and thought a pastebin link with my code would be handy : http://pastebin.com/t8PdtDEK
Added this to my code :
and added this to my get collision method :
What it does is if its precisely on the edge subtract 1 so it doesn't add that tile.
Also the link on pastebin doesn't contain the interpolation to make sure that the object isn't moving to fast.
Thanks for all the help everyone !