使用操作映射為遊戲行為分配按鈕

更新頁 :
頁面創建日期 :

驗證環境

窗戶
  • 視窗 11
統一編輯器
  • 2020.3.25f1
輸入系統包
  • 1.2.0

此提示的先決條件

作為此提示描述的前提,已預先進行了以下設置。

關於操作地圖

鍵盤、滑鼠和遊戲手柄上的使用者輸入程式基本上表明,按下按鈕時執行了某個操作。 例如,在操作映射中,您可以定義「跳躍」操作並為其分配控制器按鈕和鍵盤鍵。 因此,程式只需要在執行特定操作時描述過程。 即使您事後在另一個控制器上分配了一個按鈕,您也可以在不更改操作程序的情況下應用它。

創建操作映射

在這裡,我想創建一個操作地圖並在文本中顯示使用者的輸入資訊。 有幾種方法可以使用操作映射獲取用戶輸入。

右鍵按兩下工程中的任何資料夾以創建輸入操作。 要創建的資料夾的位置是任意的,但請根據您的項目進行管理。 檔名也是任意的,但這裡是 InputActionSample .

按兩下建立的檔案時,將顯示以下視窗。

首先,按兩下「操作映射」中的 + 按鈕以創建操作映射。 作為創建單元,如果操作內容因場景而異,則會在該單元中定義。 例如,在橫向卷軸動作遊戲的情況下,操作的內容在操作期間和功能表中會發生變化,因此您將為每個操作創建一個操作地圖。

在這裡,作為一個例子,我們定義一個橫向滾動操作並將其命名為「橫向滾動動作映射」。。

接下來,創建操作。 由於這是一個示例,我不會做很多,但在這裡我們將為移動創建“移動”動作,為攻擊創建“攻擊”動作。 由於已經創建了一個,請更改名稱或創建一個新名稱,按兩下右上角的+按鈕並輸入它。

首先,配置移動配置。 控制器假定您使用搖桿、方向鍵和鍵盤游標鍵。 在橫向滾動操作的情況下,有時只使用左鍵和右鍵,但在這裡我們假設您使用四個方向,考慮使用上鍵跳躍並使用向下鍵蹲下。

選擇「移動」時,右側會有一個「操作類型」選項,因此請將其設置為“值”。

你將在下面看到控件類型,因此請選擇 Vector2。 這是因為頂部和底部分配給 Y,左側和右側分配給 X。

然後選擇要分配給此事件的金鑰。 選擇中間的“無綁定”,然後選擇右側的“路徑”。 在這裡,我們選擇遊戲手柄左搖桿。

這會將GamePad的LeftStick綁定到移動中。

要同時綁定其他控制器,請從「移動」右側的 + 按鈕中選擇「添加綁定」。。

添加無綁定后,我們為遊戲手柄分配一個 Dpad。

通過這種方式,您可以添加要支援的控制器類型,以及按鍵和搖桿。 也可以專門為特定的遊戲機設置它。

搖桿和 Dpad 是假定向上、向下、向左和向右的按鈕,因此可以使用此按鈕添加它們,但在鍵盤的情況下,它們都是單鍵,因此沒有向上、向下、向左和向右的定義。 要設置鍵盤向上、向下、向左或向右,請從 + 按鈕中選擇向上向下添加左右複合。

然後將添加一個 2D 向量,您可以將其分配給每個左下右上,如下圖所示。

例如,如果您使用向上,請在鍵盤上設置「向上箭頭」。 順便說一句,如果您很難找到一個鍵,您可以通過在按單擊“收聽”按鈕的同時按目標鍵輕鬆選擇它。

向上現在設置為向上箭頭。

同樣,設置向下、向左和向右,您就完成了。

當然,不僅可以設置游標鍵,還可以設置 WASD。

接下來,配置攻擊。 攻擊很容易分配,因為它是一個按鈕。 首先,選擇「攻擊」並確保「操作類型」為按鈕。

然後選擇「無綁定」,並從「路徑」中選擇要分配的按鈕。

如果要添加更多,請從 + 按鈕中選擇「添加綁定」。

根據需要添加任意數量。 由於它被視為按鈕,因此可以像遊戲控制器一樣設置鍵盤。

完成所有設置后,按下「保存資產」 進行保存。 您可以關閉此視窗。

最後,使用專案的輸入操作檔(在本例中為之前創建的 InputActionSample 檔),在檢查器中選中“生成 C# 類”。 將添加參數,但按原樣按單擊“應用”按鈕。

這將生成一個同名的腳本檔。 它包含用於使用程式中的操作映射的類。

如何接收輸入資訊

有幾種方法可以接收基於操作映射的輸入。 這個技巧解釋了三種模式,但在實際製作遊戲時最好專注於其中一種。 如果單獨使用它們,管理起來會很麻煩。

