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

RigidBody

RigidBodyは、物理シミュレーションに参加するエンティティです。2つのコンポーネントが必要です。物理エンジンがエンティティをどう扱うかを決めるRigidBodyコンポーネントと、形状を与えるCollisionコンポーネントです。Collisionコンポーネントのないrigidbodyコンポーネントには衝突する形がなく、何もしません。形状はコリジョン形状のページで扱います。このページはボディそのものについてです。

ボディのタイプ

RigidBodyのtypeは、誰がそれを動かすかを決めます。

  • Static - 決して動きません。地面や壁など、環境の一部となるものに使います。Staticなボディは低コストで、エンジンはそれらが動かないことを前提とします。
  • Dynamic - 完全にシミュレートされます。重力で落下し、衝突や力とインパルスに応答し、位置と回転は物理エンジンが所有します。
  • Kinematic - エンティティのトランスフォームを通して開発者が動かします。Dynamicなボディを押しのけますが、それらや重力の影響は受けません。動くプラットフォーム、アニメーションで駆動されるドアなど、物理法則ではなくスクリプトに従うものに使います。

下にあるものの上に落ちる、1メートルのDynamicな箱の例です。

const box = new pc.Entity('box');
box.addComponent('render', { type: 'box' });
box.addComponent('collision', { type: 'box' });
box.addComponent('rigidbody', { type: pc.BODYTYPE_DYNAMIC, mass: 2 });
box.setPosition(0, 5, 0);
app.root.addChild(box);
Falling Shapes

質量とマテリアル

4つのプロパティが、ボディの重さと接触時の表面の振る舞いを決めます。

プロパティ説明
MassDynamicなボディの質量(キログラム)。重いボディは加速により大きな力を必要とし、軽いボディを押しのけます。デフォルトは1で、StaticとKinematicのボディでは無視されます
Friction表面が滑りにどれだけ強く抵抗するか(0から1)。デフォルトは0.5
Rolling Friction転がりに対する抵抗。球や円柱が永遠に転がり続けるのを防ぎます。デフォルトは0
Restitution弾力性(0から1)。デフォルトは0。接触する2つのボディの値は掛け合わされるため、反発係数1のボールも反発係数0の床では跳ねません
entity.rigidbody.mass = 5;
entity.rigidbody.friction = 0.8;
entity.rigidbody.rollingFriction = 0.1;
entity.rigidbody.restitution = 0.6;

ダンピングとファクター

2組のプロパティが、動き始めたDynamicなボディの運動を調整します。

  • Linear DampingAngular Dampingは、空気抵抗のように、ボディが毎秒失う速度の割合(0から1)です。デフォルトは0です。
  • Linear FactorAngular Factorは、ワールド軸ごとに移動と回転をスケーリングします。ファクターが0の軸はロックされます。Angular Factorを0, 0, 0にするとキャラクターが直立を保ち、Linear Factorを1, 1, 0、Angular Factorを0, 0, 1にすると2Dゲーム用にボディをXY平面に閉じ込められます。デフォルトは1, 1, 1です。
// 空気抵抗のように、時間とともにボディを減速させる
entity.rigidbody.linearDamping = 0.2;
entity.rigidbody.angularDamping = 0.2;

// キャラクターを直立させる:どの軸でも回転しない
entity.rigidbody.angularFactor = new pc.Vec3(0, 0, 0);

// 2DゲームのXY平面にボディを閉じ込める
entity.rigidbody.linearFactor = new pc.Vec3(1, 1, 0);

スリープ

静止したDynamicなボディは物理エンジンによってスリープ状態にされ、何かに乱されるまでシミュレーションが止まります。力、インパルス、トルクを加えたり、速度を代入したり、テレポートしたりすると自動的に復帰し、他のボディにぶつかられた場合も同様です。自分で復帰させることもできます。

if (!entity.rigidbody.isActive()) {
entity.rigidbody.activate();
}

移動とテレポート

Dynamicなボディの位置と回転は物理エンジンが所有するため、エンティティのトランスフォームに設定した値は次のステップで上書きされます。Dynamicなボディを動かすには、力や速度を使うか、リスポーン時のようにどこかへ瞬間移動させる必要があるときにrigidbodyコンポーネントのteleportを呼び出します。テレポートはボディの速度をクリアしないため、静止した状態で到着させたい場合は先に速度をリセットしてください。

// 現在の回転を保ったまま位置を移動する
entity.rigidbody.teleport(0, 10, 0);

// 移動と回転。回転はオイラー角(度)で指定
entity.rigidbody.teleport(new pc.Vec3(0, 10, 0), new pc.Vec3(0, 90, 0));

// 静止した状態でリスポーンする:以前の動きをクリアし、クォータニオンで移動と回転を行う
entity.rigidbody.linearVelocity = pc.Vec3.ZERO;
entity.rigidbody.angularVelocity = pc.Vec3.ZERO;
entity.rigidbody.teleport(spawn.getPosition(), spawn.getRotation());

Kinematicなボディは逆の仕組みです。setPositionsetRotationlookAtなどのトランスフォームAPIでエンティティを動かすと、ボディは次のステップで追従し、その上に乗っているDynamicなボディを運びます。

// X軸に沿って前後に滑るプラットフォーム
platform.setPosition(Math.sin(time) * 2, 0.5, 0);

linearVelocityangularFactorなどのベクトルプロパティは、読み取り専用のスナップショットを返します。返されたベクトルを編集するのではなく、新しいベクトルを代入してください。

これらの呼び出しは、どの方法で構築しても同じです。Reactでは<Entity>の中に配置したコンポーネントからuseParentフックでエンティティを取得し、Web Componentsでは<pc-entity>要素のentityプロパティから取得します。ボディを動かすでは、各環境で毎フレームのコードをどこで実行するかを示しています。

コリジョングループとマスク

すべてのボディはコリジョングループに属し、衝突する相手のグループを表すマスクを持ちます。2つのボディは、それぞれのグループが相手のマスクに含まれているときにだけ相互作用します。エンジンはボディのタイプが設定されたときに両方を割り当てます。Dynamicなボディはすべてと衝突し、StaticとKinematicのボディは互いに衝突しません。例えば弾丸同士が当たらないようにするなど、コードからこれを絞り込むことができます。

// ボディをユーザーグループに入れ、同じグループの他のメンバーと衝突しないようにする。
// タイプを変更するとリセットされるため、タイプの後に設定する。
entity.rigidbody.group = pc.BODYGROUP_USER_1;
entity.rigidbody.mask = pc.BODYMASK_ALL ^ pc.BODYGROUP_USER_1;

pc.BODYGROUP_USER_1からpc.BODYGROUP_USER_8までの8つのユーザーグループを自由に使用できます。同じグループとマスクでレイキャストをフィルタリングすることもできます。

関連情報