脳汁portal

アメリカ在住(だった)新米エンジニアがその日学んだIT知識を書き綴るブログ

Unityで3D空間をコントローラーで移動させて、障害物に衝突したらちゃんと止まるようにする

コントローラーを使ってキャラクターを移動させて、障害物にぶつかったら止まるという基本の動作をUnityで実装する方法

つかったもの

Unity version

  • unity 5.6.4f1

ユニティちゃん

Oculus Utilities

コントローラー

  • みんな大好き箱〇コントローラー(PC用)

f:id:portaltan:20171127153135p:plain

準備

床と障害物となる柱を設置

  • 床は3D object > Terrain
  • 柱は3D object > Cylinder

f:id:portaltan:20171127151048p:plain

その前にユニティちゃんを配置

  • import package > custom packageでダウンロードしてきたユニティちゃんパッケージをimport
  • unitychan prefabsをHierarchyにD&Dして配置、位置調整

f:id:portaltan:20171127151631p:plain

スクリプト(今回はunityWalking.cs)を作成してunitychanにセット

  • create > C# script

f:id:portaltan:20171127152004p:plain

Oculus Utilityのimport

  • import package > custom packageでダウンロードしてきたOculus Utilityパッケージをimport

(コントローラーの十字キーの設定)

portaltan.hatenablog.com

開発

以下のサイト様がとてもわかりやすかったので、上から試していってみた
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;
		}
	}
}

f:id:portaltan:20171127170805g:plain
これで移動はできるようになったがcylinderを突き抜けていってしまうので衝突判定の設定をする

cylinderにはデフォルトでCapsule colliderがセットされているので、unitychanの方にcolliderとrigitbodyを設定する

  • rigidbody
    • use Gravity:オフ
    • Is Kinematic:オフ
  • capsule collider
    • height: 2
    • Center: 0, 1, 0

これで衝突判定されるようになったが、柱にぶつかった時の挙動がちょっと微妙。
f:id:portaltan:20171219190106g:plain

調べればよい解決法があるのかもしれないがとりあえず次の方法を試してみる

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に力を加えて押す感じ?慣性で動き続けてしまうので微妙
f:id:portaltan:20171129095022g:plain

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);
	}
}
  • 慣性はなくなった
  • ただ衝突判定時に回転してしまう

f:id:portaltan:20171129095155g:plain

これもちゃんと調べればきちんと動く方法があるかもしれないのだが、とりあえず次を試してみる

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);
	}
}

f:id:portaltan:20171129095252g:plain