Appearance
第01回 Input Systemとキャラクター操作
この授業の目的
ゲーム制作を通じてC#の文法と設計を学ぶ
- ゲームの機能を段階的に実装しながら C#の用法と設計の基本を実践的に学ぶ
- 個人でゲームを完成させる過程を通じて ゲーム制作の経験と全体観を養う
- ソフトウエア部品の責務を理解し 保守と拡張を考慮した設計を身につける
制作するゲーム
2.5D形式の見下ろし型アクション

- 床は3DのPlaneまたはMesh
- カメラは斜め上からフィールドを見る
- プレイヤー、敵、アイテム等は3Dオブジェクト
- 移動は水平面(X-Z平面)に限定する
- ジャンプ、複雑な段差は授業内では扱わないが 実装は自由とする
10回の流れ
段階を踏んで基本的なゲームの構成要素を実装する
- Input Systemとキャラクター操作
- カメラ操作と参照設計
- 衝突判定とダメージ
- 攻撃処理と生成
- 敵AIとゲームフィール調整
- アイテムと回復
- GameManagerとゲーム状態
- タイトル画面とシーン遷移
- UIとリザルト表示
- 完成確認と発表
今回のテーマ
モダンな方法で キャラクターを動かす
ベタ書きしない 入力と移動の基本
今回の到達目標
プレイヤーキャラクターを操作できるようにする
- Input Systemで移動入力を受け取る
- 入力値から移動方向を作る
- X-Z平面でキャラクターを移動させる
- キャラクターを移動方向へ振り向かせる
- 移動速度と回転速度をInspectorで調整できるようにする
突然ですが、入力のベタ書きはNG
Input.GetKey(KeyCode.W) などのコードは避ける
- キーコードを直接書くと、入力の種類や割り当てが固定されてしまい、 ゲームパッドなど他の入力方法をサポートしにくくなります
- 従来のInputは簡単に使えますが、 複数デバイスやキーコンフィグを扱うと複雑になります
- 今回はInput Systemを使い、 「移動したい方向」をActionとして受け取ります
Input System とは
Unityの入力管理システム
Input Systemは従来のInputクラスに代わる入力管理の仕組みです- キーボード、ゲームパッド、タッチなどの入力を統一的に扱えます
Input Actionsアセットで、入力の種類や割り当てを定義します- スクリプトからはActionを通じて入力値を読み取ります
Input System を使用した入力
入力を抽象化する
- 「Wキーが押されたか」ではなく 「プレイヤーの移動方向」として入力を扱います
- 入力方法が変わっても、 移動処理側のコードを変えずに済みます
- 今回は
MoveActionで移動入力を扱います MoveActionはVector2として読み取ります
Input Actions
入力の割り当てを定義するアセット

Input Actionsアセットを作成します- 今回は
MoveActionを使いますMoveはWASD、方向キー、 左スティックなどに割り当てます - Action Typeは
Valueで数値を得ます ボタン入力の場合はButtonを選びます - Control Typeは
Vector2ゲームコントローラーのLTやRTはAxisを 選びます
Input Actions の C# コード生成
生成されたクラスから入力を読む

クラス名は自由に命名可能 デフォルトは InputSystem_Actions だが やや長いので授業では InputActions とする
Input ActionsアセットでGenerate C# Classを有効にすると、 アセットからC#コードを生成できます- 生成されたクラスを利用することで、 Actionへのアクセスが型安全になります
- 今回はコード生成を使用して、 生成されたクラスから入力を読み取ります
- クラス名は自由に命名できますが、ここでは デフォルトの
InputSystem_Actionsとします
入力値を読む
生成されたInputActionsを使う
AwakeでInputActionsを作成しますOnEnableでAction Mapを有効化しますReadValue<Vector2>()で移動入力を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移動へ変換する
Vector2からVector3へ
cs
var direction = new Vector3(
moveInput.x,
0f,
moveInput.y
);
// 斜め移動が速くなりすぎないようにする
direction =
Vector3.ClampMagnitude(direction, 1f);- Input Systemの移動入力は
Vector2ですが 3D 空間の移動方向はVector3で扱います - 入力の
xをワールドのxに 入力のyをワールドのzに適用します - そのままでは斜め入力時の移動の速度が √2倍(約1.414倍)になってしまいますので 長さを最大1に制限します
調整できる値はInspectorへ
コードに固定値を書かない
cs
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float rotationSpeed = 720f;- プレイ感に関わる数値は何度も調整しますので、 コードを書き換えずに変更できるようにするのがゲーム制作の基本です
- 変数の定義時に
SerializeFieldを付けると Inspectorから値を設定できるようになります - アクセス修飾子 を
publicにしても表示されますが、外部公開されてしまいます 特に理由がなければprivateを基本とするのがおすすめです
まずは素直に動かす
ワールド基準で移動する
cs
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
private InputActions 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を掛けて フレームあたりの移動量を求めます - まずは 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.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();
}cs
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#コード生成を有効にして
InputActionsを生成する PlayerControllerをPlayerに追加する- WASDまたは左スティックで 移動を確認する
- 移動方向へ振り向くことを確認する
動作しない場合は
上から順番に確認してみましょう
MoveActionの型がVector2になっているかInputActions.csが生成されているかOnEnableでPlayerAction Mapを有効化しているかmoveSpeedが0になっていないかrotationSpeedが0になっていないかdirectionの値がゼロのままになっていないか
今日のポイント
入力、移動、回転を分けて考え、順番に処理する
- 入力は
Input Actionから受け取る - 移動方向は入力値から作る
- 移動量は速度と時間から作る
- 回転は移動方向から作る
提出
動作確認項目
- WASDまたは左スティックで移動できる
- 斜め移動が速くなりすぎない
- キャラクターが移動方向へ振り向く
MoveActionをInput Systemで設定しているInputActionsのC#コード生成を有効にしているmoveSpeedとrotationSpeedをInspectorで調整できる