Skip to content

Latest commit

 

History

History
333 lines (257 loc) · 24 KB

File metadata and controls

333 lines (257 loc) · 24 KB
title description
Input Action System
The cross-platform Input Action System lets you connect actions and arrange bindings across various hardware inputs at edit time.

import DefaultBindings from '../includes/default-bindings.md'

The cross-platform Input Action System lets you connect actions and arrange bindings across various hardware inputs at edit time. Combined with contexts, you can easily configure and edit a modular input system that works on any device in any phase of play. Use cases include:

  • A first-person shooter system with actions dynamically swapping in and out depending on if the player is in battle mode or spectator mode.
  • A comprehensive driving system equipped with acceleration/deceleration, car boosters, and refuel stations.
  • Hotkeys for an abilities system in a fighting game to swap out moves seamlessly without players missing a punch.

Input contexts

An Class.InputContext is a collection of actions which holds related input actions, for example PlayContext for in‑experience character controls and NavContext for controls to navigate around UI menus. You can enable or disable contexts (and their corresponding actions) through their Class.InputContext.Enabled|Enabled property, such as to enable the NavContext when an inventory menu is open and then change to the PlayContext when the player closes the menu and returns to primary gameplay.

Even if an experience may not use multiple input contexts initially, best practice is to create a primary context at the top level of any input system, for example the PlayContext instance for input that occurs during gameplay.

  1. Insert a new Class.InputContext into Class.StarterGui.

  2. Rename it to PlayContext.

    New InputContext instance inside StarterGui, renamed to PlayContext

Input actions

An Class.InputAction defines a gameplay action mechanic such as "Jump," "Sprint," or "Shoot." These actions are then mapped to hardware inputs using input bindings.

An Class.InputAction can be of several variations depending on its Class.InputAction.Type|Type property (Enum.InputActionType). The default is Enum.InputActionType|Bool, designed to receive true/false values from press/release of inputs such as Enum.KeyCode|ButtonA, Enum.KeyCode|E, or Enum.KeyCode|MouseLeftButton. The Enum.InputActionType|Bool type also exposes the Class.InputBinding.UIButton|UIButton property on child bindings, allowing you to easily hook up press/release of a specific Class.GuiButton for the action.

Input Action Type Example Usage
`Enum.InputActionType|Bool` Triggered actions such as jump, shoot, sprint, etc. with support for pressed/released thresholds on analog inputs.
`Enum.InputActionType|Direction1D` Variable zero-to-full actions such as a car's accelerator pedal or a view scope's zoom level.
`Enum.InputActionType|Direction2D` 2D directional movement such as camera rotation, or the standard Roblox character movement.
`Enum.InputActionType|Direction3D` 3D directional movement like an airborne vehicle that can levitate up/down, accelerate/decelerate, and drift left/right.

To test an Class.InputAction for simple character sprinting:

  1. Create a new Class.InputAction inside the PlayContext context within Class.StarterGui. Rename it to CharacterSprint to indicate its dedicated action.

    New InputAction instance inside an InputContext, renamed to CharacterSprint
  2. In the Properties window, notice that the action's Class.InputAction.Type|Type is Enum.InputActionType|Bool (default). This is a logical type for simple character sprinting as a boolean true/false action (character is either sprinting or not sprinting).

    Type property of an InputAction set to Bool

Input bindings

An Class.InputBinding defines which hardware binding should trigger the parent Class.InputAction, for example a key press, gamepad button, or tap on a touch‑enabled device. For cross‑platform compatibility, each Class.InputAction should have an Class.InputBinding for gamepad, keyboard/mouse, and touch as illustrated here.

The Class.InputAction.Type|Type assigned to the parent Class.InputAction directly affects which general input types (key/button/tap, analog trigger, thumbstick, etc.) are valid for child Class.InputBinding instances. In turn, values sent to the parent action's connected events depend on a binding's chosen input type. See input events for details on the correlation between action types, bindings, and return values.

To hook up bindings for simple character sprinting:

  1. Insert a new Class.InputBinding into the CharacterSprint action and rename it to KeyboardBinding. Then set the binding's Class.InputBinding.KeyCode|KeyCode property to Enum.KeyCode|LeftShift.

  2. To ensure mouse Shift-lock does not interfere with the key binding, select Class.StarterPlayer in the Explorer and disable its Class.StarterPlayer.EnableMouseLockOption|EnableMouseLockOption in the Properties window.

  3. Insert another Class.InputBinding into the CharacterSprint action and rename it to GamepadBinding. Then set the binding's Class.InputBinding.KeyCode|KeyCode property to Enum.KeyCode|ButtonY.

  4. Inside a Class.ScreenGui container inside Class.StarterGui, create an on-screen button, rename it to SprintButton, and position/resize it as desired.

  5. Insert another Class.InputBinding into the CharacterSprint action and rename it to TouchBinding. Then, in the Properties window, link the binding's Class.InputBinding.UIButton|UIButton property to the SprintButton button you created previously inside Class.StarterGui.

