Hello! I’d like to know what’s wrong with my code. It’s generating spam when saving the player’s position, and I only want it to happen once when the platformArea is touched and when it’s touchedended.
script:
local platform = script.Parent.Parent.Platform
local platformArea = platform.platformArea
local checkpointParts = {
platform.Arrow,
platform.Part1,
platform.Part2,
platform.part3
}
local colorsToChange = {
Color3.fromRGB(255, 0, 0), -- Red
Color3.fromRGB(0, 255, 0), -- Green
Color3.fromRGB(0, 0, 255), -- Blue
Color3.fromRGB(255, 255, 0) -- Yellow
}
local defaultColor = Color3.fromRGB(192, 192, 192) -- Default color: Gray
-- SAVE DATA
local DataStoreService = game:GetService("DataStoreService")
-- Define the key to store the player's position in DataStore
local PLAYER_POSITION_KEY = "PlayerPosition"
-- Get the DataStore instance
local playerDataStore = DataStoreService:GetDataStore("PlayerDataStore")
-- Table to keep track of which players have already saved their position during the current touch event
local savedPositions = {}
-- Function to save the player's position in DataStore once, based on a specific part
local function savePlayerPositionOnce(player, basePart)
-- Check if the player's position has already been saved for this touch event
if savedPositions[player.UserId] then
return -- If position has already been saved, exit the function
end
-- Check if the basePart argument is a BasePart
if not basePart:IsA("BasePart") then
error("Argument 'basePart' must be a BasePart.")
end
-- Construct the key to store the player's position
local key = PLAYER_POSITION_KEY .. player.UserId
-- Get the position of the specified basePart
local position = basePart.Position
-- Convert Vector3 position to string
local positionString = table.concat({position.X, position.Y, position.Z}, ",")
-- Attempt to save the player's position in DataStore
local success, _ = pcall(function()
playerDataStore:SetAsync(key, positionString)
end)
-- Check if the saving operation was successful
if success then
print("Player position saved successfully for player: " .. player.Name)
-- Mark player's position as saved to prevent saving again for this touch event
savedPositions[player.UserId] = true
else
warn("Failed to save player position for player: " .. player.Name)
end
end
-- END SAVE DATA
local function changeColors(color)
for i, part in ipairs(checkpointParts) do
if part then
part.Color = color[i] or defaultColor -- Use the corresponding color or default color
end
end
end
platformArea.Touched:Connect(function(hit)
local character = hit.Parent
local player = game.Players:GetPlayerFromCharacter(character)
if player then
print("platformArea touched by player: " .. player.Name) -- Debug print
changeColors(colorsToChange)
savePlayerPositionOnce(player, platformArea)
end
end)
platformArea.TouchEnded:Connect(function()
print("platformArea touch ended") -- Debug print
changeColors({defaultColor, defaultColor, defaultColor, defaultColor}) -- Change all colors to default (gray)
-- Reset saved positions table for the next touch event
savedPositions = {}
end)
This looks like a debounce issue - the problem is that Touched will fire several times, and I think it’s the same with TouchEnded.
Usually the solution is just to add a debounce variable, check that variable, and then not do anything if you’re already within the Touched handler. There’s some Documentation around that here: Debounce Patterns | Documentation - Roblox Creator Hub
Right, I tried that, but it still keeps spamming. I think the debounce isn’t working properly.
local platform = script.Parent.Parent.Platform
local platformArea = platform.platformArea
local checkpointParts = {
platform.Arrow,
platform.Part1,
platform.Part2,
platform.part3
}
local colorsToChange = {
Color3.fromRGB(255, 0, 0), -- Red
Color3.fromRGB(0, 255, 0), -- Green
Color3.fromRGB(0, 0, 255), -- Blue
Color3.fromRGB(255, 255, 0) -- Yellow
}
local defaultColor = Color3.fromRGB(192, 192, 192) -- Default color: Gray
-- SAVE DATA
local DataStoreService = game:GetService("DataStoreService")
-- Define the key to store the player's position in DataStore
local PLAYER_POSITION_KEY = "PlayerPosition"
-- Get the DataStore instance
local playerDataStore = DataStoreService:GetDataStore("PlayerDataStore")
-- Table to keep track of which players have already saved their position during the current touch event
local savedPositions = {}
-- Function to save the player's position in DataStore once, based on a specific part
local function savePlayerPositionOnce(player, basePart)
-- Check if the player's position has already been saved for this touch event
if savedPositions[player.UserId] then
return -- If position has already been saved, exit the function
end
-- Check if the basePart argument is a BasePart
if not basePart:IsA("BasePart") then
error("Argument 'basePart' must be a BasePart.")
end
-- Construct the key to store the player's position
local key = PLAYER_POSITION_KEY .. player.UserId
-- Get the position of the specified basePart
local position = basePart.Position
-- Convert Vector3 position to string
local positionString = table.concat({position.X, position.Y, position.Z}, ",")
-- Attempt to save the player's position in DataStore
local success, _ = pcall(function()
playerDataStore:SetAsync(key, positionString)
end)
-- Check if the saving operation was successful
if success then
print("Player position saved successfully for player: " .. player.Name)
-- Mark player's position as saved to prevent saving again for this touch event
savedPositions[player.UserId] = true
else
warn("Failed to save player position for player: " .. player.Name)
end
end
-- END SAVE DATA
local function changeColors(color)
for i, part in ipairs(checkpointParts) do
if part then
part.Color = color[i] or defaultColor -- Use the corresponding color or default color
end
end
end
local debounceTime = 2 -- Tiempo de espera en segundos
local debounceActiveTouched = false -- Indica si el debounce para Touched está activo
local debounceActiveTouchEnded = false -- Indica si el debounce para TouchEnded está activo
platformArea.Touched:Connect(function(hit)
if debounceActiveTouched then
return
end
local character = hit.Parent
local player = game.Players:GetPlayerFromCharacter(character)
if player then
print("platformArea touched by player: " .. player.Name) -- Debug print
changeColors(colorsToChange)
savePlayerPositionOnce(player, platformArea)
end
debounceActiveTouched = true
wait(debounceTime)
debounceActiveTouched = false
end)
platformArea.TouchEnded:Connect(function()
if debounceActiveTouchEnded then
return
end
print("platformArea touch ended") -- Debug print
changeColors({defaultColor, defaultColor, defaultColor, defaultColor}) -- Change all colors to default (gray)
-- Reset saved positions table for the next touch event
savedPositions = {}
debounceActiveTouchEnded = true
wait(debounceTime)
debounceActiveTouchEnded = false
end)
I’d move your debounceActiveTouched right away to after you check it - the saving is going to take some time to run (specifically the SetAsync call) and that’s where the problems would be coming from here.
I am personally not a fan of TouchEnded, so I suggest using something like ZonePlus to handle player touching logic. Additionally, your debounce will block every player, is that really what you want?
Also I’m curious about that ZonePlus module - how efficient is it? I usually try avoiding those GetPartBoundsInBox methods because they seem pretty slow if you repeatedly use them. That’s a super useful module if it can run efficiently though.
local platform = script.Parent.Parent.Platform
local platformArea = platform.platformArea
local checkpointParts = {
platform.Arrow,
platform.Part1,
platform.Part2,
platform.part3
}
local colorsToChange = {
Color3.fromRGB(255, 0, 0), -- Red
Color3.fromRGB(0, 255, 0), -- Green
Color3.fromRGB(0, 0, 255), -- Blue
Color3.fromRGB(255, 255, 0) -- Yellow
}
local defaultColor = Color3.fromRGB(192, 192, 192) -- Default color: Gray
-- SAVE DATA
local DataStoreService = game:GetService("DataStoreService")
-- Define the key to store the player's position in DataStore
local PLAYER_POSITION_KEY = "PlayerPosition"
-- Get the DataStore instance
local playerDataStore = DataStoreService:GetDataStore("PlayerDataStore")
-- Table to keep track of which players have already saved their position during the current touch event
local savedPositions = {}
-- Function to save the player's position in DataStore once, based on a specific part
local function savePlayerPositionOnce(player, basePart)
-- Check if the player's position has already been saved for this touch event
if savedPositions[player.UserId] then
return -- If position has already been saved, exit the function
end
-- Check if the basePart argument is a BasePart
if not basePart:IsA("BasePart") then
error("Argument 'basePart' must be a BasePart.")
end
-- Construct the key to store the player's position
local key = PLAYER_POSITION_KEY .. player.UserId
-- Get the position of the specified basePart
local position = basePart.Position
-- Convert Vector3 position to string
local positionString = table.concat({position.X, position.Y, position.Z}, ",")
-- Attempt to save the player's position in DataStore
local success, _ = pcall(function()
playerDataStore:SetAsync(key, positionString)
end)
-- Check if the saving operation was successful
if success then
print("Player position saved successfully for player: " .. player.Name)
-- Mark player's position as saved to prevent saving again for this touch event
savedPositions[player.UserId] = true
else
warn("Failed to save player position for player: " .. player.Name)
end
end
-- END SAVE DATA
local debounceTime = 2 -- Tiempo de espera en segundos
local debounceActiveTouched = false -- Indica si el debounce para Touched está activo
local debounceActiveTouchEnded = false -- Indica si el debounce para TouchEnded está activo
local function changeColors(color)
for i, part in ipairs(checkpointParts) do
if part then
part.Color = color[i] or defaultColor -- Use the corresponding color or default color
end
end
end
local function handleTouch(hit, debounceFlag)
local character = hit.Parent
local player = game.Players:GetPlayerFromCharacter(character)
if player then
print("platformArea touched by player: " .. player.Name) -- Debug print
changeColors(colorsToChange)
savePlayerPositionOnce(player, platformArea)
end
debounceFlag = true
wait(debounceTime)
debounceFlag = false
end
platformArea.Touched:Connect(function(hit)
if debounceActiveTouched then
return
end
handleTouch(hit, debounceActiveTouched)
end)
platformArea.TouchEnded:Connect(function()
if debounceActiveTouchEnded then
return
end
print("platformArea touch ended") -- Debug print
changeColors({defaultColor, defaultColor, defaultColor, defaultColor}) -- Change all colors to default (gray)
-- Reset saved positions table for the next touch event
savedPositions = {}
debounceActiveTouchEnded = true
wait(debounceTime)
debounceActiveTouchEnded = false
end)
Okay instead of doing alla that let’s make this a little simpler using a table, that way you can also track what player is in the cooldown.
Your code is a little bit everywhere (not saying this as an insult but because I’m simply too tired to read all of it) so I’ll just hope this is easier to understand:
local DebounceTable = {}
platformArea.Touched:Connect(function(hit)
-- is it only supposed to work when players hit it? i'll assume so
if hit.Parent:FindFirstChildOfClass("Humanoid") then -- character
if not table.find(DebounceTable, hit.Parent.Name) then
table.insert(DebounceTable, hit.Parent.Name)
handleTouch(hit, debounceActiveTouched) -- idk how relevant this is so i wont touch it
end
end
end)
platformArea.TouchEnded:Connect(function(hit)
if hit.Parent:FindFirstChildOfClass("Humanoid") then
if table.find(DebounceTable, hit.Parent.Name) then
print("platformArea touch ended") -- Debug print
changeColors({defaultColor, defaultColor, defaultColor, defaultColor}) -- Change all colors to default (gray)
-- Reset saved positions table for the next touch event
savedPositions = {}
task.wait(debounceTime)
table.remove(DebounceTable, table.find(DebounceTable, hit.Parent.Name))
end
end
end)
though i will agree using touchended is bad cuz it sux but do wat u wanna do