【Unity】character controllerについて整理してみた C#
このアセットは、『ユニティちゃんライセンス』で提供されています。このアセットをご利用される場合は、『キャラクター利用のガイドライン』も併せてご確認ください。
ようやく少しUnityに触れる機会があったのでcharacter controllerについて調査してみました。
今回はUnityちゃんを対象にして実験していきます。
用意したのは
- Unityちゃん
- cube 2つ
- plane 1つ
です。
サンプル用のprojectはこちらの記事から
さらにUnityちゃんを動かすのにはこちらをそのまま参考にさせてもらいました。
今回はcharacter controllerのみについて扱うのでassetのimport等は省略しますね。
で、ここまできて動くことには動くようになりましたが、問題はここからです。 有名なテラシュールブログさんにもあるようにcharacter controllerには罠があるそうです。
でも便利なことは便利なものだと思うわけで、なんとか実用的な使い方はないものかと。
とりあえずcharacter controller について公式で説明を発見しました。
CharacterController は Rigidbdy による処理を持たなくてもコリジョンによって簡単に動きの制限を行うことが可能です。 CharacterController は力には影響されず、Move 関数を呼び出した時のみ移動します。 その時に移動を行いますがコリジョンによって制限されます。
さりげなくRigidbdyになってる... というのはいいとして、rigidbodyなしでcollsionがあるイメージでいいとのことです(テラシュールブログさんより) 確かにものが少ないほうが負荷は減るし助かるんですが、扱いが厄介で...
設定を間違えるとこのように浮いてしまいます。
そのため自動生成してもらえるAssetを買うか、自分で調整するしかない気がします。
とりあえず今回は上手くいったのでこのまま進めます。
他のcubeとの衝突について実験します。 左側のcubeにはrigidbodyを追加してあります。
衝突させると... このように動かせます。
反対側のcubeは 刺さります。
なるほどなるほど。普通ですね。
では試しに character controller -> capsule collider に差し替えてみます。
お風呂みたいになってしまいます。(反対も同じ
ならばさらに capsule collider + Rigidbody では rigidbodyなしのcubeは問題なさそう
では反対のcubeは お、 座標軸が変わってしまったようです。 cubeと一緒にunityちゃんも傾いていったようす。 このまま歩いたり、回れるんですが、重力があるせいで下に落ちてきます。不思議なかんじ。
おとなしくcharacter controllerを使えとのことのようです。
ここでcharacter controllerの衝突判定に使うOnControllerColliderHitを使ってみます。 コードはこんな感じにしました。
unitychanScript
using UnityEngine; using System.Collections; public class unitychanScript : MonoBehaviour { private Animator animator; GameObject plane,cube1,cube2; // Use this for initialization void Start () { animator = GetComponent<Animator>(); } // Update is called once per frame void Update () { if (Input.GetKey("up")) { transform.position += transform.forward * 0.01f; animator.SetBool("is_running", true); } else { animator.SetBool("is_running", false); } if (Input.GetKey("right")) { transform.Rotate(0, 10, 0); } if (Input.GetKey ("left")) { transform.Rotate(0, -10, 0); } } void OnControllerColliderHit(ControllerColliderHit hit){ if (hit.gameObject.CompareTag("cube1")) { Debug.Log(hit.gameObject); } else if (hit.gameObject.CompareTag("cube2")) { Debug.Log(hit.gameObject); } else if (hit.gameObject.CompareTag("plane")) { Debug.Log(hit.gameObject); } else { Debug.Log ("OnControllerColliderHit"); } } }
検出用にそれぞれのオブジェクトを設定しました。 tagで管理する方法が主流っぽい。
さて実験すると、 Planeしか出ない。一応if elseで優先度も意識したんだけどな。
上からなら 正常に判断してくれます。(左も一緒)
うーん。どうしたものか。cubeにscriptつけてみる。 scriptの詳細はこちら shop-0761.hatenablog.com 簡潔に言えばもろもろの衝突を検出する関数が書いてあります。 Logの出力は (衝突元のobject) hit (そのときの関数) with (衝突先のobject) となってます。
結果。 これならまだ納得いくけど、cube2が反応しない。 (こっちはcube2にrigidbody追加すれば反応しました。)
いっそunitychanに同じようなscript実装すればそっちでこと足りるのでは、と思い実装
このとき、unitychanとcube1にそれぞれscriptを追加。
いいかんじじゃん! 行けそう
てかcube1側でのscriptを無効にしてもいいんじゃね な ぜ お 前 が 生 き て い る ん だ(衝突判定はする)
componentからremoveすれば消えることには消えるんだけど、そうすると今度はunitychan側の 衝突関数が反応しない。
もう訳がわからない。これも使うなってことか。
と、巡り巡ってcharacter controllerに帰ってくるわけか。 ただplaneばっかり検出されて他のobjectが拾えない。
もう少し検証する必要がありそうだ。
なにか間違ってるところやこうしたら上手くいった、などなど教えてほしいです。
monodevelop嫌いになりそう(早く乗り換えたい