What is the best method in implement a debounce?

Hi I am pretty new to trying Event-based programming and OOP I am still experimenting and I can’t find a way to implement a simple debounce, without having to use Wait(), Delay(), Coroutines. based on what I read about making consistent games. Event-based programming is king.

I am trying to make a bus that count’s people inside and list them in a table using modules since there’s going to be multiple bus and to avoid repeated code. My situation is when I touch the door it immediately puts me back out instead of staying inside of the bus. How can I avoid this?

local BusHandler = require(game:GetService("ServerScriptService").BusHandler)

local Trigger = script.Parent.Trigger
local TeleportInside = script.Parent.TeleportInside
local TeleportOutside = script.Parent.TeleportOutside


local PlayerEntering = false
local PlayersInside = {}

function TeleportPlayer(Character, Check)
	if not Check then
		BusHandler:TeleportPlayer(Character, TeleportInside)
	else
		BusHandler:TeleportPlayer(Character, TeleportOutside)
	end
end


function AddPlayersToBus(Hit)
	local CheckPlayerInside
	local Player = game.Players:FindFirstChild(Hit.Parent.Name)
	
	if Player then
		if PlayerEntering then return end
		
		CheckPlayerInside = BusHandler:CheckPlayerListed(PlayersInside, Player) --returns true or false
		
		if not CheckPlayerInside then -- Add Player
			PlayerEntering = true
			PlayersInside = BusHandler:AddPlayer(PlayersInside, Player)
			TeleportPlayer(Player.Character, CheckPlayerInside)
			
		elseif CheckPlayerInside then -- Remove Player
			PlayerEntering = true
			PlayersInside = BusHandler:RemovePlayer(PlayersInside, Player)
			TeleportPlayer(Player.Character, CheckPlayerInside)
		end
	end
	
	wait(1)
	PlayerEntering = false
end

Trigger.Touched:Connect(AddPlayersToBus)

Currently, I implemented the wait(n) just to show that the solution work doing this way. but I want to avoid this and how?

2 Likes

Using a classic debounce wouldn’t be viable for this, as the values would keep swapping depending on who is on it. So I recommend using tables. A setup like this might work:

local playersTouching = {}


part.Touched:Connect(function(hit)
	if (hit.Parent:FindFirstChildOfClass("Humanoid")) then
		local player = game.Players:GetPlayerFromCharacter(hit.Parent)
		if (player) then
			if (not playersTouching[player] == player) then
				playersTouching[player] = player
				
				-- Code
				wait(1)
				playersTouching[player] = nil
			end
			
			
		end
	end
end)

The cleanest way would be to use the functions meant to handle tables, such as table.insert, table.remove and table.find, in my opinion.

Here’s an example:

local Debounces = {}

if (table.find(Debounces, Player.UserId)) -- Check if player is already in the table.
then return end -- Return end if they already exist.

table.insert(Debounces, Player.UserId) -- Add player.
table.remove(Debounces, table.find(Debounces, Player.UserId)) -- Remove player.
1 Like

I already use this on my module script

function busHandler:AddPlayer(PlayersTable, Player)
	local CurrentTable = PlayersTable
	table.insert(CurrentTable, Player.Name)
	return CurrentTable
end

function busHandler:RemovePlayer(PlayersTable, Player)
	local CurrentTable = PlayersTable
	local Check = table.find(CurrentTable, Player.Name)
	if Check then
		table.remove(CurrentTable, Check)
		return CurrentTable
	end
	
end

Then that’s good, I see no room for improvements if that’s what you already have.

It seems I didn’t quite portray a better explanation of the problem. As I said I need to find a way to prevent players from Listing and Un-listing immediately. Since I want the players to get inside and had to touch the door again to get out.

And I didn’t want to use delay or wait() to fix this since it is not consistent.

There’s nothing wrong with wait() in this case, it will work as intended if implemented correctly.

1 Like

Use a global debounce for both for listing and un-listing method. Don’t define it within the method but rather within the global scope of the script.

This still uses wait(n) :frowning:

this is my preferred method as I don’t use wait in script

local debounceTable = {}

local function coolDown(plr, second)
	if debounceTable[plr.UserId] == nil then
		debounceTable[plr.UserId] = os.time()

		return true
	else
		if os.time() - debounceTable[plr.UserId] >= second then
			debounceTable[plr.UserId] = os.time()

			return true
		else
			return false
		end
	end
end

if coolDown(Player, 1) then
	-- do staff here
else
	print("please wait for cooldown")
end

I tried making a delay on a module script so each bus can share it is this consistent?

local COUNT_DOWN_TIME = 0.5

local busHandler = {}

function busHandler:Cooldown(Event)
	delay(COUNT_DOWN_TIME, function()
		Event:Fire()
	end)
end

But why os.time(). It works but wait() is more than sufficient for this. Over complicating things, somewhat

I don’t see why it would cause any issues.
delay is used for, as the name implies, to delay the call of the function provided given for the given amount of seconds, without interrupting the current thread.

I read something on another thread that sometimes when using delay or wait() too much on a script it can throttle and produce weird unwanted bugs.

If there is a code after the wait function and that code must run without waiting
How do you do this with the wait function ?

Specially, for me is I have multiple bus to put in the game.

The safest approach here would be wait(n) as it will yield the current thread instead of running anything below in the meantime (such as delay).

But that doesn’t happen. A new thread is created when the function is called. It’ll still pause for a certain amount of time before setting the player within the player array to nil.

local playerList = {}



-- Function goes here but can stil be called even when waiting
if (not playerList[player] == player) then
	playerList[player] = player
	
	-- Code
	wait(2) -- Will wait
	playerList[player] = nil
end

have you tried my method?

30