Я делаю симулятор силы тяжести, чтобы почувствовать физическое кодирование, и я сделал здесь идею. Но у меня есть проблема, после некоторого момента после прыжка частица (квадрат) застревает, подпрыгивая в одну точку. Кто-нибудь знает, почему?
Вот ссылка на 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);
Основная причина, по которой ваш отскок застревает, заключается в том, что вы применяете гравитацию к точке, даже когда она находится на земле. После этого вы меняете скорость, и она возвращается в воздух.
Вам нужно проверить, находится ли он на земле и не применять гравитацию, если это:
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]
sparticle.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>