How do I make this only run once instead of 15 times?

Since I’d like to reward players upon mining an ore, I wish to implement a currency granting segment. However, I’m currently facing an issue in regards to how many times it runs. Currently, due to the amount of parts in the model, it’s repeating a code 15 times and I don’t wish to keep it that way. I’ve tried adding a debounce, but this didn’t work unfortunately. Below you’ll find the script responsible for this. Any help would be appreciated!

OreTouchedEvent.OnServerEvent:Connect(function(player, Ore)
	local char = player.Character
	local hum = char:FindFirstChildOfClass("Humanoid")
	if not debounce then
	if hum then
		local pickaxe = char:FindFirstChild("Pickaxe")
		if pickaxe then
			for _, v  in(Ore:GetChildren()) do
				if v:IsA("BasePart") and v.Name ~= "Hitbox" then
					v.Transparency += 0.25	
						if v.Transparency == 1 then
							if Ore.Name == "Rock" then
								print("rock!")
							elseif Ore.Name == "IronOre" then
								print("iron!")
							
							end
						end
						end
					end
				debounce = true
				task.wait(3)
				debounce = false
			end
		end				
	end
end)

image

2 Likes

The thing is that .Touched events fire for every part that touches them, so here it would run 15 times. It is better to put the debounce on the server anyway, is there any way you can send your code on the server side so we can take a look please?

Oh! This is my serversided code. I presume you wish to see the localscript?

I’ll put the code here, so if there’s an issue with my localscript, it can be found.

local Rock = script.Parent
local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local Hitbox = script.Parent:WaitForChild("Hitbox")
local replicatedStorage = game:GetService("ReplicatedStorage")
local OreTouchedEvent = replicatedStorage.OreTouchedEvent
local Character = Player.Character or Player.CharacterAdded:Wait()
local Pickaxe = Character:WaitForChild("Pickaxe")
local Handle = Pickaxe:WaitForChild("Handle")
local Count = 0

Hitbox.Touched:Connect(function(player)
	local function Check()
		if Handle:GetAttribute("IsActivated") == true then
			Count += 1
			local Cast = workspace:Raycast(Handle.Position, Handle.CFrame.LookVector * 2)
			if Cast then
				if Cast.Instance.Name ~= Rock.Name then return end
			else
				return
			end
		end
	end

	repeat task.wait(1) Check() until Count == 5
	OreTouchedEvent:FireServer(Rock)
	Count = 0
end)

Set debounce to true right after checking if it’s false.

I’ve tried doing so, and it still runs the code 15 times.
image

if v.Transparency == 1 and not debounce2 then
							debounce2 = true
							if Ore.Name == "Rock" then
								print("rock!")
							elseif Ore.Name == "IronOre" then
								print("iron!")
							debounce2 = false

Declare your Check() function outside of the touched event, no need to declare it every touch.

Debounce should be true immediately after the check for if it is false, otherwise in the time it takes to run the function, the remote event can be fired many times and start running. This will cause multiple print outs. Try that and see if it helps.

I’ve tried doing this, however, the code still runs 15 times…

if v.Transparency == 1 and not debounce2 then
							debounce2 = true
							if Ore.Name == "Rock" then
								print("rock!")
							elseif Ore.Name == "IronOre" then
								print("iron!")
							debounce2 = false

What I’d do is: check if anything is touching the players pickaxe on client → fire event to server and complete a sanity check which checks if the players pickaxe is actually touching an ore → if the sanity check if passed then reward the player.

You removed the task.wait() before setting the debounce to false.
Also you should put the debounce in your localscript so you save memory by not firing the event 15 times.
If you want to keep the debounce on the server, then make it a table and give every player a boolean like this:

local devounce = {}
debounce[player.UserId] = false

Make sure to delete set it to nil when the player leaves. Only do this if you want multiple people to be able to toch ores at the same time.

Oh, it wasn’t deleted, I just made a new debounce variable as the first one is being used to ensure the ore doesn’t disappear instantly. I wish to somehow make it so that the code snippet is only ran once instead of 15 times over.

The debounce2 variable didn’t really do as I wished, as it still runs the code 15 times instead of only once…

You could use a RemoteFunction that returns once finished instead of a RemoteEvent and put the debounce in your LocalScript. Before you’d call the RemoteFunction set the debounce to true, then after the RemoteFunction set it back to false. And ofcourse you’d check if the debounce is false before doing all of this.

Sorry if I’m not being very clear or don’t format my text nicely, it’s late and I’m on my phone.

Do something like this on client:

local hitBox -- put your hotbox here
hitbox.Touched:Connect(function(hit)
	if hit.Name == "Ore" then
		mineOre:FireServer(hit)
	end
end)

and this on server:

mineOre.OnServerEvent:Connect(function(player, ore)
	local character = player.Character
	if not character then
		return
	end
	local pickaxe = character:FindFirstChild("Pickaxe")
	if pickaxe then
		local hitbox = pickaxe:FindFirstChild("Hitbox")
		if hitbox then
			if table.find(hitbox:GetTouchingParts(), ore) then
				print("Reward player")
			end
		end
	end
end)

Maybe something like this:

local Idkwhattocallthisboolvalue = true --You can change the name of this--
OreTouchedEvent.OnServerEvent:Connect(function(player, Ore)
	local char = player.Character
	local hum = char:FindFirstChildOfClass("Humanoid")
	if not debounce then
	if hum then
		local pickaxe = char:FindFirstChild("Pickaxe")
		if pickaxe then
			for _, v  in(Ore:GetChildren()) do
				if v:IsA("BasePart") and v.Name ~= "Hitbox" and Idkwhattocallthisboolvalue then
					v.Transparency += 0.25	
						if v.Transparency == 1 then
							if Ore.Name == "Rock" then
								print("rock!")
                            Idkwhattocallthisboolvalue = false
							elseif Ore.Name == "IronOre" then
								print("iron!")
							Idkwhattocallthisboolvalue = false
							end
						end
						end
					end
				debounce = true
				task.wait(3)
				debounce = false
 
			end
		end				
	end
end)

Apologies for not getting back until a day later, but where exactly would I put the debounce within the localscript? This is my first time using a remote function, and I’m rather new at setting a debounce.

your original script with the de bounce

local debounce = {}

OreTouchedEvent.OnServerEvent:Connect(function(player, Ore)
    local char = player.Character
    local hum = char:FindFirstChildOfClass("Humanoid")
    
    if not debounce[Ore] then
        debounce[Ore] = true
        
        if hum then
            local pickaxe = char:FindFirstChild("Pickaxe")
            if pickaxe then
                local fullyTransparent = true
                for _, v in pairs(Ore:GetChildren()) do
                    if v:IsA("BasePart") and v.Name ~= "Hitbox" then
                        v.Transparency += 0.25
                        if v.Transparency < 1 then
                            fullyTransparent = false
                        end
                    end
                end
                
                if fullyTransparent then
                    if Ore.Name == "Rock" then
                        print("rock!")
                    elseif Ore.Name == "IronOre" then
                        print("iron!")
                    end
                end
            end
        end
        
        task.wait(3)
        debounce[Ore] = false
    end
end)

This doesn’t seem to work, as when I try to mine the ore, it doesn’t do anything unfortunately.
image