ゲームパッドで操作する (入力システムパッケージ版)

ページ更新日 :
ページ作成日 :

検証環境

Windows
  • Windows 11
Unity エディター
  • 2020.3.25f1
入力システムパッケージ
  • 1.2.0

この Tips の前提設定

この Tips の説明の前提として以下の設定を事前に行っています。

XInput と DirectInput について

Windows 限定の話になりますが、ゲームコントローラーの接続形式として「DirectInput」と「XInput」というものがあります。 ここでの「ゲームパッドは「XInput」に該当します。

今回のプログラムでは Gamepad クラスを扱っていますがこれは「XInput」に対応したコントローラーしか扱うことができません。 「DirectInput」に対応したコントローラーを使うには別の Joystick クラスを使う必要があります。

「DirectInput」は古くからある接続形式でボタンの定義などが割とあいまいになっており特殊な形状のコントローラーなどを扱うことができます。 しかし最近は「XInput」が主流になっていることもあり「DirectInput」に対応していないコントローラーも増えてきています。 「DirectInput」はボタンの定義が「1」「2」「3」という風になっているのでゲーム制作者はゲームとコントローラーのボタン対応を適切に設定できるように作らなければなりません。

「XInput」は「DirectInput」の次世代として定義されたもので A ボタンや B ボタン、トリガー、スティックなどあらかじめ定義されています。 そのためコントローラーの形状はほぼ決まったものしか使えませんが、 ボタンなどの定義がきちんと決まっているのでゲーム制作者はボタンの配置などを気にせずにコントローラーに合ったゲームを作ることができます。 最近のゲームコントローラーでは「XInput」のみに対応しているものも増えてきています。

ボタンを押しているかどうかを判定する

ボタンを押しているかどうかについてはキーボードやマウスと同様に xxxxxxxx.isPressed プロパティで判定することができます。 ここでは押しているボタンの種類をテキストに表示させてみたいと思います。

まず表示用テキストオブジェクトを配置します。

判定用のスクリプトを作成します。ファイル名は任意ですがここでは GamepadButtons とします。

スクリプトは以下のようにします。

using System.Text;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class GamepadButtons : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  StringBuilder Builder = new StringBuilder();

  // 更新はフレームごとに1回呼び出されます
  void Update()
  {
    if (TextObject == null)
    {
      Debug.Log($"{nameof(TextObject)} が null です。");
      return;
    }

    // 1つ目のゲームパッドの情報を取得
    var gamepad = Gamepad.current;
    if (gamepad == null)
    {
      Debug.Log("ゲームパッドがありません。");
      TextObject.text = "";
      return;
    }

    Builder.Clear();

    // ボタンを押している間は xxxxxxxx.isPressed が true を返します

    // B ボタンや East ボタン、○ボタンは読み方が違うだけで同じボタンです
    // これは PlayStation や Xbox, Switch などでボタンの読み方が違うためです
    if (gamepad.aButton.isPressed) Builder.AppendLine($"A");
    if (gamepad.bButton.isPressed) Builder.AppendLine($"B");
    if (gamepad.xButton.isPressed) Builder.AppendLine($"X");
    if (gamepad.yButton.isPressed) Builder.AppendLine($"Y");

    if (gamepad.buttonEast.isPressed) Builder.AppendLine($"East");
    if (gamepad.buttonWest.isPressed) Builder.AppendLine($"West");
    if (gamepad.buttonNorth.isPressed) Builder.AppendLine($"North");
    if (gamepad.buttonSouth.isPressed) Builder.AppendLine($"South");

    if (gamepad.circleButton.isPressed) Builder.AppendLine($"Circle");
    if (gamepad.crossButton.isPressed) Builder.AppendLine($"Cross");
    if (gamepad.triangleButton.isPressed) Builder.AppendLine($"Triangle");
    if (gamepad.squareButton.isPressed) Builder.AppendLine($"Square");

    // コントローラーの中央にあるスタートボタン、セレクトボタン、メニューボタン、ビューボタンなどに該当します。
    if (gamepad.startButton.isPressed) Builder.AppendLine($"Start");
    if (gamepad.selectButton.isPressed) Builder.AppendLine($"Select");

    // 左と右のスティックをまっすぐ押し込んだかどうかを判定します
    if (gamepad.leftStickButton.isPressed) Builder.AppendLine($"LeftStickButton");
    if (gamepad.rightStickButton.isPressed) Builder.AppendLine($"RightStickButton");

    // 左上と右上にあるボタン。PlayStation だと L1 や R1 に該当します
    if (gamepad.leftShoulder.isPressed) Builder.AppendLine($"LeftShoulder");
    if (gamepad.rightShoulder.isPressed) Builder.AppendLine($"RightShoulder");

    // 押しているボタン一覧をテキストで表示
    TextObject.text = Builder.ToString();
  }
}

