Set up an action map dynamically

Page update date :
Page creation date :

Verification environment

Windows
  • Windows 11
Unity Editor
  • 2020.3.25f1
Input System Package
  • 1.2.0

Prerequisites for this tip

The following settings have been made in advance as a premise for the description of this tip.

You should also be familiar with the following tips:

About dynamic action map configuration

It is common to add and set action maps to the project in advance, In this case, the controller button assignments are fixed during game execution and cannot be freely changed by the user during the game. This is mainly expected for games that require key configuration.

This tip describes how to arbitrarily change the key assignments of an action map in a script.

Dynamic action map change handling

This time, the initial action map is also set by the script, and the action map change in the middle is also done in the script. I think this method is used when loading and setting the key configuration saved at game startup.

The contents of the sample are to change the key assignment of the action map when you press the button, and to display the operated content as text. The button placement and display text are arranged as shown in the figure, but they are not very important, so please place them freely.

Action Map Initial Configuration Process

Create a script. The name is arbitrary, but in this case InputActionMap it is . This time, all the processes will be described here, but in the actual production, please divide them according to the creation of the project.

The script looks like this: First, create a default action map at startup.

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class InputActionMap : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  /// <summary>Move アクション用の定義。</summary>
  public InputAction MoveAction { get; set; }

  /// <summary>Attack アクション用の定義。</summary>
  public InputAction AttackAction { get; set; }

  private void Awake()
  {
    // Move アクションの作成
    MoveAction = new InputAction("Move");

    // バインド(キー割り当て)の追加
    // 設定する文字列の形式はアクションマップ設定画面の Path に表示される文字列となる
    MoveAction.AddBinding("<Gamepad>/leftStick");

    // キーボードに上下左右を割り当てるにはコンポジットの 2DVector を設定する
    MoveAction.AddCompositeBinding("2DVector")
        .With("Up", "<Keyboard>/upArrow")
        .With("Down", "<Keyboard>/downArrow")
        .With("Left", "<Keyboard>/leftArrow")
        .With("Right", "<Keyboard>/rightArrow");

    // Attack アクションの作成
    AttackAction = new InputAction("Attack");

    // バインド(キー割り当て)の追加
    AttackAction.AddBinding("<Gamepad>/buttonSouth");
    AttackAction.AddBinding("<Keyboard>/z");

    // 操作時のイベントを設定
    MoveAction.performed += context => OnMove(context);
    MoveAction.canceled += context => OnMove(context);
    AttackAction.performed += context => OnAttack(context);
    AttackAction.canceled += context => OnAttack(context);
  }

  private void OnEnable()
  {
    // オブジェクトが有効になったときにアクションマップを有効にする
    MoveAction.Enable();
    AttackAction.Enable();
  }

  private void OnDisable()
  {
    // アクションマップが誤動作しないようにオブジェクト終了時に無効にする
    MoveAction.Disable();
    AttackAction.Disable();
  }

  /// <summary>
  /// Move 操作を行ったときに呼ばれる。
  /// </summary>
  /// <param name="context">コールバック内容。</param>
  public void OnMove(InputAction.CallbackContext context)
  {
    var vec = context.ReadValue<Vector2>();
    TextObject.text = $"Move:({vec.x:f2}, {vec.y:f2})\n{TextObject.text}";
  }

  /// <summary>
  /// Move 操作を行ったときに呼ばれる。
  /// </summary>
  /// <param name="context">コールバック内容。</param>
  public void OnAttack(InputAction.CallbackContext context)
  {
    var value = context.ReadValueAsButton();
    TextObject.text = $"Attack:{value}\n{TextObject.text}";
  }
}

First, define as many actions in the class as you InputAction want to implement in the field. Here, we will prepare the fields for "Move" and "Attack", which were also used in the previous action map explanation. If the number of actions increases, you need to declare that number, but if there are List Dictionary many, you can manage them with , , etc. It is not used here, but if you have your own InputActionMap class, you can manage it there.

