本記事ではInput Systemの導入方法と、各種入力処理の実装方法*を解説してきます。
*Input Systemの概要や利点は他の方が書いた解説記事が多くあるため割愛します。
Input Systemの導入
Input Systemはパッケージとして提供されるシステムのため、以下の手順でUnityプロジェクトへ導入します。
上部メニュー[Window(ウィンドウ)]→[Package Manager(パッケージマネージャー)]からパッケージマネージャーウィンドウを開き、上部タブから[Unityレジストリ(Unity Registry)]を表示します。
Input Systemを選択し、インストールボタンをクリックします。
→ウィンドウ右上の検索機能を使うとスムーズに選択できます。
以下のような警告メッセージ*が表示されます。
→[Yes]をクリックするとUnityエディタが再起動し、Input Systemが有効化されます。
*:「新Input Systemを有効化すると旧Unity.Input APIは使用できなくなりますよー」といった内容で、共存させるには以下の手順を踏む必要があります。
アセットの互換性等の都合、旧Input APIを有効のままにしたい場合は設定の変更が必要です。
[編集]→[プロジェクト設定]→[プレイヤー]→[アクティブな入力処理]で、[両方(Both)]を選択
Action の設定
インプットアクションファイル(.inputactions)の作成
① ヒエラルキーウィンドウ右クリックから空のオブジェクトを作成し、[Player Input]コンポーネントをアタッチします。
② アタッチされたPlayer Inputのインスペクターから[Create Actions…]ボタンをクリックします。
③ エクスプローラーが表示されますので、任意の名前を付けて.inputactionsファイルを作成します。
④ ②の[Create Actions…]から作成した場合、[Player Input]の[Actions]に自動的に作成したインプットアクションファイルがアタッチされ、以下のようなインプットアクションウィンドウが展開します。
*プロジェクトウィンドウで右クリック→新規作成からも作成できます。
インプットアクションの基礎と構築ワークフロー
インプットアクションの各要素は以下のような内容になります。(クリックで拡大)
自分でオリジナルの入力アクションを定義する際は大まかに以下のような流れで作業を進めていきます。
- Action Maps(操作を受け付ける状況)を選択または新規作成
- Actions(どんな動作か)を選択または新規作成
- 2.のActionsに対応する入力をバインド(割り当て)
- Propertiesでバインドしたキー入力やアクションの詳細情報を調整する
各デバイスの入力設定(バインドの追加)
① Action右上の[+]ボタンをクリックして新規アクションを作成できます。
→今回は[Jump]というアクションを追加します。
② アクションの作成が完了したら、その下に現れた[No Binding]をクリックします。
右側にBinding Propertiesが表示されますので、[Path]右側の[▼]をクリックして[Listen]ボタンを押します。
[Listen]ボタンを押すと、Unityが入力待機状態となりますので、接続しているゲームパッドやキーボードの割り当て隊ボタンを押します。(例はゲームパッドのボタンを入力します。)
入力したボタンと対応する設定が自動で表示されます。
複数のコントローラに対応するため、[Button South]を選択します。(コントローラ種別で別設定も可)
最後に使用するコントロールスキームの[Gamepad](キーボードの方は[Keyboard&Mouse])にチェックを入れて、左上の[SaveAsset]をクリックして保存します。
これで、InputSystemでは[ゲームパッド南側のボタン(Xbox:Aボタン)]=[Jump入力]として扱うことができるようになりました。
設定したアクションをスクリプトで処理につなげる
ここからは、設定した[Jump]アクションを実際にスクリプトで認識する方法を解説していきます。
Player Input – Behavior (スクリプトへの通知方法)の設定
インプットアクションをアタッチしたPlayer Inputコンポーネントで[Behavior]を設定します。
→今回は[Invoke Unity Events]
Invoke Unity Eventsを設定すると現れる[イベント]タブを展開して先ほど追加した[Jump]アクションが存在することを確認しましょう。
プレイヤーゲームオブジェクトの準備
ここで、コントローラー(キーボード)で動かす対象となるオブジェクトを用意しましょう。
今回は以下の二つを構成します。
- Player:入力値によって動く対象
- InputSystem:PlayerInputがアタッチされているゲームオブジェクト
まずはPlayerInputをアタッチしているゲームオブジェクトの名前を[InputSystem]とリネームします。(任意)
入力内容が反映されるプレイヤーオブジェクトを追加します。
…ヒエラルキーウィンドウで右クリック→空のオブジェクトを作成
新規作成したPlayerオブジェクトに[SpriteRenderer]コンポーネントをアタッチして、デフォルトで用意されている[Background]スプライトを設定します。
次にプレイヤー用の入力受付スクリプトを用意します。
プロジェクトウィンドウで右クリック→C#スクリプト でスクリプトファイルを作成し、[Player]と名前を付けます。
スクリプト名は任意ですが、同プロジェクト内で重複が発生しないように注意が必要です
作成したスクリプトをPlayerオブジェクトにアタッチします。
(プロジェクトウィンドウからドラッグアンドドロップ)
スクリプトの作成
プレイヤーオブジェクトにアタッチしたPlayer.csを作成していきましょう。
Unity Eventsでの入力値の受け取り方は以下の形式になります。
using UnityEngine.InputSystem;
public void /*メソッド名*/ (InputAction.CallbackContext context){
//ここに入力を受け付けたときの処理を記述
}
今回は先ほど追加した[Jump]アクションに反応する以下のようなスクリプトを書きます。
using UnityEngine;
using UnityEngine.InputSystem;
public class Player : MonoBehaviour
{
public void OnJump(InputAction.CallbackContext context)
{
Debug.Log("ジャンプしました");
}
}
アクションイベントとスクリプトメソッドの紐づけ
スクリプトの追記が終了したら、PlayerInputで、Jumpアクションと作成した(OnJump)メソッドの紐づけをしていきます。
まずはPlayer Input-[イベント]→Player→[Jump]のオブジェクト欄にPlayerオブジェクトをアタッチします。
[No Function]の欄をクリックすると、Playerオブジェクトの持つコンポーネントが表示されますので、[Player]→[OnJump](先ほど定義したジャンプ入力受付メソッド)を選択します。
動作確認と現スクリプトの問題点
ここまでで、入力アクションを定義し、スクリプトと紐づける作業が完了しました。
プレイボタンを押して実際に動作を確認してみます。
ゲーム起動状態で、割り当てたゲームパッドのボタンを押してみると、「1回のボタン入力につき3回」設定したデバッグメッセージが出力されているのが分かります。
→つまり、一度ボタンを押すごとに、設定した3回分コールバックが呼び出されていることになります。
これには、InputSystemで入力処理を組み込んでいく上で重要な、[フェーズ]と[Action Type]の仕組みがかかわっており、これらを実現したい入力に応じて設定するのが、インプットアクションで少しだけ触れた[Interaction]の箇所になります。(↓)
次項でひとつづつ仕組みを確認しながら設定を修正していきましょう。
InputSystemのインタラクションフェーズ
InputSystemでの入力処理には、以下4つのフェーズ*が存在します。
- Waiting:入力待ち(入力0値状態)
- Started:Waiting状態で、入力を検知した(0値からの変化)
- Performed:入力を検知しており、かつそれが0値に戻らず変化している(入力強度の変化)
- Canceled:規定値(0値含む)以下の入力があった(≒アクションが終了)
*各フェーズの定義は設定により異なりますので、ここでは大まかな理解のための表現となっていることに注意してください(各設定の詳細は後述)
ためしに先ほどのコードにフェーズを出力するコードを追加して実行してみましょう。
public void OnJump(InputAction.CallbackContext context)
{
Debug.Log(context.phase); //フェーズの表示を追加
Debug.Log("ジャンプしました");
}
以下のように、Started、Performed、Canceledの三つのタイミングでコールバックが発生していることが分かります。
補足:フェーズについては、以下の公式ドキュメントでも解説されています。
Action Typeの設定
前項で4種類のフェーズについて触れましたが、
「どのフェーズでコールバックが発生するか」=「どのような時にフェーズの遷移が起きるか」
は、Action Typeで設定を行います。
Action Typeは、設定した各アクションの[Action Properties]から確認、編集ができます。
作成した[Jump]アクションのAction Typeを確認すると、[ボタン(Button)]が設定されていることが分かります。
Action Typeの種類は、Value・Button・Pass Throughの三種ですが、今回はValueとButtonについて解説します。
*以下、「W=Waiting、S=Started、P=Performed、C=Canceled」で表記します。
Value (値):
- W→S:入力値が0から0以上へ変化した時(Started)
- S→P:自動的に遷移。(Performed)
- P→P:再発火。入力値が0とならない範囲で値が変化した時。(Performed)
- P→C:入力値が0となった時。(Canceled)
- C→W:自動的に遷移。次回の入力を待つ。(Waiting)
>Point
- ゲームパッドのアナログスティックや強弱のあるボタン(トリガーボタン等)向き
- Started→Performedは自動的に遷移するため、重複処理が実行されないように注意
[if (context.started) などで処理を省くことが有効]
Button (ボタン):
- W→S:入力値が0から0以上へ変化した時(Started)
- S→P:入力値が閾値*以上となった時。(Performed)
- S/P→C:入力値が、S状態で0/P状態で閾値以下となった時。(Canceled)
- C→W:自動的に遷移。次回の入力を待つ。(Waiting)
>Point
- キーボード入力や、強弱のないゲームパッドボタン向き
- トリガーボタンなど以外でも、入力値に遊びが出る場合があるため、
基本的にはPerformedステートで入力判定を行うことが有効
例のJumpアクションはAction Type:Buttonでしたので、Started(=ボタン入力)、Performed(=閾値超過)、Canceled(=ボタンを離したとき)の三つのタイミングでコールバックが発生していたということになります。
スクリプトの修正~完成
Action Type、そしてフェーズごとのコールバックタイミングを確認したところで、現在のスクリプトを修正します。
現状の問題は、「Started、Performed、Canceledの三回コールバックが発生している」=「三回ジャンプを認識している」ことでした。
ジャンプボタンの機能としては、「ボタンを押したときに一回だけ」反応してほしいので、閾値以上の入力値を認識するPerformedフェーズで処理を発火するように設定します。
using UnityEngine;
using UnityEngine.InputSystem;
public class Player : MonoBehaviour
{
public void OnJump(InputAction.CallbackContext context)
{
// Performedフェーズの判定を行う
if (context.phase == InputActionPhase.Performed)
{
Debug.Log(context.phase);
Debug.Log("ジャンプしました");
}
}
}
実行してみると、Performedフェーズで一回だけメッセージが出ていることを確認できます。
今回の例が、最も基本的な入力処理実装の仕組みです。
→フェーズの遷移フローと、Action Typeでの違い、そしてスクリプトでのフェーズ判定がポイントです
その他のより詳細な設定や、逆引き形式での実装方法は追って記事にする予定です。
参考サイト
> Unity Doc
>マニュアル
コメント