1

I am making a gravity simulator to get the feel for physics based coding and I have made an idea here. But I have a problem, after some point after bouncing, the particle (square) gets stuck bouncing to the same point. Does anyone know why?

Heres a link to the 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);
Bestlogo56
  • 75
  • 6

1 Answers1

3

The main reason your bounce gets stuck is that you are applying gravity to the dot even when it is on the ground. After that, you reverse its velocity and it flies back up into the air.

You need to check whether it's on the ground and not apply gravity if it is:

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

Once that's fixed, what you'll actually find is that the bounce goes back and forth between its initial height and the ground, and this is to be expected - it's conservation of momentum.

In order to make the bounce more realistic, you need to introduce a "coefficient of restitution" that is less than 1:

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

Once that's done, you get a pretty nice simulation: https://jsfiddle.net/jjndeokk/17/

I've also made the following modifications:

  • Used .forEach so that the code isn't completely littered with [i]s
  • Made the gravity and velocity calculations take time into account
  • Renamed particle.a and particle.ha to particle.vy and particle.vx because those properties were measuring velocity, not acceleration.
  • Moved all of the calculations into the update() function so you don't have most of them in the draw() function.

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>
JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • Thanks so much. That's much more help than I expected. Very helpful. – Bestlogo56 Nov 21 '17 at 14:10
  • I don’t know why you conditionally applied gravity. All you needed was restitution and checking vy instead of a. – cdo256 Nov 22 '17 at 05:50
  • @cdo256 Feel free to provide a fiddle or your own answer if you think there's a better approach. As I stated in my answer, I am conditionally applying gravity because the particle should not be accelerating downward if it is already on the ground. Restitution accounts for the momentum lost in a collision. It doesn't account for an object's inability to accelerate into a surface it is already touching. – JLRishe Nov 22 '17 at 06:10