【问题标题】:What is the correct order of operations for collision detection and response?碰撞检测和响应的正确操作顺序是什么?
【发布时间】:2016-06-20 21:22:23
【问题描述】:

我正在尝试制作一个 2D 游戏引擎,但我似乎无法始终让碰撞工作(通常情况下,事情会卡住或相互穿过)。无需过多介绍代码,这里是我更新的顺序。

  1. 获取用户输入并更新玩家速度
  2. 保存每个实体的位置,然后移动速度/更新间隔单位
  3. 检查每个可移动实体是否与所有其他实体发生碰撞。如果实体与某物发生碰撞,则会将其移至旧位置,并为两个碰撞实体设置新速度。

碰撞冲量在这个函数中计算:

private static void CollisionImpulse(PhysicsEntity a, PhysicsEntity b)
    {
        var relative = b.Velocity.Vector - a.Velocity.Vector;
        var normal = Vector2.Normalize(relative);
        var e = Math.Min(a.Material.Elasticity, b.Material.Elasticity);
        var j = (-(1 + e) * Vector2.Dot(relative, normal)) /
                (Vector2.Dot(normal, normal) * (a.InverseMass + b.InverseMass));
        if (double.IsNaN(j)) return;

        var velocityA = normal * (float) (j / a.Mass);
        var velocityB = normal * (float) (j / b.Mass);

        a.Velocity.X -= velocityA.X;
        a.Velocity.Y -= velocityA.Y;

        if (!b.Movable) return;
        b.Velocity.X += velocityB.X;
        b.Velocity.Y += velocityB.Y;
        b.Position = b.OldPosition;
    }

这是检查碰撞的函数:

public override void Update()
        {
            foreach (var entity in Universe.PhysicsEntities)
            {
                if (entity.Equals(this) || entity.Collided) continue;
                CollisionResolution.ResolveCollision(this, entity);
                if (!Collided) continue;
                Position = OldPosition;
                break;
            }
        }

几天来我一直在尝试调整代码,但我不知道出了什么问题。我希望一些新鲜的眼睛可以为我的困境提供一些启示。

【问题讨论】:

  • 您观察到的不良影响是什么?
  • 有很多,因为我一直在更改代码。第一个是如果 A 在 B 旁边,他们几乎没有接触,A 向左移动,B 越过 A。有时 A 和 B 会互相卡住。

标签: c# collision-detection game-engine collision


【解决方案1】:

第 3 步存在一个基本问题“如果实体与某物发生碰撞,则将其移至其旧位置...” - 因为您现在再次移动该实体,您需要重新运行碰撞检测所有以前的实体都针对这个实体,否则你可能会导致重叠。

例如如果您有 3 个台球(A、B、C),您将所有 3 个移动到他们想要的新位置 A'、B'、C'(在您的步骤 2 中)。现在对于第 3 步,您检查 A'B' 和 A'C' 没有碰撞,它们没有碰撞,但是您检查 B'C' 并且它们确实发生了碰撞,所以在您的解决方案中,您移动 B',C ' 回到 B,C - 但现在从技术上讲,您可能已经移动了 B 和/或 C,因此它现在与 A 相交。

要使您的第 3 步有效,您需要:

1) 确保在开始时没有对象重叠,并且每当您在步骤 3 中检测到碰撞时,(a) 对我们之前所说的未与这些对象发生碰撞的每个先前对象重新运行碰撞, 或者继续重新运行整个步骤 3,直到在最后一个循环中没有对象被重置。如果您有很多对象并且它们都开始相互重置,这可能会变得很昂贵。

或:

2) 不是每次都将对象重置到其最后一帧的“安全”位置,而是合成力(即加速度,而不是速度)与对象相互穿透的程度有关。这在 3D 物理引擎中很常见,如果相互渗透过多,可能会导致对象爆炸。

另外请注意,如果您曾经在 1 帧中将对象移动得很远(例如,超过其大小的一半),它可能会穿过另一个对象而不会触发碰撞重叠检测。这通常被称为子弹穿纸问题

【讨论】:

  • 大约一两周前我得出了同样的结论。第 3 步需要在实体被碰撞时递归地向后移动,但您解释它的方式也很有意义。
猜你喜欢
  • 2011-09-05
  • 1970-01-01
  • 2014-04-26
  • 2016-12-19
  • 2017-11-26
  • 1970-01-01
  • 1970-01-01
  • 2016-05-19
  • 2019-10-15
相关资源
最近更新 更多