Making a sprint system.. what am i doing wrong?

hi fellas
i am working on a game.

i really need to make a sprinting system or a stamina system in general. i was following along a person in an online platform who told me what they did and their practices, and i tried to follow to the best of my ability..

i cant do this. i cant take it anymore.

the sprint states are changed and stuff, but it doesnt matter for some reason.. it’s always 100 and it never drops..

-- // SERVICES
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

-- // DEPENDENCY
local RemoteEvents = ReplicatedStorage.RemoteEvents
local PlayerStaminaEvent = RemoteEvents:WaitForChild("StaminaAction", 7)

-- // MODULE
local StaminaModule = {}

StaminaModule.ActivePlayers = {}
StaminaModule.UpdateLoop = nil

-- // CONFIGURATION <<<
local LOOP_RATE = 1/10
local REGEN_RATE = 2 -- per loop
local DRAIN_RATE = 1.25 -- per loop

------------------------->>>


function StaminaModule.SetRunning(self, player, state)
	local data = self.ActivePlayers[player]
	if data then
		data.IsRunning = state
	end
end

function StaminaModule.GetStamina(self, player)
	local character = player.Character
	local humanoid = character:FindFirstChildOfClass("Humanoid") :: Humanoid
	return humanoid:GetAttribute("Stamina") or 0
end

function StaminaModule.SetMaxStamina(self, player, amount)
	local character = player.Character
	local humanoid = character:FindFirstChildOfClass("Humanoid") :: Humanoid
	humanoid:SetAttribute("MaxStamina", amount)
end

function StaminaModule.SetStamina(self, player, amount)
	local character = player.Character
	local humanoid = character:FindFirstChildOfClass("Humanoid") :: Humanoid
	humanoid:SetAttribute("Stamina", amount)
end

function StaminaModule.AdjustMaxStamina(self, player, amount)
	local character = player.Character
	local humanoid = character:FindFirstChildOfClass("Humanoid") :: Humanoid
	local maxStamina = humanoid:GetAttribute("MaxStamina")
	if maxStamina then
		humanoid:SetAttribute("MaxStamina", maxStamina + amount)
	end
end

function StaminaModule.AdjustStamina(self, player, amount)
	local character = player.Character
	local humanoid = character:FindFirstChildOfClass("Humanoid") :: Humanoid
	local maxStamina = humanoid:GetAttribute("MaxStamina")
	if maxStamina then
		humanoid:SetAttribute("Stamina", math.clamp(humanoid:GetAttribute("Stamina") + amount, 0, maxStamina))
	end
end

function StaminaModule.Initialize(self)
	if self.UpdateLoop then self.UpdateLoop:Disconnect() end
	
	StaminaModule.UpdateLoop = RunService.Heartbeat:Connect(function()
		for player, isRunning in next, self.ActivePlayers do
			local character = player.Character :: Model
			local humanoid = character and character:FindFirstChildOfClass("Humanoid")
			if not humanoid or humanoid.Health <= 0 then continue end
			if player:GetAttribute("Menu") == true then continue end
			
			if isRunning then
				self.AdjustStamina(self, player, -DRAIN_RATE)
			else
				self.AdjustStamina(self, player, REGEN_RATE)
			end
			print(player.Name, self.GetStamina(self, player))
		end
		task.wait(LOOP_RATE)
	end)
end

local function OnPlayerStaminaEvent(player, data)
	if typeof(data) == "table" and data.Action ~= nil then
		StaminaModule:SetRunning(player, data.Action)
	end
end

local function OnPlayerJoin(player: Player) StaminaModule.ActivePlayers[player] = false end
local function OnPlayerLeave(player: Player) StaminaModule.ActivePlayers[player] = nil end
Players.PlayerAdded:Connect(OnPlayerJoin)
Players.PlayerRemoving:Connect(OnPlayerLeave)
PlayerStaminaEvent.OnServerEvent:Connect(OnPlayerStaminaEvent)

return StaminaModule

and then here’s the clientside.

-- // SERVICES
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")

