Gamepad input

ROBLOX accepts input commands from USB gamepads such as the Xbox and Playstation controllers. A game can support up to 4 local controllers per client.

Detecting gamepad[edit]

You can detect whether a player's device currently has a gamepad active using the GamepadEnabled property. Note that this property merely shows whether or not any gamepads are connected, it does not specify how many are plugged in or which slots they are in.

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

Since up to four controllers can be connected to a client at once, it is important to know which gamepads are active. One way to do this is to listen to the GamepadConnected and GamepadDisconnected events. These events will fire when a device is enabled or disabled respectively, and both will pass an UserInputType enum to the connected function indicating which gamepad caused the event. In most cases the controller will be Enum.UserInputType.Gamepad1 but if your game supports local multiplayer then you will have to check.

local UIS = game:GetService("UserInputService")
 
UIS.GamepadConnected:connect(function(gamepad)
	print("Player has plugged in controller: " .. tostring(gamepad))
end)
 
UIS.GamepadDisconnected:connect(function(gamepad)
	print("Player has unplugged in controller: " .. tostring(gamepad))
end)

You can also actively query whether a particular controller is connected using the GetGamepadConnected function. This function takes an UserInputType enum as an argument and will only work with the values of Gamepad1 through Gamepad4.

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

Getting input[edit]

There are three ways to get input from a controller. A straightforward way is to listen for events in UserInputService. If you plan on allowing a variety of control schemes for various inputs you can use ContextActionService. Lastly, you can query the state of all of a controller's input with the GetGamepadState function.

UserInputService events[edit]

All of the buttons on a gamepad will fire the InputBegan and InputEnded events. The passed in InputObject will contain which controller fired the event in the UserInputType property. The specific button or stick that fired the event will be in the KeyCode property.

game:GetService("UserInputService").InputBegan:connect(function(input)
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		if input.KeyCode == Enum.KeyCode.ButtonA then
			character.Humanoid.Jump = true
		end
	end
end)

Some gamepads support analog controls. To get input from these controls, the InputChanged function can be used. Note that ROBLOX only supports analog thumbsticks and trigger buttons (L2 and R2). In the Changed event the position of the input's axis can be read in the Position. The thumbsticks position will always be on the X Y axes between the values of -1 to 1 for both axes. The trigger buttons will only have values between 0 and 1 on the Z axis: 0 at its starting position, 1 when fully depressed.

game:GetService("UserInputService").InputChanged:connect(function(input, processed)
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		if input.KeyCode == Enum.KeyCode.Thumbstick1 then
			character.Humanoid:Move(Vector3.new(input.Position.X, 0, -input.Position.Y), true)
		end
	end
end)

ContextActionService[edit]

You can bind functions to input from a gamepad using ContextActionService. This is particularly useful if you want to bind controls both to a gamepad and to other inputs (such as keyboard or touch controls). For example, suppose you want to bind a custom control to jump in your game. In this case, say the player can jump if either they press the A button on a gamepad or if they press the "F" key on their keyboard. ContextActionService can handle both cases in one function:

local function jumpFunction(actionName, state, inputObject)
	game.Players.LocalPlayer.Character.Humanoid.Jump = true
end
 
game:GetService("ContextActionService"):BindActionToInputTypes("Jump", jumpFunction, false, "f", Enum.KeyCode.ButtonA)

Keep in mind that ContextActionService bound functions will fire on all input events: Began, Changed, and Ended. In the bound function it is recommended to check the UserInputState so the desired action only happens on the state you intend it to:

local function printFunction(actionName, state, inputObject)
	if state == Enum.UserInputState.Begin then
		print("I only print on the begin event")
	end
	print("I print on every event!")
end
 
game:GetService("ContextActionService"):BindActionToInputTypes("Print", printFunction, false, "p", Enum.KeyCode.ButtonB)

Gamepad input state[edit]

The state of all the buttons and sticks on a gamepad can be gotten at any time with the GetGamepadState. This can be useful for events in your game when something happens to your player and you want to check to see if that player is holding down an input. For example, the following code will detect when a character's left leg touches something while the player is holding down the A button:

local player = game.Players.LocalPlayer
while not player.Character do wait() end
local character = player.Character
 
local userInputService = game:GetService("UserInputService")
 
character["Left Leg"].Touched:connect(function(hit)
	local state = userInputService:GetGamepadState(Enum.UserInputType.Gamepad1)
	for _, input in pairs(state) do
		if input.KeyCode == Enum.KeyCode.ButtonA and input.UserInputState == Enum.UserInputState.Begin then
			print("I stepped on something while holding A")
		end
	end
end)

Gamepad keycodes[edit]