スクリプトを保存したら EventSystem にアタッチし、表示用テキストオブジェクトを設定します。

ゲームを実行して各ボタンが反応するか確認してみてください。

ちなみに以下のボタンはゲーム機によって読み方が異なるため複数用意されているものですが同じボタンとして定義されています。 上記プログラムではそれぞれ判定処理を入れているのでボタンを押すとボタンが3つ表示されるようになっています。

Xbox PlayStation そのほか
bButton circleButton buttonEast
aButton crossButton buttonSouth
xButton squareButton buttonWest
yButton triangleButton buttonNorth

ボタンとして判定できるものは以下の通りです。

  • A ボタン, ×ボタン, 下ボタン
  • B ボタン, ○ボタン, 右ボタン
  • X ボタン, □ボタン, 左ボタン
  • Y ボタン, △ボタン, 上ボタン
  • スタートボタン, メニューボタン
  • セレクトボタン, ビューボタン
  • 左ショルダーボタン, L1 ボタン
  • 右ショルダーボタン, R1 ボタン
  • 左スティックボタン
  • 右スティックボタン

ボタンを押した瞬間か判定する

押した瞬間の判定についてはキーボードやマウスと同じく xxxxxxxx.wasPressedThisFrame プロパティで判定できます。 押した瞬間に true の値を返し、それ以降は押しっぱなしでも false を返します。

動作確認として押したボタンをテキストで表示させてみます。表示用のテキストオブジェクトを配置してください。

スクリプトのファイル名はなんでも良いですがここでは GamepadButtonsOneFrame とします。

スクリプトは以下のようにします。簡略化のため4ボタンのみ判定しています。

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class GamepadButtonsOneFrame : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  // 更新はフレームごとに1回呼び出されます
  void Update()
  {
    if (TextObject == null)
    {
      Debug.Log($"{nameof(TextObject)} が null です。");
      return;
    }

    // 1つ目のゲームパッドの情報を取得
    var gamepad = Gamepad.current;
    if (gamepad == null)
    {
      Debug.Log("ゲームパッドがありません。");
      TextObject.text = "";
      return;
    }

    // ボタンが押された瞬間かどうかを判定
    if (gamepad.aButton.wasPressedThisFrame) TextObject.text += "A";
    if (gamepad.bButton.wasPressedThisFrame) TextObject.text += "B";
    if (gamepad.xButton.wasPressedThisFrame) TextObject.text += "X";
    if (gamepad.yButton.wasPressedThisFrame) TextObject.text += "Y";
  }
}

スクリプトを保存したら EventSystem にアタッチして表示用テキストオブジェクトをセットします。

ゲームを実行してボタンを押してみてください。押したボタンが追加されていくと思います。 また、ボタンを押しっぱなしにしても文字は追加されないことも確認できます。

ボタンを離した瞬間か判定する

サンプルはありませんが wasPressedThisFrame プロパティの代わりに wasReleasedThisFrame プロパティを使用することによって離した瞬間であるか判定することができます。

Dpad (方向キー) の押下を判定する

