Debounce by event, not by time

I’m trying to have the colors change every time a player steps on a brick. My current debounce uses time (1 second), however if the player moves around on the brick after 1 second the function triggers again.

local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")
local lighting = game.Lighting
local atmosphere = lighting:FindFirstChildWhichIsA("Atmosphere")

-- Settings
local debounceTime = 1 -- seconds between touches
local touchCooldown = {} -- player debounce tracker

-- Function to get a random bright rainbow color
local function getRandomRainbowColor()
	-- Hue 0–0.85 roughly covers red → violet (excludes pinks & browns)
	local hue = math.random() * 0.85
	return Color3.fromHSV(hue, 1, 1)
end

-- Apply color to environment + player + tagged parts
local function applyColor(player, color)
	-- Environment
	lighting.Ambient = color
	if workspace.Terrain:FindFirstChild("Clouds") then
		workspace.Terrain.Clouds.Color = color
	end
	if atmosphere then
		atmosphere.Color = color
	end

	-- All tagged rgbParts
	for _, part in pairs(CollectionService:GetTagged("rgbPart")) do
		if part:IsA("BasePart") then
			part.Color = color
		end
	end

	-- Player character
	local character = player.Character
	if character then
		for _, part in pairs(character:GetDescendants()) do
			if part:IsA("BasePart") then
				part.Color = color
			end
		end
	end
end

-- When player touches a touchPart
local function onTouch(hit, part)
	local character = hit.Parent
	local player = Players:GetPlayerFromCharacter(character)
	if not player then return end

	-- Time-based debounce
	if touchCooldown[player] and tick() - touchCooldown[player] < debounceTime then
		return
	end
	touchCooldown[player] = tick()

	-- Pick random vivid rainbow color
	local color = getRandomRainbowColor()
	print(player.Name .. " stepped on " .. part.Name .. " — random rainbow color chosen!")

	-- Apply color
	applyColor(player, color)
end

-- Connect all existing tagged parts
for _, part in pairs(CollectionService:GetTagged("touchPart")) do
	if part:IsA("BasePart") then
		part.Touched:Connect(function(hit)
			onTouch(hit, part)
		end)
	end
end

-- Connect new tagged parts added later
CollectionService:GetInstanceAddedSignal("touchPart"):Connect(function(newPart)
	if newPart:IsA("BasePart") then
		newPart.Touched:Connect(function(hit)
			onTouch(hit, newPart)
		end)
	end
end)

I solved this using Touched and TouchEnded and debouncing by Player(HumanoidRootPart) instead of the Player’s part (such as right leg). Working code below.

local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local lighting = game.Lighting
local atmosphere = lighting:FindFirstChildWhichIsA("Atmosphere")

-- Track which parts the player's HumanoidRootPart is touching
local touchingParts = {}

-- Random bright rainbow color
local function getRandomRainbowColor()
	local hue = math.random() * 0.85 -- ROYGBIV
	return Color3.fromHSV(hue, 1, 1)
end

-- Apply color locally
local function applyColor(player, color)
	lighting.Ambient = color
	if workspace.Terrain:FindFirstChild("Clouds") then
		workspace.Terrain.Clouds.Color = color
	end
	if atmosphere then
		atmosphere.Color = color
	end

	for _, part in pairs(CollectionService:GetTagged("rgbPart")) do
		if part:IsA("BasePart") then
			part.Color = color
		end
	end

	local character = player.Character
	if character then
		for _, part in pairs(character:GetDescendants()) do
			if part:IsA("BasePart") then
				part.Color = color
			end
		end
	end
end

-- Only trigger on HumanoidRootPart touches
local function onTouch(hit, part)
	local character = hit.Parent
	local player = Players:GetPlayerFromCharacter(character)
	if not player then return end

	local hrp = character:FindFirstChild("HumanoidRootPart")
	if hit ~= hrp then
		return -- ignore touches from other parts
	end

	-- If already touching this brick, ignore
	if touchingParts[hrp] and touchingParts[hrp][part] then
		return
	end

	touchingParts[hrp] = touchingParts[hrp] or {}
	touchingParts[hrp][part] = true

	-- Pick random rainbow color
	local color = getRandomRainbowColor()
	applyColor(player, color)
	print(player.Name .. " stepped on " .. part.Name .. " — color changed!")

	-- Reset when HumanoidRootPart leaves the part
	local connection
	connection = part.TouchEnded:Connect(function(endedPart)
		if endedPart == hrp then
			touchingParts[hrp][part] = nil
			connection:Disconnect()
		end
	end)
end

-- Connect all existing touchParts
for _, part in pairs(CollectionService:GetTagged("touchPart")) do
	if part:IsA("BasePart") then
		part.Touched:Connect(function(hit)
			onTouch(hit, part)
		end)
	end
end

-- Connect newly tagged parts dynamically
CollectionService:GetInstanceAddedSignal("touchPart"):Connect(function(newPart)
	if newPart:IsA("BasePart") then
		newPart.Touched:Connect(function(hit)
			onTouch(hit, newPart)
		end)
	end
end)

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.