Reputation: 75
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
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:
.forEach
so that the code isn't completely littered with [i]
sparticle.a
and particle.ha
to particle.vy
and particle.vx
because those properties were measuring velocity, not acceleration.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