Background:
Bear minimal objects. Just a player and a part (rectangular prism) that's floating in the air and anchored.
I honestly don't understand what is happening under the hood so its hard to figure out. Without debounce, upon event firing, the callback function is invoked by connect() or the event handler (not sure), and, without debouncing, the function is invoked multiple times as print statements are repeated on the output box. So, with a variable (of type boolean) that stores a debounce flag, that solves it. I then try to "un-debounce" when the player's model is outside out of the box's model. But, I don't know how to do that properly.
Here's my code attempt:
local box = game.Workspace.BoxModel;
local debounce = false;
local function onTouchedDebounced()
if (debounce == false)
then
debounce = true;
print("Hello! onTouchedDebounced() has run.");
box.Touched:Connect(onTouchedDebounced));
end
end
local function onTouchedUndebounced()
if (debounce == true)
then
print("Hello! onTouchedUndebounced() has run.");
debounce = false;
end
end
box.Touched:Connect(onTouchedDebounced);
box.TouchEnded:Connect(onTouchedUndebounced);
The heart of what you're doing is sound : start blocking after the first event, and unblock some time later. If this were with button presses or mouse-clicks, your solution would work fine. This is complicated by the Touched event, as it fires with any part that touches it, and a player's character could have multiple touch points.
The Touched and TouchEndeded events give you a reference to the instance that has touched the part.
If the goal is to only fire the box event once per player or once while anyone is touching it, you can keep a dictionary of parts that are currently touching the box. When a part touches, you increment a counter. When a part stops, you decrement it. You only remove the debounced flag once all touch points have been removed.
local Players = game:GetService("Players")
local box = game.Workspace.BoxModel
local playersTouching = {} --<string playerName, int totalParts>
local function onTouched(otherPart)
-- check that the thing that touched is a player
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if not player then
warn(otherPart.Name .. " isn't a child of a character. Exiting")
return
end
-- check whether this player is already touching the box
local playerName = player.Name
local total = playersTouching[playerName]
if total and total > 0 then
warn(playerName .. " is already touching the box")
playersTouching[playerName] = total + 1
return
end
-- handle a new player touching the box
playersTouching[playerName] = 1
-- Do a thing here that you only want to happen once per event...
print(string.format("%s has begun touching", playerName))
end
local function onTouchEnded(otherPart)
-- decrement the counter for this player
local playerName = otherPart.Parent.Name
if playersTouching[playerName] == nil then
return
end
local newTotal = playersTouching[playerName] - 1
playersTouching[playerName] = newTotal
-- if the total is back down to zero, clear the debounce flag
if newTotal == 0 then
playersTouching[playerName] = nil
print(string.format("%s has stopped touching", playerName))
end
end
box.Touched:Connect(onTouched)
box.TouchEnded:Connect(onTouchEnded)