Need help with my jumpscare system!

  1. What do you want to achieve? Keep it simple and clear!
    -If a player touch a part, everyone in the server will get the jumpscare
  2. What is the issue? Include screenshots / videos if possible!
    -The jumpscare worked, but after that the camera of Player1 changed to Player2 camera. (the camera returned to wrong player)
  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub? -Yes
    -I also tried something with FireClient, FireAllClients and player.
    After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

this is the server script of the part

local debounce = false

local Players = game:GetService("Players")

local ghostCamera = workspace.Cameras.JumpscareCamera
local ghostAnim = script.Animation
local jumpscareDuration = 0.6
local dieAfter = false

script.Parent.Touched:connect(function(hit)
	if not debounce then
		debounce = true
		
		for _,player in ipairs(Players:GetPlayers()) do

			local JumpscareDummy = workspace.JumpscareDummy
			local dummyHum = JumpscareDummy.Humanoid
			local scare = JumpscareDummy.Head.scarysound
			
			local camRemote = game.ReplicatedStorage.ChangeCamera
			camRemote:FireAllClients(player,ghostCamera,jumpscareDuration)
			
			dummyHum:LoadAnimation(ghostAnim):Play() 
			scare:Play()
			
			wait(jumpscareDuration)
			if dieAfter then
				player.Character:BreakJoints()
			end
		end
		
		wait()

		script.Parent:Destroy()
		debounce = false
	end
end)

this is the local script in the StarterGUI

local camera = workspace.CurrentCamera

game.ReplicatedStorage.ChangeCamera.OnClientEvent:Connect(function(player,camera2,duration)	
	local character = player.Character
	
	camera.CameraType = "Scriptable"
	camera.CFrame = camera2.CFrame
	wait(1)
	camera.CameraSubject = character:WaitForChild("Humanoid")
	camera.CameraType = "Custom"
	camera.CFrame = character.Head.CFrame
end)

Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category. -Yes, I knew, any help would be appreciate!

3 Likes

Three things.

  1. You’re calling camRemote:FireAllClients() within a for-each player loop. This means that you’re firing all of the clients for each client in the server. Since FireAllClients already fires a signal to each client, you should have no need to nest it in the for loop that runs through all of the players. This also applies to the animation part. Given n is the amount of players currently in the server, you are playing the scare sound and ghostAnim animation a total of n times, which I don’t see the purpose of. You should only need to call it once. If I’m missing something and you’re trying to do something specific, let me know.

  2. The reason your camera is going to the wrong player is because you’re passing in a specific player in your FireAllClients() call and using it. Because of this, the variable character in your LocalScript refers to the player passed through the FireAllClients call (whichever player is the current player in your for loop) instead of the player local to that client.

  3. I see that you added a wait function in the for-each loop. The problem with this is that for each iteration, the code is yielded the specified amount of time, meaning when the script reaches the last player, it will have taken jumpscareDuration * (n-1) seconds, which I’m sure is not what you intended. I have combatted this with a task.spawn() approach.

Also, note that there is no need to set debounce back to false once you’ve already deleted the parent and established that the function is a one-and-done function.

Here is a suggested revamp of your scripts:

Server script:

local debounce = false

local Players = game:GetService("Players")

local ghostCamera = workspace.Cameras.JumpscareCamera
local ghostAnim = script.Animation
local jumpscareDuration = 0.6
local dieAfter = false

script.Parent.Touched:connect(function(hit)
	if not debounce then
		debounce = true
		
		local JumpscareDummy = workspace.JumpscareDummy
		local dummyHum = JumpscareDummy.Humanoid
		local scare = JumpscareDummy.Head.scarysound

		local camRemote = game.ReplicatedStorage.ChangeCamera
		camRemote:FireAllClients(ghostCamera,jumpscareDuration)

		dummyHum:LoadAnimation(ghostAnim):Play() 
		scare:Play()

		for _,player in ipairs(Players:GetPlayers()) do
			task.spawn(function()
				wait(jumpscareDuration)
				if dieAfter then
					player.Character:BreakJoints()
				end
			end)
		end

		task.wait()

		script.Parent:Destroy()
	end
end)

