【意外とカンタン】世界一わかりやすいInput Systemの実装解説!コントローラーでゲームを動かそう!

ころもちゃん

ゲームをコントローラーを使って動かしたい!どうやったらいいのかな?

本記事の内容

・Unityでコントローラーから入力を受け付ける方法
・Input Systemの基本的な使い方
・Input Systemの応用方法(ゲームシーンでの操作とUI操作を切り替える)

目次

ゲームを操作する方法のあれこれ

ゲームの操作方法といえば...?

ゲームの基本としては、何かしらの操作をユーザが行うと、ゲームが反応する、ですよね。
この基本の「ユーザが操作を行うと処理を行う」には色んな方法があります。主な操作方法を挙げると以下のとおり。

操作方法概要
キーボード入力WASDで移動、スペースキーでジャンプ、みたいな操作
マウス操作マウス操作でカメラの向きを変更する、クリックで弾を発射するみたいな操作
タップ・フリック操作 画面内をタップ、スワイプなどの操作
コントローラー入力コントローラーの左スティックで移動、右スティックでカメラ変更、みたいな操作

これらの操作を統合的に管理できるのがInputSystemです。InputSystemを使うことで、複数の操作方法に簡単に対応できるようになるので、多様なプラットフォームへの展開やキーコンフィグの実装などが非常にラクになります。

そもそもInput Systemってなに?

Input Systemは、Unityが提供している、入力周りの操作をサポートしてくれるパッケージのことです。
2020年以前は、Input Managerというパッケージが提供されており、WEB上にはInput Systemよりも、Input Managerについての解説記事が多くあると感じます。
名前も似ているからどっちが最新かわからなくなったら、アルファベットが後(MよりS)の方が新しい方と覚えておくのがよいでしょう。

Input Managerを使った実装は古い実装となっており、今後Unityからサポートされづらくなりますし、なによりもInput Systemの方が使いやすい(主観)ので、これからゲームを作ろうという方には、オススメしません。

Input Systemを使うことで、以下のようなことが比較的簡単に実装することが可能になります。
【マルチプラットフォーム対応】キーボード入力と、コントローラーの入力どちらでも操作可能にする
【複雑な入力検知】単押し、長押し、同時押しなどの多様な操作コマンドの実装
【操作の切替】キャラクターの操作と、メニューを開いた時のUI操作に切り替える

ただ、Input Systemは困ったことに、少々のとっつきづらさと、日本語の解説が少ない、という欠点があります。
一度理解してしまえば、そこまで難しくないのですが、最初の理解までがちょっと難しかったりします。

そのため、できるだけ噛み砕いて、分かりやすくInput Systemの使い方を解説していきます。

Input Systemの基本的な使い方

インストール方法

このInput Systemですが、デフォルトのプロジェクトではインストールされていません。
デフォルトはInput Managerの方が有効になっているんですね。そのため、まずはInput Systemをインストールする必要があります。

インストールはいたって簡単。パッケージマネージャーから、Unityレジストリを選択し、

Input Systemと検索窓に入れてインストールをしましょう。

インストールボタンを押すと、以下のようなポップアップが表示されるので、Yesを押して進みましょう。
これは、前述したとおりデフォルトだと、旧式のInput Manager前提になっているので、新しいInput Systemに色々と書き換えますよ、という警告です。
Yesを押してエディタを再起動させましょう。

Yesを押して再起動

余談ですが、Input Systemをインストールすると、ビルド設定の有効な入力が、「InputManager(Old)」から、「Both」に自動で切り替わります。

Input Systemインストール後のビルド設定

これでインストール作業は完了です!

参考:チュートリアルプロジェクト

本題に入る前に、参考として。

Input Systemを使って、キャラクター操作を可能とするサンプルプロジェクトがUnityから無料で配布されています。
以下のUnity公式アセットをインストールすると、Input System実装済みプロジェクトを自由に使えます。

あわせて読みたい
Starter Assets - ThirdPerson | URP | Essentials | Unity Asset Store Get the Starter Assets - ThirdPerson | URP package from Unity Technologies and speed up your game development process. Find this & other Essentials options on t...

アセットストアからのインストール方法がわからない人はこちらの記事がオススメです。

シンプルな操作の人間を操作する3Dゲームだったら、このアセットの内容を流用するだけで十分だったりします。
キャラクターの歩き、ダッシュ、ジャンプ、カメラ操作などが、コントローラー操作とスマホでの操作、マウス・キーボード操作のすべてに対応しています。もちろんすべてのソースコードを見ることができます。

解説読むより実際のモノを見た方が早いんじゃ、という人はインストールしてみて、色々といじってみると勉強になるでしょう。

今回紹介実装の全体イメージと事前準備

では早速、本題のコントローラーによる操作を受け付けるセットアップをしていきます。
今回は、以下の操作が出来ることをゴールにしていきます。

なお、ボタン配置は、XBoxのコントローラーをベースにしています。

