【Unity】InputSystemを使ってキャラクターの移動を実装【dualshock4の問題にも対応】【2023年版】

Unity入門2 - Project FireKeeper

InputSystem のインストールと設定

PackageManager でInputSystem をインストール

PackageMagager を開きます。

Packagesで UnityRegistry を選択します。

Input System を選択し、Install ボタンを押します。

Input System を有効にするために、Unityエディタを再起動するか聞かれるので Yes を選択します。

Player のキャラクターに PlayerInput を取り付ける

Unityエディタの再起動が終わったら、Player キャラクターに PlayerInput を追加します。HumanMale_Character_Free を選択し、 Add Component ボタンを押します。

Input から Player Input を選択します。

アクションの定義ファイル作成

追加した Player Input コンポーネントから Create Actions ボタンを押して、アクションを作成します。

保存場所とファイル名を聞かれるので、適当に名前を付けてアクションファイルを保存します。今回は Assets 直下に、MyInputActions という名称で保存しました。

初期設定状態で次のようなものが定義されています。

DualShock の×ボタンを押したら走るようにしたいので、中央の列のActions の + ボタンを押しAction 名を Sprint として新しいアクションを登録します。このとき、Action Type を Pass TroughControl Type を Button にします。

ここでAction Type を Button にすると、DualShock4 で正常に動作しなくなります。DualSense や XBox コントローラーなら、Action Type を Button にしても問題ありませんでした。

Sprint の下に GamePad の Button South と Left Shift を割り当てておきます。

修正が終わったら Save Asset ボタンを押して終了します。

Player Input の Actionsに 今作ったファイル名が登録されているはずです。このとき Behavior は Send Messages にしておきます。Send Message の場合、アクションに何か起こると、OnMove のように定義してあるアクション名の前に On が付いている関数が呼び出されます。

Send Message 以外の方法は後で説明します。

キャラクタの設定

キャラクタを操作して歩いたり走ったりできるようにするために、Character Controllerを追加し、アニメーションを設定していきます。

Character Controller の追加と設定

キャラクタの移動が可能になるように、HumanMale_Character_Free のコンポーネントに Character Controller を追加します。Inspecter から Add Component ボタンを押し、Physics を選択した後、Character Controller を選択します。

Character Controller に次のような値を設定します。

アニメーターコントローラの追加と設定

PlayerCharacter というフォルダを作成して、その中に Animator Controller を追加します。

作成したAnimator Controllerは、PlayerAnimatorController という名前にします。そして、

PlayerAnimatorController をHumanMale_Character_Free の Animator コンポーネントの Cotroller に設定します。(ドラッグアンドドロップ、または ⦿を押してPlayerAnimatorControllerを選択します。)

PlayerAnimatorController をダブルクリックして、Animatorの設定画面を開きます。

そうしたら Parameters を選択し、 +ボタンから Float を選択してパラメータを追加します。追加するパラメータ名は Speed にします。

続いて、Base Layer の開いているところで右クリックして、Create State から From New Blend Tree を選択して、BlendTreeを追加します。

追加した BrendTree の名前を Locomotion に変更します。

Locomotion をダブルクリックして BrendTree の設定を開きます。Inspecter の Motion の + ボタンを押して、 Add Motion Field で Motion を追加します。Add Motion Field を 3回実行します。

1個目のMotion の ⦿ を押して、Idle アニメーションを選択します。

同様の操作を繰り返して、WalkForward アニメーションと Sprint アニメーションを設定します。アニメーションの追加後に、Automate Thresholds のチェックを外し、Threshold の値を画像のように設定します。

スクリプトの追加

Assets フォルダに、スクリプトを置くための Scripts フォルダを作成します。

Scripts フォルダに、PlayerMove.cs を入れます。ファイルは、記事の後ろの方に添付してあります。

PlayerMove.cs を HumanMale_Character_Free のコンポーネントに追加します。(ドラッグアンドドロップ、または、Add Component から Scripts を選択して、PlayerMove.cs を選択します)

PlayerMove.cs