Since ROBLOX supports a generic USB gamepad, many different types of controllers can be used. Not all controllers have the same number of inputs and so it is important to check which inputs a connected controller has. If your game relies on the left analog stick for control it is important to make sure the player's controller actually has one! You can check what inputs a given controller supports with the GetSupportedGamepadKeyCodes function. This function takes an UserInputType enum as an argument, expecting the values of Gamepad1 through Gamepad4. This function returns a table with a list of all the available inputs for the specified controller. Note that the Start and Select buttons are being used internally by roblox by default.

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

You can also check to see if a gamepad supports a specific button with the GamepadSupports function.

KeyCodeLayout.png

Example[edit]

This example binds character controls to the gamepad. The left thumbstick controls movement, the right thumbstick controls the camera, the A button makes the character jump, and R1 toggles increased runspeed.

-- Make variables for services
local userInputService = game:GetService("UserInputService")
local runService = game:GetService("RunService")
 
-- Make variables for player, character, and camera
local player = game.Players.LocalPlayer
while not player.Character do wait() end
local character = player.Character
local camera = game.Workspace.CurrentCamera
 
-- Update camera rotation every render frame
local currentAngle = 0
local deltaAngle = 0
runService.RenderStepped:connect(function()
	currentAngle = currentAngle + deltaAngle
	camera.CoordinateFrame = CFrame.new(character.Head.Position) 
										* CFrame.Angles(0, math.rad(currentAngle), 0)
										* CFrame.new(0, 0, 10)
end)
 
-- Check for change event in input. Used for thumbstick input as those are analog
userInputService.InputChanged:connect(function(input, processed)
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		-- Check left thumbstick and move character on change
		if input.KeyCode == Enum.KeyCode.Thumbstick1 then
			character.Humanoid:Move(Vector3.new(input.Position.X, 0, -input.Position.Y), true)
		end
		-- Check right thumbstick and change camera angle on change
		if input.KeyCode == Enum.KeyCode.Thumbstick2 then
			deltaAngle = input.Position.X * 5
		end
	end
end)
 
-- Check for user input ended events. Handles release of R1 and thumbsticks
userInputService.InputEnded:connect(function(input, processed)
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		-- Stop moving character if left thumbstick released
		if input.KeyCode == Enum.KeyCode.Thumbstick1 then
			character.Humanoid:Move(Vector3.new(0,0,0))
		end
		-- Stop moving camera if right thumbstick released
		if input.KeyCode == Enum.KeyCode.Thumbstick2 then
			deltaAngle = 0
		end
		-- Make character move at normal speed if R1 is released
		if input.KeyCode == Enum.KeyCode.ButtonR1 then
			character.Humanoid.WalkSpeed = 16
		end
	end
end)
 
-- Check for user input began events. Handles jumping and increasing speed
userInputService.InputBegan:connect(function(input, processed)
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		-- If A button is pressed then make the character jump
		if input.KeyCode == Enum.KeyCode.ButtonA then
			character.Humanoid.Jump = true
		end
		-- If R1 is pressed then make the character move faster
		if input.KeyCode == Enum.KeyCode.ButtonR1 then
			character.Humanoid.WalkSpeed = 30
		end
	end
end)

Default Controls[edit]

ROBLOX by default ships a control scheme for gamepads connected to computers, tablets and mobile devices so you can control the standard ROBLOX character and camera with a gamepad. In your game you can inspect this code by doing the following:

  1. Open a new or saved place in ROBLOX Studio
  2. Click Play Solo or press F5.
  3. In the Explorer, open StarterPlayer. Under StarterPlayer there should be two scripts, CameraScript and ControlScript. Here is what they look like with all the children scripts.
ControlAndCameraScripts.PNG


The default gamepad control script is found in StarterPlayerScripts.ControlScript.MasterControl.Gamepad. This is a good script to start with if you are interested in creating your own gamepad control scheme, or want to get ideas about ways to do gamepad controls. If you copy these scripts and press the Stop button in studio, you can paste them back into StarterPlayerScripts and override the default control schemes. Note: this script only does character movement, if you are interested in learning about camera movement look at StarterPlayerScripts.CameraScript.RootCamera.

Best Practices[edit]

As with any method of user input, it is best to have some consistencies across different games and applications. This ensures the user can immediately feel familiar and comfortable with your control scheme. Below are some suggested practices when implementing any gamepad controls.

  • If you implement any user prompts/GUI selection, pressing the A button should be the accept button
  • Any GUI or any state that is modal should be able to be cancelled by pressing the B button.
  • Hints on screen for what button does what are helpful, especially when using a complicated GUI (Ex: Inventory GUIs, Trade GUIs, Dialog Systems, etc.)
  • Character movement should be tied the left thumbstick.
  • Camera movement should be tied to the right thumbstick.
  • Primary actions usually happen with the right trigger (R2) or the A button
  • Secondary actions usually happen with the left trigger (L2) or the R1 and L1 buttons. If tying a secondary action to a face button, X button and Y buttons are good choices.
  • Left thumbstick and DPad should both be able to move the GUI selection around.
  • Allowing the user to remap buttons can make your game much more accessible.