360 Secure SkillHub
360 安全技能中心

roblox-input

该 Skill 面向 Roblox 客户端开发,讲解 Input Action System、UserInputService、ContextActionService 与 BindToRenderStep 自定义相机,并给出键盘、触摸、手柄和 VR 的绑定、提示、鼠标锁定及跨平台测试建议,强调客户端发送意图并由服务器校验。

EL4CTEO
热度 0.00
最近更新 2026-10-19 02:20:09
分类:开发依赖:纯提示词应用场景:代码生成

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add el4cteo/roblox-skills/roblox-input
Metadata
name
roblox-input
description
Player input and cameras across keyboard/mouse, touch, gamepad, VR - Input Action System (InputContext, InputAction, InputBinding), UserInputService (PreferredInput, gameProcessedEvent, mouse lock), ContextActionService, reserved keys, custom cameras with BindToRenderStep. Use when adding controls, keybinds, abilities, vehicles, on-screen buttons, or custom cameras.

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.
  • InputBinding fields: KeyCode; composite directions Up/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.Enabled switches whole control schemes (gameplay ↔ menu ↔ vehicle); Priority + Sink lets a higher context consume keys so lower contexts don't also fire.
  • Set Workspace.PlayerScriptsUseInputActionSystem = Enabled to 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.
  • PreferredInput reflects what the player is actually using (phone + Bluetooth gamepad → Gamepad); don't branch on TouchEnabled/KeyboardEnabled alone.
  • Mouse: UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter for 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, thumbstick input.Position in 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), not Heartbeat/task.wait loops.
  • 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 UIButton or on-screen buttons).
  • Prompts/hints update when PreferredInput changes. 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 Simulator (touch hints included) and Controller Emulator.

Related skills

roblox-ui (buttons, gamepad selection), roblox-characters-animation (movement, abilities), roblox-networking (sending intents), roblox-physics (vehicles).