【Unity 6】ジャンプや攻撃の入力を受け取る ― Input Systemで「押した瞬間」を扱う2つの方法

広告

はじめに

前の記事では、Input Systemを使って、キーボードでキャラクターを動かしました。

移動は、キーを押している間ずっと処理を続ける操作です。

一方、ジャンプや攻撃は、押した瞬間に1回だけ処理したい操作です。

今回は、スペースキーを押したときにConsoleへ「ジャンプ!」と表示することで、「押した瞬間」を受け取る2つの方法を学びます。

今回作るもの

  • スペースキーを押した瞬間に、Consoleに「ジャンプ!」と表示する
  • 方法1:Updateの中で、WasPressedThisFrame()を使う
  • 方法2:performedイベントで受け取る

キャラクターを実際にジャンプさせる処理は扱いません。今回は、「入力を受け取る」ことに集中します。

既定のInput ActionsにあるJumpとAttack

前の記事で使ったInputSystem_Actionsには、Move以外にも、JumpやAttackなどのActionが最初から用意されています。

ProjectウィンドウでInputSystem_Actionsをダブルクリックして、Input Actionsエディターを開いてみましょう。Playerマップの中に、次のようなActionが並んでいます。

  • Move
  • Look
  • Attack
  • Interact
  • Crouch
  • Jump
  • Previous
  • Next
  • Sprint

Jumpにはスペースキーなどが、Attackにはマウスの左ボタンなどが割り当てられています。

これらは、前の記事のMoveと同じように、「マップ名/Action名」で取得できます。

  • "Player/Jump"
  • "Player/Attack"

方法1:WasPressedThisFrame()で確認する

一番簡単な方法です。移動のときと同じように、Updateの中で毎フレーム確認します。

using UnityEngine;
using UnityEngine.InputSystem;

public class JumpInput : MonoBehaviour
{
    private InputAction jumpAction;

    void Start()
    {
        jumpAction = InputSystem.actions.FindAction("Player/Jump");
    }

    void Update()
    {
        if (jumpAction.WasPressedThisFrame())
        {
            Debug.Log("ジャンプ!");
        }
    }
}

Startで、FindActionを使ってJumpを探し、変数に保存します。

Updateでは、WasPressedThisFrame()を確認します。このメソッドは、そのフレームでキーが押されたときだけtrueになります。

実行して、スペースキーを押してみましょう。押した瞬間に、Consoleに「ジャンプ!」と1回だけ表示されます。押し続けても、表示は増えません。

IsPressed()との違い

押している間と、押した瞬間の違いは、図で見ると分かりやすくなります。

メソッドtrueになるとき向いている操作
IsPressed()押している間ずっと移動、ダッシュなど
WasPressedThisFrame()押したフレームだけジャンプ、攻撃など
WasReleasedThisFrame()離したフレームだけためた攻撃を放つ操作など

方法2:イベントで受け取る

イベントは、入力があったときに、Unityから自動で呼んでもらう仕組みです。Updateで毎フレーム確認する必要がありません。

using UnityEngine;
using UnityEngine.InputSystem;

public class JumpEvent : MonoBehaviour
{
    private InputAction jumpAction;

    void Awake()
    {
        jumpAction = InputSystem.actions.FindAction("Player/Jump");
    }

    void OnEnable()
    {
        jumpAction.performed += OnJump;
    }

    void OnDisable()
    {
        jumpAction.performed -= OnJump;
    }

    private void OnJump(InputAction.CallbackContext context)
    {
        Debug.Log("ジャンプ!");
    }
}

performed += OnJump;は、「Jumpが実行されたら、OnJumpを呼んでください」という登録です。

登録はOnEnableで行い、OnDisableで-=を使って解除します。オブジェクトが有効になったときに登録し、無効になったときに解除する、という対になります。

OnJumpの引数contextには、入力の情報が入っています。移動のときは、ここからReadValue<Vector2>()で値を読みました。

