Dino Survival Game - Hunger not increasing

Developing my own game, and I’m fairly new to scripting.

Most things in my game are working well, but I’m having difficulty with Food.

My game is designed for a player to click on a plant and their hunger should increase.
When I run my script, absolutely nothing happens with hunger - it doesn’t increase and I don’t get any errors, etc.

Here is the code, any help is appreciated.
Thanks in advance!

CODE:

local foodClicked = game.ReplicatedStorage:WaitForChild("FoodClicked")
local eaten = false
local clickdetector = script.Parent.ClickDetector


function FoodClicked(Player, full)
	if eaten == false then
		if full == false then
			foodClicked:FireClient(Player)
			clickdetector.MaxActivationDistance = 0
			script.Parent.Transparency = 1
			eaten = true
			print("FOOD CLICKED")
			wait(2)
			script.Parent.Transparency = 0
			clickdetector.MaxActivationDistance = 10
			eaten = false
		end
	end
end

script.Parent.ClickDetector.MouseClick:Connect(FoodClicked)

the MouseClick signal does not have a second parameter to pass to a function that is connected to it.

In your FoodClicked function you expect a second parameter full to be passed, which does not exist.

You will have to reference the fullness of a player a diferent way, such as an ObjectValue inside their player.

1 Like

Thank you!
I got it working now, here’s the script:

local foodClicked = game.ReplicatedStorage:WaitForChild("FoodClicked")
local eaten = false
local clickdetector = script.Parent.ClickDetector


function FoodClicked(Player)
	if eaten == false then
		if Player.PlayerGui.HungerBar.Background.Positive.Full.value == false then
			foodClicked:FireClient(Player)
			clickdetector.MaxActivationDistance = 0
			script.Parent.Transparency = 1
			eaten = true
			print("FOOD CLICKED")
			wait(2)
			script.Parent.Transparency = 0
			clickdetector.MaxActivationDistance = 10
			eaten = false
		end
	end
end

script.Parent.ClickDetector.MouseClick:Connect(FoodClicked)

New problem is:
Even when the player is full, when they click on a plant it disappears like it’s eaten. I want the script to know when player is full and not allow them to eat.

I really appreciate your time and help!

In your nested-if statement, where you’re checking the value is false, it should be .Value and not .value. Also, is this supposed to be a BoolValue or what is it? Why are you storing a BoolValue so deep within PlayerGui? If you’re not using a BoolValue then that’s the problem because you can only use bool values to check if an object has a value that is set to true or not.

Also, is there anything setting the full value to true? I don’t see anything doing that, unless it’s in a different script.

1 Like

In your nested-if statement, where you’re checking the value is false, it should be .Value and not .value.

I changed it to .Value and it didn’t fix it.

Also, is this supposed to be a BoolValue or what is it? Why are you storing a BoolValue so deep within PlayerGui?

Yes, this is a BoolValue, and it’s deep within PlayerGui because I don’t know where else to put it. Can you tell me a better place to put it?

Also, is there anything setting the full value to true? I don’t see anything doing that, unless it’s in a different script.

Yes, different localscript that sets it to true. Should I post it also?

Yes, this is a BoolValue, and it’s deep within PlayerGui because I don’t know where else to put it. Can you tell me a better place to put it?

It would be better to put it in a folder inside of the player. Similar to the way you create leaderstats but instead of naming the folder leaderstats, you would name it something like “Data” so you can store different values within that folder.

Yes, different localscript that sets it to true. Should I post it also?

I see the problem now. You can’t be using LocalScripts to set values to true/false as it won’t replicate to the server. Let me try to illustrate this. Currently, you have a LocalScript inside of StarterGui that is made to change a value. Since all of the contents in StarterGui are replicated to PlayerGui that means the LocalScript will run on the client. Because it runs on the client, that means if it tries to modify something server-sided like stuff within game.Players, it won’t work because FilteringEnabled essentially blocks this from happening. It can’t trust the client. This is why hackers can’t go to a game and change their coins to 999,999,999 because they can only run code client sided and them changing their money won’t replicate to the server.

You can read more about the client-server model here.

Instead, you should be modifying the value (after you relocate the value to a better space, perhaps using my recommendation from above) on the server using a server script. If you follow my recommendation, you would have to get the value using a variable and then set the variable to true or false based on the conditions you want.

I don’t know what you’re specifically trying to check for to determine if the player is full or not, but you can implement something like this in your server script to make it work. Just create a function to check if the player is full or not based on whatever conditions you have, and then if they are full, then the rest of the code wont function because we added a check on the if-statement down below.

local foodClicked = game.ReplicatedStorage:WaitForChild("FoodClicked")
local eaten = false
local clickdetector = script.Parent.ClickDetector

