Unityにおけるゲームパッドの使い方

こんにちは、あおいちです。
この記事は[Life is Tech! Advent Calendar 2024](https://qiita.com/advent-calendar/2024/mentors "Qiita Home")の12日目の記事です。
~~この記事を12月12日当日に閲覧をしている方は今日自分の誕生日なので是非「誕生日おめでとう」と連絡をください。泣いて喜びます。~~
タスクを後回しにしすぎて12日に書き終わりませんでした、全て忘れてください。

今回はUnityにおけるゲームパッドの使い方について書こうと思います。

# 1. はじめに
**Unityのゲームを作る際にゲームパッド（Dualsense, Pro Controller, DualShockなど）を使用したことはありますか？**
普段はキーボードやマウスなど、PCにある入力装置を使ったゲームを作ることが多いと思いますが、実は簡単にゲームパッドを使用できるということは知っていましたたか？

なので、今回はゲームパッドの基本的な実装方法や、ゲームパッドを使うことによるゲームの拡張性についても少し述べていければと思います。
また、今回はDualShock（PS5のコントローラ）を使用しますが、上記で挙げたような他のゲームパッドでも操作可能です。

# 2. 動作について
まずは基本的なプレイヤーの動きや視点移動について解説していきます。
Unityでゲームパッドを使用するためには、**Input System**のパッケージを入れる必要があるので、こちらをPackage Managerから追加しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600193/cf4bdd2b-d57c-215c-569c-a97dcc2318a1.png)

<br>

次に、移動について実装をする際に、大きく分けて

**1. Player Inputコンポーネントを使用する方法**と
**2. コードでゲームパッドを直接処理する方法**

の二種類に分けられます。


## 2.1 Player Inputにおける実装
Player Inputとは、UnityのInput Systemパッケージで提供されているコンポーネントであり、入力データをイベントとして受け取ることができます。
要は**コードを少なく抑えながら複数の入力デバイスを定義することができる**ということです。

例えば、下記のPlayer Inputでは、Moveというイベントが定義されており、そのイベントに対してそれぞれゲームパッドの左スティックやキーボードのWASDなどが割り当てられており、どれかの入力デバイスにおいて該当する入力が検知されたらMoveイベントをトリガーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600193/485e0697-da27-ac4d-cdb8-828f2248ea52.png)

定義したアクションの入力データは、下記のようなスクリプトで呼び出すことができます。
この時注意する必要があるのは、関数が必ず`"On" + アクション名`である必要があるということです。
なので、今回であれば関数名は必ず`OnMove`でなければなりません。

```csharp:PlayerController.cs

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour
{
    private Vector2 movementInput;
    public float moveSpeed = 5f;

    private void Update()
    {
        // 移動処理
        MoveCharacter();
    }

    // Moveアクションの入力イベントを受け取る
    public void OnMove(InputValue value)
    {
        // 入力値（Vector2型）を取得
        movementInput = value.Get<Vector2>();
    }

    private void MoveCharacter()
    {
        // 入力に基づいてキャラクターを移動
        Vector3 movement = new Vector3(movementInput.x, 0, movementInput.y);
        transform.Translate(movement * moveSpeed * Time.deltaTime, Space.World);
    }
}
```


## 2.2 コードでゲームパッドを直接処理する方法

先ほどの説明で「Player Inputちょっとわかりにくいな、、」や「全部自分のコードでまとめたいな、、」という人には、こちらの方法で直接コードに書いてしまいましょう。
こちらは先に実装方法を提示してから解説をしようと思います。

```csharp:GamepadMovement.cs

using UnityEngine;
using UnityEngine.InputSystem;

public class GamepadMovement : MonoBehaviour
{
    public float moveSpeed = 5f;
    private Gamepad gamepad;

    void Update()
    {
        // 現在接続されているGamepadを取得
        gamepad = Gamepad.current;
        if (gamepad == null) return;

        // 左スティックの入力値を取得
        Vector2 stickInput = gamepad.leftStick.ReadValue();

        Vector3 movement = new Vector3(stickInput.x, 0, stickInput.y);
        transform.Translate(movement * moveSpeed * Time.deltaTime, Space.World);
    }
}

```

まず、わかりやすい違いとして、こちらでは`Gamepad`型が指定されていると思います。
Player Inputを使用するときと異なり、こちらは接続されているゲームパッドを明示的に取得する必要があります。
取得できたら、そのゲームパッドから`leftStick.ReadValue()`を呼ぶことで`Vector2型`の値が返ってくるので、そちらをもとに方向ベクトルを取得し移動の処理に落とし込めば実装完了です。
参考：https://docs.unity3d.com/ja/Packages/com.unity.inputsystem@1.4/manual/Controls.html

:::note info
ちなみに、複数のゲームパッドを接続している場合は`Gamepad.all[n]`から接続された順番で取得することができます。
なので、複数の`Gamepad`型の変数を設定して割り当てを行えばマルチプレイ実装も可能です。
:::



## 2.3 動作のまとめ
どうでしたか？意外と簡単に実装ができることがわかったと思います。
Player Inputと直接ゲームパッドを使用するのではそれぞれメリットでメリットがあります。
例えば、Player Inputはイベントベースであることから効率的なのに対して、動作を自身でコーディングする場合は入力を毎フレーム処理するためやや負荷が高いことが伺えると思います。
もちろん、イベントが発火された時のみに処理を行う、という実装もできるのですが、すべて自分で実装をすると設計をしてから実装をしないと煩雑になるため個人的には初めはPlayer Inputで実装をするのがおすすめです。

次は、コントローラの振動などのハプティクスや、光の出し方など、コントローラ特有の実装について解説したいと思います。


# ハプティクスについて

WIP