Instantiation and key assignment AddBinding in the InputAction method called Awake at initialization are performed. You can think of what you are doing as a program that adds a binding on the action map setting screen. AddBinding The string specified for Method, etc. is the same as the string displayed in Path on the action map setting screen. To display a character string, press the "T" button on the right.

The event handling called when a button is operated is the same as the processing of the scripted version of a normal action map. The callback process is also diverted as it is.

// 操作時のイベントを設定
MoveAction.performed += context => OnMove(context);
MoveAction.canceled += context => OnMove(context);
AttackAction.performed += context => OnAttack(context);
AttackAction.canceled += context => OnAttack(context);
/// <summary>
/// Move 操作を行ったときに呼ばれる。
/// </summary>
/// <param name="context">コールバック内容。</param>
public void OnMove(InputAction.CallbackContext context)
{
  var vec = context.ReadValue<Vector2>();
  TextObject.text = $"Move:({vec.x:f2}, {vec.y:f2})\n{TextObject.text}";
}

Enable, Disable is InputAction a unit, so describe as many actions as you want. If it is troublesome, you can manage it List with etc.

private void OnEnable()
{
  // オブジェクトが有効になったときにアクションマップを有効にする
  MoveAction.Enable();
  AttackAction.Enable();
}

After EventSystem you save the script, attach it to and configure a text object for display.

Run the game and see if the input information appears. The result should be the same as the scripted version of the action map static process.

Action Map Dynamic Change Processing

Since the dynamic change of the action map is done when the button is pressed, define the method that will be called when the button is pressed. OnClickButton For now, we'll leave it as .

// 省略

public class InputActionMap : MonoBehaviour
{
  // 省略

  /// <summary>
  /// ボタンをクリックしたときに呼ばれる。
  /// </summary>
  public void OnClickButton()
  {
  }
}

Sets the click event for the button.

The action map rewrite process is as follows:

/// <summary>
/// ボタンをクリックしたときに呼ばれる。
/// </summary>
public void OnClickButton()
{
  TextObject.text = "アクションマップを変更しました。";

  // Move アクションのキーを置き換える
  MoveAction.ApplyBindingOverride(new InputBinding { path = "<Gamepad>/leftStick", overridePath = "<Gamepad>/dpad" } );
  MoveAction.ApplyBindingOverride(new InputBinding { path = "<Keyboard>/upArrow", overridePath = "<Keyboard>/w" });
  MoveAction.ApplyBindingOverride(new InputBinding { path = "<Keyboard>/downArrow", overridePath = "<Keyboard>/s" });
  MoveAction.ApplyBindingOverride(new InputBinding { path = "<Keyboard>/leftArrow", overridePath = "<Keyboard>/a" });
  MoveAction.ApplyBindingOverride(new InputBinding { path = "<Keyboard>/rightArrow", overridePath = "<Keyboard>/d" });

  // Attack アクションのキーを置き換える
  AttackAction.ApplyBindingOverride(new InputBinding { path = "<Gamepad>/buttonSouth", overridePath = "<Gamepad>/buttonEast" });
  AttackAction.ApplyBindingOverride(new InputBinding { path = "<Keyboard>/z", overridePath = "<Keyboard>/space" });
}

Since a method is provided for ApplyBindingOverride each action, the path path of the key or button that was initialized to , overridePath Write the path of the key or button you want to override.

By the way, this is just setting the overwrite path, so the original path remains as it is. For example, in an Attack action, change the z key to the spacebar. Furthermore, if you want to change from space to x key, the description will be overwritten for the z key instead of based on space, as follows.

AttackAction.ApplyBindingOverride(new InputBinding { path = "<Keyboard>/z", overridePath = "<Keyboard>/x" });

Once saved, run the game and click the button to see if the keys or buttons you interact with change.

InputAction This time, we are changing the action map for the one that created an instance of , There is also InputAction a script generated by the action map setting of the GUI, so please implement it in the one that is easy to do.