Мой симулятор гравитации застрял

1

Я делаю симулятор силы тяжести, чтобы почувствовать физическое кодирование, и я сделал здесь идею. Но у меня есть проблема, после некоторого момента после прыжка частица (квадрат) застревает, подпрыгивая в одну точку. Кто-нибудь знает, почему?

Вот ссылка на jsfiddle: https://jsfiddle.net/jjndeokk/6/

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var gravity, objectDensity, force;
gravity = 10.8;

function Object(mass, x, y, w, h, acc, hacc) {
  this.m = mass;
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;
  this.a = acc;
  this.ha = hacc;
};
var particle = [];
var rows = [1];
for (let i = 0, len = rows.length; i < len; i++) {
  particle.push(new Object(10, i * 30, 10, 20, 20, 0, 0));
};

function draw() {
  ctx.clearRect(0, 0, c.width, c.height)
  for (let i = 0, len = particle.length; i < len; i++) {
    ctx.fillRect(particle[i].x, particle[i].y, particle[i].w, particle[i].h)
    particle[i].a += gravity;
    particle[i].ha = 3;
    particle[i].x += particle[i].ha;
    if (particle[i].y + particle[i].h + particle[i].a > c.height) {
      particle[i].y = c.height - particle[i].h;
    } else {
      particle[i].y += particle[i].a;
    }
  }
}

function update() {
  for (let i = 0, len = particle.length; i < len; i++) {
    if (particle[i].a >= 0) {
      if (particle[i].y + particle[i].h >= c.height) {
        particle[i].a *= -1;

      }
    }
  }
  draw();
}
setInterval(update, 60);
Теги:
arrays
physics

1 ответ

3
Лучший ответ

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

Вам нужно проверить, находится ли он на земле и не применять гравитацию, если это:

if (isAboveFloor(particle)) {
  particle.a += gravity;
}

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

Чтобы сделать отскок более реалистичным, вам нужно ввести "коэффициент реституции", который меньше 1:

if (particle.y + particle.h >= c.height) {
  particle.a *= -cRest;   // cRest is between 0 and 1
}

После этого вы получите неплохую симуляцию: https://jsfiddle.net/jjndeokk/17/

Я также внесла следующие изменения:

  • Используется .forEach так что код не полностью завален [i] s
  • Расчеты гравитации и скорости учитывают время
  • Переименовали particle.a.a и particle.ha в particle.vy и particle.vx потому что эти свойства измеряли скорость, а не ускорение.
  • Перемещено все вычисления в функцию update() поэтому у вас не будет большинства из них в функции draw().

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var gravity, objectDensity, force;
gravity = 240; // pixels / second / second
var cRest = 0.6;

var interval = 60;
var secondsPerInterval = interval / 1000;

function Object(mass, x, y, w, h, vxi, vyi) {
  this.m = mass;
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;
  this.vx = vxi;
  this.vy = vyi;
};
var particles = [];
var rows = [1];
for (let i = 0, len = rows.length; i < len; i++) {
  particles.push(new Object(10, i * 30, 10, 20, 20, 40, 0));
};

function draw() {
  ctx.clearRect(0, 0, c.width, c.height);
  particles.forEach(function(particle) {
ctx.fillRect(particle.x, particle.y, particle.w, particle.h);
  })
}

function isAboveFloor(particle) {
  return Math.abs(particle.y + particle.h - c.height) > 1;
}

function update() {
  particles.forEach(function(particle) {
if (particle.vy < 0 || isAboveFloor(particle)) {
  particle.x += particle.vx * secondsPerInterval;
  particle.y = Math.min(particle.y + particle.vy * secondsPerInterval, c.height - particle.h);
  
  // if still above floor, accelerate
  if(isAboveFloor(particle)){
    particle.vy += gravity * secondsPerInterval;
  }
}

if (particle.vy >= 0 && particle.y + particle.h >= c.height) {
  particle.vy *= -cRest;
}
console.log(particle);
  });
  draw();
}
setInterval(update, interval);
<canvas id="canvas" height="600" width="800"></canvas>
  • 0
    Спасибо. Это намного больше, чем я ожидал. Очень полезно.
  • 0
    Я не знаю, почему вы применили гравитацию условно. Все, что вам нужно, это реституция и проверка vy вместо a.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню