【Unity】Input Actionの3種類のコールバック挙動

こじゃらこじゃら

Input Systemの入力をコールバックで受け取りたいんだけど、何回も呼ばれたり逆に呼び出されなかったりするのは何故なの?

このはこのは

コールバックは3種類あって、呼び出されるタイミングや条件が決まっているからなの。

Input SystemActionでは、スティックやボタン入力の変化などによって、次の3種類のコールバックが呼ばれるようになっています。

コールバックの種類
  • started – 入力され始めた時などに呼ばれる
  • performed – 特定の入力があった時などに呼ばれる
  • canceled – 入力が中断された時などに呼ばれる

参考:Actions | Input System | 1.3.0

これらのコールバックは、例えば次のように使います。

public void OnJump(InputAction.CallbackContext context)
{
    // performedコールバックを拾って処理
    if (context.performed)
        キャラをジャンプさせる処理;
}

コールバックが呼び出されるタイミングは、Input Actionの設定により変化します。設定によっては複数回呼ばれたり、逆に特定条件でしか呼ばれなかったりします。

このような仕様は公式リファレンスに明記されていますが、一見するとバグと見間違えやすい挙動をすることもあり注意が必要です。

本記事では、これら3種類のコールバックの動きについて、具体的な設定とデモを示しながら解説していきます。

スポンサーリンク

前提条件

Input Systemがインストールされ、有効化されているものとします。

また、本記事では、以下のようにPlayer InputとInput Actionの設定が済んでいるものとして解説を進めていきます。

Player Inputの使い方についてわからない方は、以下記事をご覧ください。

コールバックの挙動に関わる設定

コールバックが呼び出される挙動は、Input ActionAction TypeInteractionsの設定によって決まります。

Action Typeとは、ボタン入力として扱うのか、スティックなどの連続入力として扱うのかなどを設定する項目です。

参考:Enum InputActionType | Input System | 1.3.0

Interactionsとは、長押しやマルチタップなどの振る舞いを設定するための項目です。

参考:Interactions | Input System | 1.3.0

これらの設定によって、どのような呼び出しタイミングになるかは、以下ページで図説されています。

参考:Interactions | Input System | 1.3.0

注意

図はバージョン1.1.1以降のページで閲覧できます。それより前のバージョンでは記載されていないので、リファレンスのページを参照する際はバージョンにご注意ください。

コールバックの挙動は、大まかに次のパターンに大別されます。

呼び出しパターン
  • ActionにInteractionsが設定されていない場合は、Action Typeの設定により挙動が決まる
  • ActionにInteractionsが設定されている場合は、Interactionsの設定内容が優先される

具体的なコールバックの挙動について、それぞれを示しながら見ていくこととします。

Default Interaction時の挙動

Actionに長押しやマルチタップなどのInteractionsの設定がされていない場合は、Default Interactionとして振る舞います。

Default Interactionでは、Action Typeの設定によってコールバックの呼び出しタイミングが変化します。

参考:Interactions | Input System | 1.3.0

設定によるタイミングの違いを見ていきます。

Action Type = Valueの場合

値が変化した時にコールバックが呼ばれます。ゲームパッドのスティックやトリガーボタンなどのアナログ入力に適しています。

コールバックの呼び出しルールは次のようになっています。

  • started – 入力が0から0以外に変化したとき
  • performed – 入力が0以外に変化したとき
  • canceled – 入力が0以外から0に変化したとき

Input Actionのフェーズ変化コールバック呼び出しを図示すると次のようになります。

入力値とコールバック呼び出しを時系列で出力した結果は次の通りです。

前半はゲームパッドのトリガー入力(アナログ)、後半はマウスのボタン入力(デジタル)です。

注意

入力値0の時の変化も含めてコールバックを受け取る場合は、以下コードのようにperformedとcanceledコールバックをチェックする必要があります。

// 移動
public void OnMove(InputAction.CallbackContext context)
{
    // performed、canceledコールバックを受け取る
    if (context.started) return;

    // Moveアクションの入力取得
    var inputMove = context.ReadValue<Vector2>();

    // 移動処理など
}

例えば、canceledのチェックを忘れると、入力値0にならずその直前の入力値でキャラクターが動き続けてしまうなどの問題が生じます。

startedコールバックをチェックしていない理由は、startedの直後にperformedが続けて呼ばれるため、重複した処理が走らないようにするためです。無駄な処理が走るだけで動きに支障は出ないため、started、performed、canceledすべてのコールバックをチェックしても操作に支障はありません。

Action Type = Buttonの場合

ボタン入力に適した設定です。

コールバックのタイミングは次のようになります。

  • started – 入力が0から0以外に変化したとき
  • performed – 入力の大きさが閾値Press以上に変化したとき
  • canceled – 入力が0以外から0に変化したとき、またはperformedが呼ばれた後に入力の大きさが閾値Release以下に変化したとき

Tips

閾値の設定は、トップメニューのEdit > Project Settings > Input System Packageの以下項目から変更できます。

閾値Pressの値はDefault Press Button Point閾値Releaseの値は「Press × Button Release Threshold」となります。閾値ReleaseはPressと掛け算した値であることに注意する必要があります。

参考:Input settings | Input System | 1.3.0

フェーズ変化コールバックのタイミングは以下のようになります。

時系列の動作は以下の通りです。

前半はマウスのボタン入力(デジタル)、後半はゲームパッドのトリガー入力(アナログ)です。

コントローラーによっては、入力値の遊び(ドリフト)が発生する可能性もあるため、基本的にstartedは使わず閾値判定があるperformedを使うのが安全です。

// 攻撃
public void OnFire(InputAction.CallbackContext context)
{
    // performedコールバックだけ受け取る
    if (!context.performed) return;

    // 攻撃処理など
    Debug.Log("攻撃!");
}

Action Type = Pass Throughの場合

基本的にデバイス入力がある間にperformedが呼ばれ続けます。

デバイスが切り替わった場合は、切り替わり前のデバイスが無効(Disabled)となり、canceledコールバックが呼び出されます。

動画の例では、ゲームパッドのトリガー入力(アナログ)とマウスのボタン入力(デジタル)の入力を交互に切り替えていて、切り替えの度にcanceledコールバックが呼ばれています。

Interactionが設定されているときの挙動

ActionまたはBindingにInteractionが設定されている場合、Interaction側の設定が優先されます。

詳細は以下リファレンスのページにまとめられています。

参考:Interactions | Input System | 1.3.0

本記事では、各Interactionのコールバック動作について一通り見ていくこととします。

InteractionsがPressの場合

ボタンなどが押された瞬間や離された瞬間にperformedを通知するInteractionです。

Trigger Behaviour項目には、どの瞬間でperformedを通知するかを指定できます。

Press Only押した瞬間のみperformedが呼ばれる
Release Only離された瞬間のみperformedが呼ばれる
Press And Release押した瞬間と離された瞬間両方でperformedが呼ばれる

Press Onlyのperformed呼び出しタイミングは、Default InteractionのButtonと一緒です。

例えば、Trigger BehaviourにRelease Onlyを設定した場合、以下のようにボタンを離したとき(入力値がRelease以下になったとき)にperformedコールバックが呼ばれるようになります。

InteractionsがHoldの場合

一定時間ボタンを押した判定になった時にperformedが呼ばれます。

長押し判定の時間などはデフォルト設定のほか、Interaction毎に設定することも可能です。

コールバックの動きは次のようになります。

より詳細な使い方については、以下記事で解説しています。

InteractionsがTapの場合

タップ操作があった時にperformedが呼ばれます。タップ操作は、押してすぐ離す操作となります。

タップ判定の最大許容時間は、Max Tap Duration項目で設定できます。

実際の動きは以下のようになります。

マウスボタンなどのデジタル入力では最大許容時間をチェックしますが、トリガーボタンなどのアナログ入力では値が変化すると最大許容時間の判定がリセットされるようです。

InteractionsがSlow Tapの場合

ゆっくりとタップした時にperformedコールバックが走るInteractionです。

タップの最小時間はMin Tap Duration項目から設定できます。

実際の挙動は以下の通りです。

InteractionsがMulti Tapの場合

マルチタップされたときにperformedコールバックが呼ばれるInteractionです。

必要なタップ回数をTap Countに、マルチタップ判定とする最大許容時間をMax Tap Spacingに、タップの最大許容時間をMax Tap Durationに設定できます。

実際の動きは以下のようになります。

複数のInteractions指定された場合

各々のInteractionのコールバックが同時に実行されるようになります。

以下はHoldMulti Tapを同時に指定した例です。

実際の動きは以下のようになります。

マルチタップと長押し両方の操作でperformedコールバックが呼ばれています。

呼び元のInteractionの判別

どのInteractionからコールバックが呼ばれたかは、以下のようにInputAction.CallbackContext引数interactionフィールドから判別できます。

// 攻撃
public void OnFire(InputAction.CallbackContext context)
{
    // performedコールバックだけ受け取る
    if (!context.performed) return;

    if (context.interaction is HoldInteraction)
    {
        Debug.Log("長押しされたよ!");
    }
    else if (context.interaction is MultiTapInteraction)
    {
        Debug.Log("マルチタップされたよ!");
    }
}

参考:Struct InputAction.CallbackContext | Input System | 1.3.0

複数の操作で動きを振り分けたい場合に役立つでしょう。

さいごに

Input SystemのActionが通知するコールバックにはstartedperformedcanceledの3種類が存在します。

これらのコールバックは、Action TypeとInteractionsの設定で決まります。

また、ボタン入力として扱う場合はperformedコールバックを扱うのが安全です。startedコールバックは閾値Press Pointに関係なく入力があった時に呼ばれることがあるため注意が必要です。

参考サイト

スポンサーリンク