Javascript에서 2D 물리 구현
30475 단어 animationwebdevtutorialjavascript
실제 애니메이션의 물리와 실현은 매우 복잡하고 어려워 보일 수 있지만 사실은 그렇지 않다.이러한 알고리즘은 속도, 가속도, 중력을 포함한 각종 물리 개념의 실제 시뮬레이션을 만들어 낼 수 있다.
그러면 자바스크립트에서 2D 물리 시뮬레이션을 실현할 때 이 알고리즘들이 어떻게 작동하는지 봅시다!
여기에서 애니메이션과 예제를 볼 수 있습니다: https://martinheinz.github.io/physics-visual/
TL;DR: 내 저장소에서 소스 코드를 찾을 수 있습니다.https://github.com/MartinHeinz/physics-visual
등속 가속 운동
우리는 가장 기본적인 일부터 물건을 움직인다.
만약 우리가 고른 속도로 운동하기만 한다면, 우리는 다음과 같은 코드를 사용할 수 있다.
function move(dt) {
x += vx * dt;
y += vy * dt;
}
위의 코드에서 x
및 y
은 타원, 다음 vx
및 vy
은 각각 수평축과 수직축의 속도, dt
(시간 증가분) 은 두 타이머 박자 사이의 시간, 자바스크립트의 경우 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;
}
이 코드에서 우리는 x축과 y축의 가속도를 나타내는 ax
과 ay
를 추가했다.우리는 가속도로 속도나 속도의 변화(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; Moved further (-0.01) than in previous example!
y = 50 += 1 * 0.1 -> 50.1 // y += vy * dt;
중력
기왕 우리가 물체를 이동할 수 있다면, 물체를 다른 물체로 옮기는 것은 어떻습니까?이게 중력이야.이 점을 실현하기 위해서 우리는 무엇을 보충해야 합니까?
그냥 우리가 뭘 해야 하는지 알려주고 싶었어요.
먼저 고등학교 때의 몇 가지 등식을 되돌아봅시다.
힘 방정식:
F = m * a ... Force is Mass times Acceleration
a = F / m ... From that we can derive that force acting on some object (mass) accelerates
만약 우리가 지금 그것을 두 물체가 상호작용하는 힘으로 확장하고 싶다면, 우리는 다음과 같은 것을 얻을 수 있다.그것은 좀 복잡해졌기 때문에 (적어도 나에게는) 그것을 분해해 봅시다.이 등식 중
|F|
은 힘의 크기로 두 물체는 모두 같지만 방향이 상반된다.이 물체들은 그 질량m_1
과 m_2
에 의해 표시된다.k
여기는 인력 상수이고 r
이 물체의 중심 거리이다.만약 이것이 여전히 큰 의미가 없다면, 다음은 그림이다.만약 우리가 가시화를 만들고 싶다면, 우리는 최종적으로 두 개 이상의 대상을 얻을 수 있을 것이다. 그렇지?그렇다면 우리가 더 많은 물체가 상호작용할 때 무슨 일이 일어날까?
그림을 보면 두 개의 주황색 물체가 검은색 물체를 끌고 있는 것을 볼 수 있다. 하나는 힘
F_1
과F_2
, 우리가 흥미를 느끼는 것은 최종력F
이다. 우리는 이렇게 계산할 수 있다.F_1
과 F_2
을 사용한다F
: 알겠습니다. 우리는 이미 필요한 수학 지식을 모두 습득했습니다. 지금 코드는 어떻게 됩니까?모든 절차를 생략하고 주석이 있는 최종 코드만 보여 드리겠습니다. 더 많은 정보가 필요하시면 언제든지 연락 주십시오.🙂
function moveWithGravity(dt, o) { // "o" refers to Array of objects we are moving
for (let o1 of o) { // Zero-out accumulator of forces for each object
o1.fx = 0;
o1.fy = 0;
}
for (let [i, o1] of o.entries()) { // For each pair of objects...
for (let [j, o2] of o.entries()) {
if (i < j) { // To not do same pair twice
let dx = o2.x - o1.x; // Compute distance between centers of objects
let dy = o2.y - o1.y;
let r = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
if (r < 1) { // To avoid division by 0
r = 1;
}
// Compute force for this pair; k = 1000
let f = (1000 * o1.m * o2.m) / Math.pow(r, 2);
let fx = f * dx / r; // Break it down into components
let fy = f * dy / r;
o1.fx += fx; // Accumulate for first object
o1.fy += fy;
o2.fx -= fx; // And for second object in opposite direction
o2.fy -= fy;
}
}
}
for (let o1 of o) { // for each object update...
let ax = o1.fx / o1.m; // ...acceleration
let ay = o1.fy / o1.m;
o1.vx += ax * dt; // ...speed
o1.vy += ay * dt;
o1.x += o1.vx * dt; // ...position
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
를 계산한다.만약 그들의 반경이 그들의 거리d
보다 작다면, 그것은 반드시 충돌 중이기 때문에 우리는 새로운 Collision
대상으로 돌아간다.이제 충돌을 해결하기 위해서는 위치 이동의 방향과 크기를 알아야 합니다.
n_x = d_x / d ... this is eigenvector
n_y = d_y / d
s = r_1 + r_2 - d ... s is size of collision (see picture)
따라서 JavaScript 코드에서는 다음과 같이 됩니다.
function resolveCollision(info) { // "info" is a Collision object from above
let nx = info.dx /info.d; // Compute eigen vectors
let ny = info.dy /info.d;
let s = info.o1.r + info.o2.r - info.d; // Compute penetration depth
info.o1.x -= nx * s/2; // Move first object by half of collision size
info.o1.y -= ny * s/2;
info.o2.x += nx * s/2; // Move other object by half of collision size in opposite direction
info.o2.y += ny * s/2;
}
이 충돌 솔루션의 상호 작용 예제를 https://martinheinz.github.io/physics-visual/ 에서 볼 수 있습니다(객체 추진 클릭).힘껏 충돌을 풀다
aaaa와 마지막 퍼즐 - 반탄물체를 통해 충돌을 해결한다.이런 상황에서 모든 수학 연산을 생략하는 것이 가장 좋다. 왜냐하면 이것은 문장의 길이를 배로 증가시킬 수 있기 때문이다. 그래서 내가 너희들에게 말하고자 하는 것은 우리가 동량보존법칙과 에너지보존법칙을 고려해야 한다는 것이다. 이것은 우리가 다음과 같은 신기한 방정식을 구축하고 구하는 데 도움이 된다.
k = -2 * ((o2.vx - o1.vx) * nx + (o2.vy - o1.vy) * ny) / (1/o1.m + 1/o2.m) ... *Magic*
그럼 이 신기한k
은 우리에게 어떤 도움이 될까요?우리는 물체가 이동하는 방향(우리는 이전처럼 특징방향량n_x
과n_y
을 사용하여 계산할 수 있지만, 이동하는 방향이 얼마나 되는지 모른다. 이것이 바로 k
이다.이것이 바로 우리가 벡터(z
를 계산하는 방법이다. 이것은 우리가 이 물체를 어디에서 이동하는지 알려준다.이제 마지막 코드:
function resolveCollisionWithBounce(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;
// Magic...
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; // Same as before, just added "k" and switched to "m" instead of "s/2"
info.o1.vy -= k * ny / info.o1.m;
info.o2.vx += k * nx / info.o2.m;
info.o2.vy += k * ny / info.o2.m;
}
결론
이 글은 많은 수학 지식을 포함하고 있지만 대부분이 간단하기 때문에 나는 이것이 네가 이러한 물리 개념을 이해하고 익히는 데 도움을 줄 수 있기를 바란다.자세한 내용을 보려면 내 저장소 here 와 대화식 프레젠테이션 here 의 코드를 보십시오.
Reference
이 문제에 관하여(Javascript에서 2D 물리 구현), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/martinheinz/implementing-2d-physics-in-javascript-1c99텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)