This document is about: QUANTUM 2
SWITCH TO

静的コライダー

はじめに

シーンに静的コライダーを追加するには、3つの簡単な手順を実行します。

  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アセット(マップ)として保存されます。

ソースとしてのUnituコライダー

Quantumの静的コライダーは、Unityコライダーからプロパティをミラーリングすることもできます。
ミラーリングは、Quantum Static ColliderコンポーネントのSource Colliderフィールドに該当するコライダーをドラッグアンドドロップするだけでおこなえます:

unity-collider-source

形状

2D物理形状は次のとおりです。

  • Circle
  • Box
  • Polygon

N.B.: どれも、2.5D形状の作成を可能にするHeightフィールドがあります。

3D物理形状は次のとおりです。

  • Sphere
  • Box
  • Mesh

設定

静的コライダーには、PhysicsMaterialUser Asset を取り付けることができます。後者は、衝突コールバックを介してシミュレーションで使用できます。

滑らかな平面メッシュコライダー

静的メッシュコライダー 3Dには、滑らかな平面メッシュ衝突というオプションがあります。このオプションをオンにすると、物理ソルバーは球体とメッシュの衝突を、あたかもメッシュが通常の平らで滑らかな平面であるかのように解決します。これにより、三角形のエッジと衝突した球体にスピンを加えることができなくなります。

Static Smooth Mesh Collider
静的メッシュコライダー
`静的メッシュコライダー 3D`の`滑らかな平面メッシュ衝突`オプションが選択されていても、メッシュが完全に平らでない場合には望ましくない衝突レスポンスが発生する可能性があります。

ランタイム時の有効化・無効化

このセクションでは、シミュレーションのランタイムで静的コライダーを有効化・無効化するいくつかのアプローチをご紹介します。

物理エンジン

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

スタティックコライダをトグル可能にするには、そのModeedit-time (Unity) で設定し、 Map アセットにベイクする必要があります。モードは以下のように設定できます。

  • Immutable (ドフォルト): コライダーをランタイムで有効または無効にすることはできません。
  • Toggleable Start On: コライダーはランタイムでトグルでき、__enabled__を開始します。
  • Toggleable Start Off: コライダーはランタイムに切り替えられ、__disabled__を開始します。
Enable toggle on 3D Static Mesh Colliders
3D Static Mesh Colliderコンポーネントのトグルを有効にします。

静的コライダがトグル可能とマークされ、ベイクされると、シミュレーション(Quantum)からランタイムに、3Dと2Dの静的コライダに対して、それぞれFrame.Physics3DFrame.Physics2DSetStaticColliderEnabled()を使って、コライダを有効にしたり無効にしたりすることができるようになります。

パラメータとして渡される index は、frame.Map.StaticColliders 配列内のコライダーのインデックスです。コリジョンコールバックは、静的コライダーのインデックス(ColliderIndex)を、その TriggerInfoCollisionInfoStaticData の一部として返します。

重要: 無効になった静的メッシュコライダは、物理クエリによって無視され、コリジョンシグナルは発生しません。

手動トラッキング

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

状態のためにグローバルなビットセットを維持する

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

C#

singleton component StaticColliderState {
    bitset[256] colliders;
}

これにより、colliderのインデックスを持つbitsetインスタンスを使用して、そのビットを設定することができます。

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 を実装する場合に特に有効です。

Toggle with Behaviour

静的なコライダーはアセットです。つまり、ステートレスでランタイム時にイミュータブルです。ただし、動的な条件に基づいて、静的なオブジェクトが有効化・無効化されるべきインスタンスが存在します。

例えば、pick-upsは通常静的な位置を表しコライダーをトリガーしますが、これらを静的なコライダーにすると動的なエンティティに菅レづけすぎることを開始します。残念ながら、pick-upクールダウンの後にpower-upをリスポーンするタイマーはステートを要求します。この難問は、前の章で述べたコンセプトで解消することができます。

まず、power-upを表す静的コライダーのステートをどこかに置く必要があります。

C#

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

power-upの有効化・無効化を処理するシステムが作成されます。

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