Unity で8番出口風ゲームを作る!#3
Unityでゲームを作る
Unity で8番出口風ゲームを作る!
Unity Version 2022.3.16
TPS風のプレーヤーコントロールとカメラ
Unity では、TPS やFPS 用のキャラクターを制御するために、CharacterController と呼ばれるコンポーネントが準備されている。今回は、このコンポーネントを使ってプレーヤーオブジェクトを作成する。
まず空のGameObject を作成して"Player" に名前を変更する。そのオブジェクトにCharacterController と PlayerInput をアタッチする。8番出口ではプレーヤーの体は全く表示されない(透明)のでレンダラー系のコンポネントをアタッチする必要はない。
CharacterController にはCollider の機能も含まれている。Collider の形はCapsule になっている。Collider系で設定するパラメータは身長(Height)と胴回り(Radius)、体の中心(Center)の3点。今回は、身長 1.7 m、胴回り 0.25 m、体の中心(0, 0.85, 0)とした。
あと、TPS視点を実現するため、MainCamera をPlayer オブジェクトの子オブジェクトにして、頭の位置に移動しておく。
PlayerInput は、マウスとキー入力イベントを取得するためにアタッチする。Input Actionの定義は、以下の4つを追加する。
- Look
- 視野移動のアクション。マウスのポジション位置をDelta(前回フレームからの差分)で取得する。
- Move
- WASD キーによる前後左右の移動のアクション。Vector2 型で入力値を取得する。
- Dash
- Dash 移動のアクション。Shift キーを押しながらWASD キーを押した場合はDash 移動する。
- Lock
設定したInput Action にそれぞれコールバック関数を設定する。
PlayerAction.cs
OnLookEvent コールバックでマウスポジションを取得して視野の移動を行う。マウスの上下移動はカメラを上下に回転させるが、マウスの左右移動は、プレーヤーオブジェクトを左右回転させることで視野を移動させる。(Cameraはプレーヤーオブジェクトの子オブジェクトになっているため)
OnMoveEvent コールバックではWASDキーによる前後左右入力をVector2 型で取得して、プレーヤーの移動を行う。このメソッド内では移動方向を計算するだけで、実際の移動処理はUpdate メソッドからコールされるDoMove メソッドにて行う。
OnDashEvent コールバックはShiftキーイベントの取得を行う。このメソッドでは単にDash中であるかどうかを判定するためのフラグのオンオフだけを行い、DoMove メソッドで実際の移動速度計算に反映させる。
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.InputSystem;
- public class PlayerActions : MonoBehaviour
- {
- [SerializeField] private CharacterController Controller;
- [SerializeField] private Camera MainCamera;
- private const float WALK_SPEED = 1.8f; // 1.8 [m/s]
- private const float DASH_SPEED = 1.8f * 3f; // 5.4 [m/s]
- private const float INVERT = -1f;
- private const float ROTATION_RATIO = 0.1f;
- private Vector3 _direction;
- private Vector3 _keyInput;
- private float _cameraAngle = 0f;
- private bool _isMoving = false;
- private bool _isDash = false;
- private bool _isLocked = false;
- public void OnLockEvent(InputAction.CallbackContext context)
- {
- if (context.phase == InputActionPhase.Started)
- {
- _isLocked = true;
- }
- else if (context.phase == InputActionPhase.Canceled)
- {
- _isLocked = false;
- }
- }
- public void OnLookEvent(InputAction.CallbackContext context)
- {
- #if UNITY_WEBGL
- if (!_isLocked) return;
- #endif
- if (context.phase == InputActionPhase.Performed)
- {
- Vector2 delta = context.ReadValue<Vector2>();
- _cameraAngle += delta.y * INVERT * ROTATION_RATIO;
- _cameraAngle = Mathf.Clamp(_cameraAngle, -89f, 89f);
- MainCamera.transform.localEulerAngles = new Vector3(_cameraAngle, 0f, 0f);
- this.transform.Rotate(new Vector3(0f, delta.x * ROTATION_RATIO, 0f), Space.Self);
- if (_isMoving)
- {
- _direction = this.transform.TransformVector(_keyInput);
- }
- }
- }
- public void OnMoveEvent(InputAction.CallbackContext context)
- {
- if (context.phase == InputActionPhase.Started)
- {
- _isMoving = true;
- Vector2 input = context.ReadValue<Vector2>();
- _keyInput = new Vector3(input.x, 0, input.y);
- _direction = this.transform.TransformVector(_keyInput);
- }
- else if (context.phase == InputActionPhase.Performed)
- {
- Vector2 input = context.ReadValue<Vector2>();
- _keyInput = new Vector3(input.x, 0, input.y);
- _direction = this.transform.TransformVector(_keyInput);
- }
- else if (context.phase == InputActionPhase.Canceled)
- {
- _isMoving = false;
- _direction = Vector2.zero;
- }
- }
- public void OnDashEvent(InputAction.CallbackContext context)
- {
- if (context.phase == InputActionPhase.Started)
- {
- _isDash = true;
- }
- else if (context.phase == InputActionPhase.Canceled)
- {
- _isDash = false;
- }
- }
- private void DoMove(float deltaTime)
- {
- var speed = (_isDash)? DASH_SPEED : WALK_SPEED;
- Controller.Move(_direction.normalized * deltaTime * speed);
- }
- // Update is called once per frame
- void Update()
- {
- DoMove(Time.deltaTime);
- }
- }
前回作成した通路Aを配置して、プレーヤーの移動のテストを行った結果がこちら。
次の記事