Contenido del repositorio de origen con títulos, ejemplos, código, tablas, enlaces e imágenes preservados.
Roblox input and camera
Choose an approach
| Approach | Use when |
|---|---|
Input Action System (InputContext → InputAction → InputBinding) | New gameplay controls. Cross-device bindings configured as instances, contexts you enable/disable, built-in on-screen button binding, prompt display. Recommended. |
UserInputService events | Raw input, text-free hotkeys, mouse position/delta, touch gestures, device detection. |
ContextActionService:BindAction | Legacy/simple bind-with-mobile-button; existing code. |
All input handling is client-side. Send intent to the server via remotes; the server validates.
Input Action System
Structure (typically in ReplicatedStorage.Inputs, or created from a client script):
Inputs (Folder)
PlayContext (InputContext, Priority 1000) -- gameplay controls
Sprint (InputAction, Type = Bool)
Keyboard (InputBinding, KeyCode = LeftShift)
Gamepad (InputBinding, KeyCode = ButtonL3)
Touch (InputBinding, UIButton = <on-screen TextButton>)
MenuContext (InputContext, Priority 2000, Sink = true, Enabled = false)InputAction.Type:Bool(press/release),Direction1D(triggers, zoom),Direction2D(move, camera),
Direction3D (flying), ViewportPosition (pointer position).
- Events:
Pressed,Released(Bool only),StateChanged(value)for every type.action:GetState()reads the current value. InputBindingfields:KeyCode; composite directionsUp/Down/Left/Right/Forward/Backward;Scale
(e.g. 0.01 for MouseDelta/TouchDelta); PressedThreshold/ReleasedThreshold for analog triggers; PrimaryModifier/SecondaryModifier for chords (Ctrl+S); UIButton to drive the action from a GUI button; DisplayName/DisplayImage for prompts.
InputContext.Enabledswitches whole control schemes (gameplay ↔ menu ↔ vehicle);Priority+Sink
lets a higher context consume keys so lower contexts don't also fire.
- Set
Workspace.PlayerScriptsUseInputActionSystem = Enabledto have Roblox's default player/camera
scripts use the system too (required for server authority).
--!strict
-- Client: build a Sprint action in code and react to it.
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local context = Instance.new("InputContext")
context.Name = "PlayContext"
context.Priority = 1000
local sprint = Instance.new("InputAction")
sprint.Name = "Sprint"
sprint.Type = Enum.InputActionType.Bool
sprint.Parent = context
local keyboard = Instance.new("InputBinding")
keyboard.KeyCode = Enum.KeyCode.LeftShift
keyboard.Parent = sprint
local gamepad = Instance.new("InputBinding")
gamepad.KeyCode = Enum.KeyCode.ButtonL3
gamepad.Parent = sprint
context.Parent = player:WaitForChild("PlayerScripts")
local function setSprinting(on: boolean)
local character = player.Character
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if humanoid then
humanoid.WalkSpeed = if on then 24 else 16 -- server should validate/own real speed limits
end
end
sprint.Pressed:Connect(function()
setSprinting(true)
end)
sprint.Released:Connect(function()
setSprinting(false)
end)Show the right key/button: an InputActionLabel (beta) auto-renders the binding for the current device, or read action.PreferredBinding (+ its DisplayName/KeyCode) and UserInputService:GetStringForKeyCode / GetImageForKeyCode, updating on GetPropertyChangedSignal("PreferredBinding").
UserInputService essentials
--!strict
local UserInputService = game:GetService("UserInputService")
UserInputService.InputBegan:Connect(function(input: InputObject, gameProcessedEvent: boolean)
if gameProcessedEvent then
return -- typing in a TextBox, clicking UI, or a core-script action consumed it
end
if input.KeyCode == Enum.KeyCode.E then
print("interact")
elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
print("click at", input.Position)
end
end)
local function onPreferredInputChanged()
local preferred = UserInputService.PreferredInput -- KeyboardAndMouse | Touch | Gamepad
print("show prompts for", preferred)
end
UserInputService:GetPropertyChangedSignal("PreferredInput"):Connect(onPreferredInputChanged)
onPreferredInputChanged()- Always honor `gameProcessedEvent` or players trigger abilities while typing in chat.
PreferredInputreflects what the player is actually using (phone + Bluetooth gamepad →Gamepad);
don't branch on TouchEnabled/KeyboardEnabled alone.
- Mouse:
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenterfor FPS (set every frame while
in first person if other scripts may reset it), GetMouseLocation() (includes top-bar inset), MouseDeltaSensitivity, MouseIconEnabled.
- Gamepad:
GetConnectedGamepads,GamepadConnected/Disconnected, thumbstickinput.Positionin
InputChanged (apply a dead zone ≈ 0.15). Haptics: HapticService / HapticEffect.
- Touch:
TouchTap,TouchLongPress,TouchPinch,TouchSwipe; hide default controls only if you
replace them (GuiService.TouchControlsEnabled).
- Reserved keys you can't override: Esc/Start (menu), F9 (console), F11, F12, PrintScreen; chat
/,
Tab (player list), backpack and tool-number keys unless you disable those core features.
ContextActionService (legacy-compatible)
ContextActionService:BindAction(name, handler, createTouchButton, ...inputs) with handler (actionName, inputState, inputObject) -> Enum.ContextActionResult?; return Pass to let other bindings see the input. Use BindActionAtPriority for ordering and UnbindAction when the context ends (e.g. tool unequipped). Prefer the Input Action System for new work.
Custom cameras
--!strict
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local camera = workspace.CurrentCamera
local OFFSET = Vector3.new(0, 30, 20)
camera.CameraType = Enum.CameraType.Scriptable
RunService:BindToRenderStep("TopDownCamera", Enum.RenderPriority.Camera.Value + 1, function()
local character = Players.LocalPlayer.Character
local root = character and character:FindFirstChild("HumanoidRootPart") :: BasePart?
if root then
local target = root.Position
camera.CFrame = CFrame.lookAt(target + OFFSET, target)
end
end)
-- Restore: RunService:UnbindFromRenderStep("TopDownCamera"); camera.CameraType = Enum.CameraType.Custom- Update cameras in
BindToRenderStep(runs before render, ordered), notHeartbeat/task.waitloops. - Smooth with
camera.CFrame:Lerp(goal, 1 - math.exp(-speed * deltaTime))(frame-rate independent). - First person:
player.CameraMode = Enum.CameraMode.LockFirstPerson; zoom limits with
player.CameraMinZoomDistance/CameraMaxZoomDistance. Shake: offset the CFrame, don't move parts.
- Screen → world:
camera:ViewportPointToRay(x, y)/ScreenPointToRay+workspace:Raycast.
Cross-platform checklist
- Every action has keyboard, gamepad, and touch bindings (touch via
UIButtonor on-screen buttons). - Prompts/hints update when
PreferredInputchanges. Console UI is navigable with D-pad and closes with B. - No hover-only interactions (touch has no hover). Hold-to-confirm for destructive actions.
- Test in Studio's Device Emulator and Controller Emulator.
Related skills
roblox-ui (buttons, gamepad selection), roblox-characters-animation (movement, abilities), roblox-networking (sending intents), roblox-physics (vehicles).

