使用圆数学进行实体碰撞

时间:2016-01-16 23:32:12

标签: javascript physics collision geometry

    function distance(x1, y1, x2, y2) {
            var x = x1 - x2;
            var y = y1 - y2;
            return(Math.sqrt((x*x) + (y*y)))   
    };

    function collisionCirc(circ1, circ2) {
            var d = distance(circ1.x, circ1.y, circ2.x, circ2.y);
            var r = circ1.radius + circ2.radius;
            return(r > d);
    };

    function collisionCircPoint(circ1, circ2) {
            var cx = ((circ1.x * circ2.radius) + (circ2.x * circ1.radius)) / (circ1.radius + circ2.radius);
            var cy = ((circ1.y * circ2.radius) + (circ2.y * circ1.radius)) / (circ1.radius + circ2.radius);
            var p = [cx, cy];
            return p;
    };

    function angleDegrees(x1, y1, x2, y2) {
            return (Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI) + 180;
    };

    function updateCollisions() {
            var a;
            var p;

            Player.hitArea = new PIXI.Circle(Player.sprite.x, Player.sprite.y, 20);
            MapObjects.chest.hitArea = new PIXI.Circle(MapObjects.chest.x, MapObjects.chest.y, 20);

            if (collisionCirc(Player.hitArea, MapObjects.chest.hitArea)) {
                a = angleDegrees(Player.sprite.x, Player.sprite.y, MapObjects.chest.x, MapObjects.chest.y);
                p = collisionCircPoint(Player.hitArea, MapObjects.chest.hitArea);
                        Player.sprite.x = p[0];
                        Player.sprite.y = p[1];
            };

    };

我在地图上有2个精灵,每个都有一个圆圈hitArea定义。我试图做一个平稳的圆形碰撞,玩家无法通过。我想我可以将Player.sprite的坐标设置为碰撞点,但它只是将它转换为MapObjects.chest的坐标,即使碰撞点是正确的并且距离MapObject.chest的中心20像素。我做错了什么或创建碰撞需要什么更多信息,就像我可以围绕圆形对象圈出的JavaScript物理库一样?

2 个答案:

答案 0 :(得分:1)

碰撞点位于玩家和障碍物之间。如果您将玩家移向碰撞点,您实际上是将玩家移近。例如,如果玩家与障碍物之间恰好有40像素(r1 + r2),则碰撞点位于它们之间,距离障碍物仅20 px!

如果你有多个物体,那么在发生碰撞时正确对象是很困难的。如果附近只有一个障碍物,您可以直接将玩家移离障碍物。但是,通过这种方式,玩家可能最终会陷入另一个障碍。

另一个解决方案是回到起点并尝试较小的动作,直到没有碰撞。这样你最终会做对,但这也可能很慢。

数学上正确的解决方案是计算碰撞发生前要移动的最大距离。这是通过求解以下向量方程来完成的:

# p = player position before moving
# o = obstacle position
# u = player direction (unit vector)
# d = distance to move
distance(o, p + d * u) = o.radius + p.radius

这个数学,你可以自己解决,也可以使用像Wolfram Alpha这样的工具。

求解此等式将为您提供零,一或两个可能的距离值。您可以忽略的负值,因为它们意味着玩家已经超越了障碍。如果你只获得一个值,则意味着玩家只会刷过障碍物,你也可以解除障碍物。两个值意味着碰撞发生在这些距离之间;较小的值是碰撞开始的地方,较大的值是玩家已经穿过障碍物的地方。此外,如果一个值是正值而另一个值是负值,则意味着玩家已经在障碍物内,这应该永远不会发生。

如果玩家不能快速移动,你应该对附近的所有障碍物进行此检查,然后根据最小的非阴性结果(即零或正)或更少来移动玩家。 / p>

最后,围绕一个圆形物体,你可以在碰撞后沿垂直方向(左或右,取决于玩家将经过的障碍物的哪一侧)移动玩家一点点,如果这不是& #39;引起任何新的碰撞。

还有许多其他可能的实现。

答案 1 :(得分:0)

        Player.hitArea = new PIXI.Circle(Player.sprite.x, Player.sprite.y, 20);
        MapObjects.chest.hitArea = new PIXI.Circle(MapObjects.chest.x, MapObjects.chest.y, 20);
        if (collisionCirc(Player.hitArea, MapObjects.chest.hitArea)) {
            p = collisionCircPoint(Player.hitArea, MapObjects.chest.hitArea);
            a = angleDegrees(Player.sprite.x, Player.sprite.y, MapObjects.chest.x, MapObjects.chest.y);
                if (Player.sprite.x - MapObjects.chest.x > 0) {
                    Player.sprite.x += 1;
                } else  if (Player.sprite.x + MapObjects.chest.x > 0) {
                    Player.sprite.x -= 1;
                };
                if (Player.sprite.y - MapObjects.chest.y > 0) {
                    Player.sprite.y += 1;
                } else  if (Player.sprite.y + MapObjects.chest.y > 0) {
                    Player.sprite.y -= 1;
                };
            };
        };

我添加了它并且它实际上运行得很好,当在特定角度运行到MapObjects.chest的hitArea时,减去玩家速度稍微太快。稍后再努力。