How to make a Once() but not using Once()?

Hello guys ! I found a bug in my game, so the bug is when I click multiples times on the button it call as many time I clicked the function, so I need to make Once() but not using Once() so the function is called only 1 time and the player can click again the button.

This is the remoteEvent when I click the button to call the function

StoreBoostEvent.OnClientEvent:Connect(function(BoostName)
	local BoostConvert = tostring(BoostName)

	BoostCount += 1
	updateMaxBoostText()

	local auraValue = player:FindFirstChild("Boosts"):FindFirstChild(BoostName)

	if not checkMaxBoostLimit() then
		print("Max boost limit reached, cannot add new boost.")
		ReplicatedStorage.Remotes.MaxBoostsLimit:FireServer(BoostName)
		BoostCount -= 1
		return
	end

	local BoostInfo = nil
	for _, BoostData in ipairs(BoostsData.Boosts) do
		if BoostData.Name == BoostName then
			BoostInfo = BoostData
			break
		end
	end

	if BoostInfo then
		local DestroyBoostFrame = ScrollingFrameBoost:FindFirstChild(BoostConvert)
		if DestroyBoostFrame then
			updateBoostAmount(DestroyBoostFrame)
			return
		else
			local clonedBoost = TemplateBoost:Clone()
			clonedBoost.Parent = ScrollingFrameBoost
			clonedBoost.Name = BoostConvert
			updateBoostAmount(clonedBoost)
			clonedBoost.Visible = true
			clonedBoost.ImageLabel.Image = BoostInfo.ImageId
			clonedBoost.Label.Text = ""
			clonedBoost.Label.TextColor3 = BoostInfo.TextColor
			clonedBoost.Label.Font = BoostInfo.TextFont
			clonedBoost.LayoutOrder = BoostInfo.LayoutOder
			clonedBoost.Effect.ImageColor3 = BoostInfo.TextColor

			clonedBoost.MouseButton1Click:Connect(function() --This is where I need Once() but not using Once()
				BoostInfoData = {
					name = BoostConvert,
					Multiplier = BoostInfo.Multiplier,
					textColor = BoostInfo.TextColor,
					textFont = BoostInfo.TextFont,
					image = BoostInfo.ImageId
				}
				lastClickedBoost = clonedBoost
				OnBoostClicked(BoostInfoData, clonedBoost)
			end)
		end
	end
end)

This is the function

local function OnBoostClicked(BoostInfo, clickedButton)
	InfoFrame.AuraFrame.BoostImage.Image = BoostInfo.image
	InfoFrame.BoostName.Text = BoostInfo.name
	InfoFrame.BoostName.TextColor3 = BoostInfo.textColor
	InfoFrame.BoostName.Font = BoostInfo.textFont
	InfoFrame.rng.Text = "X" .. tostring(BoostInfo.Multiplier)
	InfoFrame.Luck.Text = ""
	InfoFrame.Speed.Text = ""
	
	InfoFrame.EquipButton.MouseButton1Click:Once(function()
		InfoFrame.EquipButton.Interactable = false

		if clickedButton == lastClickedBoost then
			if lastClickedBoost == nil then return end
			BoostCount -= 1
			giveBoost(BoostInfo.name)
			updateBoostAmount(clickedButton)
			updateMaxBoostText()
			OnBoostClicked(BoostInfo, clickedButton)
			clickedButton.Active = true
			clickedButton.Interactable = true
			local ValBoost = player.Boosts:FindFirstChild(clickedButton.Name)
			if ValBoost.Value <= 0 then
				clickedButton:Destroy()
				lastClickedBoost = nil
				clickedButton = nil
				InfoFrame.AuraFrame.BoostImage.Image = ""
				InfoFrame.AuraFrame.auraNameText.Text = ""
				InfoFrame.BoostName.Text = ""
				InfoFrame.rng.Text = "X"
				task.wait(0.1)
				InfoFrame.EquipButton.Interactable = true
			else
				task.wait(0.1)
				InfoFrame.EquipButton.Interactable = true
				lastClickedBoost = nil
				clickedButton = nil
			end
		end 
	end)
end

I don’t know if im clear im sorry

You can use a debounce system, barring the localplayer from using it again.

Can you explain me how it works I never understood sry :sweat_smile:

1 Like

Sure. So basically just make a variable called “used” or anything, and set it to false. In the script, whenever the player triggers it, set the “used” value to true. In the function at the top check if the used value is true. If it is, stop the function from running by returning nil or something. If the used value is false, let the script resume

1 Like
local PlayerHasUsedButton = false;

Button.MouseButton1Click:Connect(function(): ()
    if (PlayerHasUsedButton) then return; end; --// checks if the player already pressed the button
    PlayerHasUsedButton = true; --// If player didnt press the button, set the variable to true
    --// ...
end);

This is a quick rundown on how debounce works

3 Likes
local used = false

if not used then
        used = true
        print("used")
        -- do whatever
else
        print("already used")
end)

apolgies for the spelling and formatting in both msgs

2 Likes

Where should I put BtnBoostDB in the function ?

