メインコンテンツまでスキップ

衝突イベント

2つのRigidBodyが接触すると、物理エンジンはその接触を両方のエンティティに通知します。サウンドを再生したり、ダメージを与えたり、パーティクルを生成したり、ゲームの状態を変えたりして応答できます。イベントは、関係する各エンティティのCollisionコンポーネントとRigidBodyコンポーネントの両方で発火するため、都合のよい方で監視できます。

イベント

イベント発火するタイミングハンドラーの引数
collisionstart2つのボディが接触し始めた物理ステップで1回ContactResult
contactボディが接触している間、毎物理ステップContactResult
collisionendボディの接触が終わったときに1回相手のEntity

接触が通知されるのは、2つのボディのうち少なくとも1つがDynamicな場合だけです。StaticなボディとKinematicなボディが互いに衝突することはありません。トリガーボリュームとの重なりでは、これらのイベントの代わりにtriggerentertriggerleaveが発火します。

衝突の監視

onで購読するとEventHandleが返されます。そのハンドルを保持し、リスナーが不要になったらハンドルのoff()メソッドを呼び出します。イベントで説明しているように、同じコールバックをコンポーネントのoff(eventName, callback)に渡してもリスナーを解除できます。衝突音のような1回限りの反応にはcollisionstartを、毎ステップ更新される接触の詳細が必要な場合にはcontactを使用します。

const handle = entity.collision.on('collisionstart', (result) => {
console.log(`${entity.name} hit ${result.other.name}`);
});

// 後で、エンティティが破棄されたときやリスナーが不要になったときに
handle.off();

このコードをどこに置くかは、構築方法によって異なります。

上記のようにエンティティにコンポーネントが揃った後で購読するか、Editorタブに示すようにエンティティにアタッチしたScriptから購読します。スクリプトについてはスクリプティングセクションを参照してください。

接触データ

collisionstartcontactは、2つのプロパティを持つContactResultを渡します。

  • other - このボディが衝突した相手のエンティティ。
  • contacts - ContactPointオブジェクトの配列。2つの形状が触れている点ごとに1つ。

各接触点には次の情報が含まれます。

プロパティ説明
pointこのエンティティ上の接触点(ワールド空間)
pointOther相手のエンティティ上の接触点(ワールド空間)
localPointこのエンティティのローカル空間での接触点
localPointOther相手のエンティティのローカル空間での接触点
normalワールド空間での接触法線。接触点において相手のエンティティの表面から離れる方向を指します
impulse物理エンジンがボディを分離するために加えたインパルス。値が大きいほど強い衝突です

インパルスは、2つのボディがどれだけ強くぶつかったかを表す便利な指標です。サウンドの音量やダメージ量のスケーリングに使ったり、かすっただけの接触を無視したりできます。

entity.collision.on('collisionstart', (result) => {
let strongest = 0;
for (const contact of result.contacts) {
strongest = Math.max(strongest, contact.impulse);
}
if (strongest > 5) {
entity.sound.play('crash');
}
});

シーン全体の接触

例えば集中管理型のオーディオやダメージのマネージャーのように、すべての接触を1か所で処理するには、個々のエンティティではなくRigidBodyコンポーネントシステムのcontactイベントを監視します。このイベントは接触点ごとに1回発火し、両方のエンティティを示すSingleContactResultを渡します。

app.systems.rigidbody.on('contact', (result) => {
// result.a と result.b が2つのエンティティ
// result.pointA、result.pointB、result.normal はワールド空間
if (result.impulse > 5) {
console.log(`${result.a.name} and ${result.b.name} collided hard`);
}
});
ヒント

contactは2つのボディが触れている間、毎物理ステップ発火します。床の上に置かれた箱の場合、これは毎フレームということです。1回限りのエフェクトにはcollisionstartを使い、contactのハンドラーは軽く保ってください。

関連情報