This document is about: QUANTUM 3
SWITCH TO

静的コライダー

はじめに

シーンに静的コライダーを追加するには、次の3つの簡単なステップを行います。

  1. Unityのゲームオブジェクトに、Quantum Static Colliderスクリプトをアタッチする。
  2. シーンの静的な障害物のジオメトリに合わせて、プロパティを編集する。
  3. MapDataスクリプトを使用して、シーンをベイクする。
Step 1 & 2 - Add Static Colliders to GameObject in Unity Scene and adjust Settings
ステップ 1 & 2 - Unityシーンのゲームオブジェクトに静的コライダーを追加し、設定を調整する
Step 3 - Baking the Map Saves the Scene Colliders as a Quantum Asset (Map)
ステップ 3 - マップをベイクして、シーンのコライダーをQuantumアセット(Map)に保存する

Unityコライダーを元に作成する

Quantumの静的コライダーは、Unityコライダーのプロパティを反映することもできます。反映したいコライダーを、Quantum Static ColliderコンポーネントのSource Colliderフィールドにドラッグ&ドロップしてください。

unity-collider-source

シェイプ

2D物理シェイプは次の通りです。

  • Circle
  • Box
  • Polygon

注意: すべてのシェイプはHeightフィールドを持ち、2.5Dシェイプを作成することが可能です。

3D物理シェイプは次の通りです。

  • Sphere
  • Box
  • Mesh

設定

静的コライダーには、PhysicsMaterialUser Assetを設定できます。後者は、コリジョンコールバックを通してシミュレーションで利用可能です。

Smooth Sphere Mesh Collider

Static Mesh Collider 3Dには、Smooth Sphere Mesh Collisionというオプションがあります。このオプションを有効にすると、物理ソルバーはメッシュを通常の平坦で滑らかな平面として、球とメッシュの衝突を解決します。これによって、トライアングルの角に衝突した球に回転が加わることを防ぎます。

Static Smooth Mesh Collider
Static Mesh Collider
Smooth Sphere Mesh Collisionオプションが有効なStatic Mesh Collider 3Dのメッシュが完全に平坦ではない場合、望ましくない衝突反応が生じる可能性があります。

実行時の有効化/無効化

ここでは、実行時にシミュレーションの静的コライダーを有効/無効にする方法をいくつか紹介します。

物理エンジン

物理エンジンでは、静的コライダーのオン/オフを実行時に直接切り替えることができます。

静的コライダーを切り替えられるようにするには、編集時(Unity)にModeを設定して、Mapアセットにベイクする必要があります。モードは次のように設定できます。

  • Immutable(デフォルト):コライダーは実行時に有効/無効にできません。
  • Toggleable Start On:コライダーは実行時に切り替え可能で、初期値は有効です。
  • Toggleable Start Off:コライダーは実行時に切り替え可能で、初期値は無効です。
Enable toggle on 3D Static Mesh Colliders
3D Static Mesh Colliderコンポーネントで切り替えを有効にする

静的コライダーが切り替え可能でベイクされると、実行時にシミュレーション(Quantum)でコライダーを有効/無効にできるようになります。3Dの静的コライダーではFrame.Physics3D、2Dの静的コライダーではFrame.Physics2DSetStaticColliderEnabled()を使用します。

パラメーターとして渡すindexは、frame.Map.StaticCollider配列のコライダーのインデックスです。コリジョンコールバックは、TriggerInfo/CollisionInfoで静的コライダーのインデックス(ColliderIndex)を返します。

重要: 無効な静的コライダーは物理クエリから無視され、衝突シグナルをトリガーしません。

手動トラッキング

静的コライダーは、物理エンジンレベルで有効/無効にできますが、これを手動で行うには様々な方法があります。

グローバルなビットセットで状態を管理

コリジョンコールバックでどの静的コライダーを考慮/無視するかを追跡するだけが目的であれば、frame.Map.StaticColliders配列以上の長さを持つグローバルBitSetを定義するのが、最も便利な方法です。これは、Frameオブジェクトの一部か、シングルトンコンポーネントとして実装できます。

C#

singleton component StaticColliderState {
    bitset[256] colliders;
}

これによって、コライダーのインデックスをビットセットのビットとして設定できるようになります。

