Bestlogo56
Bestlogo56

Reputation: 75

My gravity simulation gets stuck

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);

Upvotes: 1

Views: 80

Answers (1)

JLRishe
JLRishe

Reputation: 101672

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>

Upvotes: 3

Related Questions