Help with spectate script

  1. What do you want to achieve?
    Up until a few months ago, my spectate script worked perfectly fine. Now when a player moves their screen using the trackpad/mouse (on any device) while spectating another player, their view resets back to their own character.

  2. What is the issue?
    In this video, I use the spectate feature in my game. When I use my mouse to maneuver the camera view, my view resets. When I move the camera around using the arrow keys, my view does not reset.

  1. What solutions have you tried so far?
    I am unsure how to proceed with this and I don’t think any forums on here directly solve my problem. I tried the AI Assistant feature but that wasn’t any help. Any help or feedback would be appreciated!

The spectate script (located in StarterGui):

local toggle = script.Parent.Toggle
local frame = script.Parent.SpectateFrame
local previous = frame.Prev
local next = frame.Next
local status = frame.Status.CurrentPlayer
local camera = game.Workspace.CurrentCamera
local num = 1

status.Text = game.Players.LocalPlayer.Name

toggle.MouseButton1Click:Connect(function()
	frame.Visible = frame.Visible
end)

previous.MouseButton1Click:Connect(function()
	local players = game.Players:GetChildren()
	local max = #players
	num = num - 1
	if num < 1 then
		num = max
	end
	local player = players[num]
	camera.CameraSubject = player.Character.Humanoid
	status.Text = player.Name
end)

next.MouseButton1Click:Connect(function()
	local players = game.Players:GetChildren()
	local max = #players
	num = num + 1
	if num > max then
		num = 1
	end
	local player = players[num]
	camera.CameraSubject = player.Character.Humanoid
	status.Text = player.Name
end)

frame.Changed:Connect(function()
	if frame.Visible then
		local A =pcall(function()
		camera.CameraSubject = game.Players.LocalPlayer.Character.Humanoid
		status.Text = game.Players.LocalPlayer.Name
		end)
		local B
		if not A then repeat 
				task.wait()
				B = pcall(function()
					camera.CameraSubject = game.Players.LocalPlayer.Character.Humanoid
					status.Text = game.Players.LocalPlayer.Name
				end)
			until
			B
		end
	end
end)

Screenshot 2024-03-22 213924

GuiObjects have a property called GuiState that changes based on user inputs. This is the state causing issues for you: Press. This state, in your case, occurs when a player presses down on their mouse button(s) while the mouse’s location is over the frame. Due to this state changing, the Changed event is triggered and therefore resets the CameraSubject back to LocalPlayer's humanoid. If you need to know when a certain property is changed, you can use :GetPropertyChangedSignal() instead of Changed.

Thanks for responding! After implementing your suggestion into the code, the camera isn’t resetting when I move my mouse but it did create another issue.

Previously, pressing the spectate button a second time to un-toggle would reset the player’s view, but now, my camera is still stuck on the player I was spectating. There is a workaround for this, which is to use the buttons to switch back to myself. However, it is a tad inconvenient and might not be an obvious solution for everyone.

I tried to add a spectating variable to track when spectating mode is active, but that did more harm than help. Would you have any suggestions to fix this as well?

local toggle = script.Parent.Toggle
local frame = script.Parent.SpectateFrame
local previous = frame.Prev
local next = frame.Next
local status = frame.Status.CurrentPlayer
local camera = game.Workspace.CurrentCamera
local num = 1

status.Text = game.Players.LocalPlayer.Name

toggle.MouseButton1Click:Connect(function()
	frame.Visible = frame.Visible
end)

previous.MouseButton1Click:Connect(function()
	local players = game.Players:GetChildren()
	local max = #players
	num = num - 1
	if num < 1 then
		num = max
	end
	local player = players[num]
	camera.CameraSubject = player.Character.Humanoid
	status.Text = player.Name
end)

next.MouseButton1Click:Connect(function()
	local players = game.Players:GetChildren()
	local max = #players
	num = num + 1
	if num > max then
		num = 1
	end
	local player = players[num]
	camera.CameraSubject = player.Character.Humanoid
	status.Text = player.Name
end)

frame:GetPropertyChangedSignal("GuiState"):Connect(function()
	if frame.Visible and frame.GuiState == Enum.GuiState.Opened then
		local A =pcall(function()
		camera.CameraSubject = game.Players.LocalPlayer.Character.Humanoid
		status.Text = game.Players.LocalPlayer.Name
		end)
		local B
		if not A then repeat 
				task.wait()
				B = pcall(function()
					camera.CameraSubject = game.Players.LocalPlayer.Character.Humanoid
					status.Text = game.Players.LocalPlayer.Name
				end)
			until
			B
		end
	end
end)

Of course! Since you’re tweening the frame (I assume from the video), let’s just use a variable to define whenever the player is spectating. Whenever the player clicks the toggle button, we will inverse the value of the variable (true would be set to false and vice versa). We then check if this variable is true, and if it is, we initiate the spectating by retrieving the player at the first index (the num variable) of the player’s list and setting the CameraSubject to their humanoid. However, if the variable is false, we will just set the CameraSubject back to LocalPlayer's humanoid and reset the index (num variable) back to 1 for when spectating is active again.

local spectating = false

