Gamepad Input

Roblox accepts input from USB gamepads such as Xbox and PlayStation controllers. Since gamepads come in different varieties, you need to follow additional setup to verify that a player's gamepad inputs are usable in your experience.

To set up gamepad inputs, you can use ContextActionService or UserInputService to detect connected gamepads for a player's device, verify supported inputs that are compatible with Roblox, receive input, and more.

When binding gamepad inputs, see common control schemas to create a consistent gamepad experience for players. After inputs are set, you can enhance the player's experience by including haptic feedback on supported controllers.

Detecting Gamepads

You can detect whether a player's device currently has a gamepad active using the UserInputService.GamepadEnabled property.

Detecting Gamepad

local UserInputService = game:GetService("UserInputService")
if UserInputService.GamepadEnabled then
print("Player has gamepad enabled...")
end

You can check for connected gamepads via UserInputService.GamepadConnected and UserInputService.GamepadDisconnected events. These events fire when a device is connected or disconnected respectively, and both events pass a Enum.UserInputType to the connected function indicating which gamepad caused the event. In most cases, the connected gamepad is Gamepad1.

Checking Connection and Disconnection

local UserInputService = game:GetService("UserInputService")
UserInputService.GamepadConnected:Connect(function(gamepad)
print("User has connected controller: " .. tostring(gamepad))
end)
UserInputService.GamepadDisconnected:Connect(function(gamepad)
print("User has disconnected controller: " .. tostring(gamepad))
end)

You can also query whether a particular controller is connected using the UserInputService:GetGamepadConnected() method. This takes a Enum.UserInputType as an argument and only accepts values of Gamepad1 through Gamepad8.

Query Specific Gamepad Connection

local UserInputService = game:GetService("UserInputService")
if UserInputService:GetGamepadConnected(Enum.UserInputType.Gamepad1) then
print("Gamepad1 is connected")
elseif UserInputService:GetGamepadConnected(Enum.UserInputType.Gamepad2) then
print("Gamepad2 is connected")
end

Verifying Supported Inputs

Since gamepads can have different sets of inputs, you should check which inputs are supported with UserInputService:GetSupportedGamepadKeyCodes(). This method takes a Enum.UserInputType as an argument and returns a table with a list of all available inputs for the specified controller.

Verifying Supported Inputs

local UserInputService = game:GetService("UserInputService")
local availableInputs = UserInputService:GetSupportedGamepadKeyCodes(Enum.UserInputType.Gamepad2)
print("This controller supports the following controls:")
for _, control in availableInputs do
print(control)
end

Receiving Input

ContextActionService is useful for binding controls to both gamepads and other input sources such as mouse and keyboard inputs or mobile touchscreen buttons, or for binding multiple functions to a single button input on any device. For example, the following code sample binds an OpenSpellBook action to the gamepad's ButtonR2 button and the keyboard's B key.

ContextActionService Bind Action

local ContextActionService = game:GetService("ContextActionService")
local function openSpellBook(actionName, inputState, inputObject)
if inputState == Enum.UserInputState.Begin then
-- Open spell book
end
end
ContextActionService:BindAction("OpenSpellBook", openSpellBook, false, Enum.KeyCode.ButtonR2, Enum.KeyCode.B)

Alternatively, you can use UserInputService to bind controls directly from a gamepad. When detecting gamepad events through this service, use the InputBegan event to detect when the button was initially pressed and InputEnded to detect when the button is released. In the handling function, the InputObject.UserInputType property indicates which gamepad fired the event and InputObject.KeyCode indicates the specific button or stick that fired it.

UserInputService Button Press Detection

local UserInputService = game:GetService("UserInputService")
UserInputService.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Gamepad1 then
if input.KeyCode == Enum.KeyCode.ButtonA then
print("Button A pressed on Gamepad1")
end
end
end)

Gamepad State

You can detect the current state of all buttons and sticks on a gamepad with the UserInputService:GetGamepadState() method. This is useful if you need to check the current gamepad inputs when a distinct event occurs in your experience, such as checking if specific buttons are being pressed when a character touches an object.

Checking State of Gamepad Inputs

