Input & Camera
Two essential systems: reading player input (keys, mouse, clicks) and controlling or reading the camera. These power keybind systems, aim features, targeting, and camera manipulation.
UserInputService
local UIS = game:GetService("UserInputService")
-- Key pressed
UIS.InputBegan:Connect(function(input, gameProcessed)
if gameProcessed then return end -- skip if typing in chat/textbox
if input.KeyCode == Enum.KeyCode.X then
print("X pressed")
end
-- Mouse buttons
if input.UserInputType == Enum.UserInputType.MouseButton1 then
print("Left click")
end
if input.UserInputType == Enum.UserInputType.MouseButton2 then
print("Right click")
end
end)
-- Key released
UIS.InputEnded:Connect(function(input, gameProcessed)
if input.KeyCode == Enum.KeyCode.LeftShift then
print("Shift released")
end
end)
-- Mouse/joystick movement
UIS.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then
print("Mouse moved:", input.Delta.X, input.Delta.Y)
end
end)
-- Check if a key is currently held (use in loops)
if UIS:IsKeyDown(Enum.KeyCode.LeftControl) then
-- Ctrl is being held
end
The Mouse Object
The mouse gives you 3D world information about where you're pointing:
local mouse = game.Players.LocalPlayer:GetMouse()
-- Where the mouse ray hits in the world
print(mouse.Hit) -- CFrame: position + orientation of hit surface
print(mouse.Hit.Position) -- Vector3: just the position
-- What instance the mouse is over
print(mouse.Target) -- Instance (BasePart) or nil
-- Screen pixel position
print(mouse.X, mouse.Y)
-- Unit ray from camera through mouse (for raycasting)
local ray = mouse.UnitRay
-- ray.Origin = camera position
-- ray.Direction = normalized direction toward mouse
Raycasting
For precise targeting — finding what's at a screen position or in a direction:
-- Raycast from mouse position into the world
local function getMouseTarget(maxDistance, ignoreList)
local mouse = game.Players.LocalPlayer:GetMouse()
local cam = workspace.CurrentCamera
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = ignoreList or {Players.LocalPlayer.Character}
local result = workspace:Raycast(
mouse.UnitRay.Origin,
mouse.UnitRay.Direction * maxDistance,
params
)
return result -- result.Instance, result.Position, result.Normal
end
-- Usage
local hit = getMouseTarget(500)
if hit then
print("Hit:", hit.Instance:GetFullName(), "at", hit.Position)
end
Raycast from any origin:
-- Raycast forward from character
local hrp = char.HumanoidRootPart
local params = RaycastParams.new()
params.FilterDescendantsInstances = {char}
local result = workspace:Raycast(hrp.Position, hrp.CFrame.LookVector * 100, params)
if result then
print("Something is 100 studs ahead:", result.Instance.Name)
end
Keybind System
A clean pattern for managing multiple keybinds:
local binds = {
[Enum.KeyCode.Q] = function() print("Q action") end,
[Enum.KeyCode.E] = function() print("E action") end,
[Enum.KeyCode.F] = function() print("F action") end,
}
UIS.InputBegan:Connect(function(input, processed)
if processed then return end
local action = binds[input.KeyCode]
if action then action() end
end)
Toggle Keybind
local enabled = false
UIS.InputBegan:Connect(function(input, processed)
if processed then return end
if input.KeyCode == Enum.KeyCode.T then
enabled = not enabled
print("Feature:", enabled and "ON" or "OFF")
end
end)
The Camera
local cam = workspace.CurrentCamera
-- Read camera position
print(cam.CFrame.Position) -- where the camera is
print(cam.CFrame.LookVector) -- direction the camera faces
-- Change FOV
cam.FieldOfView = 70 -- default is 70; lower = zoomed in
-- Camera types
cam.CameraType = Enum.CameraType.Custom -- normal follow camera
cam.CameraType = Enum.CameraType.Scriptable -- full manual control (your script drives it)
Scriptable Camera
Setting camera to Scriptable gives you full control:
cam.CameraType = Enum.CameraType.Scriptable
-- Now move it manually
cam.CFrame = CFrame.new(0, 50, 0) * CFrame.Angles(math.rad(-90), 0, 0) -- looking down
-- Animate it
game:GetService("RunService").RenderStepped:Connect(function()
-- Keep camera above player
local hrp = Players.LocalPlayer.Character and
Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart")
if hrp then
local pos = hrp.Position + Vector3.new(0, 20, -10)
cam.CFrame = CFrame.lookAt(pos, hrp.Position)
end
end)
Reset camera to normal:
cam.CameraType = Enum.CameraType.Custom
World ↔ Screen Conversions
local cam = workspace.CurrentCamera
-- World position → screen position
local screenPos, onScreen = cam:WorldToViewportPoint(worldPos)
-- screenPos.X, screenPos.Y = pixel coordinates
-- screenPos.Z = distance from camera (negative = behind camera)
-- onScreen = true if within viewport bounds
-- Screen position → world ray (for clicking at screen positions)
local ray = cam:ViewportPointToRay(screenPos.X, screenPos.Y)
-- ray.Origin, ray.Direction
Mouse Locking and Sensitivity
Some scripts need to lock or control the mouse:
-- Lock mouse to center of screen
UIS.MouseBehavior = Enum.MouseBehavior.LockCenter
-- Free mouse
UIS.MouseBehavior = Enum.MouseBehavior.Default
-- Get raw mouse delta (works with locked mouse)
UIS.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then
local delta = UIS:GetMouseDelta() -- more accurate than input.Delta
print(delta.X, delta.Y)
end
end)
Click Detection on Screen Elements
-- Detect left click anywhere on screen
UIS.InputBegan:Connect(function(input, processed)
if processed then return end -- don't fire if clicking a GUI element
if input.UserInputType == Enum.UserInputType.MouseButton1 then
-- Get the 3D position clicked
local hit = getMouseTarget(500)
if hit then
-- Do something with what was clicked
end
end
end)