I am tired of creating listeners for the User Input service over and over again, it makes a huge mess! Here is the best way I have figured out to handle all user inputs from PC, Mobile, and Console.
The goal of this method is to prevent the need for duplicate code that listens for specific user inputs, and centralize all the input listeners into one reliable script.
Step 1:
Make a list of all the controls for your game.
Example:
Attack
(Button A on Console)
(X Key on PC)
(Touchscreen button on Mobile)
Block
(Button B on Console)
(C Key on PC)
(Touchscreen button on Mobile)
Step 2:
Create a LocalScript under StarterCharacterScripts. Create a Bindable Event under the script for each control action you have listed.
Step 3:
Listen for events in the PlayerController script.
Example -
-- 📜 This script is the entry point for any/all controller inputs.
-- The events that are children of this script will be fired and other scripts can listen for controller inputs.
local PlayerController = script
-- 📜
-- ⚡ Events (client)
local evt_Attack = script:WaitForChild("Attack")
local evt_Block = script:WaitForChild("Block")
-- ⚡
-- ⚙️ Services
local UserInputService = game:GetService("UserInputService")
-- ⚙️
-- This is a GUI that contains buttons to be used for mobile controls
local MobileActionGui = game:GetService("Players").LocalPlayer:WaitForChild("PlayerGui"):WaitForChild("MobileActionGui")
-- Enable this GUI if we are on Mobile
MobileActionGui.Enabled = UserInputService.TouchEnabled
-- 📱 Mobile Controls
local MobileAttackButton = MobileActionGui:WaitForChild("AttackButton")
local MobileBlockButton = MobileActionGui:WaitForChild("BlockButton")
-- When the button is activated, call the attack/block event
MobileAttackButton.Activated:Connect(function()
evt_Attack:Fire()
end)
MobileBlockButton.Activated:Connect(function()
evt_Block:Fire()
end)
-- 📱
-- ⌨️ Keyboard Controls
local function onKeyboardInputBegan(input)
if input.KeyCode == Enum.KeyCode.X then
evt_Attack:Fire()
elseif input.KeyCode == Enum.KeyCode.C then
evt_Block:Fire()
end
end
UserInputService.InputBegan:Connect(onKeyboardInputBegan)
-- ⌨️
-- 🎮 Console Controls
local function onControllerInputBegan(input)
if input.KeyCode == Enum.KeyCode.ButtonR2 then
evt_Attack:Fire()
elseif input.KeyCode == Enum.KeyCode.ButtonL2 then
evt_Block:Fire()
end
end
UserInputService.InputBegan:Connect(onControllerInputBegan)
-- 🎮
Step 4:
In your other (client side) scripts where you normally listen for controller inputs, instead listen for the Bindable Events being fired.
Example usage -
-- Event listeners
local character = Players.LocalPlayer.Character or Players.LocalPlayer.CharacterAdded:Wait()
local PlayerController = character:WaitForChild("PlayerController")
local evt_Attack = PlayerController:WaitForChild("Attack")
local evt_Block = PlayerController:WaitForChild("Block")
evt_Attack.Event:Connect(function()
print("Attack")
end)
evt_Block.Event:Connect(function()
print("Block")
end)