Tycoon buttons help

Hello, I am trying to create a new tycoon game sorta following AlvinBlox’s tutorial from back in 2024 (I’m using some of his knowledge and applying it to my own scripting, so some of it is similar but some of it is not) and I have a separate script to handle buttons.

However, even when I destroy the button, it runs the event multiple times and the purchased items will get duplicated several times. I’ve tried multiple methods to add a “debounce” to prevent the event from running more than once, but none of it seemed to work. Any suggestions are appreciated!

Code from my button handler:

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

local tycoons = game.Workspace.Tycoons
local templateTycoon = tycoons.TemplateMiner

local looping = true

while looping do
	for i, tycoon in tycoons:GetChildren() do
		local buttonFolder = tycoon.Buttons
		for i, button in buttonFolder:GetChildren() do
			button.PrimaryPart.Touched:Connect(function(part)
				local player = Players:GetPlayerFromCharacter(part.Parent)

				if not player then return end
				if tycoon.Owner.Value ~= player then return end

				-- TODO: Buying functions
				local unlockID = button:GetAttribute("UnlockID")
				for i, object in templateTycoon.Purchases:GetChildren() do
					if object:GetAttribute("ID") ~= unlockID then continue end
					
					local purchase = object:Clone()
					local objectCFrame
					
					if purchase:IsA("Model") then
						objectCFrame = purchase:GetPivot()
					elseif purchase:IsA("BasePart") then
						objectCFrame = purchase.CFrame
					end
					
					local relativeCFrame = templateTycoon.Entrance.CFrame:ToObjectSpace(objectCFrame)
					local tycoonWorldCFrame = tycoon.Entrance.CFrame:ToWorldSpace(relativeCFrame)
					
					if purchase:IsA("Model") then
						purchase:PivotTo(tycoonWorldCFrame)
					elseif purchase:IsA("BasePart") then
						purchase.CFrame = tycoonWorldCFrame
					end
					
					purchase.Parent = tycoon.Purchases
					button:Destroy()
				end
			end)
		end
	end
	task.wait(1)
end
1 Like

Okay I added a simple debounce system. Sorry if it’s a little sloppy I did this on my phone.


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

local tycoons = game.Workspace.Tycoons
local templateTycoon = tycoons.TemplateMiner

local looping = true
local Debounces = {}

while looping do
	for i, tycoon in tycoons:GetChildren() do
		local buttonFolder = tycoon.Buttons
		for i, button in buttonFolder:GetChildren() do
			button.PrimaryPart.Touched:Connect(function(part)
				local player = Players:GetPlayerFromCharacter(part.Parent)

				if Debounces[player.UserId] then return end
Debounces[player.UserId] = true

				if not player then return end
				if tycoon.Owner.Value ~= player then return end

				-- TODO: Buying functions
				local unlockID = button:GetAttribute("UnlockID")
				for i, object in templateTycoon.Purchases:GetChildren() do
					if object:GetAttribute("ID") ~= unlockID then continue end
					
					local purchase = object:Clone()
					local objectCFrame
					
					if purchase:IsA("Model") then
						objectCFrame = purchase:GetPivot()
					elseif purchase:IsA("BasePart") then
						objectCFrame = purchase.CFrame
					end
					
					local relativeCFrame = templateTycoon.Entrance.CFrame:ToObjectSpace(objectCFrame)
					local tycoonWorldCFrame = tycoon.Entrance.CFrame:ToWorldSpace(relativeCFrame)
					
					if purchase:IsA("Model") then
						purchase:PivotTo(tycoonWorldCFrame)
					elseif purchase:IsA("BasePart") then
						purchase.CFrame = tycoonWorldCFrame
					end
					
					purchase.Parent = tycoon.Purchases
					button:Destroy()

task.delay(1, function()
Debounces[player.UserId] = nil

end)

				end
			end)
		end
	end
	task.wait(1)
end

Seems that you set new Touched handler each second.
Do you really need that loop?..
Sorry if I missed something but seems that debounce logic here fixes consequences but not the cause.

As af_2048 mentions, a debounce is likely not going to be helpful here. Sure, if the computation necessary to decide whether the button should be destroyed took a long time then it’s possible the button’s touched event would get triggered more then one time before the button got destroyed. If that’s the case, a debounce would help with that.

The main issue here however is very clearly the fact that all buttons for all tycoons are being given a touched connection once a second. You only need 1 touched connection that will last the entirety of the game, so just remove the while loop.

3 Likes

Ah I see. I tried that before and the other problem I had was that when new buttons are added, no event is assigned to them. This was my lazy solution to that issue but it seems it was not a very good solution at all. Do you have any recommendations for how I’d be able to account for new buttons being added during a test?

EDIT:
I have split up the button function into a separate function that is now called by a couple connect events. One of them is the same one I have here, just only checking once the game starts to activate any buttons that might be there. The second one is detecting for buttons being added to the button folders, and then activating those buttons as well. I have tested it and it works!

Thank you everybody, I appreciate your help!

Thanks for this clarification, now I see why you need the loop.
My 5 cents here is that most likely you know the place you add such buttons so it looks reasonable to initialize Touched handler there once.

It helps for me to have this, cause the way my tycoons are set up is that it pulls from a single template and just adds everything over time as you buy. That way I don’t have to copy and paste the same tycoon 4-6 times when I make a small change, it’ll just be automatically applied to all of the tycoons.

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