toggle.MouseButton1Click:Connect(function()
	spectating = not spectating -- toggles the value (true-> false / false-> true)
	
	if spectating then
		-- this player has started spectating
		local plr = players[num]
		camera.CameraSubject = plr.Character.Humanoid
		status.Text = plr.Name
		
		-- tween the frame up
	else
		-- this player is no longer spectating
		camera.CameraSubject = player.Character.Humanoid
		status.Text = player.Name
		num = 1 -- we also want to reset the index back to 1
		
		-- tween the frame down
	end
end

This also gets rid of the need for the PropertyChangedSignal event, as the function above does everything that the function connected to PropertyChangedSignal did. The final code would look like this:

local players = game:GetService("Players")
local player = players.LocalPlayer
local frame = script.Parent.SpectateFrame
local previous = frame.Prev
local next = frame.Next
local status = frame.Status.CurrentPlayer
local camera = game.Workspace.CurrentCamera
local spectating = false -- we default it to false

toggle.MouseButton1Click:Connect(function()
	spectating = not spectating -- toggles the value (true-> false / false-> true)
	
	if spectating then
		-- this player has started spectating
		local plr = players[num]
		camera.CameraSubject = plr.Character.Humanoid
		status.Text = plr.Name
		
		-- tween the frame up
	else
		-- this player is no longer spectating
		camera.CameraSubject = player.Character.Humanoid
		status.Text = player.Name
		num = 1 -- we also want to reset the index back to 1
		
		-- tween the frame down
	end
end

previous.MouseButton1Click:Connect(function()
	local players = game.Players:GetChildren()
	local max = #players
	num = num - 1
	if num < 1 then
		num = max
	end
	local player = players[num]
	camera.CameraSubject = player.Character.Humanoid
	status.Text = player.Name
end)

next.MouseButton1Click:Connect(function()
	local players = game.Players:GetChildren()
	local max = #players
	num = num + 1
	if num > max then
		num = 1
	end
	local player = players[num]
	camera.CameraSubject = player.Character.Humanoid
	status.Text = player.Name
end)

If you have any more questions, let me know. :slight_smile:

Thanks again for your response! I implemented the modified version of the code you provided, but unfortunately, there are some issues. The player’s name doesn’t appear on the spectate GUI and I am unable to switch views.

I attempted to modify part of the code. It displays the player’s names but I’m still having trouble switching views.

local toggle = script.Parent.Toggle
local players = game:GetService("Players")
local player = players.LocalPlayer
local frame = script.Parent.SpectateFrame
local previous = frame.Prev
local next = frame.Next
local status = frame.Status.CurrentPlayer
local camera = game.Workspace.CurrentCamera
local spectating = false -- we default it to false

status.Text = game.Players.LocalPlayer.Name

toggle.MouseButton1Click:Connect(function()
	spectating = not spectating -- toggles the value (true-> false / false-> true)

	if spectating then
		-- this player has started spectating
		local plr = players[num]
		camera.CameraSubject = plr.Character.Humanoid
		status.Text = plr.Name

		-- tween the frame up
	else
		-- this player is no longer spectating
		camera.CameraSubject = player.Character.Humanoid
		status.Text = player.Name
		num = 1 -- we also want to reset the index back to 1

		-- tween the frame down
	end
end)

previous.MouseButton1Click:Connect(function()
	local players = game.Players:GetChildren()
	local max = #players
	num = num - 1
	if num < 1 then
		num = max
	end
	local player = players[num]
	camera.CameraSubject = player.Character.Humanoid
	status.Text = player.Name
end)

next.MouseButton1Click:Connect(function()
	local players = game.Players:GetChildren()
	local max = #players
	num = num + 1
	if num > max then
		num = 1
	end
	local player = players[num]
	camera.CameraSubject = player.Character.Humanoid
	status.Text = player.Name
end)

Oops, my bad. I forgot to define num as a variable in the final code. I also realized another mistake that I made. Try replacing it with this:

local toggle = script.Parent.Toggle
local players = game:GetService("Players")
local player = players.LocalPlayer
local frame = script.Parent.SpectateFrame
local previous = frame.Prev
local next = frame.Next
local status = frame.Status.CurrentPlayer
local camera = game.Workspace.CurrentCamera
local spectating = false -- we default it to false
local num = 1 -- default index is 1

status.Text = game.Players.LocalPlayer.Name

toggle.MouseButton1Click:Connect(function()
	spectating = not spectating -- toggles the value (true-> false / false-> true)

	if spectating then
		-- this player has started spectating
        local plrs = players:GetPlayers()
		local plr = plrs[num]
		camera.CameraSubject = plr.Character.Humanoid
		status.Text = plr.Name

		-- tween the frame up
	else
		-- this player is no longer spectating
		camera.CameraSubject = player.Character.Humanoid
		status.Text = player.Name
		num = 1 -- we also want to reset the index back to 1

		-- tween the frame down
	end
end)

previous.MouseButton1Click:Connect(function()
	local plrs = players:GetPlayers()
	local max = #plrs
	num = num - 1
	if num < 1 then
		num = max
	end
	local player = plrs[num]
	camera.CameraSubject = player.Character.Humanoid
	status.Text = player.Name
end)

next.MouseButton1Click:Connect(function()
	local plrs = players:GetPlayers()
	local max = #plrs
	num = num + 1
	if num > max then
		num = 1
	end
	local player = plrs[num]
	camera.CameraSubject = player.Character.Humanoid
	status.Text = player.Name
end)

It worked, thanks for your help!

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