Input events

The Class.InputAction instance has three built-in events to handle player input coming from Class.InputBinding|InputBindings.

  • Class.InputAction.Pressed|Pressed — This event fires only when the input action's Class.InputAction.Type|Type is set to Enum.InputActionType|Bool, and only when the state transitions from false to true.
  • Class.InputAction.Released|Released — This event fires only when the input action's Class.InputAction.Type|Type is set to Enum.InputActionType|Bool, and only when the state transitions from true to false.
  • Class.InputAction.StateChanged|StateChanged — This event fires for all input action types whenever the state changes, except if the state attempts to transition to the same state.

Depending on the input action's Class.InputAction.Type|Type (Enum.InputActionType|Bool, Enum.InputActionType|Direction1D, Enum.InputActionType|Direction2D, or Enum.InputActionType|Direction3D) and the general input type coming from a child Class.InputBinding (key/button/tap, analog trigger, thumbstick, etc.), different values are returned to the Class.InputAction.Pressed|Pressed, Class.InputAction.Released|Released, and Class.InputAction.StateChanged|StateChanged event handlers. Examine the following tables to better understand the correlation.

The `Enum.InputActionType|Bool` type is best for triggered actions such as jump, shoot, sprint, etc. with support for pressed/released thresholds on analog inputs.
Valid Input Types on `Class.InputBinding|InputBindings` Returned to the `Class.InputAction` Event(s)
Boolean inputs from keyboard keys or basic mouse/gamepad buttons through the binding's `Class.InputBinding.KeyCode|KeyCode` property, or a `Class.GuiButton` press/release through the binding's `Class.InputBinding.UIButton|UIButton` property.
  • `Class.InputAction.Pressed|Pressed` event:
    • `true` when pressed
  • `Class.InputAction.Released|Released` event:
    • `true` when released
  • `Class.InputAction.StateChanged|StateChanged` event:
    • `true` (pressed) or `false` (released)
Variable input amounts from analog inputs like gamepad triggers (`Enum.KeyCode|ButtonL2`/`Enum.KeyCode|ButtonR2`) through the binding's `Class.InputBinding.KeyCode|KeyCode` property.
  • `Class.InputAction.Pressed|Pressed` event:
    • `true` when trigger press is `>=` `Class.InputBinding.PressedThreshold|PressedThreshold`
  • `Class.InputAction.Released|Released` event:
    • `true` when trigger press is `<=` `Class.InputBinding.ReleasedThreshold|ReleasedThreshold`
  • `Class.InputAction.StateChanged|StateChanged` event:
    • `true` when trigger press is `>=` `Class.InputBinding.PressedThreshold|PressedThreshold`
    • `false` when trigger press is `<=` `Class.InputBinding.ReleasedThreshold|ReleasedThreshold`
The `Enum.InputActionType|Direction1D` type is best for variable zero‑to‑full actions such as a car's accelerator pedal or a view scope's zoom level.
Valid Input Types on `Class.InputBinding|InputBindings` Returned to the `Class.InputAction` Event(s)
Variable input amounts from analog inputs like gamepad triggers (`Enum.KeyCode|ButtonL2`/`Enum.KeyCode|ButtonR2`) through the binding's `Class.InputBinding.KeyCode|KeyCode`, `Class.InputBinding.Up|Up`, and `Class.InputBinding.Down|Down` properties.
  • `Class.InputAction.StateChanged|StateChanged` event:
    • `0` to `1` (fully released to fully pressed) through the `Class.InputBinding.KeyCode|KeyCode` or `Class.InputBinding.Up|Up` properties
    • `0` to `-1` (fully released to fully pressed) through the `Class.InputBinding.Down|Down` property
Boolean inputs from keyboard keys or basic mouse/gamepad buttons through the binding's `Class.InputBinding.KeyCode|KeyCode`, `Class.InputBinding.Up|Up`, and `Class.InputBinding.Down|Down` properties.
  • `Class.InputAction.StateChanged|StateChanged` event:
    • `1` (pressed) or `0` (released) through the `Class.InputBinding.KeyCode|KeyCode` or `Class.InputBinding.Up|Up` properties
    • `-1` (pressed) or `0` (released) through the `Class.InputBinding.Down|Down` property