function determineIfFull(Player) -- New function; not sure what your conditions are
   if Player.Data.FoodEaten >= 10 then
          return true;
    else
          return false;
    end
end

function FoodClicked(Player)
	if eaten == false and determineIfTrue(Player) == false then --Modified
		if Player.PlayerGui.HungerBar.Background.Positive.Full.value == false then
			foodClicked:FireClient(Player)
			clickdetector.MaxActivationDistance = 0
			script.Parent.Transparency = 1
			eaten = true
			print("FOOD CLICKED")
			wait(2)
			script.Parent.Transparency = 0
			clickdetector.MaxActivationDistance = 10
			eaten = false
		end
	end
end

script.Parent.ClickDetector.MouseClick:Connect(FoodClicked)
2 Likes

Thanks so much for the help! I’m working on that now.

So, this is what I’ve been working on and still can’t get the full value to change.

local foodClicked = game.ReplicatedStorage:WaitForChild("FoodClicked")
local eaten = script.Parent.Eaten
local clickdetector = script.Parent.ClickDetector

function determineIfFull(Player)
	local full = Player.Data.Full
	if Player.Data.Hunger.Value == 1 then
		full.Value = true
		print(full.Value)
		return true;
	else
		full.Value = false
		print(full.Value)
		return false;
	end
end


function FoodClicked(Player)
	if eaten.Value == false and determineIfFull(Player) == false then
		if Player.Data.Full.Value == false then
			foodClicked:FireClient(Player)
			clickdetector.MaxActivationDistance = 0
			script.Parent.Transparency = 1
			eaten.Value = true
			print("FOOD CLICKED")
			wait(2)
			script.Parent.Transparency = 0
			clickdetector.MaxActivationDistance = 10
			eaten.Value = false
		end
	end
end

script.Parent.ClickDetector.MouseClick:Connect(FoodClicked)

I believe I see the problem. I think you’re using way too many values and you’re most likely getting confused. I would just stick to using one BoolValue called “Hunger” to track if the player is hungry or not. (Or use it to track if the player is Full if you’re a glass is half-full kind of guy)

Here’s how I would try to do it. I’ll also try to clean up your code while you’re at it. I named the variables more appropriately and made it easier to read. I also added another function to clean it up so it isn’t as cluttered.


local foodClicked = game.ReplicatedStorage:WaitForChild("FoodClicked")
local eaten = script.Parent.Eaten
local clickdetector = script.Parent.ClickDetector

function makeFoodVisible(gameWantsFoodVisible)
	if gameWantsFoodVisible then
		script.Parent.Transparency = 0
		clickdetector.MaxActivationDistance = 10;
	else
		script.Parent.Transparency = 1;
		clickdetector.MaxActivationDistance = 0;
	end
end

function FoodClicked(Player)
	local playerIsHungry = Player.Hunger.Value
	local thisFoodEaten = eaten.Value
	
	if not thisFoodEaten and playerIsHungry then -- 'if not thisFoodEaten' is the same as saying if 'thisFoodEaten == false'
		print("The player is able to eat the food!")
		
		playerIsHungry = false -- make them not hungry anymore since they just ate it
		
		foodClicked:FireClient(Player)
		thisFoodEaten = true
		makeFoodVisible(false)
		
		wait(2)
		
		thisFoodEaten = false
		makeFoodVisible(true)
	end
	
end

script.Parent.ClickDetector.MouseClick:Connect(FoodClicked)

If doing that doesn’t work, then I would add some print statements.

Create a few more print statements to debug where the problem is occurring. I would start by printing the value of the different values you’re using to track if the player can eat or not. You should try to put prints between if-statements to see where the problem is occurring specifically.

1 Like

Thank you! Sorry for slow reply, that script worked great!!
Unfortunately, it looks like this has caused another issue:
The playerIsHungry value is only changing when the player eats (clicks) food.
Instead, I only want playerIsHungry value to change when ‘player hunger bar’ reaches max.
I’ve been trouble-shooting and wrote some new script but it’s causing I’m back to the same problem, it’s not changing the playerIsHungry value again. Ugh.

Here’s the code:
Localscript (Manages the player’s hungerBar size and hungerAmount)

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:wait()
local Human = Character:WaitForChild("Humanoid")
local hungerFrameScale = script.Parent.Size.X.Scale
local hungerFrame = script.Parent
local foodClicked = game.ReplicatedStorage:WaitForChild("FoodClicked")
local data = Player:WaitForChild("Data")
local depletion = data:WaitForChild("Depletion")
local hungerAmount = data:WaitForChild("HungerAmount")
local hunger = data:WaitForChild("Hunger")
local remoteHungerEvent = game.ReplicatedStorage:WaitForChild("RemoteHungerEvent")