-- // DEPENDENCIES
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local Remotes = ReplicatedStorage.RemoteEvents
local StaminaEvent = Remotes.StaminaAction :: RemoteEvent

-- // CODE
local db = false

local function ResetDebounce()
	db = false
end

local function OnStartSprinting()
	if db then return end
	StaminaEvent:FireServer({
		Action = true
	})
end

local function OnStopSprinting()
	if db then return end
	db = true
	task.delay(0.7, ResetDebounce)
	StaminaEvent:FireServer({
		Action = false
	})
end

local function OnInput(InputObj: InputObject, GPE: boolean)
	if GPE then return end
	if InputObj.UserInputType == Enum.UserInputType.Keyboard then
		if InputObj.KeyCode == Enum.KeyCode.LeftShift then
			OnStartSprinting()
		elseif InputObj.KeyCode == Enum.KeyCode.RightShift then
			OnStartSprinting()
		end
	end
end

local function OnStopInput(InputObj: InputObject, GPE: boolean)
	if GPE then return end
	if InputObj.UserInputType == Enum.UserInputType.Keyboard then
		if InputObj.KeyCode == Enum.KeyCode.LeftShift then
			OnStopSprinting()
		elseif InputObj.KeyCode == Enum.KeyCode.RightShift then
			OnStopSprinting()
		end
	end
end

UserInputService.InputBegan:Connect(OnInput)
UserInputService.InputEnded:Connect(OnStopInput)

hell, have the character module too while you’re at it

-- // SERVICES
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local ServerStorage = game:GetService("ServerStorage")

-- // DEPENDENCIES
local assets = ServerStorage.Assets
local tools = assets.Tools

local spawns = {}
for _, child in pairs(workspace.Spawns:GetChildren()) do
	if child:IsA("BasePart") then
		table.insert(spawns, child)
	end
end

local RemoteEvents = ReplicatedStorage.RemoteEvents
local RemoteFunctions = ReplicatedStorage.RemoteFunctions
local ReplicatedModules = ReplicatedStorage.Modules

local mod1 = ReplicatedModules.CharacterDetails
local mod2 = script.Parent.CharacterDefs

local CharacterDetails = require(mod1)

local SelectionEvent = RemoteEvents:WaitForChild("Selection", 7)
local RetrieveInfo = RemoteFunctions:WaitForChild("RetrieveCharInfo", 7)

local CharacterManager = {}

function CharacterManager.Initialize()
	print("Initialized - Character!")
end

-- // Documentation or whatever
--[[
MaxHealth - The maximum amount of health the character can have.
MaxSanity - The maximum amount of sanity the character can have.
WalkSpeed - The character's walking speed.
SprintSpeed - The character's speed while sprinting.
DamageResistance - Damage multiplier.
HungerDecay - How fast the player goes hungry (per interval)
ThirstDecay - How fast the player goes thirsty (per interval)
HungerInterval - How often the player's hunger ticks down.
ThirstInterval - How often the player's thirst ticks down.

Tags - A list of tags to apply to the character.
StartingTools - A list of tool names to give the player when they spawn.
]]

CharacterManager.Characters = require(mod2)

