Creating a sprint button for mobile

I wanna know if this is the ‘cleanest’ way to go abouts this

local Sprinting = false

local function sprintFunction(actionName, inputState, inputObject)
	if inputState == Enum.UserInputState.Begin then
		if Sprinting then
			if not GamepassCheck(Player, 'Running Shoes') then return end
	
			if Humanoid.WalkSpeed == 0 then return end
	
			Humanoid.WalkSpeed = 16
			Sprinting = false
		else
			if not GamepassCheck(Player, 'Running Shoes') then return end
	
			if Humanoid.WalkSpeed == 0 then return end
			
			Humanoid.WalkSpeed = 24
			Sprinting = true
		end
	end
end

UserInputService.InputBegan:Connect(function(input)
    if input.KeyCode ~= Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.ButtonR2 then return end
	
	if not GamepassCheck(Player, 'Running Shoes') then return end
	
	if Humanoid.WalkSpeed == 0 then return end
	
	Humanoid.WalkSpeed = 24
end)

UserInputService.InputEnded:Connect(function(input)
    if input.KeyCode ~= Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.ButtonR2 then return end
	
	if not GamepassCheck(Player, 'Running Shoes') then return end
	
	if Humanoid.WalkSpeed == 0 then return end
	
	Humanoid.WalkSpeed = 16
end)
 
ContextActionService:BindAction("Sprint", sprintFunction, true, Enum.KeyCode.LeftShift, Enum.KeyCode.ButtonR2)

Basically, on pc and console, you hold down a key to sprint. Touch devices it’s you tap, sprinting is turned on, you tap again, it’s turned off (so they dont need to a hold a button down)

Also, is there a clean way to only create the touch button if they own the gamepass?

7 Likes

run a sanity check when a player joins to see if they have the gamepass, and have a non-visible GUI that contains the sprint button. If they have the gamepass, then enable the GUI and the sprinting script.

edit:

ALSO I wouldn’t recommend having the client dictate their own walkspeed. Try using remoteevents to change their walkspeed property through the server

1 Like

A post was moved out for being offtopic.

I’m not going to give you straight code for this, but here are some improvements:

  • Don’t manage the walkspeed on the Client, tie a RemoteEvent to it, e.g SprintRemote:FireServer
  • Don’t check for the gamepass when player has stopped running, because if they haven’t bought it the speed would stay the same
  • For mobile, at the start of the script you can just say
    if UserInputService.TouchEnabled then, so it determines if the user has an enabled touch screen, so it would show the UI if this is true
2 Likes

I don’t see how connecting it to the server will fix anything?

If I have a RemoteEvent, an exploiter could still fire the event and there’s nothing on the server I could do to check, except for check the gamepass, which I check on the client anyway.

cc @overflowed

1 Like

I managed to clean up your code a bit by simplifying some sections.

local Sprinting = false

local function sprintFunction(actionName, inputState, inputObject)
	if inputState == Enum.UserInputState.Begin then
        if not GamepassCheck(Player, 'Running Shoes') or Humanoid.WalkSpeed == 0 then 
            return 
         end
         
		Humanoid.WalkSpeed = Sprinting and 16 or 24
		Sprinting = not Sprinting
	end
end

UserInputService.InputBegan:Connect(function(inputObject, gameProcessed)
    if gameProcessed or not GamepassCheck(Player, 'Running Shoes') or Humanoid.WalkSpeed == 0 then 
        return 
    end

    if inputObject.KeyCode == Enum.KeyCode.LeftShift or inputObject.KeyCode == Enum.KeyCode.ButtonR2 then
        Humanoid.WalkSpeed = 24
        Sprinting = true
    end
end)

UserInputService.InputEnded:Connect(function(inputObject, gameProcessed)
    if gameProcessed or not GamepassCheck(Player, 'Running Shoes') or Humanoid.WalkSpeed == 0 then 
        return 
    end

    if inputObject.KeyCode == Enum.KeyCode.LeftShift or inputObject.KeyCode == Enum.KeyCode.ButtonR2 then
        Humanoid.WalkSpeed = 16
        Sprinting = false
    end
end)

