Appearance
第01回 Input Systemとキャラクター操作
次回: 第02回 カメラ操作とコンポーネント分割。
この授業の目的
- ゲームの機能を段階的に実装しながら C#の用法と設計の基本を実践的に学ぶ
- 個人でゲームを完成させる過程を通じて ゲーム制作の経験と全体観を養う
- ソフトウェア部品の責務を理解し 保守と拡張を考慮した設計を身につける
制作するゲーム

- 床は3DのPlaneまたはMesh
- カメラは斜め上からフィールドを見下ろす俯瞰カメラ
- プレイヤー、敵、アイテム等は3Dオブジェクト
- 移動は水平面(X-Z平面)に限定する
- ジャンプ、複雑な段差は授業内では扱わないが 実装は自由とする
全10回の流れ
- Input Systemとキャラクター操作
- カメラ操作とコンポーネント分割
- 攻撃入力と攻撃モーション
- 衝突判定とダメージ
- Enemyの探索・追跡・攻撃
- Enemyの状態制御とゲームフィール
- アイテムとオブジェクトプール
- GameManagerとゲーム状態
- UIとシーン遷移
- ビルドと公開
今回の授業内容
- Input Systemで移動入力を受け取る
- 入力値から移動方向を作る
- X-Z平面でキャラクターを移動させる
- キャラクターを移動方向へ振り向かせる
- 移動速度と回転速度をInspectorで調整できるようにする
今回の配布コード
この回で使う完成コードは、以下から個別に確認できます。
| ファイル | 内容 |
|---|---|
| Assets/Scripts/PlayerController.cs | 入力を読み取り、移動と振り向きを行う |
入力を抽象化する
Unityの入力マネージャー(Input Manager)はキーボードやマウス、ゲームパッドなどの入力を扱うための仕組みです。 例えば以下のように書けば、キーボードのWASDキーでプレイヤーを移動させることができます。
cs
// キーボードでの入力と移動の処理
if (Input.GetKey(KeyCode.W))
{
// 前進
}
else
if (Input.GetKey(KeyCode.S))
{
// 後退
}
else
if (Input.GetKey(KeyCode.A))
{
// 左移動
}
else
if (Input.GetKey(KeyCode.D))
{
// 右移動
}ですがここでゲームパッドの左スティックでも移動できるようにするには Input.GetAxis を併用しなければなりません。
cs
// ゲームパッドでの入力と移動の処理
if (Input.GetAxis("Vertical") > 0)
...Input Managerは簡単に使えますが、こうした個別対応のコードを都度書き加えながら複数の入力方法に対応するのは大変です。 キーボードとコントローラーの操作感を揃える手間もかかりますし、キーコンフィグの実装も自前で行う必要があります。
実はInput Managerは古い仕組みで、Unity 2019.1以降は新しいInput Systemの利用が推奨されています。 今回は新しい入力システムであるInput Systemの利用方法と、入力の抽象化の仕組みを学びます。
Input Systemで入力を抽象化する
Input Systemは従来のInput Managerに代わる入力管理のシステムで、その最も大きな特徴は入力をアクションとして抽象化できることです。 ゲーム側は入力デバイスやキーコードを意識せず、移動方向やジャンプ、メニューを開くといった必要なアクションの単位で入力を扱えるようになります。
アクション単位で入力をまとめることで、キーボード、ゲームパッド、タッチなどの複数デバイスを統一的に扱えるようになるのがInput Systemの大きな利点です。
Input Actionsアセットを設定する
Input SystemではInput Actionsアセットで入力の種類や割り当てを定義し、スクリプトからはActionを通じて入力値を読み取ります。
Input Actionsの設定手順
今回は Move Actionで移動入力を扱います。Move Actionはキー入力ではなく移動量を表す Vector2 として読み取ることができます。

Input Actionsアセットを作成しますPlayerAction MapにMoveActionを追加しますAction TypeをValue、Control TypeをVector2にします- WASD、方向キー、左スティックを割り当てます
Input ActionsからC#クラスを生成する