The `Enum.InputActionType|Direction2D` type is best for 2D directional movement such as camera rotation, or the standard Roblox character movement.
Valid Input Types on `Class.InputBinding|InputBindings` Returned to the `Class.InputAction` Event(s)
Variable input amounts from 2D analog inputs like gamepad thumbsticks (`Enum.KeyCode|Thumbstick1`/`Enum.KeyCode|Thumbstick2`) through the binding's `Class.InputBinding.KeyCode|KeyCode` property.
  • `Class.InputAction.StateChanged|StateChanged` event:
    • `Datatype.Vector2` between `(-1, -1)` and `(1, 1)`
Variable input amounts from analog inputs like gamepad triggers (`Enum.KeyCode|ButtonL2`/`Enum.KeyCode|ButtonR2`) through the binding's `Class.InputBinding.Up|Up`, `Class.InputBinding.Down|Down`, `Class.InputBinding.Left|Left`, and `Class.InputBinding.Right|Right` properties.
  • `Class.InputAction.StateChanged|StateChanged` event:
    • `Datatype.Vector2` with `Datatype.Vector2.Y|Y` component between `0` and `1` (fully released to fully pressed) through the `Class.InputBinding.Up|Up` property
    • `Datatype.Vector2` with `Datatype.Vector2.Y|Y` component between `0` and `-1` (fully released to fully pressed) through the `Class.InputBinding.Down|Down` property
    • `Datatype.Vector2` with `Datatype.Vector2.X|X` component between `0` and `-1` (fully released to fully pressed) through the `Class.InputBinding.Left|Left` property
    • `Datatype.Vector2` with `Datatype.Vector2.X|X` component between `0` and `1` (fully released to fully pressed) through the `Class.InputBinding.Right|Right` property
Boolean inputs from keyboard keys or basic mouse/gamepad buttons through the binding's `Class.InputBinding.Up|Up`, `Class.InputBinding.Down|Down`, `Class.InputBinding.Left|Left`, and `Class.InputBinding.Right|Right` properties.
  • `Class.InputAction.StateChanged|StateChanged` event:
    • `Datatype.Vector2` of `(0, 1)` (pressed) or `(0, 0)` (released) through the `Class.InputBinding.Up|Up` property
    • `Datatype.Vector2` of `(0, -1)` (pressed) or `(0, 0)` (released) through the `Class.InputBinding.Down|Down` property
    • `Datatype.Vector2` of `(-1, 0)` (pressed) or `(0, 0)` (released) through the `Class.InputBinding.Left|Left` property
    • `Datatype.Vector2` of `(1, 0)` (pressed) or `(0, 0)` (released) through the `Class.InputBinding.Right|Right` property
The `Enum.InputActionType|Direction3D` type is best for 3D directional movement like an airborne vehicle that can levitate up/down, accelerate/decelerate, and drift left/right.
Valid Input Types on `Class.InputBinding|InputBindings` Returned to the `Class.InputAction` Event(s)
Variable input amounts from analog inputs like gamepad triggers (`Enum.KeyCode|ButtonL2`/`Enum.KeyCode|ButtonR2`) through the binding's `Class.InputBinding.Up|Up`, `Class.InputBinding.Down|Down`, `Class.InputBinding.Left|Left`, `Class.InputBinding.Right|Right`, `Class.InputBinding.Forward|Forward`, and `Class.InputBinding.Backward|Backward` properties.
  • `Class.InputAction.StateChanged|StateChanged` event:
    • `Datatype.Vector3` with `Datatype.Vector3.Y|Y` component between `0` and `1` (fully released to fully pressed) through the `Class.InputBinding.Up|Up` property
    • `Datatype.Vector3` with `Datatype.Vector3.Y|Y` component between `0` and `-1` (fully released to fully pressed) through the `Class.InputBinding.Down|Down` property
    • `Datatype.Vector3` with `Datatype.Vector3.X|X` component between `0` and `-1` (fully released to fully pressed) through the `Class.InputBinding.Left|Left` property
    • `Datatype.Vector3` with `Datatype.Vector3.X|X` component between `0` and `1` (fully released to fully pressed) through the `Class.InputBinding.Right|Right` property
    • `Datatype.Vector3` with `Datatype.Vector3.Z|Z` component between `0` and `1` (fully released to fully pressed) through the `Class.InputBinding.Forward|Forward` property
    • `Datatype.Vector3` with `Datatype.Vector3.Z|Z` component between `0` and `-1` (fully released to fully pressed) through the `Class.InputBinding.Backward|Backward` property
