I shouldn’t have to explain what my spectate UI does, but I have an issue where attempting to spectate a player will just make the player’s camera get stuck in the last position the player was.
I haven’t been able to find any similar issues to mine (which is surprising because I feel like this is common, or I’m just overlooking it)
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
local GetActivePlayers = ReplicatedStorage.Storage.Remotes.ServerFunctions:WaitForChild("GetActivePlayers")
local gui = script.Parent
local container = gui:WaitForChild("Container")
local nextButton = gui:WaitForChild("Next")
local prevButton = gui:WaitForChild("Previous")
local headshot = container:WaitForChild("PlayerHeadshot")
local displayName = container:WaitForChild("DisplayName")
local userName = container:WaitForChild("UserName")
local healthLabel = container:WaitForChild("Health")
local activePlayers = {}
local index = 1
local currentTarget = nil
local function isValidPlayer(plr)
return plr
and plr.Parent == Players
and plr.Character
and plr.Character:FindFirstChildOfClass("Humanoid")
end
local function getHumanoid(plr)
if not plr or not plr.Character then return nil end
return plr.Character:FindFirstChildOfClass("Humanoid")
end
local function getHeadshot(plr)
local ok, result = pcall(function()
return Players:GetUserThumbnailAsync(
plr.UserId,
Enum.ThumbnailType.HeadShot,
Enum.ThumbnailSize.Size420x420
)
end)
return ok and result or ""
end
local function setSpectateTarget(plr)
if not isValidPlayer(plr) then return end
local hum = getHumanoid(plr)
if not hum then return end
camera.CameraType = Enum.CameraType.Custom
camera.CameraSubject = hum
currentTarget = plr
end
local function updateUI(plr)
if not plr then return end
local hum = getHumanoid(plr)
if not hum then return end
displayName.Text = plr.DisplayName
userName.Text = "@" .. plr.Name
healthLabel.Text = tostring(math.floor(hum.Health)) .. "%"
headshot.Image = getHeadshot(plr)
end
local function sanitizeList(list)
local cleaned = {}
for _, plr in ipairs(list) do
if isValidPlayer(plr) and plr ~= player then
table.insert(cleaned, plr)
end
end
return cleaned
end
local function applySpectate()
activePlayers = sanitizeList(activePlayers)
if #activePlayers == 0 then
local hum = player.Character and player.Character:FindFirstChildOfClass("Humanoid")
if hum then
camera.CameraType = Enum.CameraType.Custom
camera.CameraSubject = hum
end
displayName.Text = "No Players"
userName.Text = ""
healthLabel.Text = ""
headshot.Image = ""
currentTarget = nil
return
end
index = math.clamp(index, 1, #activePlayers)
local target = activePlayers[index]
if target ~= currentTarget then
setSpectateTarget(target)
end
updateUI(target)
end
local function nextPlayer()
if #activePlayers == 0 then return end
index = index + 1
if index > #activePlayers then
index = 1
end
applySpectate()
end
local function prevPlayer()
if #activePlayers == 0 then return end
index = index - 1
if index < 1 then
index = #activePlayers
end
applySpectate()
end
local function refreshActivePlayers()
local ok, result = pcall(function()
return GetActivePlayers:InvokeServer()
end)
if ok and typeof(result) == "table" then
activePlayers = sanitizeList(result)
else
activePlayers = {}
end
applySpectate()
end
RunService.RenderStepped:Connect(function()
if currentTarget and not isValidPlayer(currentTarget) then
currentTarget = nil
applySpectate()
end
end)
nextButton.MouseButton1Click:Connect(nextPlayer)
prevButton.MouseButton1Click:Connect(prevPlayer)
task.spawn(function()
while true do
refreshActivePlayers()
task.wait(2)
end
end)
refreshActivePlayers()