c++ - 2D C++ 碰撞检测几近完美,但还不够完美?

标签 c++ collision-detection physics game-physics sdl-2

只是作为这个问题的序言,请注意我不是在问“修复我的代码”,而是我将采用什么技术来修复这个问题。如果我的拼写不是很好,我也深表歉意。

好吧,我有一个 2D 平台游戏,它比较玩家的位置和所有的瓷砖(在一个循环中),相应地解决碰撞。这几乎就是主游戏循环的结构:

  1. 检查所有碰撞(如果碰撞低于 播放器发生)
  2. 获得输入并相应地改变玩家速度
  3. 将重力添加到 Y 速度
  4. 对玩家位置施加速度和摩擦力
  5. 绘制游戏
  6. 重复

但是尽管这个系统可以工作,但碰撞系统有两个小但明显的问题(我提供了图像以使其更容易)。有两个问题,第一个没那么糟糕,但第二个渲染游戏几乎无法玩!

问题 1. 在游戏中左右移动地板时,有时玩家会失去其获得的所有速度,然后必须重新积累该速度。我认为这是因为我的碰撞检测功能有时无法正常返回。这是一张图片:

The prblem that is occuring

我希望这很清楚,只有在穿过大片平坦的土地时,问题才会真正变得明显。

问题 2(这个更糟)问题是玩家基本上可以跳上墙,因为如果你说例如按住左箭头并按住跳跃,玩家就会跳上墙。我假设这是因为如果碰撞来自侧面,我的碰撞检测功能将返回 true(尽管它不应该)。这是另一张图(文字很小,抱歉): Edge collision bug

所以这是我的碰撞检测函数,它应该接受两个“对象”,然后从发生碰撞的第一个对象返回方向,我认为问题是在确定方向时引起的,因为这会导致问题,如上图:

//Find the collision vectors
        float vectorX = (a.Position.x + (a.Scale.x / 2)) - (b.Position.x + (b.Scale.x / 2));
        float vectorY = (a.Position.y + (a.Scale.y / 2)) - (b.Position.y + (b.Scale.y / 2));

        //Find the distance between the two objects
        float deltaWidth = (a.Scale.x / 2) + (b.Scale.x / 2);
        float deltaHeight = (a.Scale.y / 2) + (b.Scale.y / 2);

        //Stores the direction of collision
        Direction collisionDir = Direction::None;

        //Check if the two objects are intersecting on the x and y axis
        if (fabs(vectorX) < deltaWidth && fabs(vectorY) < deltaHeight)
        {
            //The direction of collision
            float directionX = deltaWidth - fabs(vectorX);
            float directionY = deltaHeight - fabs(vectorY);
            
            //Check for vertical collision
            if (directionX >= directionY)
            {
                //Check for collisions from the top
                if (vectorY > 0) 
                {
                    a.Velocity.y = 0;
                    a.Position.y += directionY;
                    collisionDir = Direction::Up;
                }

                //Collisions form the botttom
                else
                {
                    a.Velocity.y = 0;
                    a.Position.y -= directionY;
                    collisionDir = Direction::Down;
                }
            }

            else if (directionX < directionY / 2)
            {
                //Check for collisions from the left
                if (vectorX > 0 )
                {
                    a.Velocity.x = 0;
                    a.Position.x += directionX;
                    collisionDir = Direction::Left;
                }

                //Collisions form the right side
                else
                {
                    a.Velocity.x = 0;
                    a.Position.x -= directionX;
                    collisionDir = Direction::Right;
                }
            }
        }

        //Return the direction.
        return collisionDir;

这将返回一个方向,我的其他代码也会检查该方向是否== Bottom,然后它将允许跳跃。

感谢您的帮助。我正在为 Ludum Dare 练习,因为我计划(可能)制作一个平台游戏,如果我不能弄清楚碰撞检测,我不知道我的游戏会有多好。

最佳答案

我建议的第一件事是让自己成为一个 Vector2D 类,它包含您的 x 和 y 坐标以及一些重载一些运算符以允许两个 Vector2D 的加法和减法以及整数、 float 和 double 的乘法和除法。相信我,这会让您的生活更轻松,因为它们可以容纳您所有的力和碰撞点。

接下来,当我使用您当前使用的碰撞样式时,我总是发现它是:

A)更难调试。

B)其他人更难遵循你的代码。

因此我建议创建一个 Rectangle2D 类来处理与其他 Rectangle 和其他所需功能的碰撞。

作为建议,将左上角和右下角作为矩形中心的 vector ,这使得缩放和碰撞检测更加容易,这也意味着您可以导出其他角而无需直接存储它们。

下面是一个代码示例,可能会对我要解释的内容有所帮助:

bool Intersects(Rectangle2D other)
{
    //Checks the right, left, bottom then top of the rectangle
    //against the other.
    if(other.topLeftCorner.x >= bottomRightCorner.x       //Checks the right
        || other.bottomRightCorner.x <= topLeftCorner.x   //Checks the left
        || other.topLeftCorner.y >= bottomRightCorner.y   //Checks the bottom
        || other.bottomRightCorner.y <= topLeftCorner.y)  //Checks the top
        return false;
    else
        return true;
}

您可以轻松地操纵此代码来为您指定碰撞的方向。希望这会有所帮助。

关于c++ - 2D C++ 碰撞检测几近完美,但还不够完美?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36589856/

相关文章:

c++ - 如何生成 cv::Mat 类型的代码?

c++ - 后增量和前增量概念?

Javascript 碰撞检测

python - DataFrame 的派生

c++ - Cuda 数学与 C++ 数学

c++ - 如何通过蓝牙从 iPhone/iPod Touch 向 Windows C++ 应用程序发送流数据?

c++ - 为什么在使用 `std::views::reverse` 时对过滤函数进行了多余的调用?

python - 椭圆和圆之间的碰撞检测

libgdx - 矩形重叠方法 libgdx

physics - 计算两个圆之间的碰撞时间 - 物理