コライダーと剛体
はじめに
コリジョンと物理挙動について、Quantumは独自のコンポーネントを持っています。
- エンティティに
PhysicsCollider2D
/PhysicsCollider3D
を追加すると、そのエンティティは動的な障害物やトリガーとなり、transform
から動かせるようになります。 PhysicsBody2D
/PhysicsBody3D
を追加すると、そのエンティティは物理ソルバーによって制御されるようになります。
要件
Transform2D
/Transform3D
・PhysicsCollider2D
/PhysicsCollider3D
・PhysicsBody2D
/PhysicsBody3D
は密接に関連しているため、あるコンポーネントは他のコンポーネントが機能するための要件になっています。完全な依存関係のリストを以下に示します。
コンポーネント / 要件 | Transform | PhysicsCollider | PhysicsBody |
---|---|---|---|
Transform | ✓ | ✗ | ✗ |
PhysicsCollider | ✓ | ✓ | ✗ |
PhysicsBody | ✓ | ✓ | ✓ |
これらの依存関係は相互に関連しています。PhysicsBody
を有効にするには、次の順序でエンティティにコンポーネントを追加する必要があります。
- Transform
- PhysicsCollider
- PhysicsBody
コリジョンのコールバックの詳細はこちらをご覧ください。
PhysicsBodyコンポーネント
エンティティにPhysicsBody
コンポーネントを追加すると、そのエンティティは物理エンジンの考慮対象になります。注意: PhysicsBody
を使用するには、エンティティにTransform
とPhysicsCollider
が既に追加されている必要があります。
このコンポーネントの作成や初期化は、コードから手動で行うことも、UnityのQuantumEntityPrototype
コンポーネントから行うことも可能です。
C#
var entity = f.Create();
var transform = new Transform2D();
var collider = PhysicsCollider2D.Create(f, Shape2D.CreateCircle(1));
var body = PhysicsBody2D.CreateDynamic(1);
f.Set(entity, transform);
f.Set(entity, collider);
f.Set(entity, body);
3D物理でも同様に適用できます。
C#
var entity = f.Create();
var transform = Transform3D.Create();
var shape = Shape3D.CreateSphere(FP._1);
var collider = PhysicsCollider3D.Create(shape);
var body = PhysicsBody3D.CreateDynamic(FP._1);
f.Set(entity, transform);
f.Set(entity, collider);
f.Set(entity, body);
QuantumEntityPrototype
を使用する場合、コンポーネントはUnityのインスペクター上で定義された値で初期化されます。

対応するシェイプ
PhysicsCollider3D
は、動的なエンティティに対して、以下の3Dシェイプのみをサポートしています。
- Sphere
- Box
- Capsule
- Compound(複数のシェイプの組み合わせ)
エディター上では、Unityのカプセルと同じプロパティ(Radius
とHeight
)を使用して、カプセルシェイプのプロパティを設定できます。ただしQuantum内部では、カプセルはRadius
とExtent
で定義され、Height
とDiameter
プロパティを持っています。
PhysicsCollider2D
は、動的なエンティティに対して、以下の2Dシェイプのみをサポートしています。
- Circle
- Box
- Polygon
- Edge
- Capsule
- Compound(複数のシェイプの組み合わせ)
使用可能なカプセルコライダーに関連するコードスニペットを以下に示します。
C#
FP radius = FP._0_50;
FP extent = FP._1;
Shape2D shape = Shape2D.CreateCapsule(radius, extent);
// カプセルを描画
Draw.Capsule(FPVector2.Zero, shape.Capsule);
Draw.Capsule(FPVector2.Zero, extent, radius);
以下の図は、QuantumとUnity間のカプセルコライダーの違いを明確に示すものです。

重心
「重心(Center of Mass:CoM)」は、PhysicsBody
コンポーネントで設定できます。重心は、Transform
コンポーネントで指定された位置に対するオフセットで表されます。重心の位置を変更すると、PhysicsBody
に作用する力に影響します。

デフォルトでは、重心はPhysicsCollider
のシェイプの幾何中心に設定されています。これは、PhysicsBody
のConfig
のReset Center of Mass On Added
によって強制されます。
注意:重心の位置をカスタマイズするには、Reset Center of Mass On Added
フラグのチェックを外すことが必須です。これを外さないと、PhysicsBody
コンポーネントがエンティティに追加された際に、重心がコライダーの幾何中心にリセットされてしまいます。

