What I am Trying to Achieve
I am creating a tycoon based game, so my goal is to make it so that when a player touches a button it takes the amount of (Cash - Cost) setting their new total in “leaderstats”.
The Issue
The current issue is when I try to use this setup I am receiving a print statement in output that there is not enough money although there is, as 0 is >= 0. I printed out some values and realized it was never making it to the function where it calculates the new amount of cash so my guess is the issue is somewhere within my first code I list below.
I currently am receiving the error “nil” when printing the value of leaderstats.
FYI: I printed it to try and narrow down what was going wrong, not as a part of the actual code
Video
Video:
Screenshots
What I’ve Tried
So far I have been looking for a solution to what seems to be a syntax error, but now I’m not so sure. I have printed out the values of my cash, cost, and many other things and have narrowed the error line of code to line 30, but still have no clue what’s wrong with it.
Code:
local Players = game:GetService("Players")
--- Leaderstats ---
local function LeaderboardSetup()
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
local Cash = Instance.new("IntValue")
Cash.Name = "Cash"
Cash.Value = 1
Cash.Parent = leaderstats
return leaderstats
end
local PlayerManager = {}
--- Hooks Events to Proper Functions ---
function PlayerManager.Start()
Players.PlayerAdded:Connect(PlayerManager.OnPlayerAdded)
end
function PlayerManager.OnPlayerAdded(player)
local leaderstats = LeaderboardSetup()
leaderstats.Parent = player
end
function PlayerManager.GetMoney(player)
local leaderstats = player:FindFirstChild("leaderstats")
--- Error: leaderstats is nil here
print(leaderstats)
if leaderstats then
local Cash = leaderstats:FindFirstChild("Cash")
print(Cash)
if Cash then
return Cash.Value
end
end
return 0
end
function PlayerManager.SetMoney(player, value)
if value then
local leaderstats = player:FindFirstChild("leaderstats")
if leaderstats then
local Cash = leaderstats:FindFirstChild("Cash")
if Cash then
Cash.Value = value
end
end
end
end
return PlayerManager
Error Code:
local leaderstats = player:FindFirstChild("leaderstats") --- Error Line 30
Code for getting new value of Cash
function Button:Press(player)
local id = self.Instance:GetAttribute("Id")
local cost = self.Instance:GetAttribute("Cost")
local cash = PlayerManager.GetMoney(player)
if player == self.Tycoon.Owner and cash >= cost then
PlayerManager.SetMoney(player, cash - cost)
self.Tycoon:PublishTopic("Button", id)
self.Instance:Destroy()
else
print("not enough money")
end
end
Thank you to anyone who takes the time to think about this one. If you need to be provided with any other information about my code please let me know. Just looking for some fresh eyes on something I am probably missing in my code.
“leaderstats” doesn’t exist when attempting to get it. You probably forgot to call :Start.
Anyways, I changed the code a little. What I did was:
Removed checks for an object existing. “leaderstats”, as well as all objects underneath it, should always exist. Getting an error faster helps you fix things faster.
Added an initialization function to the bottom of the module.
local PlayerManager = {}
local Players = game:GetService("Players")
--- Leaderstats ---
local function createLeaderstats(player: Player)
-- Leaderstats folder
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
-- The values
local Cash = Instance.new("IntValue")
Cash.Name = "Cash"
Cash.Value = 1
Cash.Parent = leaderstats
-- Finally, set the parent of the leaderstats folder
leaderstats.Parent = player
end
--- Hooks Events to Proper Functions ---
function PlayerManager.Start()
Players.PlayerAdded:Connect(PlayerManager.OnPlayerAdded)
end
function PlayerManager.OnPlayerAdded(player)
createLeaderstats(player)
end
function PlayerManager.GetMoney(player)
local leaderstats = player.leaderstats
local Cash = leaderstats.Cash
return Cash.Value
end
function PlayerManager.SetMoney(player, value)
local leaderstats = player.leaderstats
local Cash = leaderstats.Cash
Cash.Value = value
end
local initialized = false
local function init()
if not initialized then
-- You can add any initialization code you want here
-- A potential issue may arise when the player has joined before the event connected
for _, player in ipairs(Players:GetPlayers()) do
createLeaderstats(player)
end
-- We'll do this to make sure that the method is always called
PlayerManager.Start()
end
return PlayerManager
end
return init()
Yes, here is the code for button. Currently looking into the first response as well.
local PlayerManager = require(script.Parent.Parent.PlayerManager)
local Button = {}
Button.__index = Button
function Button.new(tycoon, part)
local self = setmetatable({}, Button)
self.Tycoon = tycoon
self.Instance = part
return self
end
--- Player Touches Button ---
function Button:Init()
self.Prompt = self:CreatePrompt()
self.Instance.Touched:Connect(function(...)
print("touched")
self:Press(...)
end)
end
function Button:CreatePrompt()
self.Instance.BillboardGui.TextLabel.Text = "$" .. self.Instance:GetAttribute("Cost")
end
--- Get's Rid of Button and Spawns The Part the Player Bought ---
function Button:Press(player)
PlayerManager.Start()
local id = self.Instance:GetAttribute("Id")
local cost = self.Instance:GetAttribute("Cost")
local cash = PlayerManager.GetMoney(player)
if player == self.Tycoon.Owner and cash >= cost then
PlayerManager.SetMoney(player, cash - cost)
self.Tycoon:PublishTopic("Button", id)
self.Instance:Destroy()
else
print("not enough money")
end
end
return Button
I tried implementing this code to see how it works and I am now getting a new error. For some reason it is acting like it is searching for leaderstats in the players body parts.
The ... that passing with Touched event is a character hit part not player instance so change that function to
function Button:Init()
self.Prompt = self:CreatePrompt()
self.Instance.Touched:Connect(function(hitPart)
if hitPart.Parent:FindFirstChild("Humanoid") then
local Player = game:GetService("Players"):GetPlayerFromCharacter(hitPart.Parent)
self:Press(Player)
end
end)
end
Yep, you were correct. I was programming it as if it was a prompt, but it was a button. So the mixture of the two made my code faulty. It now works exactly like what I was looking for with minimum change. Thanks so much! I really appreciate it!