XBoxコントローラーのボタン配置
括りアクション操作内容
プレイ時の操作・【コントローラー】Aボタン
・【キーボード】スペース
ボールを上下左右に移動・【コントローラー】左スティック
・【キーボード】WASD
ボールを高速に上下左右に移動・【コントローラー】Bボタン+左スティック
・【キーボード】Shift+WASD
ボールを消滅・【コントローラー】L+Rボタン
ボールを吹っ飛ばす・【コントローラー】Xボタン長押し
UI操作UIの選択カーソルを移動(省略)
操作一覧


なお、Amazonや家電量販店などで、2000円程度でPC用のコントローラーは販売されているので、コントローラー操作を試す場合は、まずコントローラーを準備しておきましょう。

ちなみに、コントローラーの入力規格には、「Direct Input」と「X Input(もともとXBox用に開発された新しい方)」という2つの規格があり、ゲーム開発をするのであれば、どちらの規格でも動くかを確認できるように、規格を切り替えられるコントローラーがオススメです。

私は以下のコントローラーを使っています。
https://amzn.asia/d/be8l9x3

コントローラーの準備が出来たら、実際のInput Systemの実装していきましょう!

Input Actionsの実装:①Input Actionsの登録

Input Systemを使った実装を行うには、Input Actionsというものをプロジェクト内に作る必要があります。
とりあえず作ってみましょう。
プロジェクトウィンドウの適当なフォルダに移動し、右クリックを押して、「作成」 > 「Input Actions」と進みます。

Input Actionsの作成

アセット名は私は「MyControls」としました。これが後続のスクリプトで使用するクラス名になります。

この作成したInput Actionsを次にダブルクリック(インスペクタのEdit assetからでも可能)すると、以下のような画面が表示されます。

このウィンドウをよくみると、Action MapsとActionsというワードがあります。
これは先程の表で見ると以下の画像のような対応関係です。

この表に則り、Action Mapsと、Actionsを順番に作っていきます。
+ボタンを押すことでActionMapsとActionsを登録できます。まずは一番シンプルなJumpというアクションを登録しました。

+ボタンからActionMapsとActionsを追加

JumpのAction TypeはButonを設定しています。

Action Typeを設定


次にBindingの登録です。
これは、登録した「Jump」というアクションをどの操作で制御するか、を決める項目です。
今回なら、キーボードとコントローラーでの制御になるので、それぞれのBindingを登録していきます。

まずはキーボード入力のBindingの設定です。
<No Bindling>を選択して、Binding内のPath > Listenボタンを選択(以下のGIFだとListenボタンは隠れた位置にいます、なぜか私の環境はListernボタンが隠れます...)。
その後、設定したいキーボードのキー(今回はスペースキー)を入力すると、候補が表示されます。
もちろんお好みのボタンでもOKです、このボタンの設定が違ってもコードの内容は変わりません。

キー入力を紐づける手順

これで、キーボードの設定は完了です。

続いて同じ手順で、コントローラーのAボタンによるジャンプも登録します。
Bindingを追加し、コントローラーがPCと接続されていることを確認して同様の手順を行いましょう。
設定すると以下のようになるはずです。

Spaceキーとボタン入力の両方がActionのBindingに登録された

これで「Jump」というアクションと操作キーの紐づけが完了しました。
最後に上部のSave Assetで保存しましょう。

Save Assetを忘れずに!

ここまでで、JumpというActionがSpaceキーとコントローラーのAボタン(下にあるボタン)とひも付きました。

Input Actionsの実装:②Input Actionsと実際の処理との紐づけを行う

InputActionsの登録が出来たら、これを実際にジャンプを行う処理のスクリプトから呼び出せるようにしてあげる必要があります。

これを行うには、Input Actionsのアセットを選択し、インスペクタからGenerate C# Classというチェックボックを押す必要があります。
地味なので忘れがちですが、忘れずに実施しましょう。

「適用する(Apply)」ボタンを押すと、プロジェクトウィンドウに、スクリプトが追加されます。
これでOKです。

これで、自分が作ったスクリプトとInput Systemのキー入力受付を紐づける準備が整いました。

ジャンプさせるオブジェクトを適当に用意して、

Planeとボールだけのシーン

ジャンプさせたいオブジェクトに以下のスクリプトをアタッチします。
今回はボールのオブジェクトにスクリプトをアタッチしました。

ボールのインスペクタの設定

スクリプトは以下の通り。

using UnityEngine;
using UnityEngine.InputSystem;

public class BallMover : MonoBehaviour
{
    [SerializeField] private float jumpForce = 5.0f;
    private Rigidbody rb;
    private MyControls controls;

    private void Awake()
    {
        // Rigidbodyコンポーネントを取得
        rb = GetComponent<Rigidbody>();

        // MyControlsのインスタンスを作成
        controls = new MyControls();

        // ActionMaps[Player]の中の[Jump]というActionに紐づくイベントリスナーを登録
        controls.Player.Jump.performed += OnJumpPerformed;
    }

    private void OnEnable()
    {
        // Inputアクションを有効化
        controls.Enable();
    }