local function TPPlayer(player: Player, character: Model)
	if #spawns == 0 then
		warn("No spawns found!")
		return
	end
	
	local chosenSpawn = player:GetAttribute("Spawn")
	
	local target
	for _, spwn in spawns do
		if spwn.Name == chosenSpawn and not spwn:IsA("Folder") then
			target = spwn
		end
	end
	
	if not target then
		target = spawns[math.random(1, #spawns)]
	end
	character:MoveTo(target.Position)
end

local function InitializeHumanoid(humanoid: Humanoid, characterData)
	if not humanoid then return end
	
	humanoid.WalkSpeed = characterData.WalkSpeed
	humanoid.MaxHealth = characterData.MaxHealth
	humanoid.Health = humanoid.MaxHealth
	
	local charStats = Instance.new("Configuration")
	charStats.Name = "Stats"
	charStats.Parent = humanoid
	
	for dataVar, value in pairs(characterData) do
		if typeof(value) ~= "table" and typeof(value) ~= "function" then			
			local propertyExists = pcall(function() return humanoid[dataVar] end)
			if propertyExists then
				humanoid[dataVar] = value
			else
				charStats:SetAttribute(dataVar, value)
			end
		end
	end
	if charStats:GetAttribute("MaxStamina") then
		humanoid:SetAttribute("MaxStamina", charStats:GetAttribute("MaxStamina"))
		humanoid:SetAttribute("Stamina", charStats:GetAttribute("MaxStamina"))
	end
	if charStats:GetAttribute("MaxSanity") then
		humanoid:SetAttribute("MaxSanity", charStats:GetAttribute("MaxSanity"))
		humanoid:SetAttribute("Sanity", charStats:GetAttribute("MaxSanity"))
	end
end

local function ApplyTags(character, characterData)
	local dataTags = characterData.Tags

	local existingTags = CollectionService:GetTags(character)
	for _, tag in existingTags do
		CollectionService:RemoveTag(character, tag)
	end

	if not dataTags then return end
	for _, tag in dataTags do
		CollectionService:AddTag(character, tag)
	end
end

local function GrantTools(player: Player, characterData)
	local dataTools = characterData.StartingTools
	if not dataTools then return end
	local backpack = player:WaitForChild("Backpack")

	for _, toolName in dataTools do
		if tools:FindFirstChild(toolName) then
			local tool = tools[toolName]:Clone()
			tool.Parent = backpack
		end
	end
end

local function GetRandomCharacterKey()
	if #CharacterManager.CharacterKeysCache == 0 then
		for name, _ in next, CharacterManager.Characters do
			table.insert(CharacterManager.CharacterKeysCache, name)
		end
	end

	return CharacterManager.CharacterKeysCache[math.random(1, #CharacterManager.CharacterKeysCache)]
end

function CharacterManager.LoadCharacter(self, player: Player)
	local character = player.Character or player.CharacterAdded:Wait()
	local humanoid = character:FindFirstChild("Humanoid") :: Humanoid
	local chosenChar = player:GetAttribute("Character")
	
	local charKey = (chosenChar and #chosenChar > 0) and chosenChar or GetRandomCharacterKey()
	local targetChar = self.Characters[charKey]

	GrantTools(player, targetChar)
	InitializeHumanoid(humanoid, targetChar)
	ApplyTags(character, targetChar)
	TPPlayer(player, character)
	player:SetAttribute("Character", charKey)
	
	if targetChar.OnSpawn then
		targetChar.OnSpawn(player, character)
	end
end

RetrieveInfo.OnServerInvoke = function(player, name: string)
	if name then
		local detailsGameplay = CharacterManager.Characters[name]
		local detailsInfo = CharacterDetails[name]
		local canUse, reason = detailsGameplay.Requirement(player)
		
		local package = {
			MaxHealth = detailsGameplay.MaxHealth,
			WalkSpeed = detailsGameplay.WalkSpeed,
			SprintSpeed = detailsGameplay.SprintSpeed,
			RegenRate = detailsGameplay.RegenRate,
			DamageResistance = detailsGameplay.DamageResistance,
			Title = detailsInfo.Title,
			Details = detailsInfo.Details,
			Icon = detailsInfo.Icon,
			RenderImage = detailsInfo.RenderImage,
			Owns = canUse,
			Reason = reason
		}
		return package
	else
		-- // Return everything
		local detailsInfo = CharacterDetails
		local package = {}
		for name, data in next, detailsInfo do
			local canUse, _ = CharacterManager.Characters[name].Requirement(player)
			package[name] = {
				Title = data.Title,
				Details = data.Details,
				Icon = data.Icon,
				Owns = canUse,
				LayoutOrder = data.LayoutOrder
			}
		end
		return package
	end
	
end

return CharacterManager

please im trying my hardest and im slowly starting to come to the conclusion that these things arent cut out for me

1 Like

Hey no need to give you hope. We all have these issues or “walls” we hit all the time. Don’t let this one wall stop you.

Did you make sure that event is properly receiving info?

1 Like

:rofl:

ServerScript
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

local PlayerStaminaEvent = ReplicatedStorage.RemoteEvents:WaitForChild("StaminaAction",7)
local StaminaModule = {ActivePlayers={},UpdateLoop=nil}
local LOOP_RATE=1/10
local REGEN_RATE=2
local DRAIN_RATE=1.25

function StaminaModule:SetRunning(player,state)
	local data=self.ActivePlayers[player]
	if data then data.IsRunning=state end
end

function StaminaModule:GetStamina(player)
	local hum=player.Character and player.Character:FindFirstChildOfClass("Humanoid")
	return hum and hum:GetAttribute("Stamina") or 0
end

function StaminaModule:SetMaxStamina(player,amt)
	local hum=player.Character and player.Character:FindFirstChildOfClass("Humanoid")
	if hum then hum:SetAttribute("MaxStamina",amt) end
end

function StaminaModule:SetStamina(player,amt)
	local hum=player.Character and player.Character:FindFirstChildOfClass("Humanoid")
	if hum then hum:SetAttribute("Stamina",amt) end
end

function StaminaModule:AdjustStamina(player,amt)
	local hum=player.Character and player.Character:FindFirstChildOfClass("Humanoid")
	if not hum then return end
	local max=hum:GetAttribute("MaxStamina") or 100
	hum:SetAttribute("Stamina",math.clamp((hum:GetAttribute("Stamina") or max)+amt,0,max))
end

function StaminaModule:Initialize()
	if self.UpdateLoop then self.UpdateLoop:Disconnect() end
	self.UpdateLoop=RunService.Heartbeat:Connect(function()
		for plr,data in next,self.ActivePlayers do
			local hum=plr.Character and plr.Character:FindFirstChildOfClass("Humanoid")
			if not hum or hum.Health<=0 then continue end
			if plr:GetAttribute("Menu")==true then continue end
			if data.IsRunning then
				self:AdjustStamina(plr,-DRAIN_RATE)
			else
				self:AdjustStamina(plr,REGEN_RATE)
			end
			print(plr.Name,hum:GetAttribute("Stamina"))
		end
		task.wait(LOOP_RATE)
	end)
end

local function OnPlayerStaminaEvent(plr,data)
	if typeof(data)=="table" and data.Action~=nil then
		StaminaModule:SetRunning(plr,data.Action)
	end
end

local function OnPlayerJoin(plr)
	StaminaModule.ActivePlayers[plr]={IsRunning=false}
	local hum=plr.Character or plr.CharacterAdded:Wait()
end

local function OnPlayerLeave(plr)
	StaminaModule.ActivePlayers[plr]=nil
end

Players.PlayerAdded:Connect(OnPlayerJoin)
Players.PlayerRemoving:Connect(OnPlayerLeave)
PlayerStaminaEvent.OnServerEvent:Connect(OnPlayerStaminaEvent)

return StaminaModule
1 Like

It does receive input, it’s just that nothing seems to update in the loop.

I’ve figured out the issue, it all comes down to trusting random people who think they’re Lua gods with their bytecode and what not. Simply, I did not initialize properly, because I used a dot instead of a colon, which is how my initializer ran the function.

Don’t trust Lua purists.

That’s pretty harsh. You think debugging your scripts is a challenge? Try doing it with someone else’s logic, sticking to their format, and only having part of the picture. I could have just rewritten the whole thing or handed you one of my 20 versions. You’re overcomplicating this anyway. You’re not even using

--!strict

There’s no reason to format it like

local function OnInput(InputObj: InputObject, GPE: boolean)

or to add local to a function that’s already local. You don’t even need

local Player = Players.LocalPlayer

because they’re local to the whole script already. The odd part of your rant is I don’t see anywhere a comma was used instead of a colon. Did we forget to use our ESP and actually read what you didn’t show us.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.