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