2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JavaScriptで物理エンジンを構築1

Last updated at Posted at 2021-06-08

ソースコードはこちら
https://github.com/horitaku1124/physics_sample/blob/main/sample5/index.html

まずはアニメーションなので、以下の様に requestAnimationFrame を使用します。これにより大体の環境で 1/60秒毎に animationFrame が呼ばれるようになります。フレームの描画で Canvas タグに描画します。

.js
const animationFrame = () => {
  // 1フレーム毎の物理計算

  ...

  request = requestAnimationFrame(animationFrame)
}


requestAnimationFrame(animationFrame);

#重力加速度

gravity が重力加速度です。この世界では距離がピクセルの世界ですので、 0.1$px/s^2$ を重力加速度としています。

.js
// 重力によって加速する
obj.speedY += gravity;
// 加速された速度によって移動していく
obj.x += obj.speedX;
obj.y += obj.speedY;
.js
// 横の壁に当たったら進行方向を逆に
if (obj.x < radius) {
  obj.x = radius;
  obj.speedX *= -1;
} else if (obj.x > canvasWidth - radius) {
  obj.x = canvasWidth - radius;
  obj.speedX *= -1;
}

// 床に接触するたびに上方向に反発する。
if (obj.y > canvasHeight - radius) {
  obj.y = canvasHeight - radius;
  obj.speedY *= -0.5;
  obj.speedX *= 0.9; // 床に接触した際の摩擦を計算
}

また壁にぶつかった場合は進行方向を逆転したり、床に接触した場合は速度を減らして反転したりしています。

これを実装した時のデモが以下になります。

#ボール同士の衝突判定

今度はボール同士が衝突した場合を考えます。
衝突した時のエネルギー保存則として、衝突前のエネルギーと衝突後のエネルギーは等しいとして以下の式で表せます。

$ma \times va+mb \times vb = ma' \times va' + mb' \times vb'$

そしてもう一つが反発係数です。

$C = -\frac{va' - vb'}{va - vb}$

この2つの公式を変形して解くと衝突後の速度 va',_vb'_は

$va' = \frac{va + vb - C(va - vb)}{2}$

$vb' = \frac{va + vb - C(vb - va)}{2}$

として計算できます。これをコードにしたのが以下になります。

.js
// 2つのオブジェクト間の距離が0以下なら衝突判定
let distance = Math.sqrt(Math.pow(obj.x - obj2.x, 2) + Math.pow(obj.y - obj2.y, 2)) - 2 * radius;
if (distance < 0) {
  distance = Math.abs(distance);
  // 2つのオブジェクトの角度
  const theta = Math.atan2(obj2.y - obj.y, obj2.x - obj.x);

  // オブジェクト間の直線速度を計算する
  const va = Math.sqrt(Math.pow(obj.speedX, 2) + Math.pow(obj.speedY, 2));
  const vb = -Math.sqrt(Math.pow(obj2.speedX, 2) + Math.pow(obj2.speedY, 2));
  // 衝突後の速度の計算
  const va2 = (va + vb - Bounce * va + Bounce * vb) / 2;
  const vb2 = (va + vb + Bounce * va - Bounce * vb) / 2;

このソースの動作デモは以下になります。

#振り子

振り子の実装に関しては参考にしているものは無く、自己流となりました。
_distance_というのは固定部分までの距離で、先端が重力で下に落ちた時に固定部分までの距離の増分をx成分とy成分に分解してそれぞれ加速度としています。

.js
let distance = Math.sqrt(
    Math.pow(obj.x - obj.consTo.x, 2)
    + Math.pow(obj.y - obj.consTo.y, 2)
);
// 計算の結果、制約から離れてしまった分を補正する
let ratio = distance / obj.distance;
// その時の差分を移動エネルギーとする
let x2 = (obj.x - obj.consTo.x) / ratio + obj.consTo.x;
let y2 = (obj.y - obj.consTo.y) / ratio + obj.consTo.y;
obj.speedX += x2 - obj.x;
obj.speedY += y2 - obj.y;
obj.x = x2;
obj.y = y2;

こちらがその時の動作です。

次は斜面の転がりや、質量保存の法則などを実装していく予定です。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?