U
タブ 03カメラと入力6 レッスン — タップで開く
04 / 06 · 11 分
カメラと入力

新しい Input System

ここまでのプロジェクト

Assets/

Scripts/

PlayerMovement.csCharacterSwitcher.csSkillCaster.csInput.GetAxis / GetKey→InputRouter.cs

Settings/

PlayerControls.inputactions

プロジェクトの設定

Input System package

すでにあるものこのレッスンで追加このレッスンで置き換え

あなたが書いた三つのスクリプトはいまだに Input を直接呼んでいます。PlayerMovement は GetAxisRaw を、CharacterSwitcher は数字キーを、SkillCaster は Q、E、R を読んでいます。三つともキーボードに縛られているので、tab 05 でスマホに出すときに問題になります。

Input System ならアクションを一度定義しておけば、キーボード、ゲームパッド、タッチ入力をそこに紐付けられます。このレッスンの後は、プレイヤーがどの端末を持っているかを気にするスクリプトは一つも残りません。

アニメーション図

左に各種デバイス、中央に一つのアクションアセット、右にあなたのゲームプレイ側のコードという並びになります。

インストールと切り替え

  1. 1

    Package Manager → Input System → Install を実行します。Unity から再起動を尋ねてくるので、はいを選んでください。

  2. 2

    Edit▸Project Settings▸Player▸Active Input Handling → 移行が終わるまでは Both にしておきます。

  3. 3

    プロジェクト側:Create▸Input Actions で PlayerControls という名前で作成し、ダブルクリックでエディタを開きます。

  4. 4

    Generate C# Class にチェックを入れて Apply を押すと、Unity がラッパークラスを自動で生成してくれます。

アクションマップを組む

  1. 1

    Gameplay という名前の Action Map を追加します。

  2. 2

    Action Move は Action Type を Value、Control Type を Vector2 にします。2D Vector Composite のバインディングで W/A/S/D を割り当て、もう一つとして Gamepad の左スティックを追加してください。

  3. 3

    Action Look は Value → Vector2 とし、Mouse Delta と Gamepad の右スティックをバインドします。

  4. 4

    Jump と Attack の二つは Action Type を Button にし、Space / South ボタン、マウス左クリック / West ボタンを割り当てます。

  5. 5

    Skill1 / Skill2 / Skill3 も Button にして Q、E、R をバインドします。SkillCaster が現在直接読んでいるキーは、これで置き換わります。

  6. 6

    SwapCharacter は Value / Axis で、1、2、3 のキーをバインドします。CharacterSwitcher の読み取りもここに置き換わります。

コードから読み取る

InputRouter.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class InputRouter : MonoBehaviour
{
    // filled by the generated class
    private PlayerControls controls;

    public Vector2 Move { get; private set; }
    public Vector2 Look { get; private set; }
    public bool JumpPressed { get; private set; }

    void Awake()
    {
        controls = new PlayerControls();

        controls.Gameplay.Move.performed += ctx => Move = ctx.ReadValue<Vector2>();
        controls.Gameplay.Move.canceled  += ctx => Move = Vector2.zero;   // never forget this line

        controls.Gameplay.Look.performed += ctx => Look = ctx.ReadValue<Vector2>();
        controls.Gameplay.Look.canceled  += ctx => Look = Vector2.zero;

        controls.Gameplay.Jump.performed += ctx => JumpPressed = true;
        controls.Gameplay.Attack.performed += ctx => GetComponent<SkillCaster>().TryCast(0);
    }

    void OnEnable()  => controls.Enable();    // no Enable = no input at all
    void OnDisable() => controls.Disable();

    void LateUpdate() => JumpPressed = false; // one-frame flag
}
  • performed は入力が始まったとき・変化したときに発火し、canceled は離したときに発火します。canceled を書き忘れると、キャラクターが延々と歩き続けます。

  • Move は Vector2 (x, y) です。三次元に持ち上げる際は (x, 0, y) にマップするので、スティックの y がワールドの Z 方向になります。

  • UI という二つ目のアクションマップを、Gameplay を無効にした状態で有効化できます。ポーズメニューでキャラクターを動けなくするのは、この仕組みです。

古い三つの読み取りを退役させる

この掃除をやってこそ、この tab の価値が出てきます。プロジェクト内の Input.GetAxis、Input.GetKey、Input.GetMouseButton をすべて削除し、入力の通り道を InputRouter に集約してください。

the three edits
// 1 — PlayerMovement.cs
- float h = Input.GetAxisRaw("Horizontal");
- float v = Input.GetAxisRaw("Vertical");
- Vector3 input = new Vector3(h, 0f, v).normalized;
+ Vector3 input = new Vector3(router.Move.x, 0f, router.Move.y).normalized;

// 2 — CharacterSwitcher.cs
- for (int i = 0; i < characters.Count && i < 9; i++)
-     if (Input.GetKeyDown(KeyCode.Alpha1 + i)) Select(i);
+ // in InputRouter.Awake:
+ controls.Gameplay.SwapCharacter.performed += c => switcher.Select((int)c.ReadValue<float>() - 1);

// 3 — SkillCaster.cs
- for (int i = 0; i < skills.Count && i < keys.Length; i++)
-     if (Input.GetKeyDown(keys[i])) TryCast(i);
+ // in InputRouter.Awake:
+ controls.Gameplay.Skill1.performed += _ => caster.TryCast(0);
+ controls.Gameplay.Skill2.performed += _ => caster.TryCast(1);
+ controls.Gameplay.Skill3.performed += _ => caster.TryCast(2);

移動スクリプトでの使い方

C# スクリプト
[SerializeField] private InputRouter input;

void Update()
{
    Vector3 dir = new Vector3(input.Move.x, 0f, input.Move.y);
    // ... rest is identical to the old script
}

✓ PlayerInput component

Send Messages / Unity Events モードが使えます。セットアップが最も速く、プロトタイプ向きです。

✓ Generated C# class

呼び出しが明示的で、名前を変えても壊れにくく、メソッド名を文字列で指定する手もない。実際のプロジェクトならこちらです。