C#

// ビットセットのすべてのビットを"On"に初期化して、すべてのコライダーをアクティブにする
public override void OnInit(Frame f)
{
    var collidersState = f.Unsafe.GetPointerSingleton<StaticColliderState>();
    for (int i = 0; i < collidersState->colliders.Length; i++) {
        collidersState->colliders.Set(i);
    }
}

public void OnTrigger3D(Frame frame, TriggerInfo3D info)
{
    if (info.IsStatic == false) return;

    // UserAssetフィールドの独自アセットを使用して、切り替え可能なコライダーを識別する
    var colliderAsset = frame.FindAsset<MyColliderAsset>(info.StaticData.Asset);
    if (colliderAsset == null) return;

    var collidersState = frame.Unsafe.GetPointerSingleton<StaticColliderState>();
    collidersState->colliders.Clear(info.StaticData.ColliderIndex);
}

値はIsSet()から読み取り可能で、衝突シグナルを処理/無視するかを判断するために使用できます。これは、インタラクション可能な静的オブジェクトや関門のような環境、移動にIKCCCallbacks3Dを実装する際に特に便利です。

挙動による切り替え

静的コライダーはアセットであるため、実行時にはステートレスかつ不変です。しかし、静的オブジェクトを動的な条件に基づいて有効/無効にしたい場合もあります。

例えば、ステージ上のアイテムは静的な位置とトリガーコライダーで通常は表現されます。これらを静的コライダーにすることで、動的エンティティ関連のオーバーヘッドを回避できます。ただし、アイテム取得後に再出現させるクールダウンタイマーには状態が必要になります。この問題は、前のセクションで説明した概念を拡張することで解決できます。

まず、パワーアップアイテムを表す静的コライダーの状態をどこかに保持する必要があります。

C#

singleton component PowerUps {
    [ExcludeFromPrototype] bitset[256] IsPowerUp;
    [ExcludeFromPrototype] bitset[256] State;
    [ExcludeFromPrototype] array<FP>[256] Timers;
    FP SpawnCooldown;
}

次に、パワーアップアイテムの有効/無効を処理するシステムを作成します。

C#

public unsafe class MyPowerUpSystem : SystemMainThread {
public override void OnInit(Frame f)
{
    var powerUps = f.Unsafe.GetPointerSingleton<PowerUps>();
    for (int i = 0; i < powerUps->IsPowerUp.Length; i++)
    {
        var powerUp = f.FindAsset<MyPowerUpAsset>(f.Map.StaticColliders3D[i].StaticData.Asset);
        if (powerUp == null) {
            powerUps->IsPowerUp.Clear(i);
            continue;
        }

        powerUps->IsPowerUp.Set(i);
        powerUps->State.Set(i);
        powerUps->Timers[i] = FP._0;
    }
}

public override void Update(Frame f){
    var powerUps = f.Unsafe.GetPointerSingleton<PowerUps>();
    for (int i = 0; i < powerUps->IsPowerUp.Length; i++)
    {
        if (powerUps->IsPowerUp.IsSet(i) == false) continue;
        if (powerUps->State.IsSet(i)) continue;

        powerUps->Timers[i] -= f.DeltaTime;
        if(powerUps->Timers[i] > 0) continue;

        powerUps->State.Set(i);
        // パワーアップアイテムの出現/再出現をレンダリングするためのコード
        // VFX・SFX・ゲームオブジェクトの有効化をトリガーするためにフレームイベントを使用できる
    }

}

public void OnTrigger3D(Frame frame, TriggerInfo3D info)
{
    if(info.IsStatic == false) return;

    var powerUps = f.Unsafe.GetPointerSingleton<PowerUps>();

    if(powerUps->IsPowerUp.IsSet(info.StaticData.ColliderIndex) == false) return;
    if(powerUps->State.IsSet(info.StaticData.ColliderIndex) == false) return;

    powerUps->State.Clear(info.StaticData.ColliderIndex);
    powerUps->Timers[info.StaticData.ColliderIndex] = powerUps->SpawnCooldown;

    // 無効状態を視覚的に伝える(例:Unityのゲームオブジェクトを無効にするフレームイベントをトリガーする)
}
Back to top