はじめに
matter.jsでワールドではなくオブジェクトに引力をつけて惑星みたいな挙動を作りたかった。
だいぶ前にもmatter.jsユーザの中でこの機能を欲する声があったらしいが、公式ライブラリではなく、プラグインで対応することになったらしい。
が、そのプラグインは7年前で更新が止まっており、最新のmatter.jsだと動かない...
幸いなことにコード見てみたら意外と簡単な実装だったので自分で再現してみようと思った。
作りたいもの
下記のデモみたいなやつ
実装
※基本的なMatter.jsの設定は実装できている前提
まず下記のAttractor
を準備する。
const setAttractor = (bodyA: Matter.Body, bodyB: Matter.Body) => {
return {
x: (bodyA.position.x - bodyB.position.x) * 1e-6,
y: (bodyA.position.y - bodyB.position.y) * 1e-6,
};
}
これは二つの物体間に発生する引力のベクトルを戻り値として返す。
次にafterUpdate
内で下記のように利用することで引力を付与する仕組みを作ることができる。
Matter.Events.on(engine, 'afterUpdate', (event) => {
let bodies = Matter.Composite.allBodies(engine.world)
for (let i = 0; i < bodies.length; i++) {
const bodyA = bodies[i]
// 引力を付与したい物体の作成時にblackhallBallsという配列にidを追加している
if (blackhallBalls.includes(bodyA.id)) {
for (let j = 0; j < bodies.length; j++) {
const bodyB = bodies[j]
const force = setAttractor(bodyA, bodyB)
// ここで引き寄せられる側の物体に引力を適用する
Matter.Body.applyForce(bodyB, bodyB.position, Matter.Vector.create(force.x, force.y))
}
}
}
})
実際に動かしてみたデモ
それっぽい感じになった!