Print firing multiple times

So I have a problem where the print “hit” is firing multiple times even though I disconnected the loop.

I only want it to fire once.

local RunService = game:GetService("RunService")

local character = script.Parent
local HumanoidRootPart = character:WaitForChild("HumanoidRootPart")
local Humanoid = character:WaitForChild("Humanoid")
local Animator = Humanoid:WaitForChild("Animator")

local Ball = workspace:WaitForChild("Ball")
local CurrentTarget = Ball:WaitForChild("CurrentTarget")

local HitAnimation = script:WaitForChild("HitAnimation")

local hitDistance = 20
local hit = false

local blockedConnection

local function ActivateBlocked()
	if blockedConnection then
		blockedConnection:Disconnect()
		blockedConnection = nil
	end

	blockedConnection = RunService.Heartbeat:Connect(function()
		if hit then
			local distance = (HumanoidRootPart.Position - Ball.Position).Magnitude

			if distance <= hitDistance then
				script.HitBall:FireServer()
				hit = false
				print("hit") <--------------------------
				
				if blockedConnection then
					blockedConnection:Disconnect()
					blockedConnection = nil
				end
			end
		end
	end)
end

local function PlayAnimation()
	local track = Animator:LoadAnimation(HitAnimation)
	track:Play()

	track.Ended:Connect(function()
		if blockedConnection then
			blockedConnection:Disconnect()
			blockedConnection = nil
		end

		hit = false
	end)
end

RunService.Heartbeat:Connect(function()
	if CurrentTarget.Value == character and not hit then
		if result then
		hit = true
		ActivateBlocked()
		PlayAnimation()
	end
end)
2 Likes

You could just return the function or add a debounce to stop it from running multiple times

3 Likes

I have tried to return the function but that doesn’t work:

local function ActivateBlocked()
	if blockedConnection then
		blockedConnection:Disconnect()
		blockedConnection = nil
	end

	blockedConnection = RunService.Heartbeat:Connect(function()
		if hit then
			local distance = (HumanoidRootPart.Position - Ball.Position).Magnitude

			if distance <= hitDistance then
				script.HitBall:FireServer()
				hit = false
				print("hit")
				
				if blockedConnection then
					blockedConnection:Disconnect()
					blockedConnection = nil
				end
				
				return
			end
		end
	end)
end

I also don’t want a debounce.

1 Like

Is there a particular reason why you don’t want to use a debounce or…? There’s nothing else I can think of at the moment

I want to check when to hit the ball when it gets close so a debounce wouldn’t work.

Ah okay I think I got it. You should use :Once instead of :Connect for the Heartbeat event.

Dunno, maybe this isn’t gonna suit your game, but I don’t got anything else in my mind.

What does that do? It also doesn’t seem to change anything.

Once basically just runs the event one time before disconnecting it immediately. Hm yeah gonna a second to think of something else

So instead of this, you would replace it with:

