Increasing a value without overwriting it

I wanted to make a system where i could Tween multiple values at once without breaking the game (FOV, WalkSpeed, etc)

local RunService = game:GetService("RunService")

local SpeedBoosts = Instance.new("Folder")
SpeedBoosts.Parent = Character
SpeedBoosts.Name = "SpeedBoosts"

local DefaultSpeed = Instance.new("NumberValue", SpeedBoosts)
DefaultSpeed.Value = 16

function GetSpeed()	
	local speed = 0
	
	for _, number in pairs(SpeedBoosts:GetChildren()) do
		if number:IsA("NumberValue") or number:IsA("IntValue") then
			speed += number.Value
		end
	end
	
	return speed
end

RunService.Heartbeat:Connect(function()
	Humanoid.WalkSpeed = GetSpeed()
end)

I’ve been using this but I’m wondering if there’s a better way to do this

If it works, it works. Buut, you can for sure do this without having to create an instance! You could use a table instead with numbers in it. I presume you’ve done the NumberValue method as it makes it convenient to add speed boost values from any other script that may effect it, e.g. a tool or pickup. In which case you could handle it with Event bindings.

local speedBoosts = {
	baseSpeed = 16,
}

function AddSpeedBoost(id, speed)
	speedBoosts[id] = speed
end
function RemoveSpeedBoost(id,)
	speedBoosts[id] = nil
end

-- If you want to add speed boost effects from other scripts, set up an Event binding!
-- For example:
Character.Events.AddSpeed.Event:Connect(AddSpeedBoost)
Character.Events.RemoveSpeed.Event:Connect(AddSpeedBoost)

function GetSpeed()
	local speed = 0
	for _, number in speedBoosts do
		speed += number
	end
	return speed
end
1 Like

I’ve Imagined a Speed Run 4 type system while reading through this. What you have here really serves as a strong foundation for stackable, temporary gameplay effects - each acting as an independent contributor to shared properties like WalkSpeed or FieldOfView.

To answer your earlier point about “increasing a value without overwriting it”, what we’re really talking about is changing state rather than resetting it entirely. The concept of mutating state rather than replacing it.

Player.Leaderstats.Coins.Value = 100

Here in this manner, You’ve just overwritten whatever their old value was. This is a complete reassignment - a total replacement. The previous value is lost.

But if what you mean to do is increase that number, carrying its state forward, then you need to read it first, and then build upon it:

Player.Leaderstats.Coins.Value = Player.Leaderstats.Coins.Value + 10

If you’re manipulating data often, like experience points or cash, a good practice is to encapsulate the increase logic into a function that ensures you can safely modify without overwriting.


In your original setup, you were running a function every single frame, even when nothing was changing. That’s not wrong, but it’s wasteful. Using signals instead lets you respond only when values actually update, which helps cut unnecessary work.

Switching to tables for storing modifier data instead of relying on NumberValue instances is another great move as ZacAttackk mentioned earlier. It reduces overhead (even if minimal) and makes your code more straightforward.

local Event = ReplicatedStorage:WaitForChild("Event")

local Modifiers = {
    Speed = { Base = 16 },
    Fov = { Base = 70 }
}

local function GetTotal(tbl)
	local total = 0
	for _, v in pairs(tbl) do
		if type(v) == "number" then
			total += v
		end
	end
	return total
end

local function Update()
	Humanoid.WalkSpeed = GetTotal(Modifiers.Speed)
	Camera.FieldOfView = GetTotal(Modifiers.Fov)
end

local function TweenModifier(TableRef, Key, StartValue, EndValue, Duration, EasingStyle, EasingDir)
	TableRef[Key] = StartValue
	Update()

	local TweenInfoObj = TweenInfo.new(
		Duration,
		EasingStyle or Enum.EasingStyle.Quad,
		EasingDir or Enum.EasingDirection.Out
	)

	local proxy = { Value = StartValue }
	local tween = TweenService:Create(proxy, TweenInfoObj, { Value = EndValue })

	tween:GetPropertyChangedSignal("Value"):Connect(function()
		TableRef[Key] = proxy.Value
		Update()
	end)

	return tween
end

local function ApplyBoost(SpeedIncrease, FovIncrease, Duration)
	local inTweenSpeed = TweenModifier(Modifiers.Speed, "Boost", 0, SpeedIncrease, 0.4)
	local inTweenFov = TweenModifier(Modifiers.Fov, "Boost", 0, FovIncrease, 0.4)

	local outTweenSpeed = TweenModifier(Modifiers.Speed, "Boost", SpeedIncrease, 0, 0.6, Enum.EasingStyle.Quad, Enum.EasingDirection.In)
	local outTweenFov = TweenModifier(Modifiers.Fov, "Boost", FovIncrease, 0, 0.6, Enum.EasingStyle.Quad, Enum.EasingDirection.In)

	inTweenSpeed:Play()
	inTweenFov:Play()
	task.wait(Duration)
	outTweenSpeed:Play()
	outTweenFov:Play()

	task.delay(Duration + 1.0, function()
		Modifiers.Speed["Boost"] = nil
		Modifiers.Fov["Boost"] = nil
		Update()
	end)
end

-- // Based on an event, we're applying that duration. 
Event.OnClientEvent:Connect(function(data)
	if typeof(data) == "table" then
		local speed = data.Speed or 0
		local fov = data.Fov or 0
		local duration = data.Duration or 2
		ApplyBoost(speed, fov, duration)
	end
end)

Update() -- Initialize

If I’ve understood your query properly, This might be of use.

2 Likes

use attributes.

something:SetAttribute() would work.

e.hg

val:SetAttribute("NewValue",val.Value+69) -- sigma
4 Likes