Skip to content

第01回 Input Systemとキャラクター操作

次回: 第02回 カメラ操作とコンポーネント分割

この授業の目的

ゲーム制作を通じてC#の文法と設計を学ぶ

  • ゲームの機能を段階的に実装しながら C#の用法と設計の基本を実践的に学ぶ
  • 個人でゲームを完成させる過程を通じて ゲーム制作の経験と全体観を養う
  • ソフトウエア部品の責務を理解し 保守と拡張を考慮した設計を身につける

制作するゲーム

2.5D形式の見下ろし型アクション

画像

  • 床は3DのPlaneまたはMesh
  • カメラは斜め上からフィールドを見る
  • プレイヤー、敵、アイテム等は3Dオブジェクト
  • 移動は水平面(X-Z平面)に限定する
  • ジャンプ、複雑な段差は授業内では扱わないが 実装は自由とする

10回の流れ

段階を踏んで基本的なゲームの構成要素を実装する

  1. Input Systemとキャラクター操作
  2. カメラ操作と参照設計
  3. 衝突判定とダメージ
  4. 攻撃処理と生成
  5. 敵AIとゲームフィール調整
  6. アイテムと回復
  7. GameManagerとゲーム状態
  8. タイトル画面とシーン遷移
  9. UIとリザルト表示
  10. 完成確認と発表

今回のテーマ

モダンな方法で キャラクターを動かす

ベタ書きしない 入力と移動の基本

今回の到達目標

プレイヤーキャラクターを操作できるようにする

  • 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キーが押されたか」ではなく 「プレイヤーの移動方向」として入力を扱います
  • 入力方法が変わっても、 移動処理側のコードを変えずに済みます
  • 今回は Move Actionで移動入力を扱います
  • Move Actionは Vector2 として読み取ります

Input Actions

入力の割り当てを定義するアセット

画像

  • Input Actions アセットを作成します
  • 今回は Move Actionを使います 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を使う

  • AwakeInputActions を作成します
  • 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);
    }
}

実習

このコードを参考にして、プレイヤーを動かしてみましょう

  1. Planeを配置する
  2. CapsuleをPlayerとして配置する
  3. Input Actionsアセットを作成する
  4. Move Actionを設定する
  5. C#コード生成を有効にして InputActions を生成する
  6. PlayerController をPlayerに追加する
  7. WASDまたは左スティックで 移動を確認する
  8. 移動方向へ振り向くことを確認する

動作しない場合は

上から順番に確認してみましょう

  • Move Actionの型が Vector2 になっているか
  • InputActions.cs が生成されているか
  • OnEnablePlayer Action Mapを有効化しているか
  • moveSpeed が0になっていないか
  • rotationSpeed が0になっていないか
  • direction の値がゼロのままになっていないか

今日のポイント

入力、移動、回転を分けて考え、順番に処理する

  • 入力は Input Action から受け取る
  • 移動方向は入力値から作る
  • 移動量は速度と時間から作る
  • 回転は移動方向から作る

提出

動作確認項目

  • WASDまたは左スティックで移動できる
  • 斜め移動が速くなりすぎない
  • キャラクターが移動方向へ振り向く
  • Move ActionをInput Systemで設定している
  • InputActions のC#コード生成を有効にしている
  • moveSpeedrotationSpeed をInspectorで調整できる

おつかれさまでした!

次回予告 第02回 カメラ操作と参照設計

カメラを動かし キャラも動かす