此外,如果在單個場景中使用多種輸入接收方法,則處理可能會在內部發生衝突,並且無法正常工作。

在「發送消息」中接收輸入資訊

這裡的第一種方法是如何在「發送消息」中接收輸入資訊。

這次,我想在文本中顯示輸入的資訊,所以我將放置一個文本物件。

此外,由於此提示將嘗試獲取多個輸入資訊,因此我們將創建一個空對象來單獨設置元件。 名稱可以是任何內容。

接下來,將玩家輸入元件添加到空物件。 玩家輸入是連接操作地圖和腳本的重要元件。

在「添加元件」中,「輸入」類別中有「玩家輸入」,因此請添加它。

添加玩家輸入元件後,設置您在「操作」 中創建的操作映射。 將其從專案中刪除,或從右側的 + 圖示中選擇它。

驗證預設映射是否是您在操作映射中創建的映射。

驗證行為是否為「發送消息」。

接下來,創建一個腳本。 檔案名可以是任何內容,但這裡是 InputSendMessage .

文稿如下所示:

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

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

  /// <summary>
  /// Move アクションが実行されたときに呼ばれる。
  /// </summary>
  /// <param name="inputValue">入力量。</param>
  public void OnMove(InputValue inputValue)
  {
    var vec = inputValue.Get<Vector2>();
    TextObject.text = $"Move:({vec.x:f2}, {vec.y:f2})\n{TextObject.text}";
  }

  /// <summary>
  /// Attack アクションが実行されたときに呼ばれる。
  /// </summary>
  public void OnAttack(InputValue inputValue)
  {
    TextObject.text = $"Attack:{inputValue.isPressed}\n{TextObject.text}";
  }
}
  • 該物件附加了一個播放器輸入,用於設置發送消息
  • 繼承自MonoBehavior

如果滿足條件,則如果定義一個名為「OnXXXXXXXX」的方法, 執行指定的操作操作時,將調用目標方法。 “XXXXXXXX”是在操作映射中創建的操作的名稱。 在這裡,我們創建了“移動”和“攻擊”動作,因此方法名稱分別是“OnMove”和“OnAttack”。

OnMove 您可以從 的參數 InputValue 中獲取輸入的金額。 由於控件類型設置為「向量 2」 ,因此將在 中接收輸入值 InputValue.Get<Vector2>

OnAttackInputValue.isPressed你也可以知道你是否在按。

保存文稿后,將其附加到具有播放機輸入元件的物件。 同時設置要顯示的文字物件。

運行遊戲並查看。 這次,我包含了遊戲手柄和鍵盤的定義,因此無論您操作哪一個,它都應該有效。

正如您在移動它時所看到的,您可以看到僅當值與先前狀態發生更改時才調用該方法。 例如,在向左移動搖桿時,一心一意地調用它,但不向左移動(- OnMove 1,0)。 OnMove Attack 按鈕也僅在按下時回應,如果按住它,則不會調用該方法。

因此,我認為理想的用法不是在調用 OnXXXXXXXX 時執行遊戲處理,而是只保留輸入內容並在遊戲的更新處理中使用這些值。

順便說一下,在當前狀態下,釋放按鈕時不會調用它,因此無法確定何時 OnAttack 釋放按鈕。 要對此做出回應,請在操作映射設置中選擇定義按鈕的攻擊操作,然後從“交互”中添加“按”。 之後,將添加的按的觸發行為設置為“按下並釋放”並保存。

執行時,您可以看到即使在釋放按鈕時也會 OnAttack 調用該按鈕。 isPressed false 既然變成,也可以確定是否是發佈的時間。

順便說一下,請刪除此交互,因為它將來不會使用。

使用調用 Unity 事件接收輸入

接收輸入的第二種方法是調用 Unity 事件,所以讓我們試試這個。 如上所述,使用多個輸入方法可能會導致處理衝突,因此如果啟用了其他處理,請禁用它。

首先,放置文本物件,以便可以顯示輸入資訊。

調用 Unity 事件會創建一個執行相關操作的空物件。

將輸入>玩家輸入添加到空物件。

設置為操作創建的操作映射檔(在本例中為 InputActionSample),並將您創建的操作映射(在本例中為 SideScrollActionMap)設置為“預設映射”。 設置行為以調用 Unity 事件。

創建腳本。 名稱是任意的,但在這種情況下 InputInvokeUnityEvents 是.

文稿如下所示:

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

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

  /// <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}";
  }
}

使用者與之交互時調用的方法名稱OnMoveOnAttack是 ,就像發送消息一樣。 在調用 Unity 事件中,您可以根據需要設置此方法名稱。

當調用每個時,它作為參數傳遞InputAction.CallbackContext,因此您可以從那裡獲取輸入狀態。 如果在操作中設置了“值”,則可以在方法中接收它,如果設置ReadValueAsButton了“按鈕”,則可以ReadValue在方法中接收它。

