有兩種方式回應Action
- Polling(輪詢):Polling方法是不斷的檢查你感興趣Action目前的狀態,通常會在
MonoBehaviour
script中的Update()
方法去做輪詢。 - Event-driven(事件驅動):Event-driven則是建立要執行的方法,當Action執行時,就會自動呼叫並執行。
Polling
在大部分的場景,特別是動作遊戲,使用者的輸入必須平滑順暢的控制遊戲中的角色,使用Polling
通常是比較容易去實作。
使用InputAction提供的ReadValue<>()
便可以取得目前Action的值
1 | using UnityEngine; |
方法 | 描述 |
---|---|
InputAction.WasPerformedThisFrame() | 在當前幀的任何時間點,如果這個Action在InputAction.phase曾經變為「已執行」(Performed),則為True。 |
InputAction.WasCompletedThisFrame() | 在當前幀的任何時間點,如果這個Action在InputAction.phase曾經從「已執行」(Performed)更改為任何其他階段(phase),則為True。這對於按鈕那些具有「按下」(Press) 或「按住」(Hold)等動作非常有用,當按住時,返回的為False。Pass-Through |
以下程式碼使用了預設的Interact Action,它包含一個「按住」(Hold)交互(interaction),使得只有綁定的控件被按住一段時間 (例如 0.4 秒) 後才會執行該動作。
1 | using UnityEngine; |
以下方法可以用來輪詢按鈕是否被按下或是釋放
方法 | 描述 |
---|---|
InputAction.IsPressed() | 如果Action的「動作水平(the level of actuation)」已經超過「按下壓力點(press point)」,並且尚未下降或低於「釋放臨界點(release threshold)」,則為True。 |
InputAction.WasPressedThisFrame() | 如果Action的「動作水平(the level of actuation)」在當前幀的任何時間點達到或超過「按下壓力點(press point)」,則為True。 |
InputAction.WasReleasedThisFrame() | 如果Action的「動作水平(the level of actuation)」在當前幀的任何時間點,在「按下壓力點(press point)」以上或是或低於「釋放臨界點(release threshold)」,則為True。 |
以下範例有三個Actions,分別為Shield
,Teleport
與Submit
(它們不是預設的action)
1 | using UnityEngine; |
Event-driven
可以為Action註冊一些callback,當某些輸入發生時,Action就會通知你,讓你可以做出相應的回應。
有以下方式可以使用callback
- 透過PlayerInput Component註冊callback
- 使用
Action
的started,performed與canceled callback - 使用
ActionMap
的actionTriggered callback - 使用
Input System
的全域InputSystem.onActionChange callback - InputActionTrace可以記錄Actions上的改變
PlayerInput Component
使用PlayerInput component
可以在inspector
中直接設定callback。此外也可以透過程式碼來設定
Phase(階段) | 描述 |
---|---|
Disabled |
此Action已停用且無法接收輸入 |
Waiting |
此Action已啟用且等待輸入 |
Started |
Input System已接收到輸入並開始與Action互動 |
Performed |
與Action的互動已經完成 |
Canceled |
與Action的互動已經被取消 |
Action callbacks
可以透過 InputAction.phase
來取得目前的階段,Started,Performed與Canceled階段各有與之關聯的callback函數
1 | var action = new InputAction(); |
每個callback都會接收一個InputAction.CallbackContext
結構,該結構包含上下文信息,您可以利用它來查詢Action的當前狀態,以及讀取觸發該動作的裝置控制的值。
- 注意:此結構的內容只在callback期間中有效,請勿把它暫存並在callback之外使用。
callback函數的觸發時機和方式取決於綁定中存在的交互 (Interactions)。如果綁定沒有適用的交互,則會應用預設的交互(Default Interaction)。
除了監聽個別Action,你也可以使用InputActionMap.actionTriggered
監聽該Map中的全部Action,使用這種方式,該單一個callback會收到started,performed與canceled,且其InputAction.CallbackContext
結構與使用個別started,performed與canceled的結構相同。
1 | var actionMap = new InputActionMap(); |
InputSystem.onActionChange
與InputSystem.onDeviceChange
類似,讓你可以全域(globally)監聽任何與Action相關的變更
1 | InputSystem.onActionChange += |
InputActionTrace
,你可以使用InputActionTrace為某些特定Action集合建立日誌(log),讓你可以追蹤它們。
- 注意:InputActionTrace會使用不受管理的記憶體,因此在使用後要去處理(disposed)它,避免造成記憶體洩漏(memory leak)
1 | // 實體化一個 InputActionTrace |
一旦紀錄完成,只要不同時進行寫入操作,並且主線程上不會同時變更Action設置,則trace可以安全地從多個線程讀取。
Action types
Action有三種類型,這些類型會影響Input System如何處理操作Action的狀態。
Action Type | 描述 |
---|---|
Value |
預設的Action Type。適用於任何需要追踪控制項(Control)狀態連續變化的輸入。Value action Type 會持續監控所有綁定到該動作(Action)的控制項(Control),然後選擇最活躍(actuated)的控制項作為驅動該動作的控制項,並在值發生變化時觸發回調函式(callback)報告該控制項的值。如果另一個綁定控制項的活躍程度更高,那麼該控制項就會成為驅動動作的控制項,動作會開始報告該控制項的值。這個過程稱為 衝突解決 (conflict resolution)。如果您希望允許遊戲中不同的控制項控制一個動作,但僅同時從一個控制項接收輸入,那麼這將非常有用。當動作(action)首次啟用時,它會對所有綁定控制項(Control)執行 初始狀態檢查(initial state check)。如果任何一個控制項被激活,則動作會觸發一個回調,傳遞當前值。 |
Button |
Button 類型非常類似於Value 類型,但有以下幾點不同:Button 類型的動作只能綁定到「按鈕控制項」(ButtonControl)。與Value 類型的動作不同,Button 類型的動作不會執行初始狀態檢查。「按鈕」類型的動作適用於每次按下時觸發一次操作的輸入。在這種情況下,初始狀態檢查通常沒有用,因為它可能會在啟用動作時,因之前按住按鈕而觸發動作 (即按鈕仍然處於按下狀態)。 |
PassThrough |
PassThrough 類型的動作與上面描述的Value 動作不同,它繞過了衝突解決。PassThrough 類型的動作不會選擇一個特定的控制項作為驅動動作的來源。 |
相反,任何綁定的控制項會變更都會觸發一個回調,並將該控制項的目前值傳遞給回調函數。PassThrough 類型的動作適用於您想要處理來自一組控制項的所有輸入的情況。 |
使用Input Debugger,可以觀察目前啟用的Action以及與他們綁定的Control。
也可以使用InputActionVisualizer在螢幕上即時可視化動作的值和交互狀態。
上一篇:Actions概念
Reference: https://docs.unity3d.com/Packages/com.unity.inputsystem@1.8/manual/RespondingToActions.html