local isMobile = UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled and not UserInputService.MouseEnabled and not UserInputService.GamepadEnabled and not GuiService:IsTenFootInterface()
if GamepassCheck(Player, 'Running Shoes') and isMobile then
    ContextActionService:BindAction("Sprint", sprintFunction, true, Enum.KeyCode.LeftShift, Enum.KeyCode.ButtonR2)
end

I added a check if the player owns the gamepass before binding the action, therefore they will only see the button if they own the gamepass. I redefined the sprinting variable on InputBegan and InputEnded as you had not done this before. Lastly, I used the second argument of InputBegan and InputEnded known as “gameProcessed” to make sure that the player was not holding left shift to capitalise a letter in chat or the like.

To make sure that the UserInputService functions do not overlap the ContextActionService ones, I added a check to see if the user is on a mobile device.

You may choose to remove your InputBegan and InputEnded functions entirely as they are not needed if you are already binding the action. Though if you do this, you will not required to hold down shift to run, you just need to click it for sprinting to be toggled as is on mobile.

6 Likes

Actually, what I meant is just to inform the server of what the client is doing, i.e. they pressed the sprint key. The server will then check for the gamepass instead of the client, and makes a decision based on whether they have the gamepass or not. You should never trust the client, as exploiters would just find a way to bypass the gamepass check.

Your code should look something like this (this probably won’t work though):
Client:

local function sprintFunction(actionName, inputState, inputObject)
if actionName = 'Touch' or inputState == Enum.UserInputState.Begin then
        game.ReplicatedStorage.SprintEvent:FireServer()
    end
end

ContextActionService:BindAction("Sprint", sprintFunction, true, Enum.KeyCode.LeftShift, Enum.KeyCode.ButtonR2)
if UserInputService.TouchEnabled and not GuiService:IsTenFootInterface then
    player.PlayerGui.ScreenGui.SprintButton.Touched:Connect(sprintFunction('Touch'))
end

Server:

local sprints = {} --setup table to store sprinting values
game.ReplicatedStorage.SprintEvent.OnServerEvent:Connect(function(player) --begin function when event fired
    if not GamepassCheck(Player, 'Running Shoes') or player.Character.Humanoid.WalkSpeed == 0 then
       return 
    end
   if not sprints[player] then --If it's not here then it'll be nil
       sprints[player] = true
       Humanoid.Walkspeed = 24
   else --player is evidently not sprinting
       sprints[player] = false
       Humanoid.Walkspeed = 16
   end
end)

This is just a semi-basic outline (using some of @RetributionVI’s code above) of what you should do to perform a server-side check of sprinting. Whenever you do pretty much anything, you should always have it done over the server, whether that be verifying a gamepass, trading, buying something out of a shop, equipping an item, etc.

I’m not going to draw this out too much, but in the future, the client shouldn’t handle any information that the server depends on, except input.

I also removed InputBegin and InputEnded, and users now have to toggle sprint (whether it be pressing the button or LeftShift).

2 Likes

Fair point. I normally run a check on the server using a RemoteFunction because the game I’m working on ATM has a stamina bar.

1 Like

Most sprint scripts change the FOV of the player to visualize the increase in speed. I suggest using Tweens to smooth that out.

1 Like

The use of the server to change the humanoid’s walk speed is not needed as the player already has network ownership over their character and all its descendants. If an exploiter wanted to be able to sprint without the gamepass, they could simply change their walk speed whether you have a server check or not.

It’s still good practice to do it on the server, amiright?

1 Like

Not really, no. Not unless you also intend to use the WalkSpeed number for velocity checks if the player is moving faster than the intended speed, though you sacrifice instantaneous transitions for the character as a result.

1 Like