我的重力模拟卡住了

时间:2017-11-20 17:09:48

标签: javascript arrays html5 physics

我正在制作一个重力模拟器,以获得基于物理的编码的感觉,我在这里提出了一个想法。但是我有一个问题,在弹跳后的一些点之后,粒子(方块)被卡住弹跳到同一点。有谁知道为什么?

这是一个指向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);

1 个答案:

答案 0 :(得分: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.aparticle.ha重命名为particle.vyparticle.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>