コリダーキャンセラー
なんて…ひねりのない名前ッ!!
閑話休題。斜面に這わせるネタ第3回で使う予定のクラスを一回ほどはさみます。
たまに自分のコリダー反応だけを一時的に回避したい時があります。でも同じPrefabクローン同士でタグとかレイヤー管理とか面倒くさい。そんなああたにコリダーキャンセラー。子オブジェクトのColliderを列挙してenable一時無効と復帰、IDisposableでusingするだけ簡単呼出し、例外発生にも強い復帰力!
MSDN - IDisposable
開けたら閉じる/繋いだら切る/終わったらすぐ片付ける。それも「絶対に!」といった処理をパターン化するためのお作法。例外のcatch構文に近いものを簡潔に記述できる(*1)。
public class ColliderCanceler : System.IDisposable { public enum TargetFilter { TriggerConditionIgnore = 0, // Trigger設定はとくに評価しない TriggerOnColliderCancel = 1, // TriggerがTrueなコリダーだけ一時的にキャンセルする TriggerOffColliderCancel = 2, // TriggerがFalseなコリダーだけ一時的にキャンセルする } private Component[] cancel_targets = null; private bool[] isCanceled = null; public ColliderCanceler( Component src ) { InitializeTargets(src, TargetFilter.TriggerConditionIgnore); } public ColliderCanceler( Component src, TargetFilter filter ) { InitializeTargets(src, filter); } ~ColliderCanceler() { Dispose(); } public void Dispose() { if ( cancel_targets == null ) return; for ( int idx = 0; idx < cancel_targets.Length; idx++ ) { if ( isCanceled[idx] == true ) ((Collider)(cancel_targets[idx])).enabled = true; } cancel_targets = null; isCanceled = null; } private void InitializeTargets( Component src, TargetFilter filter ) { cancel_targets = src.GetComponentsInChildren<Collider>(); if ( cancel_targets == null || 0 == cancel_targets.Length ) return; isCanceled = new bool[cancel_targets.Length]; for ( int idx = 0; idx < cancel_targets.Length; idx++ ) { Collider cld = (Collider)cancel_targets[idx]; if ( filter == TargetFilter.TriggerConditionIgnore ) isCanceled[idx] = cld.enabled; else if ( filter == TargetFilter.TriggerOnColliderCancel ) isCanceled[idx] = ( cld.enabled == true && cld.isTrigger == true); else if ( filter == TargetFilter.TriggerOffColliderCancel ) isCanceled[idx] = ( cld.enabled == true && cld.isTrigger == false); if ( isCanceled[idx] ) cld.enabled = false; } } }
ColliderCanceler( Component src, TargetFilter filter )
Component src
親オブジェクトのコンポーネントを指定します。例えば自分自身(MonoBehavior)や、とくに後付けコンポーネントが無ければtransformなどをセット。
TargetFilter filterTrigger状態を条件に出来ます。各フラグの意味はコード中のコメントを参照。
使い方
public class SampleClass : MonoBehaviour { // ・・・<略>・・・ void Update() { using (ColliderCanceler cc = new ColliderCanceler(this, ColliderCanceler.TargetFilter.TriggerOffColliderCancel)) { // このスコープ内では自身の子コリダーは停止中。指定したのがTriggerOffColliderCancelなので非Triggerコリダーだけ一時無効中。 Vector3 fwd = transform.TransformDirection(Vector3.forward); if (Physics.Raycast(transform.position, fwd, 10)) return; if ( some_condition ) throw new System.Exception("hoge"); // こんなふうに途中でreturnしたり例外で飛んでも子コリダーはusing突入前に戻る(:スコープ脱出時にColliderCanceler.Dispose()が呼び出される)。 } // ここではもうコリダーが復帰してる } }