Hi everyone! I’m trying to make a hunger system where your hunger decreases every few seconds and you can increase it by eating food, and if it hits 0, you die.
The problem is it’s glitching out a lot and sometimes it goes over 100 and below 0. There were minor things like this happening before so I tried using math.clamp and made a new function to increase and decrease the hunger and now almost every single time it goes over 100 and below 0. The code feels like a mess now and I don’t know what’s causing it. Another issue is after the hunger decreases by the right amount one time (5), it starts decreasing by double the amount.
I’m trying to solve everything myself right now but it would be great if anyone has any tips or ways I can make the code better or if anyone knows the issue. I’m new to math.clamp
so if anyone knows how to fix this it would be amazing!!
Here is a video of the issue: Streamable
This is the entire code for the project:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")
local Remotes = ReplicatedStorage:WaitForChild("Events")
local MainEvent = Remotes:WaitForChild("Eat")
-- HUNGER
local MAX_HUNGER = 100
local MIN_HUNGER = 1
local STARTING_VALUE = MAX_HUNGER
local DECREASE_AMOUNT = 5
local DECREASE_TIME = 2
local START_DECREASE_TIME = DECREASE_TIME * 2
local HUNGRY_AMOUNT = 50
-- SATURATION
local MAX_SATURATION = 100
local SATURATION_STARTING_VALUE = 0
local SATURATION_DECREASE_AMOUNT = 4
local MIN_SATURATION = 0
local SATURATION_DECREASE_TIME = DECREASE_TIME / 4
-- STARVE
local STARVE_INTERVAL = 0.5
local STARVE_DAMAGE = 10
-- EFFECTS
local DEFAULT_SPEED = 16
local SOUR_SPEED = 20
local SOUR_INTERVAL = 5
local EAT_INTERVAL = 3
--
local DEBOUNCE = false
--
local Foods = {
["Carrot"] = {["Sour"] = false, ["HungerIncrement"] = 35, ["Saturate"] = 20},
["Apple"] = {["Sour"] = true, ["HungerIncrement"] = 30, ["Saturate"] = 35},
["Lemon"] = {["Sour"] = true, ["HungerIncrement"] = 10, ["Saturate"] = 10},
["Orange"] = {["Sour"] = true, ["HungerIncrement"] = 40, ["Saturate"] = 30}
}
local Drinks = {
["Soda"] = {["Sweet"] = true, ["SpeedIncrement"] = 5},
["Lemonade"] = {["Sweet"] = false, ["SpeedIncrement"] = 3},
["Orange Juice"] = {["Sweet"] = true, ["SpeedIncrement"] = 4},
}
--
local Saturated = true
local State = nil
function RBX_ASSET_ID(number)
if number then
number = tostring(number)
return "rbxassetid://".. number
end
return false
end
-- Function to change/set hunger/saturation by number
function Change(object, amount, method)
if tonumber(method) == 1 then
object.Value += tonumber(amount)
elseif tonumber(method) == 2 then object.Value -= tonumber(amount) elseif not method or tonumber(method) == 3 then object.Value = tonumber(amount) end
return object.Value
end
-- Create hunger and playerData for a new player, called when a player joins the servrer
function new(Player)
-- Check if there is a player data folder, if not, create one
local PlayerData = nil
if not Player:FindFirstChild("playerData") then
PlayerData = Instance.new("Folder")
PlayerData.Name = "playerData"
PlayerData.Parent = Player
else PlayerData = Player:WaitForChild("playerData") end
-- Create the hunger value
local Hunger = Instance.new("IntValue")
Hunger.Name = "Hunger"
Hunger.Value = STARTING_VALUE
Hunger.Parent = PlayerData
-- Create the saturation value
local Saturation = Instance.new("IntValue")
Saturation.Name = "Saturation"
Saturation.Value = SATURATION_STARTING_VALUE
Saturation.Parent = PlayerData
-- Set attributes function so variables can be accessed by other scripts, it is a function so it can be called multiple times
local function setAttributes(HUMANOID)
if HUMANOID then
HUMANOID:SetAttribute("MaxHunger", MAX_HUNGER)
HUMANOID:SetAttribute("MinHunger", MIN_HUNGER)
end
end
-- Hunger/saturation decrease
Player.CharacterAdded:Connect(function(Character)
local Humanoid = Character:WaitForChild("Humanoid")
-- Call set attributes each time the character gets added
setAttributes(Humanoid)
task.wait(START_DECREASE_TIME) -- Wait the start decrease time amount before the players hunger starts decreasing
while task.wait() do
-- HUNGER (Uses two if statements to check if saturated to make the code look less messy)
if not Saturated then
if (Hunger.Value >= MIN_HUNGER) and not (Change(Hunger, DECREASE_AMOUNT, 2) <= MIN_HUNGER) then
-- DECREASE
task.wait(DECREASE_TIME)
Change(Hunger, DECREASE_AMOUNT, 2)
Hunger.Value = math.clamp(Hunger.Value, MIN_HUNGER, MAX_HUNGER)
if Hunger.Value <= HUNGRY_AMOUNT then
State = "Hungry"
end
else
-- STARVING
task.wait(STARVE_INTERVAL)
Change(Hunger, MIN_HUNGER)
Hunger.Value = math.clamp(Hunger.Value, MIN_HUNGER, MAX_HUNGER)
if Humanoid then
Humanoid:TakeDamage(STARVE_DAMAGE)
end
State = "Starving"
end
end
-- SATURATION
if Saturated then
if (Saturation.Value >= MIN_SATURATION) and not (Change(Saturation, SATURATION_DECREASE_AMOUNT, 2) <= MIN_SATURATION) then
task.wait(SATURATION_DECREASE_TIME)
Change(Saturation, SATURATION_DECREASE_AMOUNT, 2)
Saturation.Value = math.clamp(Saturation.Value, MIN_SATURATION, MAX_SATURATION)
else Saturation.Value = 0 Saturated = false end
if (Change(Saturation, SATURATION_DECREASE_AMOUNT, 2) == MIN_SATURATION) then
task.wait(SATURATION_DECREASE_TIME)
Change(Saturation, MIN_SATURATION)
Saturation.Value = math.clamp(Saturation.Value, MIN_SATURATION, MAX_SATURATION)
end
end
Humanoid.Died:Connect(function()
Change(Hunger, MAX_HUNGER, 3)
Change(Saturation, MAX_SATURATION, 3)
end)
end
end)
end
Players.PlayerAdded:Connect(new)
function Activated(Player, Name, FoodInstance)
-- Define the players character
local Character = Player.Character
if not Character or not Character.Parent then
Character = Player.CharacterAdded:Wait()
end
local Humanoid = Character:WaitForChild("Humanoid")
-- Food
if Foods[Name.Value] then
local Food = Foods[Name.Value]
local PlayerData = Player:FindFirstChild("playerData")
local Hunger = PlayerData:FindFirstChild("Hunger")
local Saturation = PlayerData:FindFirstChild("Saturation")
if PlayerData and Hunger and not DEBOUNCE then
DEBOUNCE = true
-- Eating animation
if FoodInstance then
local Animator = Humanoid:WaitForChild("Animator")
local EatAnimation = Instance.new("Animation")
EatAnimation.AnimationId = RBX_ASSET_ID(9039489111)
local EatAnimationTrack = Animator:LoadAnimation(EatAnimation)
EatAnimationTrack:Play()
Debris:AddItem(FoodInstance, 3)
task.wait(EAT_INTERVAL) DEBOUNCE = false
end
-- Increase hunger
if not (Change(Hunger, Food["HungerIncrement"], 1) >= MAX_HUNGER) then
Change(Hunger, Food["HungerIncrement"], 1)
Hunger.Value = math.clamp(Hunger.Value, MIN_HUNGER, MAX_HUNGER)
else Hunger.Value = MAX_HUNGER State = "Full" end
-- Increase saturation
if Food["Saturate"] then
Saturated = true
if not (Change(Hunger, Food["Saturate"], 1) >= MAX_SATURATION)then
Change(Hunger, Food["Saturate"], 1)
Saturation.Value = math.clamp(Saturation.Value, MIN_SATURATION, MAX_SATURATION)
else Saturation.Value = MAX_SATURATION end
end
-- Check if the food is sour
if Food["Sour"] then
if Humanoid.WalkSpeed == SOUR_SPEED then repeat task.wait() until Humanoid.WalkSpeed ~= SOUR_SPEED end
Humanoid.WalkSpeed = SOUR_SPEED
task.wait(SOUR_INTERVAL)
Humanoid.WalkSpeed = DEFAULT_SPEED
end
end
end
-- Drink
if Drinks[Name.Value] then
local Drink = Drinks[Name.Value]
end
end
MainEvent.OnServerEvent:Connect(Activated)
Any help is appreciated!! If anyone knows even the smallest way I can make the code better or if you want more information, please tell me. Thank you so much!!