local function increaseFood(Player)
	hungerAmount.Value = hungerFrameScale + .1
	hungerFrame.Size = UDim2.new(hungerFrameScale+.1,0,1,0)
	hungerFrameScale = script.Parent.Size.X.Scale
	if hungerFrameScale > 1 then
		hungerFrameScale = 1
		hungerFrame.Size = UDim2.new(1,0,1,0)
	end
	hungerAmount.Value = hungerFrameScale
	print("Food eaten")
end

remoteHungerEvent.OnClientEvent:Connect(increaseFood)

while true do
	if hungerFrameScale > 0 then
		wait(5)
		hungerFrame.Size = UDim2.new(hungerFrameScale-depletion.Value,0,1,0)
		hungerFrameScale = script.Parent.Size.X.Scale
		hungerAmount.Value = hungerFrameScale
		print("Hunger loop")
	else
		wait(5)
		Player.Character.Humanoid:TakeDamage(5)
		print("Death loop")
	end
end

Foodscript (Changed, manages the plant and fires the hungerEvent to hungerManager when eaten)

local foodClicked = game.ReplicatedStorage:WaitForChild("FoodClicked")
local eaten = script.Parent.Eaten
local clickDetector = script.Parent.ClickDetector
local hungerEvent = game.ReplicatedStorage:WaitForChild("HungerEvent")

function makeFoodVisible(gameWantsFoodVisible)
	if gameWantsFoodVisible then
		script.Parent.Transparency = 0
		clickDetector.MaxActivationDistance = 10;
	else
		script.Parent.Transparency = 1;
		clickDetector.MaxActivationDistance = 0;
	end
end

function FoodClicked(Player)
	local playerIsHungry = Player.Data.Hunger.Value
	local hungerAmount = Player.Data.HungerAmount.Value
	local thisFoodEaten = eaten.Value
	
	if not thisFoodEaten and playerIsHungry then -- 'if not thisFoodEaten' is the same as saying if 'thisFoodEaten == false'
		print("The player is able to eat the food!")
		
		hungerEvent:Fire(playerIsHungry, Player, hungerAmount)
		thisFoodEaten = true
		makeFoodVisible(false)
		
		wait(2)
		
		thisFoodEaten = false
		makeFoodVisible(true)
	end
	
end

clickDetector.MouseClick:Connect(FoodClicked)

HungerManager (Determines whether the player is hungry or not.)

local hungerEvent = game.ReplicatedStorage:WaitForChild("HungerEvent")
local remoteHungerEvent = game.ReplicatedStorage:WaitForChild("RemoteHungerEvent")

hungerEvent.Event:Connect(function(playerIsHungry, Player, hungerAmount)
	if hungerAmount == 1 then
		playerIsHungry = false
		print(playerIsHungry)
	else
		playerIsHungry = true
		print(playerIsHungry)
		remoteHungerEvent:FireClient(Player)
	end
end)

Kinda stumped and not sure where to go from here. I know I went a little of track here so if that’s a problem I still have the script you sent me, and we can work off of just that if you’d like to. TYIA

You can just make it a variable to track when the value of hunger changes, and then if it reaches a certain value then you can make it so playerIsHungry changes value. I would do this in a server script that controls the eating (using collection service) and then when they click the food, it will update their hunger and if they reach a hunger value of lets say 10 then it will set PlayerIsHungry to false. You should also have code that detects when the value of Hunger is changed and it should update the frame size.

--Server script

function FoodClicked(Player)
	local playerIsHungry = Player.Data.Hunger
	local hungerAmount = Player.Data.HungerAmount
	local thisFoodEaten = eaten.Value
	
	if not thisFoodEaten.Value and playerIsHungry.Value then
		print("The player is able to eat the food!")
		
		hungerEvent:Fire(playerIsHungry.Value, Player, hungerAmount.Value)
		thisFoodEaten = true
		makeFoodVisible(false)
        
        if hungerAmount.Value == 10 then
             -- do your code here
        else
             hungerAmount.Value += 1; --increment it if it has not reached the limit
        end
      

		
		wait(2)
		
		thisFoodEaten = false
		makeFoodVisible(true)
	end
	
end

clickDetector.MouseClick:Connect(FoodClicked)

-- Local script
-- Updates the bar

local player = game.Players.LocalPlayer
local Hunger = player:WaitForChild('Hunger') -- int value in player
local hungerFrame = script.Parent.HungerFrame

Hunger:GetPropertyChangedSignal("Value"):Connect(function()
       hungerFrame.Size = UDim2.new(Hunger.Value, 0, 1, 0)
end)
2 Likes

Awesome, that worked! Now I just need to figure out how to set the hunger value back to true when the bar decreases. I put it inside the local script and it didn’t work, and I tried to debug it with print statements. According to the prints the script was setting it back to true, but for some reason it still didn’t work. :man_shrugging:

--Local Script
local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:wait()
local Humanoid = Character:WaitForChild("Humanoid")
local hungerFrameScale = script.Parent.Size.X.Scale
local hungerFrame = script.Parent
local data = Player:WaitForChild("Data")
local depletion = data:WaitForChild("Depletion")
local hungerAmount = data:WaitForChild("HungerAmount")
local hunger = data:WaitForChild("Hunger")

hunger:GetPropertyChangedSignal("Value"):Connect(function()
	hungerAmount.Value = hungerFrameScale + .1
	hungerFrame.Size = UDim2.new(hungerFrameScale+.1,0,1,0)
	hungerFrameScale = script.Parent.Size.X.Scale
	if hungerFrameScale > 1 then
		hungerFrameScale = 1
		hungerFrame.Size = UDim2.new(1,0,1,0)
	end
	hungerAmount.Value = hungerFrameScale
	print("Food eaten")
end)

while true do
	if hungerFrameScale > 0 then
		wait(5)
		hungerFrame.Size = UDim2.new(hungerFrameScale-depletion.Value,0,1,0)
		hungerFrameScale = script.Parent.Size.X.Scale
		hungerAmount.Value = hungerFrameScale
		if hungerAmount.Value < 1 then
			hunger.Value = true
			print("Hunger changed to true")
			print(hungerAmount.Value)
			print(hunger.Value)
		end
		print("Hunger loop")
	else
		wait(5)
		Character.Humanoid:TakeDamage(5)
		print("Death loop")
	end
end

Also, I’m not super familiar with CollectionService yet but I read up on it and applied it to my script, but got an error: attempt to index nil with 'MouseClick' on line 48 and I’m not sure why.

--Server Script
local collectionService = game:GetService("CollectionService")
local taggedPart = collectionService:GetTagged("CycadLeaf")
local foodClicked = game.ReplicatedStorage:WaitForChild("FoodClicked")
local eaten = taggedPart.Eaten
local clickDetector = taggedPart.ClickDetector
local hungerEvent = game.ReplicatedStorage:WaitForChild("HungerEvent")



function makeFoodVisible(gameWantsFoodVisible)
	if gameWantsFoodVisible then
		taggedPart.Transparency = 0
		clickDetector.MaxActivationDistance = 10;
	else
		taggedPart.Transparency = 1;
		clickDetector.MaxActivationDistance = 0;
	end
end

function FoodClicked(Player)
	local playerIsHungry = Player.Data.Hunger
	local hungerAmount = Player.Data.HungerAmount
	local thisFoodEaten = eaten
	
	if not thisFoodEaten.Value and playerIsHungry.Value then
		print("The player is able to eat the food!")
		
		thisFoodEaten = true
		makeFoodVisible(false)
        
		if hungerAmount.Value == 1 then
			hungerEvent:Fire(playerIsHungry, Player, hungerAmount)
			print("Player is no longer hungry.")
		else
			hungerAmount.Value += .1; 
		end
		
		wait(2)
		
		thisFoodEaten = false
		makeFoodVisible(true)
	end
	
end

for _, taggedPart in pairs(taggedPart) do
	clickDetector.MouseClick:Connect(FoodClicked)  --Where i got the error
end

The problem arises because you can’t change values in a LocalScript: it won’t replicate it to the server. I would recommend doing the checking of HungerAmount and setting values on the server since it stops exploiters. You can add a check in the foodClicked function and see if hungerAmount is less than 1. If it is, then set hunger to true.

As for your second error, the name of the value variable in the for loop is used twice in the script. You already defined it in line 3. Also, you need to make it so you get the ClickDetector inside of each taggedPart instead of using the click detector in one of the parts. You usually put CollectionService runners in one separate server script (not inside multiple parts) and then add a tag of every object you want that script to run for using :AddTag()

local tag = "Food"

for _, food in pairs(CollectionService:GetTagged(tag)) do
    food.ClickDetector.MouseClick:Connect(FoodClicked)
end

Read more about it here: CollectionService | Documentation - Roblox Creator Hub

After working on this for a while and the input I’ve gotten here, I can’t seem to find a fix so I just think I need to start fresh and rewrite my script from scratch.
I really appreciate your help and I’ll keep you updated as things progress with my new code.

I’m back to update that I found a solution!
I realized I need to use bindable functions to detect if the player is full. I did end up rewriting my script and this is what I did:
I put a serverscript inside of ServerScriptService and another script inside of the food. When player clicks on food, it sends a bindablefunction to the serverscript that checks if the player is full or not. If not, then it sends a remoteevent to a localscript inside of the player’s hungerbar gui to increase it.
So, it’s working perfectly now and your suggestions made a big difference. If anyone is interested in a further explanation feel free to DM me. Thanks again!