LocalScript:

local players = game:GetService("Players")

local player = players.LocalPlayer
repeat task.wait() until player.Character
local character = player.Character
local camera = workspace.CurrentCamera

game.ReplicatedStorage.ChangeCamera.OnClientEvent:Connect(function(camera2,duration)	
	camera.CameraType = "Scriptable"
	camera.CFrame = camera2.CFrame
	task.wait(1)
	camera.CameraSubject = character:WaitForChild("Humanoid")
	camera.CameraType = "Custom"
	camera.CFrame = character.Head.CFrame
end)

I cannot accurately test your scripts because, obviously, I don’t have access to your place or any of the other required assets in it, so there may be errors. If so, please let me know.

Hopefully this helped. If you have any questions or further issues, feel free to reach out.

1 Like

hello! I tested it out and the camera issued fixed, I thought the error
Player argument must be a player object will appear because I did something like this before, but it didn’t! However, I tried to mute sound from Player1 and I used Player2 to touch the part (player2’s volume was maxed), I didn’t hear the sound! Which I heard when I play-solo mode. Thanks for your help anyways!

I don’t understand what you mean. Could you send a video of the code in action?

1 Like

Don’t mind this I just need to fill 30 digits

1 Like

For this issue, I suggest you move the scare object sound into a folder called “Sounds” in the Workspace. Then, play the sound locally from the LocalScript once the ChangeCamera RemoteEvent is fired.

I have recreated your scenario in my own workspace.

Here is a picture of the Sounds folder in the workspace, containing a sound object.

image

Here is the updated LocalScript.

local players = game:GetService("Players")

local sounds = workspace:WaitForChild("Sounds")
local scarysound = sounds:WaitForChild("scarysound")

local player = players.LocalPlayer
repeat task.wait() until player.Character
local character = player.Character
local camera = workspace.CurrentCamera

game.ReplicatedStorage.ChangeCamera.OnClientEvent:Connect(function(camera2,duration)	
	camera.CameraType = "Scriptable"
	camera.CFrame = camera2.CFrame
	scarysound:Play()
	task.wait(1)
	camera.CameraSubject = character:WaitForChild("Humanoid")
	camera.CameraType = "Custom"
	camera.CFrame = character.Head.CFrame
end)

Sound replication and handling can especially be tricky when working with 3D sound.
The following article explains sound very thoroughly. I suggest you read this.
https://developer.roblox.com/en-us/api-reference/class/Sound

Also, are we okay with the camera going to the wrong player issue? Is that all fixed now?

If you have any other issues, let me know.

3 Likes

It still didn’t work! Player2 still can’t hear the sound.

Are there any errors in the output?

Nothing, it seems like only Player1 can hear it.

The camera issue seems OK now…

Delete the workspace folder with the sound inside it and try the following.

local players = game:GetService("Players")
local soundService = game:GetService("SoundService")
local sound = Instance.new("Sound")
sound.Parent = soundService
sound.SoundId = "rbxassetid://1836983505" --change this to id of sound

local player = players.LocalPlayer
repeat task.wait() until player.Character
local character = player.Character
local camera = workspace.CurrentCamera

game.ReplicatedStorage.ChangeCamera.OnClientEvent:Connect(function(camera2,duration)	
	camera.CameraType = "Scriptable"
	camera.CFrame = camera2.CFrame
	soundService:PlayLocalSound(sound)
	task.wait(1)
	camera.CameraSubject = character:WaitForChild("Humanoid")
	camera.CameraType = "Custom"
	camera.CFrame = character.Head.CFrame
end)
1 Like

Oh no! Maybe your solutions worked at first, I found out that whenever I tab out, the studio will be mute, so that’s why I thought I couldn’t hear the sound. Thank you so much!

Thank you too! I found out that the problem belongs to my side…