Unityで3D空間をコントローラーで移動させて、障害物に衝突したらちゃんと止まるようにする
コントローラーを使ってキャラクターを移動させて、障害物にぶつかったら止まるという基本の動作をUnityで実装する方法
つかったもの
Unity version
- unity 5.6.4f1
ユニティちゃん
- なんでもいいんだけど、以前から使ってみたかったユニティちゃんを利用
- ダウンロード - UNITY-CHAN!
Oculus Utilities
- versionは1.20.0(2017/11/09 release)
- https://developer.oculus.com/downloads/package/oculus-utilities-for-unity-5/
コントローラー
- みんな大好き箱〇コントローラー(PC用)
準備
床と障害物となる柱を設置
- 床は3D object > Terrain
- 柱は3D object > Cylinder
その前にユニティちゃんを配置
- import package > custom packageでダウンロードしてきたユニティちゃんパッケージをimport
- unitychan prefabsをHierarchyにD&Dして配置、位置調整
スクリプト(今回はunityWalking.cs)を作成してunitychanにセット
- create > C# script
Oculus Utilityのimport
- import package > custom packageでダウンロードしてきたOculus Utilityパッケージをimport
(コントローラーの十字キーの設定)
開発
以下のサイト様がとてもわかりやすかったので、上から試していってみた
tama-lab.net
1. transform.position
- 座標を直接書き換えることで移動する
- 移動というより瞬間移動的なもの
- 上記の理由より衝突判定を抜けてしまうことが多い
using System.Collections; using System.Collections.Generic; using UnityEngine; public class unityWalking : MonoBehaviour { public float speed = 3f; void Update () { if (Input.GetAxis("Vertical") > 0){ transform.position += transform.forward * speed * Time.deltaTime; } if (Input.GetAxis("Vertical") < 0){ transform.position -= transform.forward * speed * Time.deltaTime; } if (Input.GetAxis("Horizontal") > 0){ transform.position += transform.right * speed * Time.deltaTime; } if (Input.GetAxis("Horizontal") < 0){ transform.position -= transform.right * speed * Time.deltaTime; } } }
これで移動はできるようになったがcylinderを突き抜けていってしまうので衝突判定の設定をする
cylinderにはデフォルトでCapsule colliderがセットされているので、unitychanの方にcolliderとrigitbodyを設定する
- rigidbody
- use Gravity:オフ
- Is Kinematic:オフ
- capsule collider
- height: 2
- Center: 0, 1, 0
これで衝突判定されるようになったが、柱にぶつかった時の挙動がちょっと微妙。
調べればよい解決法があるのかもしれないがとりあえず次の方法を試してみる
2. RigidBody
Rigidbody.AddForce
- rigidbody
- use Gravity:オフ
- Is Kinematic:オフ
- capsule collider
- height: 2
- Center: 0, 1, 0
using System.Collections; using System.Collections.Generic; using UnityEngine; public class unityWalking : MonoBehaviour { public float speed = 10f; public Rigidbody rb; void Start(){ rb = GetComponent<Rigidbody> (); } void FixedUpdate () { float x = Input.GetAxis ("Horizontal") * speed; float z = Input.GetAxis ("Vertical") * speed; rb.AddForce (x, 0, z); } }
rigidbodyに力を加えて押す感じ?慣性で動き続けてしまうので微妙
Rigidbody.Velocity
using System.Collections; using System.Collections.Generic; using UnityEngine; public class unityWalking : MonoBehaviour { public float speed = 3f; float moveX = 0f; float moveZ = 0f; Rigidbody rb; void Start(){ rb = GetComponent<Rigidbody> (); } void Update () { moveX = Input.GetAxis ("Horizontal") * speed; moveZ = Input.GetAxis ("Vertical") * speed; Vector3 direction = new Vector3 (moveX, 0, moveZ); } void FixedUpdate(){ rb.velocity = new Vector3 (moveX, 0, moveZ); } }
- 慣性はなくなった
- ただ衝突判定時に回転してしまう
これもちゃんと調べればきちんと動く方法があるかもしれないのだが、とりあえず次を試してみる
3. CharacterController
CharacterController.SimpleMove
結論から言うとこのCharacter Controllerを使うと自分の意図してた動きを実現することができた
このCharacter Controllerとはカプセルcolliderと移動機能をセットにしたものでrigidbodyもセットしても反映されないらしいので、上の方法でセットしていたcolliderとrigidbodyは今回はセットしない
その代わりにCharacter Controllerをセットする
- Character Controller
- Center : 0, 1, 0
- Height : 2
using System.Collections; using System.Collections.Generic; using UnityEngine; public class unityWalking : MonoBehaviour { public float speed = 3f; float moveX = 0f; float moveZ = 0f; CharacterController controller; void Start(){ controller = GetComponent<CharacterController> (); } void Update () { moveX = Input.GetAxis ("Horizontal") * speed; moveZ = Input.GetAxis ("Vertical") * speed; Vector3 direction = new Vector3 (moveX, 0, moveZ); controller.SimpleMove (direction); } }