本日のエンジニアブログを担当する安藤です。
今回はColliderの使い方について触れたいと思います。
はじめに
Colliderは形状が様々あるものの、
大きく非Trigger ColliderとTrigger Colliderの二つに分けられると思います。
(Character Controllerは別物とする)
そこで今回は
非Trigger ColliderとTrigger Colliderの使い分けについて触れていきたいと思います。
Colliderについて
衝突判定に使用するComponent、
Rigidbody Componentと組み合わせて物理的な挙動を簡単に実現出来る。
物理挙動有効化
Colliderをただ付けただけでは衝突処理を行いません。
RigidBodyを付けます。
※ 動かない判定のみのオブジェクトはColliderのみで機能します。
非Trigger Collider
Script例
// 衝突した瞬間に呼ばれる void OnCollisionEnter(Collision collision) { } // 衝突している間呼ばれ続ける void OnCollisionStay(Collision collision) { } // 衝突から離れた瞬間に呼ばれる void OnCollisionExit(Collision collision) { }
Trigger Collider
Script例
// 衝突した瞬間に呼ばれる void OnTriggerEnter(Collider other) { } // 衝突している間呼ばれ続ける void OnTriggerStay(Collider other) { } // 衝突から離れた瞬間に呼ばれる void OnTriggerExit(Collider other) { }
非TriggerとTriggerの組み合わせ例
爆発
Script
範囲内の大量のrigidbody付きColliderを飛ばします。
using UnityEngine; using System.Collections; public class Explosion : MonoBehaviour { [SerializeField] GameObject _obj; [SerializeField] int _count = 27; [SerializeField] int _maxX = 3; [SerializeField] int _maxZ = 3; [SerializeField] int _explosionRadius = 3; [SerializeField] int _explosionForce = 10; SphereCollider _collider; void Start () { for(int i=0;i<_count;i++){ GameObject obj = Instantiate(_obj,Vector3.zero,Quaternion.identity) as GameObject; Vector3 pos = Vector3.zero; float scale = obj.transform.localScale.x; pos.x = (i % _maxX) * scale; pos.z = ((i / _maxX) % _maxZ) * scale; pos.y = (i / (_maxX * _maxZ)) * scale; pos += transform.position; obj.transform.position = pos; } } Rect buttonRect = new Rect(5,5,100,50); void OnGUI(){ if(GUI.Button(buttonRect,"execute")){ if (_collider){ Destroy(_collider); } _collider = this.gameObject.AddComponent<SphereCollider>(); _collider.isTrigger = true; _collider.radius = _explosionRadius; } } void OnTriggerEnter(Collider other){ Vector3 normal = (other.transform.position - this.transform.position).normalized; other.rigidbody.AddForce(normal*_explosionForce,ForceMode.VelocityChange); if (_collider){ Destroy(_collider); } } }
イベントセンサー
Script
拡張性に欠けるがrigidbodyを減らす手段の一つとして
using UnityEngine; using System.Collections; public class Character : MonoBehaviour { [SerializeField] GameObject _string; void Start () { rigidbody.AddForce(Vector3.left,ForceMode.VelocityChange); _string.SetActive(false); } void OnTriggerEnter(Collider other){ _string.SetActive(true); } void OnTriggerExit(Collider other){ _string.SetActive(false); } }
TIPS
非Triggerの複数判定
void OnCollisionEnter(Collision collision) { foreach(ContactPoint point in collision.contacts){ // pointから色々取得して処理を行う } }
※ Trigger系は当たった数だけメソッドが呼ばれます。
接触点の検出
非Trigger
void OnCollisionEnter(Collision collision){ foreach(ContactPoint point in collision.contacts){ Vector3 hitPos = point.point; // hitPosの座標を使ってエフェクトなどを生成 } }
Trigger
void OnTriggerEnter(Collider other){ // おおまかなの場所を検出 Vector3 hitPos = other.ClosestPointOnBounds(this.transform.position); // hitPosの座標を使ってエフェクトなどを生成 }
高速化
処理が一番軽いのはSphere Colliderです。
距離で当たり判定をとっていると思われるので、
Scaleを均等に変更しないと実体と判定が乖離します。
判定のレイヤー分け
InspectorでMask行列のチェックを外すと判定処理されなくなる。
見えない壁
空のGameObjectに複数のColliderを追加して実装します。
以上です。