I followed a tutorial online on how to do a basic sprinting system. It works fine, but after working with it for a few months there are things that kind of annoy me.
Here’s how it works:
The client picks up any user input and detects whether or not the shift key has been pressed. If it has been pressed, it would fire a remote event to the server.
In the server, it would make adjustments to the character’s walk speed and inserts them in an array. The stamina initialization and regeneration are also handled in the server. (that was a mouthful sorry about that)
There are two things I’m not satisfied with:
-
I’ve added sprinting animations to the client and work okay. However, the player’s sprinting animation won’t stop playing even when they returned to normal walk speed. I’ve tried checking the walk speed with no luck.
-
Sometimes pressing the shift key won’t even speed me up, but it’ll still play my sprinting animations.
I want my system to stay mostly server sided so people won’t try to hack the values of how fast the character goes. The stamina variable is also created and set on the server as well.
I also want to move away from the base code of the tutorial because it seems like there are small flaws in it that can not be fixed.
You can try out the code on the video embedded earlier in the post. The code snippets below are mostly from the original code, but I have added a few more variables overtime for the game that is not shown below. Feedback is greatly appreciated!
(assume all variables are declared)
Server
-- [[ Configureable ]] --
local MAX_STAMINA = 100
local STAMINA_REGEN = 0.1
local SPRINT_MODIFIER = 1.6
local SPRINT_STAMINA_COST = 0.4
local sprintingPlayers = {}
Players.PlayerAdded:Connect(function(player)
local playerStats = player:WaitForChild("PlayerStats")
local stamina = playerStats:WaitForChild("Stamina")
stamina.Value = MAX_STAMINA
-- Will update the stamina gui locally
stamina.Changed:Connect(function(property)
UpdateStamina:FireClient(player, stamina.Value, MAX_STAMINA)
end)
end)
-- Detects when sprint key is pressed or released
Sprint.OnServerEvent:Connect(function(player, state)
local localCharacter = player.Character or player.CharacterAdded:wait()
local localHumanoid = localCharacter:WaitForChild("Humanoid")
-- Checks if the player can sprint
if state == "Began" and localHumanoid:GetState() == Enum.HumanoidStateType.RunningNoPhysics and localHumanoid.MoveDirection.Magnitude > 0 then
sprintingPlayers[player.Name] = localHumanoid.WalkSpeed
localHumanoid.WalkSpeed = localHumanoid.WalkSpeed * SPRINT_MODIFIER
elseif state == "Ended" and sprintingPlayers[player.Name] then
localHumanoid.WalkSpeed = sprintingPlayers[player.Name]
sprintingPlayers[player.Name] = nil
end
end)
-- Updates stamina value
RunService.Heartbeat:Connect(function()
for _,player in pairs(Players:GetChildren()) do
local localCharacter = player.Character or player.CharacterAdded:wait()
local localHumanoid = localCharacter:WaitForChild("Humanoid")
-- Changes stamina value when player is not sprinting
if not sprintingPlayers[name] then
if stamina.Value > MAX_STAMINA then
stamina.Value = MAX_STAMINA
elseif stamina.Value < MAX_STAMINA then
stamina.Value += STAMINA_REGEN
end
else
-- Changes stamina value when player is sprinting
if stamina.Value >= SPRINT_STAMINA_COST then
stamina.Value -= SPRINT_STAMINA_COST
else
player.Character.Humanoid.WalkSpeed = sprintingPlayers[name]
sprintingPlayers[name] = nil
end
end
end
end)
Client
-- Detects when shift key or space key is pressed
UserInputService.InputBegan:Connect(function(input,GDE)
if GDE then return end
if input.KeyCode == Enum.KeyCode.LeftShift then
Sprint:FireServer("Began")
if localHumanoid:GetState() == Enum.HumanoidStateType.RunningNoPhysics and localHumanoid.MoveDirection.Magnitude > 0 then
while camera.FieldOfView <= sprintingFOV do
camera.FieldOfView += 1
wait()
end
runningAnimTrack:Play()
end
end
end)
-- Detects when shift key is released
UserInputService.InputEnded:Connect(function(input)
if input.KeyCode == Enum.KeyCode.LeftShift then
Sprint:FireServer("Ended")
runningAnimTrack:Stop()
while camera.FieldOfView >= defaultFOV do
camera.FieldOfView -= 2
wait()
end
end
end)
-- Updates stamina gui locally
UpdateStamina.OnClientEvent:Connect(function(stamina, maxStamina)
staminaBar.Size = UDim2.new((stamina / maxStamina) * staminaBarScaleX, 0, staminaBarScaleY, 0)
end)