今回はCharacterControllerの進化版であるOpenCharacterControllerコンポーネントを使ってキャラクターを操作してみたいと思います。
OpenCharacterControllerコンポーネントは以前からあるCharacterControllerの機能の不具合を修正していたり、より高度な機能になっているようです。
OpenCharacterControllerは現在(2020/04/07時点)ではベータ版です。
OpenCharacterControllerを使ってキャラクターを動かすと以下のようになりました。
OpenCharacterControllerを使ったキャラクタープレハブを含むプロジェクトは以下のページのClone or downloadからダウンロードしてください。
上記のページからOpenCharacterControllerコンポーネントの使い方が書かれたページに移動出来るので、詳しい事を知りたい方はそちらを参照すると良いでしょう。
ダウンロードしてプロジェクトを開くとAssets/_Standard Assets/Charactersフォルダ以下にキャラクターに関するファイルがあるので、さらにPrefabs/ThirdPersonフォルダのThirdPerson(Male)もしくはThirdPerson(Female)のいずれかをヒエラルキー上にドラッグ&ドロップしてUnityを実行するとすぐにOpenCharacterControllerを使ったキャラクターの動きを確認する事が出来ます。
もしくはAssets/_Standard Assets/Characters/Examples/Simple Movement Controller/Scenes/SimpleMovementControllerシーンに地面やキャラクターの設定がされているのでこちらで確認してください。
OpenCharacterController
OpenCharacterControllerコンポーネント(スクリプト)はスクリプトの中身を確認出来ます。
が、中身を解析するのは大変なので、今までのCharacterControllerと同じように設定値だけ見ていきます。
OpenCharacterControllerスクリプトはAssets/_Standard Assets/Characters/Scripts/Physicsフォルダにあります。
Player Root Transformにはキャラクターのルートボーンを設定します。
Root Transform Offsetはルートボーンからのオフセット値を指定出来ます。
Slope Limitはキャラクターが登れる坂の角度の限界値
Step Offsetはキャラクターが登れる高さ(階段等に上る時の段差)
Centerはコライダの中心位置
Radiusはコライダの半径
Heightはコライダの高さ
Collision Layer Maskは衝突として判定する相手のレイヤー
Slow Against Wallsは壁に対して速度を落とすかどうか
Min Slow Against Walls Angleは壁の角度に対しての最低速度
Slide Down Slopesは角度がSlope Limitを超えた場合にキャラクターが坂を滑り落ちるかどうか(チェックしてもしなくても滑り落ちるかも?)
Slide Max Speedは坂を滑り落ちる最大スピード
Slide Gravity Scaleは坂を滑り落ちる時の重力のスケール
Slide Start Timeは坂を滑り落ち状態になってから滑り落ち開始した時間(滑り落ちるまでの時間?、ジャンプを無効にする為に使用するようです)
Skin Widthは衝突するコライダが食い込む幅
Min Move Distanceはキャラクターが移動と判断する最小距離
Is Local Humanはキャラクターがローカルの人間によって制御されるかどうか(ちょっとわかりません)。
Slide Along Ceillingは天井にぶつかった時に天井が斜めであった場合にスライドするかどうか
Trigger Queryはキャストクエリがトリガーコライダーにヒットするかどうか(ちょっとわかりません)。
となっています。
以前からあるCharacterControllerだと坂を滑り落ちるということはなかったので、そこら辺の設定等が増えていますね。
キャラクターを動かしてみる
ThirdPersonのプレハブを配置して動かすだけだと自分用にキャラクターのプレハブを使いたい時に大変なのと、
ThirdPersonプレハブで使われている他のスクリプトは設定値が多くてどのような使ったらいいのかが分かり辛いので
今回は今まで作ってきたスクリプトで同じようにキャラクターを動かしてみます。
キャラクターの配置
OpenCharacterControllerについて見てきたので、実際にキャラクターに取り付けて使ってみます。
あらかじめAnimatorControllerを作成し、Idle状態、Walk状態を作成し、アニメーションパラメータ―にFloat型のSpeedを用意し、0.1以上の時にWalk、0.1以下の時にIdleへと遷移するようにしておきます。
ここら辺は
を参照してください。
ヒエラルキー上にキャラクターモデルを配置し、AnimatorにAnimatorControllerを設定し、Assets/_Standard Assets/Characters/Scripts/PhysicsのOpenCharacterControllerを取り付けます。
OpenCharacterControllerを取り付けるとRigidbodyとCapsule Colliderが一緒に取り付けられます。
上のようにOpenCharacterControllerコンポーネントの設定をしました。
今までのCharacterControllerの設定と坂を滑り落ちるようにする設定をしました。
Rigidbodyは取り付けられた状態のままにし、Capsule ColliderはOpenCharacterControllerコンポーネントのコライダの設定と同じサイズのコライダにします。
Capsule Colliderは特に設定をしなくてもOpenCharacterControllerの設定がUnity実行時に反映されます。
キャラクター操作スクリプトの作成
キャラクターの設定が出来たので後は入力があった時にキャラクターを操作するスクリプトを作成し動かすだけです。
入力システムはInputManager(昔の入力システム)とInputSystem(新しい入力システムのベータ版)があるので二つのスクリプトを載せておきます。
キャラクターを移動させるスクリプトの詳細は
InputManagerの場合は
InputSystemの場合は
を参照してください。
InputManagerを使ったキャラクター操作スクリプト
まずはInputManagerを使ったキャラクター操作スクリプトです。
InputManagerの設定はデフォルトでされているものを使用しているので特に変更する必要はありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | using StandardAssets.Characters.Physics; using System.Collections; using System.Collections.Generic; using UnityEngine; public class NewCharacterTest : MonoBehaviour { private OpenCharacterController openCharacterController; private Animator animator; [SerializeField] private float walkSpeed = 2f; [SerializeField] private float jumpPower = 5f; private Vector3 velocity; // Start is called before the first frame update void Start() { openCharacterController = GetComponent<OpenCharacterController>(); animator = GetComponent<Animator>(); } // Update is called once per frame void Update() { if(openCharacterController.isGrounded) { velocity = Vector3.zero; var input = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical")); if(input.magnitude > 0f) { transform.LookAt(transform.position + input); velocity = input.normalized * walkSpeed; animator.SetFloat("Speed", input.magnitude); } else { animator.SetFloat("Speed", 0f); } if(Input.GetButtonDown("Jump")) { velocity.y += jumpPower; } } velocity.y += Physics.gravity.y * Time.deltaTime; openCharacterController.Move(velocity * Time.deltaTime); } } |
以前からあるCharacterControllerとの違いはusingディレクティブでStandardAssets.Characters.Physicsを指定している事と、CharacterControllerの部分をOpenCharacterControllerへと変更している事です。
そのまま代替しているだけですね。
InputSystemを使ったキャラクター操作スクリプト
次にInputSystemを使ったキャラクター操作スクリプトです。
InputSystemの場合はアクション設定ファイルを作成します。
アクション設定ファイルの作り方は
を参照してください。
移動はMoveアクション、ジャンプはJumpアクションを作成しています。
Player Inputコンポーネントをキャラクターに取り付け、Actionsにアクション設定ファイルを設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | using StandardAssets.Characters.Physics; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UI; public class NewCharacterTest2 : MonoBehaviour { private OpenCharacterController openCharacterController; private Animator animator; private Vector3 velocity; [SerializeField] private float walkSpeed = 2f; [SerializeField] private float jumpPower = 5f; private PlayerInput playerInput; private InputAction moveAction; private InputAction jumpAction; // Start is called before the first frame update void Start() { openCharacterController = GetComponent<OpenCharacterController>(); animator = GetComponent<Animator>(); playerInput = GetComponent<PlayerInput>(); moveAction = playerInput.currentActionMap.FindAction("Move"); jumpAction = playerInput.currentActionMap.FindAction("Jump"); } // Update is called once per frame void Update() { if (openCharacterController.isGrounded) { velocity = Vector3.zero; // 入力値を取得 var input = new Vector3(moveAction.ReadValue<Vector2>().x, 0f, moveAction.ReadValue<Vector2>().y); if (input.magnitude > 0f) { transform.LookAt(transform.position + input); velocity = transform.forward * walkSpeed; animator.SetFloat("Speed", input.magnitude); } else { animator.SetFloat("Speed", 0f); } // ジャンプ if(jumpAction.triggered) { velocity.y += jumpPower; } } velocity.y += Physics.gravity.y * Time.deltaTime; openCharacterController.Move(velocity * Time.deltaTime); } public void OnOpenCharacterControllerHit() { Debug.Log("衝突した相手"); } } |
StartメソッドでPlayerInputコンポーネントに設定したアクション設定ファイルから移動用のアクションをmoveAction、ジャンプ用のアクションをjumpActionに入れます。
移動はReadValueでVector2の値を取得しxとyのfloat値を入力とします。
ジャンプの場合はjumpActionのtriggeredプロパティでボタンが押されたかどうかを確認し、ジャンプ値を速度のy値に足しています。
これでInputSystemの入力での移動とジャンプが可能です。
最後に以前からあるCharacterControllerのコライダが衝突した時に実行されるOnControllerColliderHitイベントのOnCharacterController版のOnOpenCharacterControllerHitを試してみましたが、呼ばれていないようです。
イベントが設定されていない?
これで全ての機能が出来ました。
InputSystemを使う場合はUnityメニューのEdit→Project Settingsを選択して開いた後PlayerのOthers SettingsのActive Input HandlingをBothからInputSystemに変更しておいた方がいいかもしれません(変更時にUnityが再起動します)。
BothだとInputManagerとInputSystemの両方を使えますが、PS4コントローラーを接続して確認したところ勝手にキャラクターが動き出しました。
問題がなければ特に変更する必要はありません。
Unityを実行してキャラクターを動かして確認してみてください。
終わりに
機能がアップデートされると便利になる一方で設定する項目が増え使い方を覚えるのが大変ですね(^_^;)
サンプルのプロジェクトではキャラクターの追従をCinemachineで行っていたり、足の接地時のエフェクト(足音や足跡を残す)のコンポーネントがあったり、ThirdPersonBrainスクリプトの設定が膨大であったり、このまま使いこなすのは難しそうです。
以前のStandardAssetsがダウンロード出来なくなってキャラクターを追従するカメラ用のスクリプトであるFollowTargetやSmoothFollowがなくなったのは機能の確認をする時に不便ですね・・・(^_^;)
今見たらアセットストアにスタンダードアセット復活してました。(^_^;)
わたくしの場合は以前のプロジェクトに入っているのを持ってくるか、自前のカメラスクリプトを使うのでもいいんですが・・・・。
Cinemachineを使えばいいんですけど仮想カメラ作ったりしなければいけないし、設定項目がいっぱいあると不安になるんですよね(謎)