我正在尝试创建一个2D平台游戏(马里奥型)游戏,我有些问题正确处理碰撞。我用C ++编写这个游戏,使用SDL进行输入,图像加载,字体加载等。我也通过FreeGLUT库和SDL一起使用OpenGL来显示图形。
我的碰撞检测方法是AABB(Axis-Aligned Bounding Box),这是我真正需要的。我需要的是一种简单的方法来检测碰撞发生在哪一侧并正确处理碰撞。所以,基本上,如果玩家与平台的顶部发生碰撞,请将他重新定位到顶部;如果两侧发生碰撞,请将玩家重新定位回对象的一侧;如果底部发生碰撞,请将玩家重新放置在平台下。
我尝试了 许多 这样做的不同方式,例如尝试找到穿透深度并通过穿透深度向后重新定位玩家。可悲的是,我尝试过的任何东西似乎都没有用。玩家的动作最终会非常小问题,并在我不想要的时候重新定位玩家。部分原因可能是因为我觉得这很简单,但我过分思考了。
如果有人认为他们可以提供帮助,请查看下面的代码,如果可以,请帮助我尝试改进。如果可能的话,我想避免使用库来处理这个问题(因为我想自己学习)或类似SAT(分离轴定理)。提前感谢您的帮助!
void world1Level1CollisionDetection()
{
for(int i; i < blocks; i++)
{
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==true)
{
de2dObj ballPrev;
ballPrev.coords[0] = ball.coords[0];
ballPrev.coords[1] = ball.coords[1];
ballPrev.coords[2] = ball.coords[2];
ballPrev.coords[3] = ball.coords[3];
ballPrev.coords[0] -= ball.xspeed;
ballPrev.coords[1] -= ball.yspeed;
ballPrev.coords[2] -= ball.xspeed;
ballPrev.coords[3] -= ball.yspeed;
int up = 0;
int left = 0;
int right = 0;
int down = 0;
if (ballPrev.coords[0] < block[i].coords[0] && ballPrev.coords[2] < block[i].coords[0] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1])) || ((ball.coords[1] < block[i].coords[3]) || ball.coords[3] < block[i].coords[3])))
{
left = 1;
}
if (ballPrev.coords[0] > block[i].coords[2] && ballPrev.coords[2] > block[i].coords[2] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1])) || ((ball.coords[1] < block[i].coords[3]) || (ball.coords[3] < block[i].coords[3]))))
{
right = 1;
}
if(ballPrev.coords[1] < block[i].coords[1] && block[i].coords[1] < ballPrev.coords[3] && ballPrev.coords[3] < block[i].coords[3])
{
up = 1;
}
if(block[i].coords[1] < ballPrev.coords[1] && ballPrev.coords[1] < block[i].coords[3] && block[i].coords[3] < ballPrev.coords[3])
{
down = 1;
}
cout << left << ", " << right << ", " << up << ", " << down << ", " << endl;
if (left == 1)
{
ball.coords[0] = block[i].coords[0] - 18.0f;
ball.coords[2] = block[i].coords[0] - 2.0f;
}
else if (right == 1)
{
ball.coords[0] = block[i].coords[2] + 2.0f;
ball.coords[2] = block[i].coords[2] + 18.0f;
}
else if (down == 1)
{
ball.coords[1] = block[i].coords[3] + 4.0f;
ball.coords[3] = block[i].coords[3] + 20.0f;
}
else if (up == 1)
{
ball.yspeed = 0.0f;
ball.gravity = 0.0f;
ball.coords[1] = block[i].coords[1] - 17.0f;
ball.coords[3] = block[i].coords[1] - 1.0f;
}
}
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==false)
{
ball.gravity = -0.5f;
}
}
}
解释一些代码的含义:
blocks变量基本上是一个整数,用于存储块或平台的数量。我正在使用for循环检查所有块,并且循环当前所在的数字由整数i表示。 坐标系似乎有点奇怪,所以值得解释。 coords [0]表示对象的x位置(左侧)(从x轴开始)。 coords [1]表示对象的y位置(顶部)(从y轴开始)。 coords [2]表示对象的宽度加上coords [0](右)。 coords [3]代表物体的高度加上coords [1](底部)。 de2dCheckCollision执行AABB碰撞检测。 在大多数游戏中,向上是负y,向下是正y。
希望我已经为某人提供了足够的信息来帮助我成功。如果遗漏的东西可能至关重要,请告诉我,我会提供必要的信息。最后,对于任何可以提供帮助的人来说,提供代码将非常有用并且非常感激。
再次感谢您的帮助!
编辑2 :我使用新算法更新了我的代码,该算法可以检查碰撞之前球的位置。拐角箱现在正确地在单个平台上工作,当我有一堵墙时,我可以现在正确地滑动它。唯一剩下的问题是,当我在地面时会发生一个小的抖动效应,球不断地上下移动,好像被重力拉动,然后球再次落回到物体中。 / p>
修改:以下是试图显示我遇到的各种问题的图片的网址: http://img8.imageshack.us/img8/4603/collisionproblem.png
如果图片中的说明没有太大意义,除非我跳过它,否则球不能向左移动超过物体的角落。但是,球可以向右移动,但在移动时会将其重新定位到对象的右侧,这是不需要的。这基本上创造了一个跳跃运动,当我向右移动时,球在跳过一半物体时出现。如果这没有意义,请问我,我会尝试澄清更多。
答案 0 :(得分:12)
您的代码存在的一个问题是您只能检测到这样的情况:
如果圆圈恰好在整个区域内,则根本不会重新定位。这是一个问题。
你试图将你的模拟看作是连续的,但要记住它是离散的。一般来说,如果你只看球的当前状态,你实在无法知道它与哪一方相撞。看看这两种可能性:
首先想到的解决方案是查看球的最后位置;更准确地说,看看delta矢量。查看delta矢量是否与墙相交。如果是这样,则在轴对齐的方向上重新定位,朝向与delta矢量相交的墙。
编辑:当我说“delta矢量”时,我忘记了你正在移动一个正方形,而不是一个点。所以,如果你只看左上角的三角形矢量,那就不够了,因为它可能无法检测到球的一部分进入一个区块。相反,您可以查看所有4个角的增量矢量。