How can I make my Obby checkpoints play a sound to only the local player?

I want players to be able to step on the checkpoint and it play a sound only to them. And then once they’ve touched that checkpoint once, they can’t press it again. (If they are on stage 3, they can’t re-trigger stage 1 or 2’s sound)

My issue is the sound plays globally and if one player triggers the sound, nobody else can. I have the script for each checkpoint within the checkpoint’s “Part” and I’m sure that’s the main problem. I’m very new to scripting. I’ve tried making the checkpoints have basically have a debounce that only allows for 1 press, but that press is basically triggered for everyone no matter who stepped on it.

I’ve searched dozens of posts but non are really my exact issue. It’s all mostly regarding a checkpoint that only triggers once. I’ve achieved that now I just need advice handling this sound issue as I’m sure that it’s just something I haven’t learned yet or overlooked.

local played = false
local completed = 0

script.Parent.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") and played == false then
		local player = game.Players:GetPlayerFromCharacter(hit.Parent)
		if game.Players:GetPlayerFromCharacter(hit.Parent) and player.leaderstats.Stage.Value < 1 then
			local Sound = game.Workspace.Sounds.CheckPoint:Clone()
			Sound.Parent = player.PlayerGui
			Sound:Play()
			played = true
			completed = 1
			
		end
	end
end)

Thanks in advance for any and all help/advice!

Hello! Just create a local script in StarterGUI and do this:

local plr = game.Players.LocalPlayer
local Debounce = false

for _,v in pairs(Yourcheckpointsfolder:GetChildren()) do
v.Touched:Connect(function(hit)
if hit.Parent == plr.Character and Debounce == false then
local sound = script.sound:Clone()
sound.Parent = plr.PlayerGui
sound:Play()
Debounce = true
task.wait(1)
Debounce = false
--Have not tested this, wrote all of it on devforum, lmk if it works
end)

I’m only just learning about fireserver/fireclient. I kind of get what you’re saying but I’m unsure where I’m putting this LocalScript at in order to utilize this.

I’ll give this a shot and get back to you on how it goes.

edit: It didn’t seem to work unfortunately.

Rip. Are there any errors in the output?

make a remoteevent in replicatedstorage, then make a localscript in StarterGUI

local remoteevent = game.ReplicatedStorage.RemoteEvent 
remoteevent.OnClientEvent:Connect(function() -- "onclientevent" means that if this remoteevent is fired on the server and this client is in the param, it will do this function
	local sound = game.Workspace.Sounds.CheckPoint:Clone()
	sound.Parent = game.SoundService
	sound:Play()
end)

and then change the serverscript to

local played = false
local completed = 0

script.Parent.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") and played == false then
		local player = game.Players:GetPlayerFromCharacter(hit.Parent)
		if game.Players:GetPlayerFromCharacter(hit.Parent) and player.leaderstats.Stage.Value < 1 then
			game.ReplicatedStorage.RemoteEvent:FireClient(player)
			played = true
			completed = 1
			
		end
	end
end)

(P.S you’ll have to do something with the whole “played = true” and “completed = 1” to make it work on the client instead of the server, since i think it’s your whole debounce system of whether or not to play the sound again) The reason it plays for everyone is due to the fact it’s a serverscript, so it counts for the WHOLE server, whenever that code is activated. aka, someone touches the checkpoint, then completed = 1 applies to everyone. hope that makes sense. you should put the “completed” and “played” values in the player themself to avoid that issue.

I will try this when I get back to working on it. I had to take a break as I’ve been stuck trying to figure this out for over 4 hours now and got a headache. Thank you and I will edit this with the outcome when I implement it! Also do you mean putting a stringvalue into the player? Make the script check if the stringvalue meets the requirements before working? I haven’t gotten to use values into players yet I’ve only heard about it being a thing.

for what you’re doing, I’d just use a numbervalue, but in a way, you already have. I’d just say to remove the whole “if played == false” and make it check if the player’s stage value < 1 instead, and then replace the whole “completed = 1” and “played = true” with

player.leaderstats.Stage.Value = 1

Sorry if that’s all confusing, but what I’m saying is that I’d just replace the whole thing with (and this is including the remoteevent thing I said as a solution to the sound playing globally, so make sure you remember to make the localscript plus put the remoteevent in replicatedstorage)

local played = false
local completed = 0

script.Parent.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") and player.leaderstats.Stage.Value < 1 then
		local player = game.Players:GetPlayerFromCharacter(hit.Parent)
		if game.Players:GetPlayerFromCharacter(hit.Parent) and player.leaderstats.Stage.Value < 1 then
			game.ReplicatedStorage.RemoteEvent:FireClient(player)
			player.leaderstats.Stage.Value = 1
			
		end
	end
end)

I’ll be giving this a try shortly thank you for continuously trying to help I appreciate it!