Javascript: сферные столкновения и возникающий импульс - PullRequest
0 голосов
/ 21 июня 2019

Я довольно новый программист, но я пытаюсь создать свой собственный физический движок без использования каких-либо библиотек.Это для межпланетной игры в мини-гольф.

У меня хорошо работает гравитация, основанная на плотности и расположении планет, и мое обнаружение столкновений работает правильно, но что делать, когда они сталкиваютсяэто то, что я не могу решить.

Планеты не будут двигаться, но использование 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 - просто объект для мяча для гольфа.

Я пробовал различные методы, но я просто не могу заставить коллизии работать должным образом.Кажется, работа с указаниями и углами приносит мне горе.Я провел много исследований, но ничего из того, что я нашел, похоже, не решает мою проблему правильно.

Итак, вот мой вопрос: как я могу рассчитать импульс, используя ванильный JavaScript?

Примечание: Планеты не двигаются, и бодрость должна быть переменной.

Ответы [ 2 ]

1 голос
/ 21 июня 2019

Может ли что-то подобное работать?(двойная проверка на синтаксические ошибки)

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 r = [0, 0]; //radial vector of length one from ball's center to planet's center
    r[0] = (p[0] - ball.coor[0]) / d; // this is the same as cos(angle)
    r[1] = (p[1] - ball.coor[1]) / d; // this is the same as sin(angle)
    // I removed your implementation, it was using redundant expensive calculations
    var m = p[3] * 4 / 3 * Math.PI * p[2] ** 3;
    var f = G * m / d ** 2;
    a[0] = a[0] + f * r[0];
    a[1] = a[1] + f * r[1];
    if (d < p[2] + ball.radius) {
      var dot_v_r = ball.v[0] * r[0] + ball.v[1] * r[1];
      ball.v[0] = bounciness * (ball.v[0] - 2 * dot_v_r * r[0]);
      ball.v[1] = bounciness * (ball.v[1] - 2 * dot_v_r * r[1]);
      // this is complete elastic reflection of the ball, leaving the planet stationary
      // then velocity's magnitude (but not direction) is corrected with bounciness 
    }
});

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

//time_step is a time step, i.e. how frequently you want to update ball's position and velocity
//you can choose a value that makes the update of frames appropriate.  
1 голос
/ 21 июня 2019

Хорошо, я думаю, что это работает.

Дано:

  • Положение планеты как {x, y}
  • Положение шара как {x, y}
  • Скорость мяча как {dx, dy}

Я думаю, что шаги следующие:

  1. Рассчитать угол между осью x и линией между центрами планеты и шара.
  2. Поверните вектор скорости по часовой стрелке на этот угол, другими словами, поверните его на отрицательный угол. Теперь у нас есть вектор скорости, как если бы планета и шар были выровнены по оси x.
  3. Теперь, чтобы «отскочить» от планеты, нам нужно только инвертировать x-компоненту скорости.
  4. Поворот новой скорости против часовой стрелки на угол.

Кажется, работает. Для ясности предположим, что b (шар), p (планета) и v (скорость) являются объектами с x и y членами.

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 вектора на некоторый коэффициент.

...