namespace UnityEngine.InputSystem { /// /// Determines the behavior with which an triggers. /// /// /// While all actions essentially function the same way, there are differences in how an action /// will react to changes in values on the controls it is bound to. /// /// The most straightforward type of behavior is which does not expect /// any kind of value change pattern but simply triggers the action on every single value change. /// A pass-through action will not use or /// except on bindings that have an interaction added to them. /// Pass-through actions are most useful for sourcing input from arbitrary many controls and /// simply piping all input through without much processing on the side of the action. /// /// /// /// // An action that triggers every time any button on the gamepad is /// // pressed or released. /// var action = new InputAction( /// type: InputActionType.PassThrough, /// binding: "<Gamepad>/<Button>"); /// /// action.performed += /// ctx => /// { /// var button = (ButtonControl)ctx.control; /// if (button.wasPressedThisFrame) /// Debug.Log($"Button {ctx.control} was pressed"); /// else if (button.wasReleasedThisFrame) /// Debug.Log($"Button {ctx.control} was released"); /// // NOTE: We may get calls here in which neither the if nor the else /// // clause are true here. A button like the gamepad left and right /// // triggers, for example, do not just have a binary on/off state /// // but rather a [0..1] value range. /// }; /// /// action.Enable(); /// /// /// /// Note that pass-through actions do not perform any kind of disambiguation of input /// which makes them great for just forwarding input from any connected controls but /// makes them a poor choice when only one input should be generated from however /// many connected controls there are. For more details, see here. /// /// The other two behavior types are and . /// /// A action starts () as soon as its /// input moves away from its default value. After that it immediately performs () /// and every time the input changes value it performs again except if the input moves back /// to the default value -- in which case the action cancels (). /// /// Also, unlike both and actions, /// actions perform what's called "initial state check" on the first input update after the action /// was enabled. What this does is check controls bound to the action and if they are already actuated /// (that is, at non-default value), the action will immediately be started and performed. What /// this means in practice is that when a value action is bound to, say, the left stick on a /// gamepad and the stick is already moved out of its resting position, then the action will /// immediately trigger instead of first requiring the stick to be moved slightly. /// /// and actions, on the other hand, perform /// no such initial state check. For buttons, for example, this means that if a button is /// already pressed when an action is enabled, it first has to be released and then /// pressed again for the action to be triggered. /// /// /// /// // An action that starts when the left stick on the gamepad is actuated /// // and stops when the stick is released. /// var action = new InputAction( /// type: InputActionType.Value, /// binding: "<Gamepad>/leftStick"); /// /// action.started += /// ctx => /// { /// Debug.Log("--- Stick Starts ---"); /// }; /// action.performed += /// ctx => /// { /// Debug.Log("Stick Value: " + ctx.ReadValue<Vector2D>(); /// }; /// action.canceled += /// ctx => /// { /// Debug.Log("# Stick Released"); /// }; /// /// action.Enable(); /// /// /// /// A action essentially operates like a action except /// that it does not perform an initial state check. /// /// One final noteworthy difference of both and compared /// to is that both of them perform what is referred to as "disambiguation" /// when multiple actions are bound to the control. does not care how /// many controls are bound to the action -- it simply passes every input through as is, no matter /// where it comes from. /// /// and , on the other hand, will treat input differently /// if it is coming from several sources at the same time. Note that this can only happen when there /// are multiple controls bound to a single actions -- either by a single binding resolving to /// more than one control (e.g. "*/{PrimaryAction}") or by multiple bindings all targeting /// the same action and being active at the same time. If only a single control is bound to an /// action, then the disambiguation code is automatically bypassed. /// /// Disambiguation works the following way: when an action has not yet been started, it will react /// to the first input that has a non-default value. Once it receives such an input, it will start /// tracking the source of that input. While the action is in-progress, if it receives input from /// a source other than the control it is currently tracking, it will check whether the input has /// a greater magnitude (see ) than the control the /// action is already tracking. If so, the action will switch from its current control to the control /// with the stronger input. /// /// Note that this process does also works in reverse. When the control currently driving the action /// lowers its value below that of another control that is also actuated and bound to the action, /// the action will switch to that control. /// /// Put simply, a or action bound to multiple controls will /// always track the control with the strongest input. /// /// public enum InputActionType { /// /// An action that reads a single value from its connected sources. If multiple bindings /// actuate at the same time, performs disambiguation (see ) to detect the highest value contributor /// at any one time. /// /// A value action starts () and then performs () /// as soon as a bound control changes to a non-default value. For example, if an action is bound to /// and the stick moves from (0,0) to (0.5,0.5), the action starts and performs. /// /// After being started, the action will perform on every value change that is not the default value. In the example here, if /// the stick goes to (0.75,0.75) and then to (1,1), the action will perform twice. /// /// Finally, if the control value changes back to the default value, the action is canceled (). /// Meaning that if the stick moves back to (0,0), will be triggered. /// Value, /// /// An action that acts as a trigger. /// /// A button action has a defined trigger point that corresponds to . /// After being performed, the action goes back to waiting state to await the next triggering. /// /// Note that a button action may still use and does not necessarily /// trigger immediately on input. For example, if is used, the /// action will start as soon as a bound button crosses its press threshold but will not trigger until the /// button is held for the set hold duration (). /// /// Irrespective of which type an action is set to, it is possible to find out whether it was or is considered /// pressed and/or released using , , /// and . /// /// /// /// action.IsPressed(); /// action.WasPressedThisFrame(); /// action.WasReleasedThisFrame(); /// /// /// Button, /// /// An action that has no specific type of behavior and instead acts as a simple pass-through for /// any value change on any bound control. In effect, this turns an action from a single value producer into a mere /// input "sink". /// /// This is in some ways similar to . However, there are two key differences. /// /// For one, the action will not perform any disambiguation when bound to multiple controls concurrently. /// This means that if, for example, the action is bound to both the left and the right stick on a , /// and the left stick goes to (0.5,0.5) and the right stick then goes to (0.25,0.25), the action will perform /// twice yielding a value of (0.5,0.5) first and a value of (0.25, 0.25) next. This is different from /// where upon actuation to (0.5,0.5), the left stick would get to drive the action and the actuation of the right /// stick would be ignored as it does not exceed the magnitude of the actuation on the left stick. /// /// The second key difference is that only is used and will get triggered /// on every value change regardless of what the value is. This is different from where the /// action will trigger when moving away from its default value and will /// trigger when going back to the default value. /// /// Note that a pass-through action my still get cancelled and thus see getting called. /// This happens when a factor other than input on a device causes an action in progress to be cancelled. An example /// of this is when an action is disabled (see ) or when focus is lost (see ) /// and a device connection to an action is reset (see ). /// /// Also note that for a pass-through action, calling is often not /// very useful as it will only return the value of the very last control that fed into the action. For pass-through /// actions, it is usually best to listen to in order to be notified about every /// single value change. Where this is not necessary, it is generally better to employ a action /// instead. /// PassThrough, } }