Creating Mobile Buttons
Creating Mobile Buttons
Porting games from a PC environment to a mobile environment can be difficult, especially when it comes to input. A computer has a wealth of input from the keyboard to the mouse, whereas a mobile device, such as an iPad only has touch. One solution is to use the
ContextActionService. This service allows you to bind a function to traditional PC input and at the same time creates an on screen button only visible on a mobile device.
Additionally, mobile screen space is at a premium, and sometimes it is desirable for on screen buttons to only show when relevant. For example, let’s say your game has doors and there is a special player action to open a door. It doesn’t make sense to show an “Open Door” button all game long. Instead, the button should only show when the player is near a door, and should disappear when the player has moved a distance away. Even in a PC game, sometimes it makes sense for a certain key to perform an action under specific circumstances and not in others. ContextActionService allows for very quick and easy manipulation of when input is tied to functions, as well as when mobile action buttons are shown or not.
To use the ContextActionService first a reference has to be declared in a
LocalScript. This service will not work in a
Server Script as the server does not handle input from players.
local contextAction = Game:GetService("ContextActionService")
Adding Mobile Buttons (Bind)
After the ContextActionService has been declared, the
ContextActionService/BindAction function can be used. This function will associate specified input with the function that should be called when the input is entered. This function will also display a mobile button if desired. This function takes several parameters:
void ContextActionService:BindAction( string actionName, function functionToBind, bool createTouchButton, Tuple inputTypes )
This string is a key used by other functions in ContextActionService to manipulate the binding.
This is the function you want to be called when the specified input is triggered. This function can be defined earlier in the script or can be defined inline. This function will be called with three arguments: a string that is the actionName that is calling this function, a
Enum/UserInputState that defines the state the input was in when it called the function, and lastly the
InputObject that caused the call to the function.
This boolean indicates whether or not you want a button to be created when your game is running on a mobile device. If you are using this service just to bind input for PC controls, then you can set this to false. Otherwise this should be true if you want a button when your game is played on a mobile device.
This tuple contains all of the input you want to bind to the function. This tuple can contain values from
Enum/UserInputType, or simple strings corresponding to keys on a keyboard.
game:GetService("ContextActionService"):BindAction("OpenDoorBinding", openDoorFunc, true, "o")
Removing Mobile Buttons (Unbind)
When you no longer want input tied to a function, or if you want to remove an mobile button from the screen, use
ContextActionService/UnbindAction. This function takes a string as an argument which is the key defined in
ContextActionService/BindAction. You can also use
ContextActionService/UnbindAllActions to remove all functions that have been bound.
ContextActionService provides several functions to manipulate the buttons that are generated by binding functions. A button can use a custom image, much like an
ImageLabel by using
ContextActionService/SetImage and providing the name of the binding and the url of the image.
The button can also be positioned using
ContextActionService/SetPosition and providing the name of the binding and the
UDim2 where you want the button to be positioned. If you do not specify this the button will appear near the jump button on the right hand side of the screen.
In this game there is a teleport pad that can take a player to the destination when they step on it. In this case, we won’t actually teleport until the user presses a button. We could make a new GUI element for this button, but we only want the button to appear when the user is on the teleporter. Using ContextActionService, we can bind a teleport function to a button when the player is in the right spot which will show the button, and then unbind it when the player leaves which will remove the button. Note this button will only show up on mobile devices. To test on a PC or Mac we will also bind the “t” key on the keyboard to the action:
-- Make variables for the local player and ContextActionService local player = game.Players.LocalPlayer local ContextActionService = game:GetService("ContextActionService") -- Define teleport function which we will bind to a button function teleportPlayer(actionName, actionInputState, actionInputObject) player.Character.Torso.CFrame = game.Workspace.DestinationPad.CFrame + Vector3.new(0, 4, 0) -- Remove binding to hide button after teleport ContextActionService:UnbindAction("teleport") end -- Setup Touched and TouchEnded events. Also making a boolean to keep track of whether we have bound the function or not. local playerOnPad = false game.Workspace.TeleportBeam.Touched:connect(function(part) if part and part.Parent == player.Character then if not playerOnPad then ContextActionService:BindAction("teleport", teleportPlayer, true, "t") end playerOnPad = true end end) game.Workspace.TeleportBeam.TouchEnded:connect(function(part) if part and part.Parent == player.Character then if playerOnPad then ContextActionService:UnbindAction("teleport") end playerOnPad = false end end)
Working with Gamepads
ContextActionService also provides an easy way to support Gamepad context actions in your game. It works the same way as any input, so something like this:
--actionName will be a string that corresponds to the name the action was given (in this case "openDoor") --actionInputState will be the Enum.UserInputState that the input was in when this function was called --actionInputObject will be the inputObject that called this function local openDoorFunction = function(actionName, actionInputState, actionInputObject) if actionInputState == Enum.UserInputState.Begin and actionInputObject.UserInputType == Enum.UserInputType.Gamepad1 then doOpenDoorFunction() end end game:GetService("ContextActionService"):BindAction("openDoor", openDoorFunction, false, Enum.KeyCode.ButtonX)
Will make any time ButtonX is pressed or released call the function
openDoorFunction. It is important to note that this will be called for all gamepads, so you should check and make sure the gamepad calling it is the one you want.
Suppose I have code like this:
game:GetService("ContextActionService"):BindAction("openDoor", openDoorFunction, false, Enum.KeyCode.ButtonX) game:GetService("ContextActionService"):BindAction("changeTool, changeToolFunction, false, Enum.KeyCode.ButtonX)
What happens when I press ButtonX?
The changeToolFunction will be called, and the
openDoorFunction will NOT be called. This is because
changeToolFunction was bound last, so it takes precedence. If the
changeTool action was unbound later, then the
openDoor action will be called for ButtonX in the future.
What happens the moment I bind an input that is already bound?
The currently bound function is called, but with a special
Enum/UserInputState/Cancel. This is to allow the currently bound function to do any clean up it might want to do (Ex: you have
Enum/KeyCode/Thumbstick1 bound to controlling the character, but you bind a menu action to thumbstick1 over that action. The character movement function will receive a cancel event so it can stop the character if it is currently moving.) If the latter bound function unbinds itself later, the original bound function will be called with
Enum/UserInputState/End indicating that the original bound function can resume handling input.