上記の構成は、一様な密度の剛体のように振る舞うエンティティの一般的な設定です。ただし、重心とコライダーのオフセットは別々に設定されています。以下の表にその組み合わせを示します。
PhysicsCollider Offset | PhysicsBody CoM | Reset Center of Mass On Addedフラグ | 最終的な位置 |
---|---|---|---|
デフォルト位置 = 0, 0, 0 カスタム値 = デフォルト位置とは異なる任意の位置 |
|||
デフォルト位置 | デフォルト位置 | On / Off | コライダーの幾何中心と重心の位置は両方とも、transformの位置と同じです。 |
カスタム値 | デフォルトの位置 | On | コライダーの幾何中心はtransformからオフセットされ、重心はコライダーの幾何中心と同じ位置になります。 |
カスタム値 | デフォルトの位置 | Off | コライダーの幾何中心はtransformの位置からオフセットされます。 重心はtransformの同じ位置になります。 |
カスタム値 | カスタム位置 | On | コライダーの幾何中心はtransformの位置からオフセットされます。 重心はコライダーの幾何中心と同じ位置になります。 |
カスタム値 | カスタム位置 | Off | コライダーの幾何中心はtransformの位置からオフセットされます。 重心はtransformの位置からオフセットされます。 |
Compoundコライダーの重心
Coumpoundシェイプの重心は、すべてのシェイプ要素の幾何中心の組み合わせで、それぞれの面積(2D)または体積(3D)の加重平均に基づきます。
重要なポイント
まとめると、重心の設定に関する重要なポイントは次の通りです。
PhysicsCollider
のオフセットとPhysicsBody
の重心位置は互いに異なります。- デフォルトでは、
PhysicsBody
のConfig
でReset Center of Mass On Added
とReset Inertia on Added
フラグが設定されています。 - カスタムの重心を設定するには、
PhysicsBody
のConfig
のReset Center of Mass On Added
フラグを外します。 PhysicsBody
のConfig
でReset Center of Mass On Added
フラグが設定されている場合、エンティティに追加される際に、重心は(エディター上で指定した重心の位置に関わらず)PhysicsCollider
の幾何中心に自動的に設定されます。
外力の適用
PhysicsBody
APIによって、手動で剛体に外力を適用できます。
C#
// これは3DのAPIですが、2Dも同様です。
public void AddTorque(FPVector3 amount)
public void AddAngularImpulse(FPVector3 amount)
public void AddForce(FPVector3 amount, FPVector3? relativePoint = null)
public void AddLinearImpulse(FPVector3 amount, FPVector3? relativePoint = null)
// relativePointは、剛体の重心から力が作用する点までのベクトルで、どちらもワールド座標系です。
// relativePointが与えられると、結果のトルクが計算され適用されます。
public void AddForceAtPosition(FPVector3 force, FPVector3 position, Transform3D* transform)
public void AddImpulseAtPosition(FPVector3 force, FPVector3 position, Transform3D* transform)
// 重心を考慮しながら、指定した位置にforce/imulseを適用する。
PhysicsBody
の角運動量と線形運動量は、以下の適用時に影響を受けます。
- forces
- impulses
これらは似ていますが、重要な違いがあります。forcesは一定期間にわたって適用されるのに対して、impulsesは即時に適用されます。次のように考えることもできます。
- Force =
deltatime
ごとの力 - Impulse = フレームごとの力
備考:Quantumのdeltatime
は固定で、Simulation Config
アセットで設定されたシミュレーションレートに依存します。
Impulseは、シミュレーションレートによらず同じ効果をもたらしますが、Forceはシミュレーションレートに依存します。シミュレーションレートが30Hz時に剛体に力を適用するとして、シミュレーションレートを60Hzにするとdeltatime
は半分になるため、積分された力も半分になります。
一般的に、Impulseは瞬間的かつ即時の変化を与えたい場合に使用し、Forceは長い期間にわたって常時適用されるものに使用することが望ましいです。
コンポーネントの初期化
PhysicsBodyを動的/キネマティックな剛体として初期化するには、対応する生成関数を使用します。これらのメソッドはPhysicsBody2D
/PhysicsBody3D
クラスから利用可能で、以下がその例です。
- PhysicsBody3D.CreateDynamic
- PhysicsBody3D.CreateKinematic
ShapeConfig
データ駆動設計によってPhysicsCollider
/PhysicsBody
を初期化するには、ShapeConfig型(Shape2DConfig
/Shape3DConfig
)を使用します。これら構造体は、任意のQuantumデータアセットにプロパティ(シェイプやサイズなど)として追加可能で、Unityから編集できます。
C#
// ShapeConfigプロパティを含むデータアセット
partial class CharacterSpec {
// これはUnityから編集できる
public Shape2DConfig Shape2D;
public Shape3DConfig Shape3D;
public FP Mass;
}
剛体を初期化する際には、シェイプを直接指定せずにShapeConfig
を使用します。
C#
// Frameオブジェクトからプレイヤーのエンティティを生成する
var playerPrototype = f.FindAsset<EntityPrototype>(PLAYER_PROTOTYPE_PATH);
var playerEntity = playerPrototype.Container.CreateEntity(f);
var playerSpec = f.FindAsset<CharacterSpec>("PlayerSpec");
var transform = Transform2D.Create();
var collider = PhysicsCollider2D.Create(playerSpec.Shape2D.CreateShape(f));
var body = PhysicsBody2D.CreateKinematic(playerSpec.Mass);
// 3Dならこちら
var transform = Transform3D.Create();
var collider = PhysicsCollider3D.Create(playerSpec.Shape3D.CreateShape())
var body = PhysicsBody3D.CreateKinematic(playerSpec.Mass);
// コンポーネントを設定する
f.Set(playerEntity, transform);
f.Set(playerEntity, collider);
f.Set(playerEntity, body);
物理コールバックの有効化
エンティティには複数の物理コールバックを関連付けることができます。これらは、コードまたはQuantum Entity Prototype
のPhysicsCollider
コンポーネントから有効にすることができます。

