Debounce for InputBegan and InputEnded

local UIS = game:GetService("UserInputService")
local debounce1 = false
local debounce2 = false

UIS.InputBegan:Connect(function(input, gpe)
	if gpe then return end
	if input.KeyCode == Enum.KeyCode.Q then
		if debounce1 then
			return
		end
		debounce1 = true
		--game.ReplicatedStorage.FireballEvent:FireServer(Mouse.Hit, "Charge")
		task.wait(2)
		debounce1 = false
	end
end)

UIS.InputEnded:Connect(function(input,gpe)
	if gpe then return end
	if input.KeyCode == Enum.KeyCode.Q  then
		if debounce2 then
			return
		end
		debounce2 = true
		--game.ReplicatedStorage.FireballEvent:FireServer(Mouse.Hit, "Fire")
		task.wait(2)
		debounce2 = false
	end
end)

Just make use of a double debounce, one for each connected function.

“debounce” isn’t really a great design pattern for this, and honestly it’s pretty much always a pretty bad idea. A better solution is to use timers, and the simplest way of doing that is to use tick() to get the time in milliseconds since the game started. It also doesn’t make sense to have separate timing logic for the release event If the press event is handled properly and has all the necessary time constraints, then it’s always valid to release the button and it should always cause the fireball to be fired. Additional timing logic is redundant because it’s impossible to be in a state where it’s actually necessary. There’s also not really a good way of handling an “invalid” release event without adding more game logic, since we don’t actually have control over the users keyboard. If the player released Q then the player released Q, no way to program your way out of that.

Here’s a simple version showing how I’d do all of this:

local fireballCooldown = 2
local lastFireballFireTime = -math.huge
local isChargingFireball = false

UIS.InputBegan:Connect(function(input, gpe)
    if gpe then return end
    
    if input.KeyCode == Enum.KeyCode.Q then
        if tick() - lastFireballFireTime >= fireballCooldown then
            print("Charging...")
            isChargingFireball = true
        end
    end
end

UIS.InputEnded:Connect(function(input)
    if input.KeyCode == Enum.KeyCode.Q and isChargingFireball then --It's possible to release Q when not charging fireball, e.g. if pressing Q while chat text field is active which would cause gpe to be true, so isChargingFireball check is necessary
        print("FIRE!")
        isChargingFireball = false
        lastFireballFireTime = tick()
    end
end)

If I were to actually make a game, I’d use the Maid library to connect and disconnect a separate event listener to UIS.InputEnded inside the UIS.InputBegan listener, resulting in less complicated if statements and less global state (there’d be no need for the isChargingFireball variable).

2 Likes

Your solution worked thank you

Yea this also works too. thanks

Don’t forget to add security on the server so exploiters can’t bypass the 2 second debounce tick limit thing whatever it’s called!