This document is about: QUANTUM 3
SWITCH TO

静的コライダー

はじめに

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

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

Unityコライダーをソースとして使用

Quantum静的コライダーは、Unityコライダーのプロパティをミラーリングすることもできます。希望するコライダーをQuantum Static ColliderコンポーネントのSource Colliderフィールドにドラッグ&ドロップするだけでこれを行えます。

unity-collider-source

シェイプ

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

  • 円(Circle)
  • ボックス(Box)
  • ポリゴン(Polygon)

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

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

  • スフィア(Sphere)
  • ボックス(Box)
  • メッシュ(Mesh)

設定

静的コライダーには、PhysicsMaterialUser Assetを設定することができます。後者は、衝突コールバックを通じてシミュレーション内で利用可能です。

スムーススフィアメッシュコライダー

Static Mesh Collider 3Dには、Smooth Sphere Mesh Collisionというオプションがあります。このオプションをオンにすると、物理ソルバーはメッシュとスフィアの衝突を、メッシュが通常の平坦で滑らかな面であるかのように解決します。これにより、三角形のエッジに衝突した際にスフィアに回転が加わるのを防ぎます。

Static Smooth Mesh Collider
Static Mesh Collider.
`Static Mesh Collider 3D`が`Smooth Sphere Mesh Collision`オプションでマークされているが、メッシュが完全に平坦でない場合、望ましくない衝突応答が発生する可能性があります。

実行時の有効化 / 無効化

このセクションでは、シミュレーション内での実行時に静的コライダーを有効化および無効化するためのいくつかのアプローチを紹介します。

物理エンジン

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

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

  • Immutable(デフォルト):コライダーは実行時に有効または無効にすることができません。
  • Toggleable Start On:コライダーは実行時に切り替えることができ、初期状態は__有効__です。
  • Toggleable Start Off:コライダーは実行時に切り替えることができ、初期状態は__無効__です。
Enable toggle on 3D Static Mesh Colliders
3D静的メッシュコライダーコンポーネントでトグルを有効にする。

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

渡す必要があるindexは、frame.Map.StaticColliders配列内のコライダーのインデックスです。衝突コールバックは、TriggerInfoまたはCollisionInfoの一部として、静的コライダーのインデックス(ColliderIndex)を返します。

重要: 無効にされた静的メッシュコライダーは物理クエリで無視され、衝突シグナルを引き起こしません。

マニュアルトラッキング

静的コライダーは物理エンジンレベルで有効/無効にすることができますが、この切り替えを手動で行うには、さまざまなアプローチがあります。

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

衝突コールバックで無視するべき静的コライダーを追跡するだけが目的であれば、最も便利なアプローチは、frame.Map.StaticColliders配列と同じ長さまたはそれ以上の長さを持つグローバルBitSetを定義することです。これは、Frameオブジェクトの一部として、またはシングルトンコンポーネントとして実装できます。

C#

singleton component StaticColliderState {
    bitset[256] colliders;
}

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

C#

// loops through the bitset to initialize all bits as "On" to mark all colliders as active
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;

    // Use a custom asset slotted in the UserAsset field to identify toggleable colliders
    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);
        // Other code visualizing the spawned / re-enabled power-up
        // can use frame event to trigger VFX, SFX, re-enable visual / GameObject
    }

}

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;

    // Remember to communicate the disabled state visually, e.g. trigger a frame event to disable the GameObject in Unity
}
Back to top