エンジニア

挫折しないUnity入門④ - Collider編

投稿日:2014年11月12日 更新日:

本日のエンジニアブログを担当する安藤です。
今回はColliderの使い方について触れたいと思います。


はじめに

Colliderは形状が様々あるものの、
大きく非Trigger ColliderとTrigger Colliderの二つに分けられると思います。
(Character Controllerは別物とする)

そこで今回は
非Trigger ColliderとTrigger Colliderの使い分けについて触れていきたいと思います。


Colliderについて

衝突判定に使用するComponent、
Rigidbody Componentと組み合わせて物理的な挙動を簡単に実現出来る。

物理挙動有効化

Colliderをただ付けただけでは衝突処理を行いません。
RigidBodyを付けます。
※ 動かない判定のみのオブジェクトはColliderのみで機能します。
スクリーンショット 2014-11-12 15.07.33


非Trigger Collider

剛体の入った判定処理を行う
主にプレイヤーや障害物に使用
スクリーンショット 2014-11-12 15.31.28

Script例

// 衝突した瞬間に呼ばれる  
void OnCollisionEnter(Collision collision) {
}
// 衝突している間呼ばれ続ける  
void OnCollisionStay(Collision collision) {
}
// 衝突から離れた瞬間に呼ばれる  
void OnCollisionExit(Collision collision) {
}

Trigger Collider

衝突検出のみを行う
爆発処理やイベント検出に使用
スクリーンショット 2014-11-12 15.31.38

Script例

// 衝突した瞬間に呼ばれる  
void OnTriggerEnter(Collider other) {
}
// 衝突している間呼ばれ続ける  
void OnTriggerStay(Collider other) {
}
// 衝突から離れた瞬間に呼ばれる  
void OnTriggerExit(Collider other) {
}

非TriggerとTriggerの組み合わせ例

爆発

スクリーンショット 2014-11-12 17.54.58 スクリーンショット 2014-11-12 17.55.59

GameObject
スクリーンショット 2014-11-12 18.01.38 スクリーンショット 2014-11-12 18.02.12

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);
        }
    }
}
イベントセンサー

スクリーンショット 2014-11-12 17.06.01 スクリーンショット 2014-11-12 17.06.18

GameObject
スクリーンショット 2014-11-12 17.10.36 スクリーンショット 2014-11-12 17.11.30

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系は当たった数だけメソッドが呼ばれます。

接触点の検出

スクリーンショット 2014-11-12 16.37.33

非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を均等に変更しないと実体と判定が乖離します。
スクリーンショット 2014-11-12 15.54.17

判定のレイヤー分け

ProjectSettingsからPhysicsを呼び出し
スクリーンショット 2014-11-12 15.47.57

InspectorでMask行列のチェックを外すと判定処理されなくなる。
スクリーンショット 2014-11-12 15.48.07

見えない壁

スクリーンショット 2014-11-12 15.27.45

空のGameObjectに複数のColliderを追加して実装します。
スクリーンショット 2014-11-12 15.35.40

以上です。

採用情報

ワンダープラネットでは、一緒に働く仲間を幅広い職種で募集しております。

-エンジニア
-

© WonderPlanet Inc.