首页 > 解决方案 > Javascript:球体碰撞和产生的脉冲

问题描述

我是一个相当新的程序员,但我正在尝试在不使用任何库的情况下创建自己的物理引擎。这是一款星际迷你高尔夫游戏。

根据行星的密度和位置,我已经使重力工作正常,并且我的碰撞检测工作正常,但是当它们碰撞时该怎么办是我无法解决的。

行星不会移动,但使用 Javascript 来进行计算结果速度所需的三角函数是非常困难的。

这是我的物理代码,使用 requestAnimationFrame 执行:

  var a = [0, 0];
  // p is in the format [x, y, radius, density]
  planets.forEach(function (p) {
    var d = Math.sqrt((p[0] - ball.coor[0]) ** 2 + (p[1] - ball.coor[1]) ** 2);
    var m = p[3] * 4 / 3 * Math.PI * p[2] ** 3;
    var f = G * m / d ** 2;
    var angle = Math.atan2(p[1] - ball.coor[1], p[0] - ball.coor[0]);
    a[0] += f * Math.cos(angle);
    a[1] += f * Math.sin(angle);
    if (d < p[2] + ball.radius) {
      var impulse = [0, 0];
      // What to do here?
      // This is the closest I got:
      var velocitya = Math.atan(b.v[1] / b.v[0]);
      var trianglea = Math.abs(velocitya - angle);
      var currV = Math.sqrt(b.v[0] ** 2 + b.v[1] ** 2);
      var newV = currV * bounciness;
      var newa = (Math.PI / 2 - trianglea) * 2 + velocitya;
      b.v[0] = newV * Math.cos(newa);
      b.v[1] = newV * Math.sin(newa);
      // Somehow I just can't get it right.
      // It's the JavaScript, not the math concepts.
    }
  });

  ball.v[0] += a[0];
  ball.v[1] += a[1];
  ball.coor[0] += ball.v[0];
  ball.coor[1] += ball.v[1];

ball只是高尔夫球的对象。

我尝试了各种方法,但我无法让碰撞正常工作。似乎使用方向和角度让我感到悲伤。我做了很多研究,但我发现没有任何东西似乎可以正确解决我的问题。

所以这是我的问题:如何使用 vanilla JavaScript 计算脉冲?

注意:行星不会移动,弹性应该是一个变量。

标签: javascriptgame-physicstrigonometrycollision

解决方案


好的,我认为这行得通。

鉴于:

  • 行星位置为 {x,y}
  • 球位置为 {x,y}
  • 球速度为 {dx,dy}

我认为步骤如下:

  1. 计算 x 轴与行星和球的中心之间的线之间的角度。
  2. 将速度矢量顺时针旋转该角度,换句话说,将其旋转负角度。现在我们有了速度矢量,就像行星和球在 x 轴上对齐时一样。
  3. 现在,要从地球上“反弹”,我们只需要反转速度的 x 分量。
  4. 通过角度逆时针旋转新速度。

它似乎工作。为清楚起见,我们假设b(ball)、p(planet) 和v(velocity) 是具有xy成员的对象。

function impact(b, p, v) {
    let a = b.x == p.x
            ? Math.PI / 2
            : Math.atan((b.y - p.y) / (b.x - p.x));
    v = rotate(v, -a);
    v.x = -v.x;
    return rotate(v, a);
}

function rotate(p, a) {
    return {
        x: p.x * Math.cos(a) - p.y * Math.sin(a),
        y: p.y * Math.cos(a) + p.x * Math.sin(a)
    );
}

您必须做一些工作才能使用数组等将其转换为您的样式。

如果你想让球慢一点,你也可以想办法做到这一点;最简单的方法是将向量的 x 和 y 分量缩小某个因子。


推荐阅读