blockedConnection = RunService.Heartbeat:Once(function()

Thats what I did but it didn’t change anything.

1 Like

That’s really strange, yep; that’s all I could think of.

1 Like

execution order seems to be workin for me assuming there isn’t nothin past the bottom and the assumed-missing end

local RunService = game:GetService("RunService")
local hit = false
local blockedConnection

function stopblock()
	if blockedConnection then
		blockedConnection:Disconnect()
		blockedConnection = nil
	end
end

local function ActivateBlocked()
	stopblock()
	blockedConnection = RunService.Heartbeat:Connect(function()
		if hit then
			if 1 <= 2 then
				hit = false
				print("hit")
				stopblock()
			end
		end
	end)
end

RunService.Heartbeat:Connect(function()
	if workspace.Baseplate == workspace.Baseplate and not hit then
		if true then
			hit = true
			ActivateBlocked()
		end
	end
end)

RunService.RenderStepped:Connect(function()
	print("renderstep")
end)

image

either i messed up the test criteria, your games just built different, or there’s something else messing with the expected results; really I’m not sure you need the two connections to the same event

Try adding another variable.

local AlreadyPrinted = false
if AlreadyPrinted == false then
    AlreadyPrinted = true
    print("hit")
end

I figured out its because this is firing multiple times causing it to call the function multiple times:

RunService.Heartbeat:Connect(function()
	if CurrentTarget.Value == character and not hit then
		local result = PredictBall()

		if result then
			hit = true
			print("Fired")
			ActivateBlocked()
			PlayAnimation()
			return
		end
	end
end)

I need help trying to fix this problem. The variable hit is set to true but it still prints “Fired” multiple times.

local RunService = game:GetService("RunService")

local character = script.Parent
local HumanoidRootPart = character:WaitForChild("HumanoidRootPart")
local Humanoid = character:WaitForChild("Humanoid")
local Animator = Humanoid:WaitForChild("Animator")

local Ball = workspace:WaitForChild("Ball")
local CurrentTarget = Ball:WaitForChild("CurrentTarget")

local HitAnimation = script:WaitForChild("HitAnimation")

local hitDistance = 20
local hit = false

local connection
local blockedConnection

local function ActivateBlocked()
	if blockedConnection then
		blockedConnection:Disconnect()
		blockedConnection = nil
	end
	
	blockedConnection = RunService.Heartbeat:Connect(function()
		if hit then
			local distance = (HumanoidRootPart.Position - Ball.Position).Magnitude

			if distance <= hitDistance then
				hit = false
				--print("hit")
				script.HitBall:FireServer()

				if blockedConnection then
					blockedConnection:Disconnect()
					blockedConnection = nil
				end
			end
		end
	end)
end

local function PlayAnimation()
	local track = Animator:LoadAnimation(HitAnimation)
	track:Play()

	track.Ended:Connect(function()
		if blockedConnection then
			blockedConnection:Disconnect()
			blockedConnection = nil
		end
		
		--print("ended")
		hit = false
	end)
end

connection = RunService.Heartbeat:Connect(function()
	if CurrentTarget.Value == character and not hit then
		local result = PredictBall()
		
		if result then
			hit = true
			print("Fired")
			PlayAnimation()
			ActivateBlocked()
		end
	end
end)

Errr… you have two connections to heartbeat in a single script, and multiple paths where you attempt to disconnect the encapsulated version. You also have several logic paths where you control the value of hit too. This will cause pain, you need a single entry point where hit is set either to true or false (then you can be sure of the execution point of the flip-flop of its value). Use a single heartbeat to do do all of this.

But I want the variable hit to set to false when the animation finishes playing or when the ball is hit.

I just tried to do this but it still has the same problem:

local connection

local function ActivateBlocked()
	local distance = (HumanoidRootPart.Position - Ball.Position).Magnitude

	if distance <= hitDistance and hit then
		hit = false
		script.HitBall:FireServer()
		print("hit")
	end
end

local function PlayAnimation()
	local track = Animator:LoadAnimation(HitAnimation)
	track:Play()

	track.Ended:Connect(function()
		--print("ended")
		hit = false
	end)
end

connection = RunService.Heartbeat:Connect(function()
	if CurrentTarget.Value == character and not hit then
		local result = PredictBall()

		if result then
			hit = true
			print("Fired")
			PlayAnimation()
			ActivateBlocked()
		end
	end
end)

Heartbeat will fire every 1/40th of a second, any logic that needs to be determined before the next execution must be very small. If it is too bloated it wont have time to execute before it is fired again. You might have to use a deltaTime to throttle the execution of the main body of code.

It works when I delete out this:

local function ActivateBlocked()
	local distance = (HumanoidRootPart.Position - Ball.Position).Magnitude

	if distance <= hitDistance and hit then
		--hit = false
		script.HitBall:FireServer()
		print("hit")
	end
end

but I need it to stay.