Wir arbeiten mit zweidimensionalen Grafiken in JavaScript

Guten Tag, Freunde!

Das Erstellen realistischer Animationen physikalischer Prozesse mag wie eine entmutigende Aufgabe erscheinen, ist es aber nicht. Die dafür verwendeten Algorithmen können sehr einfach sein und gleichzeitig physikalische Phänomene wie Bewegung, Beschleunigung und Schwerkraft (Anziehung) genau wiedergeben.

Möchten Sie wissen, wie diese Algorithmen in JS implementiert sind?



Beispiele finden Sie hier .

Der Quellcode ist hier .

Gleichmäßige und beschleunigte Bewegung


Beginnen wir mit der Bewegung.

Für eine gleichmäßige Bewegung können wir den folgenden Code verwenden:

function move(dt) {
    x += vx * dt
    y += vy * dt
}

Hier sind x und y die Koordinaten des Objekts, vx und vy sind die Geschwindigkeit des Objekts entlang der horizontalen bzw. vertikalen Achse. Dt (Zeitdelta - Zeitdelta) ist die Zeit zwischen zwei Zeitmarken, was in JS zwei Aufrufen von requestAnimationFrame entspricht.

Wenn wir beispielsweise ein Objekt an einem Punkt mit den Koordinaten 150, 50 nach Südwesten verschieben möchten, können wir Folgendes tun (eine Zeitmarke oder einen Schritt):

x = 150 += -1 * 0.1 - > 149.9
y = 50 += 1 * 0.1 - > 50.1

Sogar Bewegung ist langweilig, also geben wir unserem Objekt eine Beschleunigung:

function move(dt) {
    vx += ax * dt
    vy += ay * dt
    x += vx * dt
    y += vy * dt
}

Hier sind ax und ay die Beschleunigung entlang der x- bzw. y-Achse. Wir verwenden die Beschleunigung, um die Geschwindigkeit zu ändern (vx / vy). Wenn wir nun das vorherige Beispiel nehmen und die Beschleunigung entlang der x-Achse (nach Westen) hinzufügen, erhalten wir Folgendes:

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

Schwere


Wir haben gelernt, wie man einzelne Objekte bewegt. Wie wäre es zu lernen, wie man sie relativ zueinander bewegt? Dies nennt man Schwerkraft oder Schwerkraft. Was müssen wir dafür tun?

Folgendes möchten wir erhalten:



Lassen Sie uns zunächst einige Gleichungen aus der High School in Erinnerung rufen.

Die auf den Körper ausgeübte Kraft wird nach folgender Formel berechnet:
F = m * a ... die Kraft ist gleich der Masse mal Beschleunigung
a = F / m ... daraus können wir schließen, dass die Kraft mit Beschleunigung auf das Objekt wirkt.

Wenn wir dies auf zwei anwenden Wenn wir Objekte interagieren, erhalten wir Folgendes:



Es sieht kompliziert aus (zumindest für mich), also lasst es uns richtig machen. In dieser Gleichung ist | F | - Dies ist die Größe der Kraft, die für beide Objekte gleich ist, jedoch in entgegengesetzte Richtungen gerichtet ist. Objekte werden durch die Massen m_1 und m_2 dargestellt. k ist die Gravitationskonstante und r ist der Abstand zwischen den Massenschwerpunkten der Objekte. Immer noch nicht klar? Hier eine Illustration:



Wenn wir etwas Interessantes machen wollen, brauchen wir mehr als zwei Objekte.



In diesem Bild sehen wir zwei orangefarbene Objekte, die mit den Kräften F_1 und F_2 Schwarz anziehen. Wir sind jedoch an der resultierenden Kraft F interessiert, die wir wie folgt berechnen können:

  • Zuerst berechnen wir die Kräfte F_1 und F_2 mit der vorherigen Formel:
  • dann übersetze alles in Vektoren:

Großartig, wir haben alle notwendigen Berechnungen. Wie übersetzen wir das in Code? Ich werde Sie nicht mit den Zwischenschritten langweilen und den fertigen Code sofort mit Kommentaren versehen. Wenn Sie weitere Informationen benötigen, können Sie mir schreiben, ich werde alle Ihre Fragen beantworten.

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
    }
}

Zusammenstoß


Bewegliche Körper kollidieren manchmal. Bei einer Kollision werden entweder Objekte von anderen herausgeschoben oder einige Objekte prallen von anderen ab.



Lassen Sie uns zunächst über das Schieben sprechen: Zunächst müssen wir feststellen, dass es eine Kollision gab:

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
    }
}

Wir deklarieren eine Kollisionsklasse, die zwei kollidierende Objekte darstellt. In der Funktion checkCollision berechnen wir zuerst die Differenz zwischen den x- und y-Koordinaten der Objekte und dann deren tatsächlichen Abstand d. Wenn die Summe der Radien der Objekte kleiner als der Abstand zwischen ihnen ist, gab es eine Kollision dieser Objekte - geben Sie das Kollisionsobjekt zurück.



Als nächstes müssen wir die Richtung der Verschiebung und ihre Größe (Größe)
bestimmen : n_x = d_x / d ... dies ist der Vektor
n_y = d_y / ds

= r_1 + r_2 - d ... dies ist die "Größe" der Kollision (siehe Bild unten)



In JS kann es so aussehen Damit:

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
}

Prallen


Der letzte Teil des Puzzles ist die Implementierung des Abpralls eines Objekts von einem anderen bei einer Kollision. Ich werde nicht alle mathematischen Berechnungen geben, da dies den Artikel sehr lang und langweilig macht. Ich werde mich auf die Tatsache beschränken, dass ich das Gesetz der Impulserhaltung und das Gesetz der Energieerhaltung erwähne, die dazu beitragen, die folgende Zauberformel zu erhalten:

k = -2 * ((o2.vx) - o1.vx) * nx + (o2.vy - o1.vy) * ny) / (1 / o1.m + 1 / o2.m) ... * Magie *

Wie können wir Magie k verwenden? Wir wissen, in welche Richtung sich die Objekte bewegen werden, aber wir wissen nicht, wie weit. Das ist k. So wird der Vektor (z) berechnet, der zeigt, wohin sich die Objekte bewegen sollen:





Der Code sieht folgendermaßen aus:

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
}

Fazit


Der Artikel enthält viele Gleichungen, die meisten sind jedoch sehr einfach. Ich hoffe, dieser Artikel hat Ihnen ein wenig geholfen zu verstehen, wie physikalische Phänomene und Prozesse in JS implementiert werden.

All Articles