Player Input コンポーネントで、Behavior を SendMessages にした場合のスクリプトです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerMove : MonoBehaviour
{
    CharacterController characterController;
    PlayerInput playerInput;
    Animator animator;

    // 移動速度
    private float walkSpeed = 2f;
    private float sprintSpeedUpRatio = 4f;
    private float rotationSpeed = 720f;

    bool isRunning = false;
    Vector2 input = Vector2.zero;

    void Start()
    {
        characterController = GetComponent<CharacterController>();
        playerInput = GetComponent<PlayerInput>();
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        var velocity = Vector3.zero;


        // 方向キーの入力があったら、その向きにキャラクターを回転させる
        if (input.magnitude != 0)
        {

            Vector3 playerDirection = Vector3.Normalize(new Vector3(input.x, 0, input.y));
            Quaternion characterTargetRotation = Quaternion.LookRotation(playerDirection);
            transform.rotation = Quaternion.RotateTowards(transform.rotation, characterTargetRotation, rotationSpeed * Time.deltaTime);
        }

        // 移動速度の計算
        float speedByStick = input.magnitude;
        float moveSpeed = walkSpeed * speedByStick;

        if (isRunning)
        {
            moveSpeed *= sprintSpeedUpRatio;
        }
        velocity = transform.forward * moveSpeed;

        // アニメーションの速度設定
        animator.SetFloat("Speed", moveSpeed);

        // キャラクターの移動
        characterController.Move(velocity * Time.deltaTime);

        Debug.Log("isRunnging : " + isRunning.ToString());
    }

    public void OnMove(InputValue value)
    {
        input = value.Get<Vector2>();
    }
    public void OnSprint(InputValue value)
    {
        isRunning = value.isPressed;
    }

}

OnMove() と OnSprint() は、InputSystem からメッセージが送られてきて実行されます。

PlayerInput から CurrentActionMap を使って入力を読み込む方法

PlayerMove.cs の OnMove() と OnSprint() を消して、 Update() 内で以下の記述をしても、入力を読み込むことができます。

input = playerInput.currentActionMap["Move"].ReadValue<Vector2>();
isRunning = playerInput.currentActionMap["Sprint"].IsPressed();

Unity Event を使う方法

PlayerInput コンポーネントで、Invoke Unity Event を設定して、イベント経由で入力を読み込む方法もあります。

まず、 PlayerInput コンポーネントの Behavior で Invoke Unity Event を選択します。

PleyerMove.cs の代わりに、PlayerMove_event.cs をHumanMale_Character_Freeに取り付けます。

PleyerMove.cs との違いは、OnMove() と OnSprint() をコールバック関数に変えたところです。

    public void OnMoveEvent(InputAction.CallbackContext context)
    {
        input = context.ReadValue<Vector2>();
    }

    public void OnSprintEvent(InputAction.CallbackContext context)
    {
        // ボタンの状態を調べるだけなら次の行だけでも良い
        // isRunning = context.ReadValueAsButton();

        // ボタンが押されたとき、離されたときで処理を書く場合次のように書く
        switch (context.phase)
        {
            case InputActionPhase.Performed:
                isRunning = true;
                break;
            case InputActionPhase.Canceled:
                isRunning = false;
                break;
        }
    }

ボタンの状態に対して柔軟にコードを書くことができます。

PlayerInput モジュールの Events の Player にそれぞれコールバック関数を設定します。

DualShock4 での動作

PS4 のコントローラである DualShock4 を使った場合、Action Type を Pass TroughControl Type を Button にして、Send Message を使った方法しかうまく動きませんでした。(Control Type はAnyでも可)

Unity Event や playerInput.currentActionMap[“Sprint”].IsPressed(); を使った場合、また、Action Type を Button にした場合は、ダッシュボタンに設定した × ボタンを押しっぱなしにしているときに、他のボタンやスティックの入力があった場合、ボタンを離したという扱いになり IsPressed() などが false を返すようになります。

DualSense や XBos360 コントローラをつないだ場合はうまく動きます。

ファイル

おわりに

以上、InputSystem を使ったキャラクターの移動処理でした。