コードから物理コールバックを設定し、対応するシグナルを実装する方法については、物理のマニュアルの「コールバック」項目をご覧ください。
キネマティック
物理エンティティにキネマティックな振る舞いをさせる方法は4つあります。
PhysicsCollider
コンポーネントのみを持つ:エンティティはPhysicsBody
コンポーネントを持たない(Mass, Drag, Force/Torqueなどがない)ため、エンティティのtransform
を自由に操作することが可能ですが、動的な剛体への衝突はエンティティが静止しているもの(速度と角速度が0)として解決されます。PhysicsBody
コンポーネントを無効にする:PhysicsBody
のIsEnabled
プロパティをfalseにすると、物理エンジンはエンティティを1と同じように(コライダーコンポーネントのみを持つように)扱い、ForceやVelocityがなくなります。一時的に静的なエンティティとして振る舞い、後で再有効化した際に設定(Mass, Dragなど)を保持するのに適しています。PhysicsBody
コンポーネントのIsKinematic
プロパティをtrueに設定する:物理エンジンはPhysicsBody
自体に影響を与えませんが、衝突時にその速度と角速度が他の剛体に影響を与えます。物理エンジンには任せずに、エンティティの移動と速度を手動で制御しつつ、他の動的な剛体に反応させることができます。CreateKinematic
からPhysicsBody
を初期化する:剛体が常にキネマティックに振る舞うことを期待する場合は、単にキネマティックな剛体を生成します。これによって、PhysicsBody
は最初から3のように振る舞います。剛体が最終的に動的になる必要がある場合は、CreateDynamic
メソッドから新しい剛体を作成してIsKinematic = true
に設定してください。IsKinematic
をtrue/falseに設定すると、いつでもPhysicsBody
コンポーネントを動的/キネマティックとして再初期化できます。
PhysicsColliderコンポーネント
コンポーネントの無効化/有効化
PhysicsCollider
コンポーネントにはEnabled
プロパティがあります。このプロパティをfalse
に設定すると、PhysicsCollider
を持つエンティティはPhysicsSystem
から無視されます。
PhysicsBody
はアクティブなPhysicsCollider
が必要とするため、効率的に無効化できます。
実行時にシェイプを変更する
PhysicsCollider
のシェイプは、初期化された後からでも変更することが可能です。
C#
var collider = f.Get<PhysicsCollider3D>(entity);
collider.Shape = myNewShape;
f.Set(entity, collider);
最初にPhysicsBody
が追加されると、PhysicsCollider
のシェイプに基づいて慣性と重心が計算されます。そのため、コライダーのシェイプを変更した後に、ResetInertia
とResetCenterOfMass
を呼び出すことを推奨します。
C#
// 上記のスニペットは次の通り
var body = f.Get<PhysicsBody3D>(entity);
body.ResetCenterOfMass(f, entity); // こちらを最初に呼び出す必要がある
body.ResetInertia(f, entity); // こちらをその後に呼び出す必要がある
f.Set(entity, body);
変更前/変更後のシェイプが以下の条件に当てはまる場合は、ResetCenterOfMass
を必ず呼び出す必要があります。
- シェイプに位置オフセットがある
- シェイプがCompoundである
- 重心にオフセットがある