started・performed・canceledの違い

Actionのイベントは、次の3種類があります。

イベント呼ばれるとき
started入力が始まったとき
performed操作が成立したとき
canceled入力が終わったとき(キーを離したときなど)

JumpやAttackのような通常のボタンでは、startedとperformedは、押した瞬間にほぼ同時に呼ばれます。そのため、「押した瞬間に1回だけ」処理したいなら、performedだけで十分です。

3つとも受け取るコードで、動きを確かめてみましょう。

using UnityEngine;
using UnityEngine.InputSystem;

public class AttackEvent : MonoBehaviour
{
    private InputAction attackAction;

    void Awake()
    {
        attackAction = InputSystem.actions.FindAction("Player/Attack");
    }

    void OnEnable()
    {
        attackAction.started += OnAttackStarted;
        attackAction.performed += OnAttackPerformed;
        attackAction.canceled += OnAttackCanceled;
    }

    void OnDisable()
    {
        attackAction.started -= OnAttackStarted;
        attackAction.performed -= OnAttackPerformed;
        attackAction.canceled -= OnAttackCanceled;
    }

    private void OnAttackStarted(InputAction.CallbackContext context)
    {
        Debug.Log("started:押し始めた");
    }

    private void OnAttackPerformed(InputAction.CallbackContext context)
    {
        Debug.Log("performed:攻撃!");
    }

    private void OnAttackCanceled(InputAction.CallbackContext context)
    {
        Debug.Log("canceled:離した");
    }
}

実行して、マウスの左ボタンを押して離すと、Consoleに次の順で表示されます。

  • started:押し始めた
  • performed:攻撃!
  • canceled:離した

なお、長押し(Hold)などのInteractionを設定したActionでは、performedが呼ばれるタイミングが変わります。たとえば、一定時間押し続けたあとにperformedが呼ばれます。

どちらを使えばよいか

方法向いているとき
WasPressedThisFrame()簡単に書きたいとき。Updateの中で、ほかの処理と一緒に確認したいとき
イベント入力があったときだけ処理を呼びたいとき。処理を別のメソッドに分けたいとき

初学者のうちは、まずWasPressedThisFrame()で十分です。イベントは、登録と解除が必要になるぶん、少し書くことが増えます。

移動のように、押している間ずっと続く処理は、前の記事のようにUpdateで毎フレーム値を読む方法が簡単です。

よくある間違い

Action名を書き間違える

FindActionに渡す名前を間違えると、Actionが見つからず、nullになります。そのまま使うと、NullReferenceExceptionのエラーになります。

"Player/Jump"のように、マップ名とAction名を、Input Actionsエディターで確認してください。

登録した処理を解除し忘れる

+=で登録した処理を-=で解除しないと、オブジェクトが無効になったり破棄されたりしたあとも呼ばれ、エラーの原因になります。OnEnableとOnDisableを対で書く習慣をつけましょう。

離したときの処理(canceled)を受け取らない

離したときに何かを止めたいのに、performedしか受け取っていないと、止める処理が呼ばれません。離したときの処理が必要なら、canceledも受け取ります。

移動をイベントだけで書こうとする

移動をイベントだけで書くと、離したとき(canceled)の処理も必要になり、コードが複雑になります。移動は、Updateで毎フレーム値を読む方法が簡単です。

まとめ

  • 押した瞬間に1回だけ処理したい操作(ジャンプ、攻撃など)は、WasPressedThisFrame()かイベントで受け取る
  • 押している間ずっと続く操作(移動など)は、Updateで毎フレーム値を読む
  • イベントは、OnEnableで登録し、OnDisableで解除する
  • started、performed、canceledは、入力の始まり、成立、終わりに対応する

まずは、スペースキーで「ジャンプ!」と表示するところから、試してみてください。

訪問数 2 回, 今日の訪問数 2回

広告

C#,Unity,Unity6

Posted by hidepon