保存文稿后,將播放器輸入附加到要設置的物件並設置顯示文字物件。

接下來,在玩家輸入中展開“事件”和“操作映射名稱(橫向滾動操作映射)”,您應該會看到您創建的“移動”和“攻擊”操作。

首先,按兩下「移動」上的+ 按鈕進行添加。

左下角的物件是你自己的物件,函數設置為你剛剛創建 OnMove 的方法。

同時配置攻擊事件。

運行遊戲以查看其工作原理。

基本上,僅當與「發送消息」相同的值更改時才會調用它,但由於某種原因,該方法可能同時調用兩次。 我不知道原因,但我認為可能是因為啟動過程和連續過程同時運行。 但是,我認為如果您只保留輸入的值,例如發送消息並在更新過程中單獨執行實際的遊戲處理,則沒有問題。

使用自動生成的腳本接收輸入資訊

第三部分介紹如何使用從操作映射檔生成的腳本獲取輸入資訊。

由於有可能與其他獲取流程發生衝突,請禁用其他獲取流程。

放置文字物件以顯示輸入資訊。

此外,創建一個空物件來檢索輸入資訊。 本文使用自動生成的腳本,因此無需添加玩家輸入。

從操作映射自動生成的腳本只是一個庫,因此請創建單獨的控制腳本。 名稱是任意的,但在這種情況下 InputScript 是.

文稿如下所示:

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

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

  /// <summary>アクションマップから自動生成されたクラス。</summary>
  private InputActionSample _actionMap;

  private void Awake()
  {
    // 各操作を行ったときに呼ばれるイベントを設定する
    _actionMap = new InputActionSample();
    _actionMap.SideScrollActionMap.Move.performed += context => OnMove(context);
    _actionMap.SideScrollActionMap.Attack.performed += context => OnAttack(context);
  }

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

  private void OnDisable()
  {
    // このオブジェクトが無効になったときにアクションマップが余計な動作を起こさないように無効にする
    _actionMap.Disable();
  }

  /// <summary>
  /// Move 操作をした時に呼ばれるメソッドです。
  /// </summary>
  /// <param name="context">コールバックパラメータ。</param>
  public void OnMove(InputAction.CallbackContext context)
  {
    // Move の入力量を取得
    var vec = context.ReadValue<Vector2>();
    TextObject.text = $"Move:({vec.x:f2}, {vec.y:f2})\n{TextObject.text}";
  }

  /// <summary>
  /// Attack 操作をした時に呼ばれるメソッドです。
  /// </summary>
  /// <param name="context">コールバックパラメータ。</param>
  public void OnAttack(InputAction.CallbackContext context)
  {
    // Attack ボタンの状態を取得
    var value = context.ReadValueAsButton();
    TextObject.text = $"Attack:{value}\n{TextObject.text}";
  }
}

從欄位中的操作映射定義自動生成的類 InputActionSample 。 此類定義操作映射中的每個操作集,您可以設置執行這些操作時調用的事件。

Awake 在該方法中,將創建的實例, InputActionSample 並設置在操作時調用的事件。 執行這些操作時 OnMove,現在將調用 , OnAttack 方法。

但是,由於我們只在此處設置事件,因此我們需要 OnEnable 在調用時 Enable 調用該方法以啟用操作映射。

此外,由於使用者的輸入行為被視為全域操作, 為了防止 OnDisable 操作映射在此物件失效后執行額外的操作,我們在方法中 Disable 調用該方法以禁用它。

保存文稿后,將其附加到您創建的空物件,並設置要顯示的文字物件。

運行遊戲以查看其工作原理。

如您所見,當Move操作變為 (0, 0) 時 OnMove ,不會調用該方法。 我不確定為什麼,但似乎執行的事件實際上只採取了啟用了擊鍵的事件。

順便說一下,如果您沒有在操作地圖中為攻擊設置交互,則在釋放按鈕時 OnAttack 不會調用它。

canceled 處理此問題,您需要設置一個事件。 如果不想在 (0, 0) 處執行特殊處理,可以按原樣 OnMove 調用該方法。 攻擊也是如此。

private void Awake()
{
  // 各操作を行ったときに呼ばれるイベントを設定する
  _actionMap = new InputActionSample();
  _actionMap.SideScrollActionMap.Move.performed += context => OnMove(context);
  _actionMap.SideScrollActionMap.Attack.performed += context => OnAttack(context);
  _actionMap.SideScrollActionMap.Move.canceled += context => OnMove(context);       // 追加
  _actionMap.SideScrollActionMap.Attack.canceled += context => OnAttack(context);   // 追加
}

運行並驗證是否顯示「移動:(0, 0) 」或「攻擊:假」。。