我们使用JavaScript处理二维图形

朋友们,美好的一天!

创建物理过程的逼真的动画似乎是一项艰巨的任务,但事实并非如此。用于此的算法可以非常简单,同时可以准确地重现诸如运动,加速度和重力(吸引力)之类的物理现象。

想知道如何在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 // vx += ax * dt
vy = 1 += 0 * 0.1 - > 1 // vy += ay * dt
x = 150 += -1.1 * 0.1 - > 149.89 // x += vx * dt;     -0.01
y = 50 += 1 * 0.1 - > 50.1 // y += vy * dt

重力


我们学习了如何移动单个对象。如何学习如何使它们彼此相对移动?这称为重力或重力。为此我们需要做什么?

这就是我们想要得到的:



首先,让我们回想一下中学时代的一些方程式。

施加到由下面的公式计算出的体上的力:
F = M * A ......的力等于质量乘以加速度
α= F /米...从此,我们可以得出这样的结论力作用加速度在物体上

如果我们应用此两个交互对象,我们得到以下信息:



它看起来很复杂(至少对我而言),所以让我们做对吧。在此等式中,| F | -这是力的大小,两个物体都相同,但方向相反。对象由质量m_1和m_2表示。k是重力常数,r是物体质心之间的距离。还不清楚吗?这是一个例子:



如果我们想做一些有趣的事情,我们需要两个以上的对象。



在此图像中,我们看到两个橙色物体以力F_1和F_2吸引黑色,但是我们对合力F感兴趣,可以通过以下公式计算:

  • 首先,我们使用前面的公式计算力F_1和F_2:
  • 然后将所有内容转换为向量:

太好了,我们已经进行了所有必要的计算。我们如何将其转换为代码?我不会对中间步骤感到厌烦,我将立即为完成的代码提供注释。如果您需要更多信息,可以给我写信,我将回答您的所有问题。

function moveWithGravity(dt, o) { // 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) { //     0
                    r = 1
                }

                //     ; k = 1000
                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 / d

s = r_1 + r_2-d ...这是碰撞的“大小”(请参见下图)



在JS中,它可能看起来像所以:

function resolveCollision(info){ // "info" -   Collision   
    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 //   ,   "k"   "s/2"  "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中如何实现物理现象和过程。

All Articles