local function OnBoostClicked(BoostInfo, clickedButton)
	if BtnBoostDB == true then
		InfoFrame.AuraFrame.BoostImage.Image = BoostInfo.image
		InfoFrame.BoostName.Text = BoostInfo.name
		InfoFrame.BoostName.TextColor3 = BoostInfo.textColor
		InfoFrame.BoostName.Font = BoostInfo.textFont
		InfoFrame.rng.Text = "X" .. tostring(BoostInfo.Multiplier)
		InfoFrame.Luck.Text = ""
		InfoFrame.Speed.Text = ""

		InfoFrame.EquipButton.MouseButton1Click:Connect(function()
			InfoFrame.EquipButton.Interactable = false

			if clickedButton == lastClickedBoost then
				if lastClickedBoost == nil then return end
				BoostCount -= 1
				giveBoost(BoostInfo.name)
				updateBoostAmount(clickedButton)
				updateMaxBoostText()
				OnBoostClicked(BoostInfo, clickedButton)
				clickedButton.Active = true
				clickedButton.Interactable = true
				local ValBoost = player.Boosts:FindFirstChild(clickedButton.Name)
				if ValBoost.Value <= 0 then
					clickedButton:Destroy()
					lastClickedBoost = nil
					clickedButton = nil
					InfoFrame.AuraFrame.BoostImage.Image = ""
					InfoFrame.AuraFrame.auraNameText.Text = ""
					InfoFrame.BoostName.Text = ""
					InfoFrame.rng.Text = "X"
					task.wait(0.1)
					InfoFrame.EquipButton.Interactable = true
				else
					task.wait(0.1)
					InfoFrame.EquipButton.Interactable = true
					lastClickedBoost = nil
					clickedButton = nil
				end
			end 
		end)
	else
		return
	end
end
1 Like

where and how it is rn is fine but make sure to change the variables value to false up in the first block so it doesnt keep on running

1 Like

Yeah im asking when should I put it to false

1 Like

put it directly after line 2

local function OnBoostClicked(BoostInfo, clickedButton)
    if BtnBoostDB == true then
        BtnBoostDB = false
1 Like

I still have the same problem because the BtnBoostDB = false right after calling the function so I still can spam click the button and that’s still spam calling the function

1 Like

wait where did you place the original variable and what scripts are they in

1 Like
local touched_the_part = false
local part = ...

part.Touched:Connect(function(...)
    if touched_the_part then return end -- if thats true, the script wont continue executing whats under this line
    touched_the_part = true

    print("I touched the part, no one can touch it now")
end)

OR, using connections like so:

local touched_connection = nil
local part = ...

touched_connection = part.Touched:Connect(function(...)
    touched_connection:Disconnect() -- disconnect the event so it doesnt happen again

    print("I touched the part, no one can touch it now")
end)
1 Like

put it in the remoteevent script with the OnBoostClicked function encased in the statement, didnt realise mb

1 Like

I place the variable at the top of the script where are every variables and its a local script to handle the inventory system

1 Like

I can’t because I have 2 remote that call the function, or I paste 2 times the function ?

1 Like

Yeah but how can I reconnect to the event ?

1 Like
touched_connection = part.Touched:Connect(function(...)
    print("reconnected the event")
end)
1 Like

Here try this

local BtnBoostDB = true

StoreBoostEvent.OnClientEvent:Connect(function(BoostName)
	local BoostConvert = tostring(BoostName)

	BoostCount += 1
	updateMaxBoostText()

	local auraValue = player:FindFirstChild("Boosts"):FindFirstChild(BoostName)

	if not checkMaxBoostLimit() then
		print("Max boost limit reached, cannot add new boost.")
		ReplicatedStorage.Remotes.MaxBoostsLimit:FireServer(BoostName)
		BoostCount -= 1
		return
	end

	local BoostInfo = nil
	for _, BoostData in ipairs(BoostsData.Boosts) do
		if BoostData.Name == BoostName then
			BoostInfo = BoostData
			break
		end
	end

	if BoostInfo then
		local DestroyBoostFrame = ScrollingFrameBoost:FindFirstChild(BoostConvert)
		if DestroyBoostFrame then
			updateBoostAmount(DestroyBoostFrame)
			return
		else
			local clonedBoost = TemplateBoost:Clone()
			clonedBoost.Parent = ScrollingFrameBoost
			clonedBoost.Name = BoostConvert
			updateBoostAmount(clonedBoost)
			clonedBoost.Visible = true
			clonedBoost.ImageLabel.Image = BoostInfo.ImageId
			clonedBoost.Label.Text = ""
			clonedBoost.Label.TextColor3 = BoostInfo.TextColor
			clonedBoost.Label.Font = BoostInfo.TextFont
			clonedBoost.LayoutOrder = BoostInfo.LayoutOder
			clonedBoost.Effect.ImageColor3 = BoostInfo.TextColor

			clonedBoost.MouseButton1Click:Connect(function() --This is where I need Once() but not using Once()
				BoostInfoData = {
					name = BoostConvert,
					Multiplier = BoostInfo.Multiplier,
					textColor = BoostInfo.TextColor,
					textFont = BoostInfo.TextFont,
					image = BoostInfo.ImageId
				}
				lastClickedBoost = clonedBoost
				if BtnBoostDB == true then
					BtnBoostDB = false
					OnBoostClicked(BoostInfoData, clonedBoost)
				end
			end)
		end
	end
end)
1 Like

That’s working but not like I wanted, wait I’ll send a video

1 Like