Unity 6でキー入力による移動を実装する ― Input Systemの基本
- 1. はじめに
- 2. 今回作るもの
- 3. Input Systemとは
- 4. Input Systemを準備する
- 5. Playerオブジェクトを作成する
- 6. 既定のInput Actionsを確認する
- 7. Moveの中身を確認する
- 8. PlayerControllerを作る
- 9. InputSystemを利用する
- 10. 移動速度を用意する
- 11. Move Actionを取得する
- 12. 入力値を読み取る
- 13. Vector2からVector3を作る
- 14. プレイヤーを移動する
- 15. なぜTime.deltaTimeを掛けるのか
- 16. 動かしてみる
- 17. 入力から移動までの流れ
- 18. 矢印キーやゲームパッドでも動かしてみる
- 19. Input Actionsを自分で作る方法(詳細)
- 20. Keyboard.currentという方法もある
- 21. 従来のInput Managerとの違い
- 22. なぜInput Systemを使うのか
- 23. まとめ
はじめに
Unityでプレイヤーをキーボード操作によって移動させる場合、以前は次のようなコードをよく使用していました。
float x = Input.GetAxis("Horizontal");
float y = Input.GetAxis("Vertical");
あるいは、
if (Input.GetKey(KeyCode.LeftArrow))
{
// 左へ移動
}
という書き方もよく使われていました。
しかし、現在のUnityでは、これらの古いInput Managerではなく、Input Systemを使う方法が基本となっています。
Unity 6の公式マニュアルでも、Input System Packageは新しく柔軟性の高い入力システムとして紹介されており、ほとんどのプロジェクトで推奨されています。従来のInput Managerはレガシー機能として扱われています。
今回は、
キーボード
↓
Input Action(Move)
↓
PlayerController
↓
GameObjectを移動
という流れで、キャラクターを上下左右に動かしてみます。
Unity 6では、Move(移動)などの基本的なInput Actionが、あらかじめ用意されています。今回はそれを使うため、自分でInput Actionsを作る必要はありません。自分で作る方法は、記事の途中にある折りたたみの中で説明します。
今回作るもの
キーボードの
W
A S D
または矢印キーを押すことで、GameObjectを上下左右に移動できるようにします。
たとえば、
W
↑
A ← Player → D
↓
S
という操作です。
今回重要なのは、
「Wキーが押されたか」をプログラムから直接調べるのではない
という点です。
Input Systemでは、
Wキー
Sキー
Aキー
Dキー
↓
Moveという入力
↓
Vector2
として扱います。
Input Systemとは
Input Systemは、Unityの新しい入力システムです。
キーボードだけでなく、
- ゲームパッド
- マウス
- タッチパネル
- ジョイスティック
- VR / XRコントローラー
など、さまざまな入力デバイスを統一的に扱えます。
Unity 6ではInput Systemが推奨されており、Input Systemパッケージのリリース版が提供されています。
Input Systemの大きな特徴は、
「ゲーム上の操作」と「実際のキー」を分離できること
です。
たとえば、
Move
という操作を作り、そこへ
キーボード WASD
キーボード 矢印キー
ゲームパッド 左スティック
などを登録できます。
つまりプログラム側では、
どのキーが押されたか
ではなく、
Moveという操作が行われた
と考えます。
Input Actionは、このように「操作の意味」と物理的な入力デバイスを分離するための仕組みです。
Input Systemを準備する
Unityのバージョンや作成したプロジェクトによっては、Input Systemがすでに利用できる状態になっている場合があります。
Package Managerを開き、「In Project」の一覧にInput Systemがあれば準備完了です。
Input Systemが入っていない場合
利用できない場合は、
Window
↓
Package Manager
を開き、
Input System
をインストールします。
インストール後に、新しい入力システムを有効にするか確認するダイアログが表示された場合は、「Yes」を選んでUnityを再起動します。
また、Edit → Project Settings → Player にある Active Input Handling が、Input System Package (New) または Both になっていることも確認しておきましょう。
Playerオブジェクトを作成する
まず、移動させるGameObjectを用意します。
2Dであれば、例えば
Hierarchy
↓
右クリック
↓
2D Object
↓
Sprites
↓
Square
などで作成できます。
名前を
Player
としておきましょう。
既定のInput Actionsを確認する
次に、Input Actionsを確認します。
Unity 6では、Move(移動)やJump(ジャンプ)など、よく使う操作があらかじめ登録されたInput Actionsが用意されています。
メニューから、
Edit
↓
Project Settings
↓
Input System Package
を開きます。
Project-wide Actions の欄に、
InputSystem_Actions
が設定されていれば、そのまま使えます。
作成用のボタンが表示されている場合は、それを押すと既定のInput Actionsが作成され、Projectウィンドウに InputSystem_Actions が追加されます。
InputSystem_Actions は、テンプレートによって、Assets 直下ではなく Assets → Settings フォルダの中にあります。見つからないときは、Projectウィンドウの検索欄に InputSystem_Actions と入力して探してください。
Project-wide Actionsに設定したInput Actionsは、プログラムから InputSystem.actions で直接使えます。また、最初から有効になっているため、有効化する処理も必要ありません。
中身は、次のようにActionがまとめられています。
InputSystem_Actions
├─ Player(Action Map)
│ ├─ Move
│ ├─ Look
│ ├─ Attack
│ ├─ Interact
│ ├─ Crouch
│ ├─ Jump
│ ├─ Previous
│ ├─ Next
│ └─ Sprint
└─ UI(Action Map)
このように、関連する操作をまとめたグループをAction Mapと呼びます。今回使うのは、Playerの中にあるMoveです。
Moveの中身を確認する
InputSystem_Actions をダブルクリックして開き、Player → Move を選んでみましょう。
Moveは、次のように設定されています。
Action Type : Value
Control Type : Vector2
なぜVector2なのでしょうか。
上下左右の移動には、
X方向
Y方向
という2つの値が必要だからです。
例えば、
右 → ( 1, 0)
左 → (-1, 0)
上 → ( 0, 1)
下 → ( 0, -1)
となります。
Moveには、キーやスティックを結び付ける「Binding」が登録されています。キーボードのBindingは、「WASD」という名前のComposite(上下左右の4方向をまとめるBinding)に入っていて、次のように登録されています。
Up → W / Up Arrow
Down → S / Down Arrow
Left → A / Left Arrow
Right → D / Right Arrow
このように、1つの方向に、WASDのキーと矢印キーの2つが割り当てられています。
これによって、
W → (0, 1)
S → (0,-1)
A → (-1,0)
D → (1, 0)
というVector2を取得できます。矢印キーでも同じ値になります。Bindingの一覧には、このほかに、ゲームパッドの左スティックなども並んでいます。
PlayerControllerを作る
次にC#スクリプトを作成します。
Playerを選択して、InspectorのAdd Componentをクリックします。
検索欄に、
PlayerController
と入力します。
検索結果の一番下に、
New script
と表示されるので、それを選びます。
名前が PlayerController になっていることを確認して作成すると、スクリプトが作成され、そのままPlayerにアタッチされます。
スクリプトの作り方は、ほかにもあります。この記事では、迷わないようにこの方法だけで進めます。
作成されたスクリプトは、Projectウィンドウでダブルクリックすると開けます。中身を、次のように書き換えます。
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
[SerializeField]
private float speed = 5.0f;
private InputAction moveAction;
private void Start()
{
moveAction = InputSystem.actions.FindAction("Player/Move");
}
private void Update()
{
Vector2 moveInput = moveAction.ReadValue<Vector2>();
Vector3 move = new Vector3(
moveInput.x,
moveInput.y,
0
);
transform.position += move * speed * Time.deltaTime;
}
}
ここからコードを詳しく見ていきます。
InputSystemを利用する
using UnityEngine.InputSystem;
Input Systemのクラスを使用するために必要です。
今回使用する、
InputAction
や、
InputSystem
もInput Systemに含まれています。
移動速度を用意する
[SerializeField]
private float speed = 5.0f;
プレイヤーの移動速度です。
SerializeFieldを付けているため、privateでありながらInspectorから値を変更できます。
例えば、
Speed
5
のように表示されます。
Move Actionを取得する
private InputAction moveAction;
ここには、Move Actionを保存します。
InputActionは、MoveやJumpのような「操作」を表すクラスです。
private void Start()
{
moveAction = InputSystem.actions.FindAction("Player/Move");
}
Start() は、ゲームを開始したときに1回だけ呼ばれるメソッドです。
InputSystem.actions は、Project-wide Actionsに設定した InputSystem_Actions を指します。
FindAction(“Player/Move") で、Action Mapの「Player」にある「Move」を探します。「Action Map名/Action名」の形で指定します。
毎フレーム探すのは無駄なので、最初に1回だけ探して、moveActionへ保存しておきます。
入力値を読み取る
Vector2 moveInput = moveAction.ReadValue<Vector2>();
ここがInput Systemで重要な部分です。
Update() の中で、Move Actionの現在の値を毎フレーム読み取ります。
例えば、
Dキー
Vector2
(1, 0)
となります。何も押していないときは、(0, 0) です。
Vector2からVector3を作る
UnityのTransformの座標はVector3です。
そのため、
Vector3 move = new Vector3(
moveInput.x,
moveInput.y,
0
);
としてVector3へ変換しています。
2Dゲームなので、
Z = 0
としています。
プレイヤーを移動する
transform.position += move * speed * Time.deltaTime;
現在位置に移動量を加えています。
考え方としては、
現在位置
+
移動方向
×
速度
×
経過時間
です。
なぜTime.deltaTimeを掛けるのか
次のように、
transform.position += move * speed;
だけにすると、Updateが呼び出される回数によって移動速度が変わってしまいます。
例えば、
60 FPS
120 FPS
ではUpdateの実行回数が異なります。
そこで、
Time.deltaTime
を掛けます。
move * speed * Time.deltaTime
とすることで、おおむね
1秒あたりspeedだけ移動
という考え方にできます。
動かしてみる
Playerに PlayerController がアタッチされていることを確認して、ゲームを再生します。
W A S D キーでPlayerが上下左右に動けば成功です。
今回は、Player Inputコンポーネントを追加していません。Project-wide Actionsを使うと、PlayerInputがなくてもMoveの値を読み取れます。
動かない場合は、次の2点を確認してください。
1つ目は、Edit → Project Settings → Input System Package で、Project-wide Actions に InputSystem_Actions が設定されているかです。
2つ目は、Edit → Project Settings → Player の Active Input Handling が、Input System Package (New) または Both になっているかです。
入力から移動までの流れ
ここまでの処理を整理すると、次のようになります。
Wキーを押す
↓
Input System
↓
Move Action
↓
Vector2 (0, 1)
↓
ReadValue<Vector2>()
↓
moveInput
↓
Update()
↓
transform.position
↓
Playerが移動
ここが今回もっとも重要なポイントです。
矢印キーやゲームパッドでも動かしてみる
既定のMoveには、WASDだけでなく、矢印キーやゲームパッドの左スティックも登録されています。
ゲームを再生して、矢印キーでもPlayerを動かしてみましょう。ゲームパッドを接続している場合は、左スティックでも動きます。
プログラムは、まったく変更していません。
Input Systemの利点は、プログラムを変更せずに入力方法を追加できることです。MoveにBindingを追加するだけで、同じPlayerControllerをそのまま使えます。
これがInput Actionを使う大きな利点です。
Input Actionsを自分で作る方法(詳細)
ここまでは、Unity 6に用意されている既定のInput Actionsを使ってきました。
ここでは、自分専用のInput Actionsを作成し、PlayerInputコンポーネントとOnMoveメソッドで入力を受け取る方法を説明します。Input Systemの仕組みを一から確認したい場合や、既定のInput Actionsを使わない場合に役立ちます。
PlayerInput方式の流れを図にすると、次のようになります。

PlayerInput+OnMoveで受け取る詳しい手順(クリックで開く)
PlayerInputを追加する
Playerを選択してInspectorから、
Add Component
をクリックします。
検索欄に、
Player Input
と入力して、
Player Input
コンポーネントを追加します。
PlayerInput は、1人のプレイヤーと、そのプレイヤーが使用するInput Actionを関連付けるためのコンポーネントです。Input Actionの有効化やコールバックの設定も補助してくれます。
Input Actionsを作成する
Player Inputコンポーネントには、
Create Actions...
というボタンがあります。
これをクリックすると、
Input Actions
を保存できます。
例えば、
PlayerControls
という名前にします。
作成するとProjectウィンドウに、
PlayerControls.inputactions
が作成されます。
Action Mapとは
Input Actionsを開くと、
Action Maps
という項目があります。
Action Mapは、
関連する操作をまとめるグループ
だと考えると分かりやすいでしょう。
例えば、
Player
├─ Move
├─ Jump
└─ Attack
のようにまとめられます。
今回は、
Player
というAction Mapの中に、
Move
を作ります。
Move Actionを作る
Actionを追加して、
Move
という名前にします。
設定は次のようにします。
Action Type : Value
Control Type : Vector2
なぜVector2なのでしょうか。
上下左右の移動には、
X方向
Y方向
という2つの値が必要だからです。
例えば、
右 → ( 1, 0)
左 → (-1, 0)
上 → ( 0, 1)
下 → ( 0, -1)
となります。
WASDを登録する
Move ActionへBindingを追加します。
通常のBindingではなく、
Add Up/Down/Left/Right Composite
を使用します。
これは、
2D Vector Composite
として扱われます。
次のように設定します。
Up → W
Down → S
Left → A
Right → D
これによって、
W → (0, 1)
S → (0,-1)
A → (-1,0)
D → (1, 0)
というVector2を取得できます。
PlayerControllerを作る(OnMove方式)
次にC#スクリプトを作成します。
名前は、
PlayerController
とします。
Playerへアタッチしてください。
まず、次のように記述します。
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
[SerializeField]
private float speed = 5.0f;
private Vector2 moveInput;
public void OnMove(InputAction.CallbackContext context)
{
moveInput = context.ReadValue<Vector2>();
}
private void Update()
{
Vector3 move = new Vector3(
moveInput.x,
moveInput.y,
0
);
transform.position += move * speed * Time.deltaTime;
}
}
using宣言、移動速度、Vector3への変換、Time.deltaTimeについては、前の説明と同じです。ここでは、PlayerInput方式で異なる部分だけを見ていきます。
入力値を保存する
private Vector2 moveInput;
ここには、現在の移動方向を保存します。
例えばDキーを押している場合、
(1, 0)
Wキーなら、
(0, 1)
が入ります。
OnMoveメソッド
public void OnMove(InputAction.CallbackContext context)
{
moveInput = context.ReadValue<Vector2>();
}
ここがInput Systemで重要な部分です。
Move Actionが発生すると、このメソッドが呼ばれます。
contextには、そのときの入力情報が渡されます。
そして、
context.ReadValue<Vector2>()
によってMove Actionの値を取得します。
例えば、
Dキー
Vector2
(1, 0)
となります。
PlayerInputとOnMoveを接続する
Player Inputコンポーネントの、
Behavior
を確認します。
授業でInput Systemの仕組みを見せるのであれば、
Invoke Unity Events
を使う方法が分かりやすいでしょう。
Player InputにActionごとのイベントが表示されるため、
Move
へPlayerオブジェクトを登録します。
そして関数として、
PlayerController
↓
OnMove
を指定します。
公式のInput Systemガイドでも、PlayerInputとInput Actionを使い、InputAction.CallbackContextを受け取るメソッドへ接続する方法が紹介されています。
入力から移動までの流れ(PlayerInput方式)
ここまでの処理を整理すると、次のようになります。
Wキーを押す
↓
Input System
↓
Move Action
↓
Vector2 (0, 1)
↓
PlayerInput
↓
OnMove()
↓
moveInput
↓
Update()
↓
transform.position
↓
Playerが移動
ここが今回もっとも重要なポイントです。
矢印キーにも対応する
Input Systemの利点は、プログラムを変更せずに入力方法を追加できることです。
Moveへもう1つ、
2D Vector Composite
を追加します。
例えば、
Up → Up Arrow
Down → Down Arrow
Left → Left Arrow
Right → Right Arrow
と設定します。
すると、
WASD
でも、
矢印キー
でも同じPlayerControllerを使用できます。
コードは変更する必要がありません。
ゲームパッドにも対応できる
さらにMoveへ、
Gamepad
↓
Left Stick
を登録すれば、ゲームパッドにも対応できます。
プログラム側は、
moveInput = context.ReadValue<Vector2>();
のままです。
つまり、
キーボード
WASD
↓
Move
↓
PlayerController
ゲームパッド
Left Stick
↑
という構造になります。
これがInput Actionを使う大きな利点です。
Keyboard.currentという方法もある
Input Systemでは、次のような書き方もできます。
if (Keyboard.current.leftArrowKey.isPressed)
{
transform.position += Vector3.left
* speed
* Time.deltaTime;
}
これは古い、
Input.GetKey()
とは異なり、新しいInput SystemのAPIです。
簡単な動作確認では便利です。
ただし、この方法では、
左矢印キー
という具体的なデバイス入力とプログラムが直接結び付きます。
Input Actionsなら、
Left Arrow
A
Gamepad Left Stick
などを、
Move
という1つの意味にまとめられます。
そのため、ゲームを作る場合はInput Actionsを使う設計の方が拡張しやすくなります。
従来のInput Managerとの違い
以前よく使用されたコードは、
Input.GetAxis("Horizontal");
や、
Input.GetKey(KeyCode.Space);
でした。
Input Systemでは考え方が変わります。
従来
キー
↓
プログラム
Input System
キー
↓
Binding
↓
Input Action
↓
プログラム
間に、
Input Action
が入るのが大きな違いです。
なぜInput Systemを使うのか
少し複雑に見えるかもしれません。
単純にキーを1つ読むだけなら、
Input.GetKey()
の方が簡単に見えます。
しかしゲームが大きくなると、
WASD
矢印キー
ゲームパッド
キーコンフィグ
複数プレイヤー
などへの対応が必要になることがあります。
Input Systemでは、
Move
Jump
Attack
のように「ゲーム上の操作」を中心に設計できます。
そのため、
入力デバイス
と、
ゲームの処理
を分離しやすくなります。
まとめ
Unity 6でキー入力を扱う場合は、Input Systemを使う方法を基本として考えるとよいでしょう。
今回の重要なポイントは、
Input System
Input Actions
InputSystem_Actions
FindAction
Vector2
Time.deltaTime
です。
特に覚えておきたい考え方は、
キーを直接調べる
のではなく、
Moveという操作を受け取る
ということです。
例えば、
W
↑
┌─────────┐
A ← │ Move │ → Vector2 → PlayerController
└─────────┘
↓
S
という構造です。
この仕組みを理解すると、後から
矢印キー
ゲームパッド
別のキー配置
を追加しても、PlayerControllerの移動処理をほとんど変更せずに対応できます。
これが、現在のUnityでInput Systemを使う大きなメリットです。
なお、PlayerInputとOnMoveを使う方法や、自分でInput Actionsを作成する方法は、記事の途中にある折りたたみの中にまとめています。










ディスカッション
コメント一覧
まだ、コメントがありません