朋友们,美好的一天!创建物理过程的逼真的动画似乎是一项艰巨的任务,但事实并非如此。用于此的算法可以非常简单,同时可以准确地重现诸如运动,加速度和重力(吸引力)之类的物理现象。想知道如何在JS中实现这些算法吗?
示例可以在这里找到。源代码在这里。匀速运动
让我们从运动开始。为了统一运动,我们可以使用以下代码:function move(dt) {
x += vx * dt
y += vy * dt
}
其中x和y是对象的坐标,vx和vy分别是对象沿水平和垂直轴的速度,dt(时间增量-时间增量)是两个计时器标记之间的时间,在JS中等于对requestAnimationFrame的两次调用。例如,如果我们想将一个坐标为150、50的点向西南移动,可以执行以下操作(一个计时器标记或一个步骤):x = 150 += -1 * 0.1 - > 149.9
y = 50 += 1 * 0.1 - > 50.1
即使运动也很无聊,所以让我们的物体加速一下:function move(dt) {
vx += ax * dt
vy += ay * dt
x += vx * dt
y += vy * dt
}
在此,ax和ay分别是沿x和y轴的加速度。我们使用加速度来更改速度(vx / vy)。现在,如果我们采用前面的示例,并沿x轴(向西)添加加速度,则会得到以下结果:vx = -1 += -1 * 0.1 - > -1.1
vy = 1 += 0 * 0.1 - > 1
x = 150 += -1.1 * 0.1 - > 149.89
y = 50 += 1 * 0.1 - > 50.1
重力
我们学习了如何移动单个对象。如何学习如何使它们彼此相对移动?这称为重力或重力。为此我们需要做什么?这就是我们想要得到的:
首先,让我们回想一下中学时代的一些方程式。施加到由下面的公式计算出的体上的力:F = M * A ......的力等于质量乘以加速度α= F /米...从此,我们可以得出这样的结论力作用加速度在物体上如果我们应用此两个交互对象,我们得到以下信息:
它看起来很复杂(至少对我而言),所以让我们做对吧。在此等式中,| F | -这是力的大小,两个物体都相同,但方向相反。对象由质量m_1和m_2表示。k是重力常数,r是物体质心之间的距离。还不清楚吗?这是一个例子:
如果我们想做一些有趣的事情,我们需要两个以上的对象。
在此图像中,我们看到两个橙色物体以力F_1和F_2吸引黑色,但是我们对合力F感兴趣,可以通过以下公式计算:- 首先,我们使用前面的公式计算力F_1和F_2:

- 然后将所有内容转换为向量:

太好了,我们已经进行了所有必要的计算。我们如何将其转换为代码?我不会对中间步骤感到厌烦,我将立即为完成的代码提供注释。如果您需要更多信息,可以给我写信,我将回答您的所有问题。function moveWithGravity(dt, o) {
for (let o1 of o) {
o1.fx = 0
o1.fy = 0
}
for (let [i, o1] of o.entries()) {
for (let [j, o2] of o.entries()) {
if (i < j) {
let dx = o2.x - o1.x
let dy = o2.y - o1.y
let r = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2))
if (r < 1) {
r = 1
}
let f = (1000 * o1.m * o2.m) / Math.pow(r, 2)
let fx = f * dx / r
let fy = f * dy / r
o1.fx += fx
o1.fy += fy
o2.fx -= fx
o2.fy -= fy
}
}
}
for (let o1 of o) {
let ax = o1.fx / o1.m
let ay = o1.fy / o1.m
o1.vx += ax * dt
o1.vy += ay * dt
o1.x += o1.vx * dt
o1.y += o1.vy * dt
}
}
冲突
运动的物体有时会碰撞。碰撞后,要么物体被其他物体推出,要么某些物体从其他物体反弹。首先
,让我们谈谈推送:首先,我们需要确定发生了碰撞:class Collision {
constructor(o1, o2, dx, dy, d) {
this.o1 = o1
this.o2 = o2
this.dx = dx
this.dy = dy
this.d = d
}
}
function checkCollision(o1, o2) {
let dx = o2.x - o1.x
let dy = o2.y - o1.y
let d = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2))
if(d < o1.r + o2.r){
return {
collisionInfo: new Collision(o1, o2, dx, dy, d),
collided: true
}
}
return {
collisionInfo: null,
collided: false
}
}
我们声明一个表示两个碰撞对象的Collision类。在checkCollision函数中,我们首先计算对象的x和y坐标之间的差,然后计算它们的实际距离d。如果对象的半径之和小于它们之间的距离,则说明这些对象发生了碰撞-返回Collision对象。
接下来,我们需要确定位移的方向及其大小(大小):n_x = d_x / d ...这是向量n_y = d_y / ds = r_1 + r_2-d ...这是碰撞的“大小”(请参见下图)
在JS中,它可能看起来像所以:function resolveCollision(info){
let nx = info.dx / info.d
let ny = info.dy / info.d
let s = info.o1.r + info.o2.r - info.d
info.o1.x -= nx * s/2
info.o1.y -= ny * s/2
info.o2.x += nx * s/2
info.o2.y += ny * s/2
}
弹跳
难题的最后一部分是在碰撞中实现一个对象与另一个对象的反弹。我不会给出所有的数学计算,因为这会使本文变得冗长而枯燥,因此我将自己局限于以下事实:我提到了动量守恒定律和能量守恒定律,这有助于得出以下魔术公式:k = -2 *((o2.vx -o1.vx)* nx +(o2.vy-o1.vy)* ny)/(1 / o1.m +1 / o2.m)... *魔术*如何使用魔术k?我们知道对象将向哪个方向移动,但我们不知道要移动多远。这是k。向量(z)的计算方法如下,显示了对象应移动的位置:
代码如下所示:function resolveCollisionWithBounce(info){
let nx = info.dx / info.dy
let ny = info.dy / info.d
let s = info.o1.r + info.o2.r - info.d
info.o1.x -= nx * s/2
info.o1.y -= ny * s/2
info.o2.x += nx * s/2
info.o2.y += ny * s/2
let k = -2 ((info.o2.vx - info.o1.vx) * nx + (info.o2.vy - info.o1.vy) * ny) / (1/info.o1.m + 1/info.o2.m)
info.o1.vx -= k * nx / info.o1.m
info.o1.vy -= k * ny / info.o1.m
info.o2.vx += k * nx / info.o2.m
info.o2.vy += k * ny / info.o2.m
}
结论
这篇文章有很多方程式,但是其中大多数非常简单。我希望本文能对您有所帮助,以了解JS中如何实现物理现象和过程。