はじめに
最近、Three.jsにハマっていて物理演算が可能な Cannon.js と組み合わせて何か作りたかった(※物理演算に関する知識はありません)。何を作ろうかと悩んだ末にあるものが思いつきました。
それが 「ニュートンのゆりかご」(正式名称初めて知った)
こういうの↓(Wikipedia)より
初めに結果から
なんか変なのできた。気持ち悪い。
See the Pen Newton's Yurikago by Ryota (@RyotaPen) on CodePen.
ソースはこちら
解説
細かい説明はしませんが、大まかにポイントだけ解説します。
紐
鉄球を吊るしている紐をどのように表現するか?ですが、複数の球を作成しそれぞれを繋ぐ方法でやってみました。いわゆるチェーンってやつです。
この関数でチェーンを生成しています。
/**
* チェーンを生成する
* @param {CANNON.Vec3} origin 基準点(チェーンの始点)
* @param {number} xAngle X角度(°)
* @param {number} zGap Z軸ずらし距離(m)
*/
function createChain(origin, xAngle, zGap){}
生成するチェーンの球を複数生成し、それぞれを固定します。
固定する場合は、CANNON.DistanceConstraint
オブジェクトで固定に関する定義を行い、world.addConstraint
関数で物理演算の世界へ追加します。
world.addConstraint(
new CANNON.DistanceConstraint(
<オブジェクト1>,<オブジェクト2>,<固定する距離>));
}
なお、new CANNON.DistanceConstraint
の第3引数(距離)は省略可能です。省略した場合、現在の位置を使用して固定されます。
鉄球同士が衝突したときの動き
こんな感じで良いのでしょうか…?
とりあえず、気持ちよく跳ね返ってほしいので反発係数は高めに設定。
let contact = new CANNON.ContactMaterial(
pairs[idx - 1].ironSphere.body.material, //ひとつ目
pair.ironSphere.body.material, //ふたつ目
{
contactEquationRelaxation: 3, // 接触式の緩和性
friction: 0.1, //摩擦係数
frictionEquationRelaxation: 3, // 摩擦式の剛性
restitution: 0.9 // 反発係数
}
);
world.addContactMaterial(contact);
一つの鉄球を支えるチェーン同士を固定
これはズルですが、鉄球を支えるチェーン同士がバラバラに動いてしまうので、固定しています。まぁ気休め程度にしか効果がないですが。
for (let i = 0; i < chain1.length; i++) {
// 対向のチェーンと接続
world.addConstraint(
new CANNON.DistanceConstraint(chain1[i].body, chain2[i].body));
}
要改善ポイント?
動きを見ていて、紐(チェーン)が色々な方向へ揺れてしまうことが問題なような気がしてきました。
なので、紐の部分をチェーンではなく、普通に細い棒に変えたらどうなるかはやってみようかなって思っています。
ニュートンのゆりかごの動きをみると紐が曲がることはないので棒でも一緒ですよね。
最後に
急募:綺麗に気持ち良くゆりかごする方法