The problem: I have a spectate script with an ‘auto spectate’-mode, which will make the camera look at certain points and follow random players around. When following a player around in auto-spectate, the camera acts really jittery. I’ve tried many methods to fix the code, but I am still unable to fix it so I’m asking if someone can do it for me.
The code: you can find the code below. I know it looks like a lot, but it’s just the ‘SpectateMap’ function which doesn’t function properly.
while script.Parent.Parent.PlayerGui:findFirstChild("ScreenGui")==nil do
wait()
end
function GetMapSpectateAngles()
local Table = {
CFrame.new(43.259758, 27.0027161, 81.7025681, 0.98601532, 0.130608171, -0.1035157, -0, 0.621136606, 0.783702433, 0.166655317, -0.772742629, 0.612450063),
CFrame.new(123.095901, 27.4490452, 10.6504364, 0.255268425, -0.741772413, 0.620170712, -7.4505806e-009, 0.641420901, 0.767189205, -0.966870248, -0.195839182, 0.163734481),
CFrame.new(153.451706, 23.9135094, 21.0269623, 0.674503803, 0.558915854, -0.482346207, -0, 0.653345406, 0.757060111, 0.738271415, -0.510639906, 0.440683931)
}
-- make sure Table is filled up in some way with CFrame's which are stored somewhere in the map hierarchy
return Table
end
--------------------------------------- Initialise everything
local Cam = game.workspace.CurrentCamera
local AutoId = 0 -- don't mind this
CurrentIndex = 1
RunnerColor = "Bright blue"
KillerColor = "Bright red"
PreviousSpectateMode = nil
CurrentSpectateMode = nil
--MapSpectatePoints = {Vector3.new(0, 0, 0)} -- this should be filled with Vector3's for map spectate angles
local SpectateOrder = {}
local P = game.Players:GetPlayers()
for i = 1, #P do
if P[i].Name~=script.Parent.Parent.Name and (P[i].TeamColor.Name == RunnerColor or P[i].TeamColor.Name == KillerColor) then
SpectateOrder[#SpectateOrder+1] = P[i]
end
end
--SpectateOrder[#SpectateOrder+1] = unpack(GetMapSpectateAngles())
SpectateOrder[#SpectateOrder+1] = "AutoSpectate"
--------------------------------------- Functions
function SpectatePlayer(PlayerName)
game.workspace.CurrentCamera.CameraType = "Custom"
if game.Players:findFirstChild(PlayerName)~=nil then
local Plr = game.Players:findFirstChild(PlayerName)
if Plr.Character:findFirstChild("Humanoid")~=nil then
game.workspace.CurrentCamera.CameraSubject = Plr.Character.Humanoid
else
game.workspace.CurrentCamera.CameraSubject = script.Parent.Parent.Character.Humanoid
end
else
game.workspace.CurrentCamera.CameraSubject = script.Parent.Parent.Character.Humanoid
end
end
function FindTorso(Model)
local P = Model:GetChildren()
for i = 1, #P do
if P[i]:IsA("BasePart") then
if P[i].Size == Vector3.new(2, 2, 1) then
return P[i]
end
end
end
end
function SpectateMap(Obj)
print("testing")
game.workspace.CurrentCamera.CameraType = "Scriptable"
local SpectateModes = {"SpectateKiller", "SpectateRandomRunner", "SpectateBestAngle"}
MapSpectateCFrames = GetMapSpectateAngles()
local function GetSumRunnerDistanceToPoint(Vec)
local Sum = 0
local SampleSize = 0
local P = game.Players:GetPlayers()
for i = 1, #P do
print(1)
if P[i].TeamColor.Name == RunnerColor then
print(2)
if P[i].Character then
print(3)
local Tor = FindTorso(P[i].Character)
if Tor~=nil then
print(4)
Sum = Sum+(Tor.Position-Vec).magnitude
SampleSize = SampleSize+1
end
end
end
end
--print("ok", Sum, SampleSize)
return Sum, SampleSize
end
local PreviousSpectateMode = CurrentSpectateMode
repeat
local Done = false
CurrentSpectateMode = SpectateModes[math.random(1, #SpectateModes)]
if CurrentSpectateMode ~= PreviousSpectateMode then
Done = true
end
until Done == true
AutoId = AutoId+1
local Cur = AutoId
if CurrentSpectateMode == "SpectateKiller" then
local P = game.Players:GetPlayers()
local T = nil
for i = 1, #P do
if P[i].TeamColor.Name == KillerColor then
if P[i].Character then
T = FindTorso(P[i].Character)
end
end
end
if T == nil then
QuitSpectate()
end
local Distance = 24
local CF = T.CFrame
local Time = 3+math.random()*2
local Now = game.workspace.DistributedGameTime
CF = CF*CFrame.Angles(0, math.pi*2*math.random(), 0)*CFrame.Angles(math.pi/4*math.random(), 0, 0)*CFrame.new(0, 0, -Distance)
Cam.CoordinateFrame = CFrame.new(CF.X, CF.Y, CF.Z)
local CallAgain = false
while Cur == AutoId do
Cam.CoordinateFrame = CFrame.new(Cam.CoordinateFrame.p.X, Cam.CoordinateFrame.p.Y, Cam.CoordinateFrame.p.Z)
Cam.CoordinateFrame = CFrame.new(Cam.CoordinateFrame.p, T.Position)
local Dis = (Cam.CoordinateFrame.p-T.Position).magnitude
Cam.CoordinateFrame = Cam.CoordinateFrame*CFrame.new(0, 0, Distance-Dis)
game:GetService("RunService").Renderstepped:wait()
if game.workspace.DistributedGameTime-Time > Now then
AutoId = AutoId+1
CallAgain = true
end
end
if CallAgain == true then
Spectate(Obj)
end
elseif CurrentSpectateMode == "SpectateRandomRunner" then
local P = game.Players:GetPlayers()
local N = 0
for i = 1, #P do
N = N+1
if P[N].TeamColor.Name ~= RunnerColor then
table.remove(P, N)
N = N-1
end
end
if #P <= 0 then
QuitSpectate()
return
end
local T = nil
repeat
local Success = false
local R = P[math.random(1, #P)]
if R.Character then
if FindTorso(R.Character) then
T = FindTorso(R.Character)
Success = true
end
end
until Success == true
local Distance = 24
local CF = T.CFrame
local Time = 3+math.random()*2
local Now = game.workspace.DistributedGameTime
CF = CF*CFrame.Angles(0, math.pi*2*math.random(), 0)*CFrame.Angles(math.pi/4*math.random(), 0, 0)*CFrame.new(0, 0, -Distance)
Cam.CoordinateFrame = CFrame.new(CF.X, CF.Y, CF.Z)
local CallAgain = false
while Cur == AutoId do
Cam.CoordinateFrame = CFrame.new(Cam.CoordinateFrame.p.X, Cam.CoordinateFrame.p.Y, Cam.CoordinateFrame.p.Z)
Cam.CoordinateFrame = CFrame.new(Cam.CoordinateFrame.p, T.Position)
local Dis = (Cam.CoordinateFrame.p-T.Position).magnitude
Cam.CoordinateFrame = Cam.CoordinateFrame*CFrame.new(0, 0, Distance-Dis)
game:GetService("RunService").Heartbeat:wait()
if game.workspace.DistributedGameTime-Time > Now then
AutoId = AutoId+1
CallAgain = true
end
end
if CallAgain == true then
Spectate(Obj)
end
elseif CurrentSpectateMode == "SpectateBestAngle" then
local Distances = {}
for i = 1, #MapSpectateCFrames do
Distances[i] = GetSumRunnerDistanceToPoint((MapSpectateCFrames[i]*CFrame.new(0, 0, -20)).p)
end
local BestAngle = CFrame.new(0, 0, 0)
local Lowest = math.min(unpack(Distances))
for i = 1, #Distances do
if Distances[i] == Lowest then
BestAngle = MapSpectateCFrames[i]
end
end
local Time = 3+math.random()*2
local Now = game.workspace.DistributedGameTime
game.workspace.CurrentCamera.CoordinateFrame = BestAngle
local CallAgain = false
--print("f", Cur, AutoId)
while Cur == AutoId do
--print("g", Cur, AutoId)
game:GetService("RunService").Heartbeat:wait()
if game.workspace.DistributedGameTime-Time > Now then
AutoId = AutoId+1
CallAgain = true
--print("h")
end
end
--print("i", Cur, AutoId)
if CallAgain == true then
Spectate(Obj)
end
end
end
function Spectate(Obj)
if type(Obj)~="string" then
SpectatePlayer(Obj.Name)
else
SpectateMap(Obj)
end
end
function QuitSpectate()
AutoId = AutoId+1
game.workspace.CurrentCamera.CameraType = "Custom"
game.workspace.CurrentCamera.CameraSubject = script.Parent.Parent.Character.Humanoid
end
function ScrollSpectateList(Direction) -- Direction should be '1' if you want to spectate the next item, -1 for previous
AutoId = AutoId+1
print(#SpectateOrder, CurrentIndex, SpectateOrder[1], SpectateOrder[2], SpectateOrder[3])
--CurrentIndex = (CurrentIndex+Direction >= 1 and (math.fmod(CurrentIndex, #SpectateOrder)+Direction)) or #SpectateOrder
CurrentIndex = CurrentIndex+Direction
if CurrentIndex > #SpectateOrder then
CurrentIndex = 1
elseif CurrentIndex <= 0 then
CurrentIndex = #SpectateOrder
end
print(#SpectateOrder, CurrentIndex, SpectateOrder[1], SpectateOrder[2], SpectateOrder[3])
Spectate(SpectateOrder[CurrentIndex])
end
function EnterSpectate()
ScrollSpectateList(0)
end
--[[function AddPlayerToList(p)
table.insert(SpectateOrder, 1, p)
end]]
--[[function RemovePlayerFromList(p)
local Num = 1
for i = 1, #SpectateOrder do
if SpectateOrder[i] == p then
Num = i
end
end
table.remove(SpectateOrder, Num)
if Num >= CurrentIndex then
ScrollSpectateList(-1)
end
end]]
function ResetSpectateList()
print("Reset")
SpectateOrder = {}
local P = game.Players:GetPlayers()
for i = 1, #P do
if P[i]~=script.Parent.Parent.Name and (P[i].TeamColor.Name == RunnerColor or P[i].TeamColor.Name == KillerColor) then
SpectateOrder[#SpectateOrder+1] = P[i]
end
end
--SpectateOrder[#SpectateOrder+1] = unpack(GetMapSpectateAngles())
SpectateOrder[#SpectateOrder+1] = "AutoSpectate"
end
--------------------------------------- Player functions
local Players = game.Players:GetChildren()
for t = 1, #Players do
--AddPlayerToList(Players[t])
ResetSpectateList()
Players[t].CharacterAdded:connect(function(char)
char:WaitForChild("Humanoid").Died:connect(function()
--RemovePlayerFromList(Players[t])
ResetSpectateList()
end)
end)
Players[t].Changed:connect(function()
--print("a")
ResetSpectateList()
end)
end
game.Players.ChildAdded:connect(function(plr)
--AddPlayerToList(plr)
print("PlayerAdded!")
ResetSpectateList()
plr.CharacterAdded:connect(function(char)
char:WaitForChild("Humanoid").Died:connect(function()
--RemovePlayerFromList(plr)
ResetSpectateList()
end)
end)
plr.Changed:connect(function()
--print("a")
ResetSpectateList()
end)
end)
game.Players.PlayerRemoving:connect(function(plr)
--RemovePlayerFromList(plr)
ResetSpectateList()
end)
wait(.5)
ResetSpectateList()
--------------------------------------- Connectors
script.Parent.Parent.PlayerGui.ScreenGui.Left.MouseButton1Down:connect(function() ScrollSpectateList(-1) end)
script.Parent.Parent.PlayerGui.ScreenGui.Right.MouseButton1Down:connect(function() ScrollSpectateList(1) end)
script.Parent.Parent.PlayerGui.ScreenGui.Toggle.MouseButton1Down:connect(function()
if script.Parent.Parent.PlayerGui.ScreenGui.Toggle.Text == "Off" then
script.Parent.Parent.PlayerGui.ScreenGui.Toggle.Text = "On"
EnterSpectate()
else
script.Parent.Parent.PlayerGui.ScreenGui.Toggle.Text = "Off"
QuitSpectate()
end
end)
Other info: Copy and paste the code above into a LocalScript inside the ‘StarterPlayerScripts’. The problem is probably the ‘game:GetService(“RunService”).Heartbeat:wait()’ on line 178 and 208 and the RenderStepped on line 130. You will need at least 3 players in 3 different Teams to test this: ‘Bright blue’-team, ‘Bright red’-team and ‘White’-team. You will also need a Gui with TextButtons that looks like this to test the code:
My thanks in advance.