Dpad の押下判定を行います。ゲーム機によっては方向キーや十字キーと飛ばれますがいずれも同じものとして扱われます。 Dpad は基本的にその方向に押したか押していないかのみの判定となります。スティックのように「少し押している」のような判定はありません。

動作確認として押しているかどうかの判定を表示するためにテキストオブジェクトを配置します。

スクリプトを作成します。ファイル名は任意ですがここでは GamepadDpad とします。

スクリプトは以下のようにします。

using System.Text;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class GamepadDpad : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  StringBuilder Builder = new StringBuilder();

  // 更新はフレームごとに1回呼び出されます
  void Update()
  {
    if (TextObject == null)
    {
      Debug.Log($"{nameof(TextObject)} が null です。");
      return;
    }

    // 1つ目のゲームパッドの情報を取得
    var gamepad = Gamepad.current;
    if (gamepad == null)
    {
      Debug.Log("ゲームパッドがありません。");
      TextObject.text = "";
      return;
    }

    Builder.Clear();

    // Dpad の押下情報を Vector2 として取得するパターン
    var value = gamepad.dpad.ReadValue();
    Builder.Append($"(x:{value.x}, y:{value.y})");

    // Dpad の各方向のボタンを押しているかどうかの判定
    if (gamepad.dpad.left.isPressed) Builder.Append(" left");
    if (gamepad.dpad.right.isPressed) Builder.Append(" right");
    if (gamepad.dpad.up.isPressed) Builder.Append(" up");
    if (gamepad.dpad.down.isPressed) Builder.Append(" down");

    // Dpad の情報をテキストで表示
    TextObject.text = Builder.ToString();
  }
}

Dpad の情報は Gamepad.dpad で取得することができます。

Dpad には left, right, up, down の各方向ごとのプロパティがあり、それぞれ isPressed プロパティなどで押しているかどうかを判定することができます。

また DpadControl.ReadValue メソッドを使用することにより押している状態を Vector2 で取得することもできます。何も押していなければ (0, 0), 左を押していれば (-1, 0) という形で取得できます。

スクリプトを保存したら EventSystem にアタッチして表示用テキストオブジェクトをセットします。

ゲームを実行して Dpad を操作してみてください。

ちなみに Vector2 は正規化された状態になっていますので、斜めを押したときは (1, 1) ではなく (0.7071, 0.7071) のような数値で取得されます。

トリガーの押下を判定する

Xbox コントローラーでは左右にトリガーと呼ばれるボタンがあります。PlayStation では L2R2 に該当します。 このボタンは通常のボタンと異なり、押している量を 0.0~1.0 で取得することができます。 他のコントローラーでもトリガー以外の名称で搭載されているものもありますが、古いコントローラーなどでは単にボタンとして配置されていることもあり、その場合は押している判定は 0, 1 のみで扱われます。

ここではトリガーの押下量を確認してみたいと思います。Canvas に表示用のテキストオブジェクトを配置します。

スクリプトを作成します。他でも使用するのでここでは GamepadReadValue という名前にしておきます。

スクリプトは以下のようにします。

using System.Text;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class GamepadReadValue : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  StringBuilder Builder = new StringBuilder();

  // 更新はフレームごとに1回呼び出されます
  void Update()
  {
    if (TextObject == null)
    {
      Debug.Log($"{nameof(TextObject)} が null です。");
      return;
    }

    // 1つ目のゲームパッドの情報を取得
    var gamepad = Gamepad.current;
    if (gamepad == null)
    {
      Debug.Log("ゲームパッドがありません。");
      TextObject.text = "";
      return;
    }

    Builder.Clear();

    // トリガーの押下量を取得
    Builder.AppendLine($"LeftTrigger:{gamepad.leftTrigger.ReadValue()}");
    Builder.AppendLine($"RightTrigger:{gamepad.rightTrigger.ReadValue()}");

    // 情報をテキストで表示
    TextObject.text = Builder.ToString();
  }
}

