Hello! I’ve noticed many posts around the forum where people are looking to detect when a mobile player is moving with their joystick and some have mentioned using the PlayerControls module, which is risky because it’s subject to change anytime, and it’s not the best way to achieve this. I was answering a post here and it seems like not a lot of people know this method of detecting joystick movement based off of some replies, so I wanted to write a tutorial on how to do this and explain each step.
Here are some of the problems I hope to address with this tutorial:
Problems
UserInputService Detection For Mobile Controls
Detecting Character Movement On Mobile Controls
Mobile movement-button detection
First, let’s go over what events we could use out of the vast methods available through UserInputService for touch.
I would say, for detecting joystick movement we would need TouchMoved (and TouchStarted/TouchEnded which is optional) since it makes the most sense in our case.
How does this work? Well, when the player touches the screen and moves their finger around, it will fire the event. How will this be useful to us? Well, now we can detect if the player is dragging their finger on the screen, which is the functionality of the joystick!
Let’s set up our code before we get into the nitty-gritty of things. First, we need to declare UserInputService which is the service we are using to detect player input.
local userInputService = game:GetService('UserInputService')
Now let’s add an event for TouchMoved so anything inside of the function will run whenever the player drags their screen. The first parameter input
is the input that the player has done based on the event. In this case, it’s going to return unknown if you try to print out input.KeyCode
because there isn’t really a KeyCode for touch movement, but we will have it there anyways. The second parameter, gameProcessed
tells if you if the player is clicking on the screen through a button or some sort. None of these are necessary in our situation because we are looking for joystick movement and clicking or dragging on a separate button or UI object will not fire the code. I will leave the parameters there just for reference and for the sake of the tutorial.
local userInputService = game:GetService('UserInputService')
userInputService.TouchMoved:Connect(function(input, gameProcessed)
-- the code in here will run whenever the player moves their finger on the screen!
end)
Now there seems to be a problem here. What happens if the mobile user drags their finger to move the camera around? This will fire when that happens so we need to find a way to detect if the player is actually using the joystick to move. There seems to be a property known as MoveDirection which allows you to tell if the player is moving or not. First before we get into anything, let’s add some variables for the player and the character so we can actually use it because it is the property of the player’s Humanoid and we need a way to access it.
local userInputService = game:GetService('UserInputService')
local player = game:GetService('Players').LocalPlayer -- gets the player
local character = player.Character -- gets the player's actual character model
local humanoid = character:WaitForChild('Humanoid') -- gets the humanoid from the character
userInputService.TouchMoved:Connect(function(input, gameProcessed)
-- the code in here will run whenever the player moves their finger on the screen!
end)
Alright sweet! Now let’s use the MoveDirection property of the humanoid to see if the player is moving or not! MoveDirection is a Vector3 value (X, Y, Z) which is set to (0, 0, 0) when the player is not moving and when the player is moving, it is set to the Vector3 value of the direction they are moving in. How can we use this to figure out of the player is moving or not? Well if we check if the MoveDirection is not (0, 0, 0) which means that they are NOT moving, we can get the function to fire only when the player is moving their finger on the screen while moving. When does this only happen? When the player uses their joystick!
(This gif is from the MoveDirection reference page)
Also, (0, 0, 0) is the same as checking if it is Vector3.new() which is automatically set to (0, 0, 0) if you don’t put anything inside the parenthesis.
local userInputService = game:GetService('UserInputService')
local player = game:GetService('Players').LocalPlayer -- gets the player
local character = player.Character -- gets the player's actual character model
local humanoid = character:WaitForChild('Humanoid') -- gets the humanoid from the character
userInputService.TouchMoved:Connect(function(input, gameProcessed)
if humanoid.MoveDirection ~= Vector3.new() then -- if they are moving then
print('Moved!')
end
end)
Yay! Now it will print ‘Moved’ when the player is dragging their finger on the screen and moving their character which only happens when they are using their joystick! This is what we wanted!
Now, if you go back and scroll up and open up the > Problems that I was hoping to address, the last one wants to find a way to tell whether the player is going UP with the joystick and I wanted to show a simple way to detect that!
We need to do some simple math, involving Delta and Position, where delta is the change in the movement of the thumbstick and position is the position of the player’s finger relative to the screen (e.g top left corner would be around 0, 0). Feel free to read more about it on the reference page.
Let’s find the old position by subtracting the position by the delta. Also remember that we are using the first parameter now since we need it to find both the Position and the Delta which is given to us through the event! How neat! So since delta is the change in position and Position is the new position, we can subtract the change from the new position to find the old position. Please check out the wiki article that I’m using this from to learn more about it here.
local oldPosition = (input.Position - input.Delta)
Alright, now we have the oldPosition, so what do we do now? Well if you add that inside of the code we did earlier and print it doing print(oldPosition)
you will see that as you drag the joystick up, it seems to make the Y value smaller and smaller so we can use that to determine which direction the player is dragging the joystick.
We need to see if the new Y position of the joystick is less than the old Y position of the joystick and if it is then that means that the player is moving the joystick up! Let’s say that the Y position of the new joystick is at Y = 50, and the old position was at Y = 60, that means that if 50 < 60 then it will run and that makes sense because as the joystick goes up, the Y gets smaller.
local oldPosition = (input.Position - input.Delta)
if input.Position.Y < oldPosition.Y then
print('Up!')
end
Now let’s just add this back to our other code and it should work well. You should also be able to use this to detect other movements such as backwards or left and right.
local userInputService = game:GetService('UserInputService')
local player = game:GetService('Players').LocalPlayer -- gets the player
local character = player.Character -- gets the player's actual character model
local humanoid = character:WaitForChild('Humanoid') -- gets the humanoid from the character
userInputService.TouchMoved:Connect(function(input, gameProcessed)
if humanoid.MoveDirection ~= Vector3.new() then -- if they are moving then
print('Moved!')
local oldPosition = (input.Position - input.Delta)
if input.Position.Y < oldPosition.Y then
print('Moving up with joystick!')
end
end
end)
Thank you for your time and I hope you learn something or can benefit from this as I did! I was just answering someone’s post and actually learned something from trying to answer his question, so I hope this can benefit everyone and solve the huge problems everyone faced from trying to do this! Let me know if you have any questions and I would love to clarify!