    private void OnDisable()
    {
        // Inputアクションを無効化
        controls.Disable();
    }

    private void OnJumpPerformed(InputAction.CallbackContext context)
    {
        // Rigidbodyに上方向の力を加える
        if (rb != null)
        {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
        }
    }
}

スクリプト内容を理解したい場合は、コピペしてChatGPTに解説してもらった方がわかりやすいと思うので、ここでは簡単に。

InputSystemと紐づいている先ほど生成したスクリプト、「MyControls」を使えるようにインスタンス化(実体化)し、対応するアクションが実行されたことを受け取って、OnJumpPerformedというメソッドが動きます。

一番のポイントはココです。

controls.Player.Jump.performed += OnJumpPerformed;

performed、すなわちJumpボタンが押されたときに、OnJumpPerformedというメソッドが動かすよ、という動きになります。

performed以外にも、以下のパターンがあります。
performed:処理が完全に成功したタイミング。例えば長押しの設定なら、長押し判定が成功したタイミングで実行される。
started:処理が開始したタイミング。例えば、長押しボタンを押し始めたタイミングで実行される。
canceled:処理がキャンセルされた場合。ボタンを離した瞬間や、移動入力が無くなった時などに使う。

アタッチ出来たら実行し、スペースキーか、登録したコントローラーのボタンを押してみてください。

Jump & Jump!

スペースキーを押した時と、コントローラーのAボタンの両方で反応していれば成功です!
思っていたよりかは難しくなかった...ですよね...?

Input Actionsの実装:③上下左右への移動を行う

先程のジャンプの処理は、キーを押したら1つの処理を実行するだけなので、シンプルでした。
次に、移動の処理を実装してみましょう。

コントローラー操作の場合、スティックを傾ける角度によって、移動する方向が変わります。
なので、どれだけ左右・上下どちらに傾けられているかの情報を取得して、その方角にキャラクターを移動させる必要があります。

これを踏まえて、先程のInput Actionsに「Move」の処理を追加していきます。
Actionsから新規アクションを追加するところまでは先程と同じですが、今回は
Action Typeが値(Value)、Control TypeがVector2Dになります。

Bindingには、WASDキーと、コントローラーの左スティックを登録していきます。
このとき、ポイントとしては上下左右をWASDキーを使って受け取る場合は、Bindingから、「UpDownLeftRightComposite」というBindingを選択する必要があります。

すると、以下のとおり上下左右に対応したBindingが表示されます。

上下左右移動に対応したBinding

Bindingを、先程のJumpの時と同じ要領で、コントローラーとキーボード(WASDキー)を設定すると以下のようになります。

これで、Input System側の設定は完了です。あとは先程のスクリプトに、移動を行う処理を追加しています。
追加後のスクリプトは以下の通りです。

using UnityEngine;
using UnityEngine.InputSystem;

public class BallMover : MonoBehaviour
{
    [SerializeField] private float jumpForce = 5.0f;
    [SerializeField] private float moveSpeed = 5.0f;

    private Rigidbody rb;
    private MyControls controls;

    private Vector2 moveInput;

    private void Awake()
    {
        // Rigidbodyコンポーネントを取得
        rb = GetComponent<Rigidbody>();

        // MyControlsのインスタンスを作成
        controls = new MyControls();

        // ActionMaps[Player]の中の[Jump]というActionに紐づくイベントリスナーを登録
        controls.Player.Jump.performed += OnJumpPerformed;

        // Moveアクションにリスナーを追加
        controls.Player.Move.performed += OnMovePerformed;
        controls.Player.Move.canceled += OnMoveCanceled;
    }

    private void OnEnable()
    {
        // Inputアクションを有効化
        controls.Enable();
    }

    private void OnDisable()
    {
        // Inputアクションを無効化
        controls.Disable();
    }

    private void OnJumpPerformed(InputAction.CallbackContext context)
    {
        // Rigidbodyに上方向の力を加える
        if (rb != null)
        {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
        }
    }

    //Moveの入力を受け取り、Rigidbodyを使ってボールを動かす
    private void FixedUpdate()
    {
        // 前後左右への移動を処理
        if (rb != null)
        {
            Vector3 move = new Vector3(moveInput.x, 0, moveInput.y) * moveSpeed * Time.fixedDeltaTime;
            rb.MovePosition(rb.position + move);
        }
    }

    private void OnMovePerformed(InputAction.CallbackContext context)
    {
        // Moveアクションの値を取得
        moveInput = context.ReadValue<Vector2>();
    }

    private void OnMoveCanceled(InputAction.CallbackContext context)
    {		

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

ゲーム制作の敷居を下げ、もっと多くの人にゲーム作りを楽しんでもらうために、ゲームをカンタンに作る方法を”網羅的に”解説しています。
よかったらブックマークお願いします。
Twitter(X)もよければフォローお願いします。

コメント

コメントする


reCaptcha の認証期間が終了しました。ページを再読み込みしてください。

目次