ソースコードはこちら
https://github.com/horitaku1124/physics_sample/blob/main/sample5/index.html
まずはアニメーションなので、以下の様に requestAnimationFrame
を使用します。これにより大体の環境で 1/60秒毎に animationFrame
が呼ばれるようになります。フレームの描画で Canvas
タグに描画します。
const animationFrame = () => {
// 1フレーム毎の物理計算
...
request = requestAnimationFrame(animationFrame)
}
requestAnimationFrame(animationFrame);
#重力加速度
gravity が重力加速度です。この世界では距離がピクセルの世界ですので、 0.1$px/s^2$ を重力加速度としています。
// 重力によって加速する
obj.speedY += gravity;
// 加速された速度によって移動していく
obj.x += obj.speedX;
obj.y += obj.speedY;
// 横の壁に当たったら進行方向を逆に
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}$
として計算できます。これをコードにしたのが以下になります。
// 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成分に分解してそれぞれ加速度としています。
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;
こちらがその時の動作です。
次は斜面の転がりや、質量保存の法則などを実装していく予定です。