Mobile

Over half of all Roblox sessions are played on mobile devices so it is important to consider cross-platform accessibility when designing your experience for a wide audience. You should aim to create an ideal cross-platform experience that supports a variety of input devices, including mouse and keyboard inputs and gamepad.

When designing a mobile experience, consider the device orientation that you intend user's to use in your experience, then implement your inputs with ContextActionService to perform the following mobile-related input tasks:

Device Orientation

On phones and tablets, the device orientation majorly affects the user experience and interaction. For example, landscape mode is best operated with two thumbs while portrait mode may lend itself to one-finger interface.

By default, Roblox experiences run in landscape mode, allowing the experience to switch between landscape "left" and landscape "right" as the user's device rotates. However, experiences can be locked to a particular orientation if desired.

Orientation Modes

There are five different orientation modes, including two sensor-based modes and three locked modes.

Sensor Modes
Landscape Sensor The default Roblox setting in which the experience always appears in landscape mode (no portrait mode) and the device detects its physical orientation to ensure the experience view is always oriented upward.
Sensor The device detects its physical orientation to ensure the experience view is always oriented upward, switching between landscape and portrait mode as needed.
Locked Modes
Landscape Left On devices with a physical home button, the home button is to the left of the display. On devices with a virtual home/nav bar, its touch region is at the bottom of the display.
Landscape Right On devices with a physical home button, the home button is to the right of the display. On devices with a virtual home/nav bar, its touch region is at the bottom of the display.
Portrait On devices with a physical home button, the home button is below the display. On devices with a virtual home/nav bar, its touch region is at the bottom of the display.

Orientation Properties

When setting an orientation, you can set the Starting Orientation, the In-Experience Orientation, and the Current Orientation.

Starting Orientation

StarterGui.ScreenOrientation sets the default orientation for a place. Acceptable values include:

Because this property affects all new users who join the experience, you can set its value in StarterGuiScreenOrientation within Studio.

In-Experience Orientation

PlayerGui.ScreenOrientation explicitly changes the experience's orientation for a user. When this property is set to one of the ScreenOrientation enums in a LocalScript, the experience will immediately orient itself to match the setting. This can be useful when a experience needs to provide a particular experience like locking the view to portrait for a minigame.

The following code sample in a LocalScript sets the screen orientation to portrait:


1local Players = game:GetService("Players")
2local playerGUI = Players.LocalPlayer:WaitForChild("PlayerGui")
3
4wait(2)
5
6playerGUI.ScreenOrientation = Enum.ScreenOrientation.Portrait
7

Current Orientation

PlayerGui.CurrentScreenOrientation gets the current device orientation. Possible values include:

The following code prints the user's current screen orientation:


1local Players = game:GetService("Players")
2local playerGUI = Players.LocalPlayer:WaitForChild("PlayerGui")
3
4print(playerGUI.CurrentScreenOrientation)
5

Movement Modes

Roblox offers several StarterPlayer properties you can set to change how users on mobile devices can move through your experience.

You can set mobile movement control schemes for Roblox experiences by changing the values of StarterPlayer.DevTouchMovementMode to one of the following:

Option Description
ClickToMove Users can only move through the experience by tapping a target location. This mode includes a jump button in the lower-right region of the screen. Automatic jumping is always active in this movement mode.
DPad
DynamicThumbstick A dynamic thumbstick appears where the user initially presses down. This mode includes a jump button in the lower-right region of the screen. This is the default user setting for mobile users if UserChoice is set.
Scriptable Disables all default controls and allows you to script your own control scheme.
Thumbpad
Thumbstick A mobile thumbstick located in the lower-left region of the screen. Unlike DynamicThumbstick, the thumbstick position is static and doesn't change position when the user touches on the screen.
UserChoice Allows users to choose their desired control scheme from the in-experience Settings menu. This is the default movement mode for experiences.

Automatic Jumping

When StarterPlayer.AutoJumpEnabled is enabled, the user's character automatically jumps across gaps when approaching the edge of a platform. StarterPlayer.AutoJumpEnabled is enabled by default for mobile devices.

Disable StarterPlayer.AutoJumpEnabled to to disable this feature and force users to jump only using their key bindings.

Adding Mobile Buttons

To add mobile buttons, use the ContextActionService:BindAction() method.

The BindAction() method takes the following parameters:

Parameter Type Description
actionName string An identifier string for the action you are binding. You can use the actionName with other functions in ContextActionService to edit the binding.
functionToBind function The function to call when the specified input is triggered. This function receives three arguments:
  • A string equal to the actionName.
  • A UserInputState which defines the input state when it called the function.
  • The InputObject used in the function call.
createTouchButton boolean When true, creates an on-screen button when the game is running on a mobile device.
inputTypes tuple The inputs you intend to bind to the function, such as enum values from a KeyCode.

You can use the following code sample to create an Interact action that creates an on-screen button and also accepts a keyboard and gamepad input:


1local ContextActionService = experience:GetService("ContextActionService")
2
3local function handleAction(actionName, inputState, inputObject)
4 if inputState == Enum.UserInputState.Begin then
5 print(actionName, inputObject)
6 end
7end
8
9-- Bind action to function
10ContextActionService:BindAction("Interact", handleAction, true, Enum.KeyCode.T, Enum.KeyCode.ButtonR1)
11

