衝突とトリガーの処理
剛体同士が衝突すると効果音が再生され、トリガーボリュームに入るとランプの上へ戻ります。
このチュートリアルでは、剛体物理、衝突イベント、トリガーボリュームの基本を紹介します。完成したシーンはチュートリアルプロジェクトで確認できます。
新しいプロジェクトでシーンを再現する場合は、剛体を追加する前に物理機能を有効化してください。
コリジョン形状
Collisionコンポーネントは、エンティティを囲むボリュームを定義します。単独で使用するとトリガーボリュームとして機能し、Rigid Bodyコンポーネントと組み合わせると剛体の物理形状を定義します。
Typeプロパティでは、次の7種類のコリジョン形状を選択できます。
- Box - 直方体です。
- Sphere - 球体です。
- Capsule - 両端が丸い円柱で、キャラクターによく使用されます。
- Cylinder - 選択したローカル軸に沿った円柱です。
- Cone - 選択したローカル軸に沿った円錐です。
- Mesh - ModelまたはRenderアセットから生成するコリジョン形状です。動的剛体でメッシュを使用する場合は、Convex Hullを有効にします。
- Compound - 子孫エンティティ上のプリミティブ形状を組み合わせた形状です。
一般に、プリミティブ形状はメッシュ形状よりもシミュレーションの負荷が低いため、オブジェクトに無理なく合う最も単純な形状を使用してください。
トリガーボリューム
トリガーボリュームを作成するには、エンティティにCollisionコンポーネントを追加し、Rigid Bodyコンポーネントは追加しません。トリガーは他の剛体の動きを物理的に遮りません。代わりに、動的またはキネマティック剛体が境界を横切ると、triggerenterイベントとtriggerleaveイベントを発生させます。
このチュートリアルでは、ランプの下に大きなボックス形状のトリガーを配置し、落下した剛体をランプの上へ戻します。

EditorのPhysics表示モードを使用すると、ビューポート内でコリジョンボリュームとトリガーボリュームを確認できます。
剛体
Rigid Bodyコンポーネントは、エンティティを物理シミュレーションに参加させます。質量、摩擦、反発、減衰などのプロパティを設定できます。形状を定義するには、同じエンティティにCollisionコンポーネントも必要です。
両方のコンポーネントを追加すると、デフォルトでは静的なボックス形状の剛体が作成されます。

Rigid BodyのTypeは、剛体の動き方を決定します。
- Static - 移動しません。通常は地形などの環境に使用します。
- Dynamic - 物理シミュレーションによって制御され、重力、力、衝突に反応します。
- Kinematic - コードから明示的に移動します。動的剛体には影響を与えますが、力には反応しません。
地面の設定
地面は、ランプの下にある大きな緑色のブロックです。

Render、Collision、Rigid Bodyコンポーネントを追加します。CollisionのTypeをBox、Half Extentsを10, 1, 10に設定し、Rigid BodyのTypeをStaticに設定します。この例では、摩擦を0.9、反発を0.5に設定し、滑りにくく少し弾む表面にしています。
トリガーの設定
ランプの下にトリガー用のエンティティを作成します。

BoxのCollisionコンポーネントを追加し、Half Extentsを20, 2, 20に設定します。Rigid Bodyコンポーネントは追加しません。Scriptコンポーネントを追加し、次のtriggerスクリプトをアタッチして、剛体がボリュームに入るイベントを監視します。
- ESM
- Classic
import { Script, Vec3 } from 'playcanvas';
export class Trigger extends Script {
static scriptName = 'trigger';
initialize() {
const triggerEnterEvent = this.entity.collision.on('triggerenter', this.onTriggerEnter, this);
this.on('destroy', () => {
triggerEnterEvent.off();
});
}
onTriggerEnter(entity) {
entity.rigidbody.linearVelocity = Vec3.ZERO;
entity.rigidbody.angularVelocity = Vec3.ZERO;
// Return the body to the top of the ramp.
const position = entity.getPosition();
entity.rigidbody.teleport(position.x, 10, 0);
}
}
var Trigger = pc.createScript('trigger');
Trigger.prototype.initialize = function () {
var triggerEnterEvent = this.entity.collision.on('triggerenter', this.onTriggerEnter, this);
this.on('destroy', function () {
triggerEnterEvent.off();
});
};
Trigger.prototype.onTriggerEnter = function (entity) {
entity.rigidbody.linearVelocity = pc.Vec3.ZERO;
entity.rigidbody.angularVelocity = pc.Vec3.ZERO;
// Return the body to the top of the ramp.
var position = entity.getPosition();
entity.rigidbody.teleport(position.x, 10, 0);
};
triggerenterイベントは、剛体がボリュームに入ったときに一度発生します。コールバックには、ボリュームに入ったEntityが渡されます。つまり、this.entityはトリガーエンティティであり、コールバックのentity引数は落下してきた剛体です。onの3番目の引数は、コールバック内のthisをスクリプトインスタンスに設定します。
スクリプトが破棄されると、イベントハンドルも解除されます。onTriggerEnterでは、剛体の直線速度と角速度を消去し、現在のX位置を保ったまま、rigidbody.teleportでランプの上へ移動します。動的剛体の位置は、エンティティのTransformを直接設定するのではなく、Rigid Body APIを使用して変更する必要があります。対応するtriggerleaveイベントは、剛体がボリュームから出たときに同じ仕組みで発生します。
動的剛体の設定
ボックス、球体、カプセルにRigid BodyコンポーネントとCollisionコンポーネントを追加します。それぞれのRigid BodyのTypeをDynamicに設定し、形状に対応するCollisionのTypeを選択します。

この例のボックスでは、質量を1、摩擦を0.5、反発を0.5に設定しています。球体とカプセルにも同じRigid Body設定を使用します。
衝突イベントの処理
Collisionコンポーネントは、剛体同士の物理接触に対して3つのイベントを発生させます。
contact- 剛体が接触している間、物理ステップごとに発生します。結果には、そのステップのすべての接触点が含まれます。collisionstart- 剛体が接触し始めたときに一度だけ発生します。collisionend- 剛体が接触しなくなったときに一度だけ発生します。
継続的に更新される接触情報が必要な場合はcontactを使用します。衝突音のように一度だけ実行する処理では、物理ステップごとに効果が繰り返されないようにcollisionstartを使用します。
- ESM
- Classic
import { Script } from 'playcanvas';
export class Collider extends Script {
static scriptName = 'collider';
initialize() {
const collisionStartEvent = this.entity.collision.on('collisionstart', this.onCollisionStart, this);
this.on('destroy', () => {
collisionStartEvent.off();
});
}
onCollisionStart() {
this.entity.sound.play('hit');
}
}
var Collider = pc.createScript('collider');
Collider.prototype.initialize = function () {
var collisionStartEvent = this.entity.collision.on('collisionstart', this.onCollisionStart, this);
this.on('destroy', function () {
collisionStartEvent.off();
});
};
Collider.prototype.onCollisionStart = function () {
this.entity.sound.play('hit');
};
hitという名前のスロットを持つSoundコンポーネントを各落下エンティティに追加し、このスクリプトをアタッチします。物理衝突が始まるとハンドラーが一度実行され、そのスロットを再生します。トリガーとの重なりではトリガーイベントが発生するため、この衝突ハンドラーは呼び出されません。
これで、静的な地面、動的な落下オブジェクト、それらをリセットするトリガー、衝突音を再生するイベントが揃いました。詳細については、物理の基本とCollisionコンポーネントAPIを参照してください。