local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local leftFoot = character:WaitForChild("LeftFoot")
-- When left foot comes into contact with something, check the gamepad input state
leftFoot.Touched:Connect(function(hit)
local state = UserInputService:GetGamepadState(Enum.UserInputType.Gamepad1)
for _, input in state do
-- If the ButtonR2 is currently held, print out a message
if input.KeyCode == Enum.KeyCode.ButtonR2 and input.UserInputState == Enum.UserInputState.Begin then
print("Character's left foot touched something while holding right trigger")
end
end
end)

Trigger Pressure

You can detect how much pressure is being placed on gamepad triggers by checking the Position.Z value of the input trigger.

Testing Trigger Pressure

local UserInputService = game:GetService("UserInputService")
UserInputService.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Gamepad1 then
if input.KeyCode == Enum.KeyCode.ButtonL1 then
print("Pressure on left trigger has changed:", input.Position.Z)
elseif input.KeyCode == Enum.KeyCode.ButtonR1 then
print("Pressure on right trigger has changed:", input.Position.Z)
end
end
end)

Common Control Schemas

Gamepads come in a variety of shapes and sizes. As with any method of player input, it's best to create some consistency across different games and experiences.

The following are common input binds that will help players immediately feel familiar and comfortable with the gamepad controls:

InputCommon Use Cases
ButtonAAccepts player prompts or GUI selections. Alternatively used for primary actions such as jumping.
ButtonBCancels player prompts or GUI selections. Alternatively used for secondary actions such as a dodge, roll, or sprint.
Thumbstick1Generally associated with character movement.
Thumbstick2Generally associated with camera movement.
ButtonL2, ButtonR2Generally used for primary actions, such as shooting.
ButtonL1, ButtonR1, ButtonX, ButtonYSecondary actions such as reloading, targeting, or accessing an inventory or minimap.

Haptic Feedback

Many gamepad controllers have motors built in to provide haptic feedback. Adding rumbles and vibrations can greatly enhance a player's experience and provide subtle feedback beyond visuals or audio. You can use the HapticService to verify vibration support before turning on the motors.

Vibration Support

Not all controllers have motors so it is important to check for support before attempting to use the haptic motors. To query if a given controller has vibration support, call HapticService:IsVibrationSupported().

Check Vibration Support

local HapticService = game:GetService("HapticService")
local gamepad = Enum.UserInputType.Gamepad1
local isVibrationSupported = HapticService:IsVibrationSupported(gamepad)

Some controllers have multiple motors for various scales of vibration. Once you've checked if a gamepad supports vibration, you should also check if it supports the motors you intend to use through HapticService:IsMotorSupported().

Check Motors Supported

local HapticService = game:GetService("HapticService")
local gamepad = Enum.UserInputType.Gamepad1
local isVibrationSupported = HapticService:IsVibrationSupported(gamepad)
if isVibrationSupported then
local largeMotor = HapticService:IsMotorSupported(gamepad, Enum.VibrationMotor.Large)
local smallMotor = HapticService:IsMotorSupported(gamepad, Enum.VibrationMotor.Small)
local leftTriggerMotor = HapticService:IsMotorSupported(gamepad, Enum.VibrationMotor.LeftTrigger)
local rightTriggerMotor = HapticService:IsMotorSupported(gamepad, Enum.VibrationMotor.RightTrigger)
local leftHandMotor = HapticService:IsMotorSupported(gamepad, Enum.VibrationMotor.LeftHand)
local rightHandMotor = HapticService:IsMotorSupported(gamepad, Enum.VibrationMotor.RightHand)
end
Size or LocationDescription
LargeLarger motor, useful for generic rumble.
SmallSmaller motor, useful for more subtle rumbles like tires slipping, electric shock, etc.
LeftTriggerUnderneath the left trigger.
RightTriggerUnderneath the right trigger.
LeftHandOn the left side of the controller.
RightHandOn the right side of the controller.

Activating Motors

Once you've confirmed that a player's gamepad supports vibration, you can turn on a specific motor with HapticService:SetMotor(). This method takes the gamepad and the amplitude of the vibration as arguments. Amplitude can be any value between 0 and 1.

Activating Motor

local HapticService = game:GetService("HapticService")
local gamepad = Enum.UserInputType.Gamepad1
local isVibrationSupported = HapticService:IsVibrationSupported(gamepad)
if isVibrationSupported then
local largeMotor = HapticService:IsMotorSupported(gamepad, Enum.VibrationMotor.Large)
if largeMotor then
HapticService:SetMotor(gamepad, Enum.VibrationMotor.Large, 0.5)
end
end