【问题标题】:2D C++ Collision detection almost perfect, but not quite?2D C++ 碰撞检测几乎完美,但还不够完美?
【发布时间】:2016-04-13 06:03:00
【问题描述】:

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

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

  1. 检查所有碰撞(如果碰撞低于 玩家发生)
  2. 获取输入并相应地更改玩家速度
  3. 为 Y 速度添加重力
  4. 将速度和摩擦力应用于玩家的位置
  5. 画出游戏
  6. 重复

但是,尽管这个系统可以正常工作,但碰撞系统仍有两个小问题,但很明显(我提供了图像以使其更容易)。有两个问题,第一个还不错,第二个渲染游戏几乎没法玩!

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

我希望这很清楚,只有在跨越许多平地时问题才会真正显现出来。

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

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

//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;

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

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

【问题讨论】:

  • 将日志记录添加到您的游戏中,这将写入与碰撞检测相关的所有数据。通过这种方式,您将能够找到其行为不正确的条件。

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


【解决方案1】:

我建议的第一件事是让自己成为一个 Vector2D 类,它保存你的 x 和 y 坐标和一些重载一些运算符,以允许两个 Vector2D 的加法和减法以及整数、浮点数和双精度数的乘法和除法。相信我,这会让你的生活变得更轻松,因为它们可以控制你所有的力量和碰撞点。

接下来当我使用了你目前使用的碰撞样式时,我一直发现它是:

A)更难调试。

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

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

建议将左上角和右下角作为矩形中心的向量,这样可以更轻松地进行缩放和碰撞检测,这也意味着您可以导出其他角而无需直接存储它们。

这是一个代码示例,可能有助于我解释的内容:

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;
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-20
    • 1970-01-01
    • 2015-09-22
    • 1970-01-01
    • 1970-01-01
    • 2013-09-03
    • 1970-01-01
    相关资源
    最近更新 更多