Gamepad クラスにはそれぞれ leftTrigger, rightTrigger プロパティがあり ReadValue メソッドを呼ぶことによって押下量を 0.0~1.0 の範囲で取得することができます。 トリガーはボタンとして扱う事もできるので isPressed などの判定も行うことができます。 ちなみに isPressed が true になる ReadValue の量は 0.5 が基準となっています。

スクリプトを保存したら EventSystem にアタッチして表示用のテキストオブジェクトをセットします。

ゲームを実行してトリガーを動かしてみてください。

スティックの情報を判定する

スティックは左スティックと右スティックそれぞれの情報を取得することができ、スティックをどの方向にどのぐらい押し倒しているかの量を取得することができます。 もちろんコントローラーにスティックがなければこれらの情報は取得できません。

スティックの情報はそれぞれ Gamepad.leftStick, Gamepad.rightStick で取得することができます。

動作確認のスクリプトについては先ほどトリガーの取得で使用したスクリプトを流用します。

// 省略

public class GamepadReadValue : MonoBehaviour
{
  // 省略

  // 更新はフレームごとに1回呼び出されます
  void Update()
  {
    // 省略

    // トリガーの押下量を取得
    Builder.AppendLine($"LeftTrigger:{gamepad.leftTrigger.ReadValue()}");
    Builder.AppendLine($"RightTrigger:{gamepad.rightTrigger.ReadValue()}");

    // スティックの入力を取得
    var leftStickValue = gamepad.leftStick.ReadValue();
    Builder.AppendLine($"LeftStick:{leftStickValue.normalized * leftStickValue.magnitude}");
    var rightStickValue = gamepad.rightStick.ReadValue();
    Builder.AppendLine($"RightStick:{rightStickValue.normalized * rightStickValue.magnitude}");

    // 情報をテキストで表示
    TextObject.text = Builder.ToString();
  }
}

leftStick や rightStick から ReadValue メソッドを呼び出すと押下情報を Vector2 を取得することができます。 Vector2 なのでX軸やY軸にどれぐらい押しているかについては x や y プロパティで取得できますし、 押している方向を取得するなら normalized プロパティ, 押している量を取得するなら magnitude プロパティで取得できます。

実際にゲームを動かしてスティックを操作してみてください。

ゲームパッドの情報を取得する

接続しているゲームパッドから ID や名前などを取得することができます。 例えば接続されているコントローラーの種類を識別するために name を参照したり、 複数のゲームパッドが接続されている場合にどのゲームパッドと紐づけるかのために deviceId を参照したりできます。

ここでは動作確認のために情報をテキストに表示させてみます。

スクリプト名は任意ですがここでは GamepadInfo とします。

スクリプトは以下のようにします。

using System.Text;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class GamepadInfo : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  StringBuilder Builder = new StringBuilder();

  // 更新はフレームごとに1回呼び出されます
  void Update()
  {
    if (TextObject == null)
    {
      Debug.Log($"{nameof(TextObject)} が null です。");
      return;
    }

    // 1つ目のゲームパッドの情報を取得
    var gamepad = Gamepad.current;
    if (gamepad == null)
    {
      Debug.Log("ゲームパッドがありません。");
      TextObject.text = "";
      return;
    }

    Builder.Clear();

    // ゲームパッドの各情報を取得
    Builder.AppendLine($"deviceId:{gamepad.deviceId}");
    Builder.AppendLine($"name:{gamepad.name}");
    Builder.AppendLine($"displayName:{gamepad.displayName}");
    Builder.AppendLine($"shortDisplayName:{gamepad.shortDisplayName}");
    Builder.AppendLine($"path:{gamepad.path}");
    Builder.AppendLine($"layout:{gamepad.layout}");

    // 情報をテキストで表示
    TextObject.text = Builder.ToString();
  }
}

取得した Gamepad からいろいろな情報を取得できます。ここではいくつか抜粋して表示させています。

スクリプトを保存したら EventSystem にアタッチして表示用のテキストオブジェクトをセットします。

ゲームを実行して情報が表示されることを確認してみてください。