Removing Mobile Buttons

To remove a mobile button from the screen, call UnbindAction() using the actionName string you passed to BindAction().

Use the following code sample to unbind the previously created Interact action:


1-- Unbind action by name
2ContextActionService:UnbindAction("Interact")
3

Customizing Button UI

You can use one of the several functions from ContextActionService to customize the on-screen buttons that are created by BindAction().

Button Text

To change the text label for a mobile button, call SetTitle() with the actionName string and a title:


1-- Set button label to "Talk"
2ContextActionService:SetTitle("Interact", "Talk")
3

Button Image

Mobile buttons can use custom images just like other GUI buttons using the SetImage() method.

Use the following sample code to set a button image, replacing the asset ID with an image of your choice:


1-- Set button image
2ContextActionService:SetImage("Interact", "rbxassetid://0123456789")
3

Button Position

By default, a new button's position appears near the lower right section of the screen. You should carefully consider button placement on mobile devices and keep in mind the positions of thumbs and hands.

Use the following sample code to set a button's position with the SetPosition() method:


1-- Set button position
2ContextActionService:SetPosition("Interact", UDim2.new(1, -70, 0, 10))
3

Context Dependent Inputs

When developing for mobile devices you may often want to change what a single button does based on the context. Since screen space on mobile devices limited, use contextual buttons that perform different actions based on what the character is able to do.

For example, you can display an active "Collect" button when the user is standing near a chest of gold:

Use the following code sample to create a mobile button that is labelled "Collect" and is bound to the function collectTreasure():


1local ContextActionService = game:GetService("ContextActionService")
2
3local function collectTreasure(actionName, inputState, inputObject)
4 if inputState == Enum.UserInputState.Begin then
5 print("Collect treasure")
6 end
7end
8
9ContextActionService:BindAction("Interact", collectTreasure, true, Enum.KeyCode.T, Enum.KeyCode.ButtonR1)
10ContextActionService:SetPosition("Interact", UDim2.new(1, -70, 0, 10))
11-- Set image to blue "Collect" button
12ContextActionService:SetImage("Interact", "rbxassetid://0123456789")
13

At another point in the game, you can change the button to "Talk" when the user is standing near an NPC. Instead of adding and removing the existing button, you can simply use ContextActionService:BindAction() on the existing Interact action, changing the function and button image.

Use the following code sample to set the existing button label to "Talk" and bind it to a function named talkToNPC():


1ContextActionService:BindAction("Interact", talkToNPC, true, Enum.KeyCode.T, Enum.KeyCode.ButtonR1)
2-- Set image to yellow "Talk" button
3ContextActionService:SetImage("Interact", "rbxassetid://0011223344")
4
5

Detecting Other Devices

In cross-platform experiences, it is necessary to know the user's current device in order to adjust the UI and display correct key binding prompts.

For example, if a user approaches a treasure chest and there's an action bound to collecting the gold, you can show mobile user's an on-screen "Collect" button and desktop users an on-screen "T" key icon.

Keep in mind that a mobile device can also have a mouse and keyboard or gamepad plugged in. It is also possible that a desktop has a touchscreen enabled. It is important to reference the user's preferred input options by displaying input options for the actively used device.

PC
Mobile

In these cases, you can use UserInputService to detect which input devices are enabled. If multiple input devices are enabled, use UserInputService:GetLastInputType() to get the user's last used input device to display on the UI.

You can use the following ModuleScript, placed within ReplicatedStorage and renamed to UserInputModule, to fetch the user's input type, after which you can adapt the UI layout or context to your experience's specific needs.

Use the following ModuleScript to check for enabled input devices and the last used input device:


1local UserInputService = game:GetService("UserInputService")
2
3local UserInput = {}
4
5local inputTypeString
6-- If device has active keyboard and mouse, assume those inputs
7if UserInputService.KeyboardEnabled and UserInputService.MouseEnabled then
8 inputTypeString = "Keyboard/Mouse"
9-- Else if device has touch capability but no keyboard and mouse, assume touch input
10elseif UserInputService.TouchEnabled then
11 inputTypeString = "Touch"
12-- Else if device has an active gamepad, assume gamepad input
13elseif UserInputService.GamepadEnabled then
14 inputTypeString = "Gamepad"
15end
16
17function UserInput.getInputType()
18 local lastInputEnum = UserInputService:GetLastInputType()
19
20 if lastInputEnum == Enum.UserInputType.Keyboard or string.find(tostring(lastInputEnum.Name), "MouseButton") or lastInputEnum == Enum.UserInputType.MouseWheel then
21 inputTypeString = "Keyboard/Mouse"
22 elseif lastInputEnum == Enum.UserInputType.Touch then
23 inputTypeString = "Touch"
24 elseif string.find(tostring(lastInputEnum.Name), "Gamepad") then
25 inputTypeString = "Gamepad"
26 end
27 return inputTypeString, lastInputEnum
28end
29
30return UserInput
31

Once the UserInputModule script is in place, use the following code sample in a LocalScript to get the user's last input type:


1local ReplicatedStorage = game:GetService("ReplicatedStorage")
2
3-- Require module
4local UserInputModule = require(ReplicatedStorage:WaitForChild("UserInputModule"))
5
6local currentUserInput, inputEnum = UserInputModule.getInputType()
7print(currentUserInput, inputEnum)
8