Roblox accepts input from USB gamepads such as Xbox and PlayStation controllers. Since gamepads can come in different varieties, you need to follow additional setup to verify that a user's gamepad inputs are usable in your experience.
To set up gamepad inputs, you can use UserInputService to perform the following:
- Detect connected gamepads to get information on currently connected or disconnected devices.
- Verify valid inputs that are compatible with Roblox.
When binding gamepad inputs, see common control schemas to create a consistent gamepad experience between experiences.
After your inputs are set, you can additionally customize your gamepads by including vibration feedback on supported controllers. See Haptic Feedback for instructions on verifying and activating vibrations.
You can detect whether a user's device currently has a gamepad active using the UserInputService.GamepadEnabled property.
Use the following sample code to print out a console message if the GamepadEnabled property is true:
local UserInputService = game:GetService("UserInputService")if UserInputService.GamepadEnabled thenprint("Player has gamepad enabled...")end
You can connect up to eight local gamepads to a client at once. You can check for connected gamepads with GamepadConnected and GamepadDisconnected events. These events will fire when a device is connected or disconnected respectively. Both events will pass a UserInputType to the connected function indicating which gamepad caused the event. In most cases, the connected gamepad is UserInputType.Gamepad1.
Use the following code sample to print out the specific gamepad that is connected and disconnected:
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() function. This takes a UserInputType as an argument and only accepts values of UserInputType.Gamepad1 through UserInputType.Gamepad8.
Use the following code sample to check for a specific gamepad and print a message if it is connected:
local UserInputService = game:GetService("UserInputService")if UserInputService:GetGamepadConnected(Enum.UserInputType.Gamepad1) thenprint("Gamepad1 is connected")elseif UserInputService:GetGamepadConnected(Enum.UserInputType.Gamepad2) thenprint("Gamepad2 is connected")end
Since gamepads can have different sets of inputs, check which inputs are supported with UserInputService:GetSupportedGamepadKeyCodes(). This function takes a UserInputType as an argument and returns a table with a list of all available inputs for the specified controller.
Use the following code sample to print out a list of available inputs detected from Gamepad 2:
local UserInputService = game:GetService("UserInputService")local availableInputs = UserInputService:GetSupportedGamepadKeyCodes(Enum.UserInputType.Gamepad2)print("This controller supports the following controls:")for _, control in pairs(availableInputs) doprint(control)end
There are three ways to receive input from a gamepad:
- Use UserInputService:GetGamepadState() to query all the current input states of gamepad.
You can use ContextActionService for binding controls to both gamepads and other input sources such as mobile touchscreen buttons or binding multiple functions to a single button input on any device. For example, use ContextActionService to bind an OpenSpellBook action to the right trigger (R2) on a gamepad and the B key on a keyboard in one function.
Use the following code sample to bind an OpenSpellBook action to the gamepad's R2 button and the B key on the keyboard:
local ContextActionService = game:GetService("ContextActionService")local function openSpellBook(actionName, inputState, inputObject)if inputState == Enum.UserInputState.Begin then-- Open spell bookendendContextActionService:BindAction("OpenSpellBook", openSpellBook, false, Enum.KeyCode.ButtonR2, Enum.KeyCode.B)
You can use UserInputService to bind controls directly from a gamepad. When detecting gamepad events with UserInputService, use UserInputService.InputBegan to detect when the button was initially pressed and UserInputService.InputEnded to detect when the button is released.
Use the following sample code to listen for an UserInputService.InputBegan event where the A button is pressed on Gamepad1:
local UserInputService = game:GetService("UserInputService")UserInputService.InputBegan:Connect(function(input)if input.UserInputType == Enum.UserInputType.Gamepad1 thenif input.KeyCode == Enum.KeyCode.ButtonA thenprint("Button A pressed on Gamepad1")endendend)
You can detect the current state of all buttons and sticks on a gamepad with the UserInputService:GetGamepadState() function. This is useful if you need to check the current gamepad inputs when a distinct event occurs in your experience. For example, you may want to check if specific buttons are being pressed when a character touches an object.
Use the following code sample to detect if the Gamepad1 R2 button is being held when the player character's left foot comes contacts a surface:
local Players = game:GetService("Players")local UserInputService = game:GetService("UserInputService")local player = Players.LocalPlayerlocal character = player.Characterif not character or not character.Parent thencharacter = player.CharacterAdded:Wait()endlocal leftFoot = character:WaitForChild("LeftFoot")-- When leftFoot comes into contact with something, check the gamepad input stateleftFoot.Touched:Connect(function(hit)local state = UserInputService:GetGamepadState(Enum.UserInputType.Gamepad1)for _, input in pairs(state) do-- If the ButtonR2 is currently held then print out a messageif input.KeyCode == Enum.KeyCode.ButtonR2 and input.UserInputState == Enum.UserInputState.Begin thenprint("Character's left foot touched something while holding right trigger")endendend)
Gamepads come in a variety of shapes and sizes. As with any method of user input, it's best to create some consistency across different games and applications.
The following are common input binds that will help users immediately feel familiar and comfortable with the gamepad controls:
|A button||Accepts user prompts or GUI selections. Alternatively used for primary actions in an experience, such as jumping.|
|B button||Cancels user prompts or GUI selections. Alternatively used for secondary actions in an experience, such as a dodge, roll, or sprint.|
|Left Thumbstick||Generally associated with character movement.|
|Right Thumbstick||Generally associated with camera movement.|
|Right Trigger||Generally used for primary actions, such as shooting.|
|R1, L1 and X and Y buttons||Secondary actions such as reloading, targeting or accessing an inventory or minimap.|
Many gamepad controllers, such as Xbox One controllers, have motors built in to provide haptic feedback. Adding rumbles and vibrations can greatly enhance a user's experience and provide subtle feedback beyond visuals or audio. You can use the HapticService to verify vibration support before turning on the controller motors.
Not all controllers support vibration so it is important to check if the plugged-in controllers have support before attempting to use the controller motors. To check if a given controller has rumble support at all, you can call HapticService:IsVibrationSupported().
Use the following sample code to verify if vibration is supported on gamepad 1:
local HapticService = game:GetService("HapticService")local isVibrationSupported = HapticService:IsVibrationSupported(Enum.UserInputType.Gamepad1)
Some controllers have multiple motors for various scales of vibration. Once you have checked if a gamepad supports vibration, you should also check if it supports the motors you intend to use. The Xbox One controller has 4 motors:
- Large: in the left side of the controller. Good for generic rumble.
- Small: in the right side of the controller. Good for more subtle rumbles(tire slipping, electric shock, etc.).
- Left Trigger: underneath the left trigger. Good for braking, gun reloading, etc.
- Right Trigger: underneath the right trigger. Good for recoil, acceleration, etc.
The user might not have a controller that supports all of these motors. Many only support the Large and Small motors (no triggers). You can use HapticService:IsMotorSupported() to see if the user's controller supports the motor you want to use.
Use the following sample code to verify if large vibration motors are supported on gamepad 1:
local HapticService = game:GetService("HapticService")local isVibrationSupported = HapticService:IsVibrationSupported(Enum.UserInputType.Gamepad1)local largeSupported = falseif isVibrationSupported thenlargeSupported = HapticService:IsMotorSupported(Enum.UserInputType.Gamepad1, Enum.VibrationMotor.Large)end
Once you have confirmed that a user's gamepad supports vibration you can start using the gamepad motors. You can use HapticService:SetMotor() to turn on a specific motor on a gamepad. This function takes the gamepad and the amplitude of the vibration as arguments. The amplitude can be any value between 0 and 1.
The following sample code sets the amplitude for gamepad 1's large motor to .5:
local HapticService = game:GetService("HapticService")HapticService:SetMotor(Enum.UserInputType.Gamepad1, Enum.VibrationMotor.Large, .5)
You can also use HapticService:GetMotor() to get the current vibration amplitude of a given motor. Use the following code sample to print the current amplitude for gamepad 1's large motor:
local HapticService = game:GetService("HapticService")print(HapticService:GetMotor(Enum.UserInputType.Gamepad1, Enum.VibrationMotor.Large)
The following code is a sample implementation of vibration when a user character gets into a vehicle, where the vibration is based on the throttle of the vehicle:
-- Serviceslocal HapticService = game:GetService("HapticService")local Players = game:GetService("Players")local RunService = game:GetService("RunService")-- Make sure you are running in a LocalScript.local player = Players.LocalPlayerassert(player,"This should be running in a LocalScript!")-- Setup Haptic Feedback Listenerlocal function updateHapticFeedback()-- Check if you currently have a character.local character = player.Characterif character then-- Do you have a Humanoid?local humanoid = character:FindFirstChildOfClass("Humanoid")if humanoid then-- Are you in a vehicle seat?local seatPart = humanoid.SeatPartif seatPart and seatPart:IsA("VehicleSeat") then-- Measure the current speed of the vehicle by taking the magnitude of the seat's velocity.local speed = seatPart.Velocity.Magnitude-- Measure the current throttle from the user.local throttle = math.abs(seatPart.ThrottleFloat)-- Compute how much the controller should be vibrating.local vibrationScale = math.min(1, (speed * throttle) / seatPart.MaxSpeed)-- Apply the vibration.HapticService:SetMotor(Enum.UserInputType.Gamepad1, Enum.VibrationMotor.Small, vibrationScale)-- Return so the motor doesn't get reset.returnendendend-- If nothing is happening, turn off the motor.HapticService:SetMotor(Enum.UserInputType.Gamepad1, Enum.VibrationMotor.Small, 0)end-- Connect the haptic feedback listener to be updated 60 times a second.RunService.Heartbeat:Connect(updateHapticFeedback)