Unityの衝突判定を数値化して不安定な接触を安定化する(デリゲート編)
キャラクターが接地しているか判定するときに思った通りにならなくて困ったことはありませんか? 今回の記事ではそんな時に役立つ、接触が不安定な場合でも安定して接触を判定する処理について説明します。
本記事で紹介する接触判定クラスはGithub (https://github.com/nyanya-nnana/CollisionDetector)にソースをあげてあります。
こちらの記事は前記事のUniRxの代わりにDeligateを利用し実装したものとなります。本ソースコード以外はとくにusingしないで使用できるようになりました。
本記事ではDeligateを使用したバージョンの使用方法とその実装について紹介します。 衝突判定の安定化の原理等の共通内容は前記事を参照してください。
手っ取り早く使いたいという方は次の手順をどうぞ。
- CollisionDetectorコンポーネントを接触判定したいGameObjectにアタッチ
- 接触対象のタグをチェックする場合はCheckTargetTagをtrueにして対象のタグをTargetTagで設定
- 接触判定を使用したいスクリプトでCollisionDetectorをGetComponent
- OnCollisionEnterで処理したいメソッド(戻り値void、引数Collision)をonCollisionEnterSmoothedに追加
- OnCollisionStayで処理したいメソッド(戻り値void、引数Collision)をonCollisionStaySmoothedに追加
- OnCollisionExitで処理したいメソッド(戻り値void、引数Collision)をonCollisionExitSmoothedに追加
- onCollisionStaySmoothedでOnCollisionStayでしたい処理を追加
- onCollisionExitSmoothedでOnCollisionExitでしたい処理を追加
CollisionDetectorクラスの使用方法
CollisionDetectorの設定
衝突判定をしたいGameObjectにCollisionDetectorをAddComponentしてください。 CollisionDetectorの設定項目は次の通りです。
Check Ohter Tag
衝突したGameObjectのタグをチェックするかしないか設定できます。
Target Tag
Check Other Tagがtrueの場合はここにTargetのタグを設定します。
Cut Off Frequency
衝突判定の安定度。低いほど判定の変化がゆっくりになります。
Detection Threshold Upper/Lower
衝突判定の閾値。2つの差が大きいほど変化しにくくなります。
衝突判定の利用
使用したいスクリプト内で
using NnanaSoft.CollisionDetector;
を宣言してください。 あとはStartかAwake内でGetComponentして 処理したいメソッドを次のようにデリゲートに追加すればおっけーです。 追加するメソッドの戻り値はvoid型、引数はCollision型にしてください。
private void Start() } var SmoothedCollision = GetComponent<CollisionDetector>(); // OnCollisionEnter SmoothedCollision.onCollisionEnterSmoothed += OnCollisionEnterMethod; // OnCollisionStay SmoothedCollision.onCollisionStaySmoothed += OnCollisionStayMethod; // OnCollisionExit SmoothedCollision.OnCollisionEnterSmoothed += OnCollisionExitMethod; } // OnCollisionEnter private void OnCollisionEnterMethod(Collision collision) { // ここに処理を記述 Debug.Log("OnCollisionEnterSmoothed"); } // OnCollisionStay private void OnCollisionStayMethod(Collision collision) { // ここに処理を記述 Debug.Log("OnCollisionStaySmoothed"); } // OnCollisionEnter private void OnCollisionExitMethod(Collision collision) { // ここに処理を記述 Debug.Log("OnCollisionExitSmoothed"); }
使用するとこんな感じになります。
CollisionDetectorクラスの実装
CollisionDetectorクラスのソースコードはGithubのコチラをご覧ください。
安定化した衝突判定のイベント通知にはデリゲートを使って実装します。
// 衝突時の処理用デリゲート public delegate void OnCollisionEnterSmoothedDelegate(Collision collision); public delegate void OnCollisionStaySmoothedDelegate(Collision collision); public delegate void OnCollisionExitSmoothedDelegate(Collision collision); // 衝突時の処理を追加する public OnCollisionEnterSmoothedDelegate onCollisionEnterSmoothed; public OnCollisionStaySmoothedDelegate onCollisionStaySmoothed; public OnCollisionExitSmoothedDelegate onCollisionExitSmoothed;
衝突時の処理用のデリゲートを用意して、そのデリゲートを宣言します。 対応するデリゲートに使用したいメソッドを加えることで該当のイベント時にメソッドが実行されます。
生の衝突判定とその時の衝突情報はOnCollisionEnter、Stay、Exitの処理中に更新して、これを使って衝突判定を数値化します。
// OnCollisionEnter private void OnCollisionEnter(Collision collision) { // タグが一致しない場合は何もしない if (checkOtherTag == false || other.gameObject.CompareTag(targetTag) == true) { _onCollisionRaw = true; _otherOnEnter = collision; _otherOnStay = collision; } } // OnCollisionStay private void OnCollisionStay(Collision collision) { // タグが一致しない場合は何もしない if (checkOtherTag == false || other.gameObject.CompareTag(targetTag) == true) { _otherOnStay = collision; } } // OnCollisionExit private void OnCollisionExit(Collision collision) { // タグが一致しない場合は何もしない if (checkOtherTag == false || other.gameObject.CompareTag(targetTag) == true) { _onCollisionRaw = false; _otherOnExit = collision; } }
衝突状態を1、していない状態を0としてFixedUpdate内で衝突判定を数値化します。_filterConstantはローパスフィルタの定数にあたります。
// 衝突しているかどうかを数値化。_filterConstantが大きいほど1サイクル前の状態を優先 _onCollisionFloat = (1.0f - _filterConstant) * onCollisionCurrent + _filterConstant * _onCollisionFloat;
次のように衝突判定の変化にヒステリシスを持たせて、
if (onCollisionPrevious) { // 1つ前のサイクルで衝突している場合、下限閾値を下回るまで状態を変化させない if (_onCollisionFloat <= detectionThresholdLower) _onCollision = false; else _onCollision = true; } else { // 1つ前のサイクルで衝突していない場合、上限閾値を上回るまで状態を変化させない if (_onCollisionFloat >= detectionThresholdUpper) _onCollision = true; else _onCollision = false; }
OnCollisionEnter、Stay、Exitになったときにデリゲートメソッドを実行します。
// OnCollisionEnterか、Stayか、Exitか判定 if (_onCollision == onCollisionPrevious) { _onCollisionEnter = false; _onCollisionExit = false; } else { if (_onCollision) { // OnNextでイベント通知 _onCollisionEnter = true; OnCollisionEnterSmoothedDelegate(onCollisionEnterSmoothed); } else { // OnNextでイベント通知 _onCollisionExit = true; OnCollisionExitSmoothedDelegate(onCollisionExitSmoothed); } } _onCollisionStay = _onCollision; // OnNextでイベント通知 if (_onCollisionStay) { OnCollisionStaySmoothedDelegate(onCollisionStaySmoothedDelegate); }
以上がCollisionDetectorの主な処理です。