Boolean inputs from keyboard keys or basic mouse/gamepad buttons through the binding's `Class.InputBinding.Up|Up`, `Class.InputBinding.Down|Down`, `Class.InputBinding.Left|Left`, `Class.InputBinding.Right|Right`, `Class.InputBinding.Forward|Forward`, and `Class.InputBinding.Backward|Backward` properties.
  • `Class.InputAction.StateChanged|StateChanged` event:
    • `Datatype.Vector3` of `(0, 1, 0)` (pressed) or `(0, 0, 0)` (released) through the `Class.InputBinding.Up|Up` property
    • `Datatype.Vector3` of `(0, -1, 0)` (pressed) or `(0, 0, 0)` (released) through the `Class.InputBinding.Down|Down` property
    • `Datatype.Vector3` of `(-1, 0, 0)` (pressed) or `(0, 0, 0)` (released) through the `Class.InputBinding.Left|Left` property
    • `Datatype.Vector3` of `(1, 0, 0)` (pressed) or `(0, 0, 0)` (released) through the `Class.InputBinding.Right|Right` property
    • `Datatype.Vector3` of `(0, 0, 1)` (pressed) or `(0, 0, 0)` (released) through the `Class.InputBinding.Forward|Forward` property
    • `Datatype.Vector3` of `(0, 0, -1)` (pressed) or `(0, 0, 0)` (released) through the `Class.InputBinding.Backward|Backward` property
Note that returned `Datatype.Vector2`/`Datatype.Vector3` values for 2D/3D inputs will be normalized such that the magnitude is never greater than `1` (unless scaling is applied). For example, a 45° up+right press on a gamepad thumbstick will return a normalized `Datatype.Vector2` of `(0.7071, 0.7071)` instead of `(1, 1)`. In practical terms of character movement, this ensures that diagonal presses do not allow players to move faster diagonally than they would in a cardinal direction.

To connect events for simple character sprinting:

  1. Insert a new Class.LocalScript into the CharacterSprint tree, alongside the various input bindings.

  2. Paste the following code into the script. Note the Class.InputAction.Pressed|Pressed event connection on lines 1315 which doubles the character's walk speed when a sprint input binding is pressed, and the corresponding Class.InputAction.Released|Released event connection on lines 1618 which resets the walk speed to default when a sprint input binding is released.

     ```lua
     local Players = game:GetService("Players")
    
     local player = Players.LocalPlayer
     local character = player.Character
     if not character or character.Parent == nil then
     	character = player.CharacterAdded:Wait()
     end
     local humanoid = character:WaitForChild("Humanoid")
     local defaultWalkSpeed = humanoid.WalkSpeed
    
     local inputAction = script.Parent
    
     inputAction.Pressed:Connect(function()
     	humanoid.WalkSpeed = defaultWalkSpeed * 2
     end)
     inputAction.Released:Connect(function()
     	humanoid.WalkSpeed = defaultWalkSpeed
     end)
     ```
    
  3. Playtest your experience and test the character sprint action with the bindings you chose previously: Enum.KeyCode|LeftShift for keyboard, Enum.KeyCode|ButtonY for gamepad, and the on‑screen SprintButton for touch‑enabled devices. Remember that you can use the Controller Emulator to test gamepad inputs directly in Roblox Studio.

Context changes

Once you have an input context such as PlayContext, you can enable/disable it during gameplay through scripting, change its Class.InputContext.Priority|Priority to determine which actions take precedence over others, and Class.InputContext.Sink|Sink inputs from being processed within contexts of lower priority.

  1. To make it easier to switch contexts from other scripts, insert a new Class.BindableEvent into Class.StarterGui and rename it to ContextEvent.

  2. Create a new Class.LocalScript inside Class.StarterGui and rename it to UpdateContext.

  3. Inside the UpdateContext script, paste the following code:

     ```lua
     local Players = game:GetService("Players")
    
     local player = Players.LocalPlayer
     local playerGui = player.PlayerGui
    
     local contextEvent = playerGui:FindFirstChild("ContextEvent")
    
     -- Connect bindable event
     contextEvent.Event:Connect(function(targetContext, enabled)
     	local context = playerGui:FindFirstChild(targetContext)
     	if context then
     		context.Enabled = enabled
     		print(context.Name .. ": " .. tostring(context.Enabled))
     	else
     		warn("InputContext not found!")
     	end
     end)
     ```
    
  4. With the UpdateContext script in place, you can now update a named Class.InputContext by firing the bindable event, for example from another Class.LocalScript that powers a Class.GuiButton inside the Class.ScreenGui container.

    <img src="../assets/studio/explorer/StarterGui-ScreenGui-TextButton.png" width="320" style={{marginBottom: 0}} />

     ```lua
     local Players = game:GetService("Players")
    
     local player = Players.LocalPlayer
     local playerGui = player.PlayerGui
    
     local contextEvent = playerGui:FindFirstChild("ContextEvent")
    
     local button = script.Parent
     button.Activated:Connect(function()
     	-- Fire bindable event with target input context and enabled state
     	contextEvent:Fire("PlayContext", true)
     end)
     ```
    

Default bindings