Generate C# Class を有効にすると、Actionへ型安全にアクセスするクラスが生成されます。 設定変更の際にコンパイルが発生しますが、TypoやAction名の変更に強く、コード補完も効き便利です。
この教材ではクラスを生成して利用します。 クラス名は InputSystem_Actions で統一しています。
生成されたクラスから入力値を読む
Awake で InputActions を作成し、OnEnable OnDisable でAction Mapを有効化/無効化します。
有効化されたAction MapのActionは ReadValue<T>() で値を読み取ることができます。 ここでは ReadValue<Vector2>() で移動入力を読み取っています。
cs
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private InputSystem_Actions _inputActions;
private void Awake()
{
_inputActions = new InputSystem_Actions();
}
private void OnEnable()
{
_inputActions.Player.Enable();
}
private void OnDisable()
{
_inputActions.Player.Disable();
}
private void Update()
{
var moveInput =
_inputActions.Player.Move.ReadValue<Vector2>();
// 省略2D入力を3Dの移動方向に変換する
cs
var direction = new Vector3(
moveInput.x,
0f,
moveInput.y
);
// 斜め移動が速くなりすぎないようにする
direction = Vector3.ClampMagnitude(direction, 1f);Input Systemの移動入力は二次元の Vector2 ですが 3D 空間の移動方向は三次元の Vector3 で扱います。 ここでは入力の x をワールドの x に、入力の y をワールドの z に適用します。
入力値は-1.0~1.0の範囲で正規化されています。 そのまま移動に適用すると斜め入力時の移動の速度が √2倍(約1.414倍)になってしまいますので、長さを最大1に制限します。
設定値をInspectorで調整可能に
cs
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float rotationSpeed = 720f;プレイ感に関わる数値は何度も調整することになります。こうした値はコードを書き換えずに変更できるようにするのがゲーム制作の基本です。 変数の定義時に SerializeField を付けると Inspector から値を設定できるようになります。
INFO
アクセス修飾子を public にしても Inspector から設定できるようになりますが、それでは変数が外部公開されてしまいます。 変数のアクセス修飾子は、特に理由がなければ private を基本とし、必要に応じて SerializeField で Inspector から設定できるようにすることをおすすめします。
プレイヤーをワールド座標基準で移動させる
cs
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
private InputSystem_Actions _inputActions;
// Awake / OnEnable / OnDisable は省略
private void Update()
{
var moveInput =
_inputActions.Player.Move.ReadValue<Vector2>();
var direction = new Vector3(moveInput.x, 0f, moveInput.y);
direction = Vector3.ClampMagnitude(direction, 1f);
transform.position +=
direction * (moveSpeed * Time.deltaTime);
}
}Time.deltaTime はフレーム内の経過時間です。移動速度に Time.deltaTime を掛ければ、1フレームあたりの移動量を求めることができます。 まずはプレイヤーを X-Z 平面で動かしてみましょう。
入力があるときだけ移動方向に振り向く
cs
if (direction != Vector3.zero)
{
var targetRotation =
Quaternion.LookRotation(direction);
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
targetRotation,
rotationSpeed * Time.deltaTime);
}Quaternion.LookRotation で、最終的な回転を表す Quaternion を作った後、Quaternion.RotateTowards で現在の回転から目標の回転へ、指定の速度で回転させます。rotationSpeed は1秒あたりに回転できる角度の速さ(度/秒)です。
これでプレイヤーが入力方向に指定の速度で振り向くようになります。
完成した PlayerController
cs
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float rotationSpeed = 720f;
private InputSystem_Actions _inputActions;
private void Awake()
{
_inputActions = new InputSystem_Actions();
}
private void OnEnable()
{
_inputActions.Player.Enable();
}
private void OnDisable()
{
_inputActions.Player.Disable();
}
private void Update()
{
var moveInput =
_inputActions.Player.Move.ReadValue<Vector2>();
var direction =
new Vector3(moveInput.x, 0f, moveInput.y);
direction = Vector3.ClampMagnitude(direction, 1f);
transform.position +=
direction * (moveSpeed * Time.deltaTime);
if (direction == Vector3.zero)
return;
var targetRotation =
Quaternion.LookRotation(direction);
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
targetRotation,
rotationSpeed * Time.deltaTime);
}
}実習:プレイヤーを操作できるようにする
- Planeを配置する
- CapsuleをPlayerとして配置する
- Input Actionsアセットを作成する
MoveActionを設定する- C#コード生成を有効にして
InputSystem_Actionsを生成する PlayerControllerをPlayerに追加する- WASDまたは左スティックで 移動を確認する
- 移動方向へ振り向くことを確認する
動作しない場合のチェックリスト
MoveActionの型がVector2になっているかInputSystem_Actions.csが生成されているかOnEnableでPlayerAction Mapを有効化しているかmoveSpeedが0になっていないかrotationSpeedが0になっていないかdirectionの値がゼロのままになっていないか
完成条件
- WASDまたはコントローラーの左スティックで移動できる
- 斜め移動が他の入力に比べて速くなっていない
- プレイヤーが移動方向へ振り向く
MoveActionをInput Systemで設定しているInputSystem_ActionsのC#コード生成を有効にしているmoveSpeedとrotationSpeedをInspectorで調整できる
まとめ
- 入力は
Input Actionから受け取る - 移動方向は入力値から作る
- 移動量は速度と時間から作る
- 回転は移動方向から作る