Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

How do I prevent a scriptable camera from being laggy? Please Help

So I've been working on a game where you control a ball, and I've had a serious problem for several months now. I've been ignoring it so I can finish the overall gameplay for the game, but now that I'm done with the gameplay I can't continue because of this.

Script for ball movement:

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local left = false
local right = false
local up = false
local down = false
local bVel = nil
local rDown = false
local xVel = 0
local zVel = 0
local functions = require(Workspace.CoreFunctions)
local runService = game:GetService("RunService")


--Don't call "Enum.KeyCode" everytime a key is pressed
local keyCode = Enum.KeyCode

--[[       0.1 - 0.5 = Heavy Friction;     0.5 - 0.9 Low Friction]]
local friction = .9
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Health, false)
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)
--game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, false)
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Chat, false)
--game.StarterGui:SetCore("TopbarEnabled",true)
local keys = game:GetService("UserInputService")
local step = game:GetService("RunService")

--[[
player.CharacterAdded:connect(function()
	wait()
	player.Character:WaitForChild("Torso").Anchored = true
	--player.Character.Parent = game.Lighting
	for i,v in pairs(game.Workspace:GetChildren())do
		if v.Name == "Ball" then
			if v:FindFirstChild('Owner') then
				if v.Owner.Value == player.Name then
					ball = v
					bVel = ball.BodyVelocity
				end
			end
		end
	end
end)
]]

wait(.5)
local ball = functions.findBall(player)


keys.InputBegan:connect(function(key)
	if player.PlayerGui.ChatHolder.ChatBar.Visible == false and player.PlayerGui.Spectating.Value == false then
		k = key.KeyCode
		if k == keyCode.Left or k == keyCode.A then
		left = true
		
		
		elseif k == keyCode.Right or k == keyCode.D then
			right = true
	

		elseif k == keyCode.Up or k == keyCode.W then
			up = true
	
		
		elseif k == keyCode.Down or k == keyCode.S then
			down = true
		end
	end
end)


keys.InputEnded:connect(function(key)
	k = key.KeyCode
	keyDown = false
	if k == keyCode.Left or k == keyCode.A then
		left = false

	
	elseif k == keyCode.Right or k == keyCode.D then
		right = false

	
	elseif k == keyCode.Up or k == keyCode.W then
		up = false

	
	elseif k == keyCode.Down or k == keyCode.S then
		down = false
	end
end)



while ball == nil do
	wait()
end





function onRenderStep()
	xVel = xVel * friction
	zVel = zVel * friction
	ball.BodyVelocity.velocity = Vector3.new(xVel,0,zVel)
		
		if left then
			zVel = zVel - 5
		end
		
		if right then
			zVel = zVel + 5
		end
		
		if up then
			xVel = xVel + 5
		end
		
		if down then
			xVel = xVel - 5
		end

end

runService:BindToRenderStep("Controls",Enum.RenderPriority.Camera.Value, onRenderStep)


Script for camera movement:

local player = game.Players.LocalPlayer
--local ball = nil
local functions = require(Workspace.CoreFunctions)
local specBall = nil
local runService = game:GetService("RunService")
--[[
player.CharacterAdded:connect(function()
	wait()
	for i,v in pairs(game.Workspace:GetChildren())do
		if v.Name == "Ball" then
			if v:FindFirstChild('Owner') then
				if v.Owner.Value == player.Name then
					ball = v
				end
			end
		end
	end	
end)
]]

wait(.5)
local ball = functions.findBall(player)
local pos = nil

while ball == nil do
	wait()
end


local cam = game.Workspace.CurrentCamera
cam.CameraType = "Scriptable"
--Camera subject is useless here
--cam.CameraSubject = ball
cam.CoordinateFrame = CFrame.new(ball.Position + Vector3.new(0,50,0))
local target = script:WaitForChild("CamTarget")



--[[
runService.RenderStepped:connect(function()
	if target.Value == "ball" then
		local campos = cam.CoordinateFrame.p:Lerp(ball.Position + Vector3.new(0,50,0),0.10)
		cam.CoordinateFrame = CFrame.new(campos,ball.Position)
	elseif target.Value ~= "ball" then
		if specBall == nil then
			specBall = functions.findBall(game.Players:FindFirstChild(target.Value))
		end
		cam:Interpolate(specBall.CFrame*CFrame.Angles(12,210,31),specBall.CFrame, .3)
		cam.CoordinateFrame = CFrame.new(specBall.Position + Vector3.new(0,50,0))
	end
end)
]]

local offset = Vector3.new(0,50,0)

function onRenderStep()
	if target.Value == "ball" then
		--[[
		pos = CFrame.new(ball.Position) + Vector3.new(0,50,0)
		cam:Interpolate(ball.CFrame, ball.CFrame,.2)
		cam.CoordinateFrame = pos
		]]
		
		local ballPos = ball.Position
		local camPos = (ballPos) + offset
		cam.CoordinateFrame = CFrame.new(camPos,ballPos)
		
		
	elseif target.Value ~= "ball" then
		if specBall == nil then
			specBall = functions.findBall(game.Players:FindFirstChild(target.Value))
		end
		cam:Interpolate(specBall.CFrame*CFrame.Angles(12,210,31),specBall.CFrame, .3)
		cam.CoordinateFrame = CFrame.new(specBall.Position + Vector3.new(0,50,0))
	end
end

runService:BindToRenderStep("Camera",Enum.RenderPriority.Camera.Value, onRenderStep)

As you can see in the scripts I'm using RenderStepped for the movement, and HeartBeat for the camera(The camera won't interpolate correctly with RenderStepped). The camera will run smoothly if you're by yourself(about 80% of the time) but if you are playing with someone else and you get near them during the "match" the lag skyrockets. If you can't tell why this is happening based on the code can you at least tell me why you think this might be happening. I'm very desperate and will take any and all advice right now. The kind of lag that happens is sort of "input lag", where when you press down on a key the response is a little slower, and at the same time there is what I think is camera movement lag. The camera starts to be slightly behind the ball and kind of bounces.

Here's the place: Freeze Tag

tl:dr PLEASE HELP ME WITH THIS. I AM SO DESPERATE

This was edited on 3/10/16

2 comments

1

Any chance that the lag is not caused by the camera?

0

I don't think it's the camera's fault, it's just that the camera just starts falling behind for some reason. I think there might be something else causing that.

1 answer

It looks like you want the Camera to hover 50 studs above the target. If so...

  1. The "angle" of the CFrame doesn't matter when you're using :Interpolate() -- only its position is used.

  2. You're calling :Interpolate() 30 times a second (heartbeat runs at approximately 30 hz), when you should preferrably only call it once.

  3. Since the object (the ball/target/whatever) moves, you probably shouldn't be using :Interpolate() at all. It would be preferrable to set the Camera's CoordinateFrame every frame (RenderStepped).

Anyway, here's my version of your second script, with your comments removed and my comments added.

local player = game.Players.LocalPlayer
local functions = require(game.Workspace.CoreFunctions)
local specBall = nil
local runService = game:GetService("RunService")

wait(.5)
local ball = functions.findBall(player)

while ball == nil do
    wait()
	ball = functions.findBall(player) -- you may want to retry looking for the ball every wait()
end

local cam = game.Workspace.CurrentCamera
cam.CameraType = "Scriptable"
--cam.CameraSubject = ball -- CameraSubject (along with Focus) is useless when the CameraType is set to "Scriptable."
cam.CoordinateFrame = CFrame.new(ball.Position + Vector3.new(0,50,0), ball.Position) -- fixed. This way, the camera starts 50 studs above the ball, looking at the ball already
--cam.Focus = CFrame.new(ball.Position) -- ditto
local target = script:WaitForChild("CamTarget")

local CurrentTarget = target.Value == "ball" and ball or functions.findBall(game.Players:FindFirstChild(target.Value)) -- sets the camera's "focus" for the first time
target.Changed:connect(function(val) -- update the camera's "focus" when the target is changed 
	CurrentTarget = val == "ball" and ball or functions.findBall(game.Players:FindFirstChild(val))
end)

function UpdateCamera(dt) -- dt is a commmon programming idiom for "Delta Time", the time elapsed between the last frame and the current frame. It's not useful in this case, however.
	if not CurrentTarget then return end -- make sure CurrentTarget is actually there or else the script will error
	local campos = cam.CoordinateFrame.p:Lerp(CurrentTarget.Position + Vector3.new(0, 50, 0), 0.10) -- every frame, the camera is a tenth of the way closer to the target. 
	-- Since RenderStepped is 60 hz, the transition should be smooth and would take less than a second.
	cam.CoordinateFrame = CFrame.new(campos, CurrentTarget.Position) -- sets the camera's CoordinateFrame
end

runService.RenderStepped:connect(UpdateCamera) -- alternatively, you can use :BindToRenderStepped()

8 comments

0

Alright. I'll try it out and get back to you. Thank you so much though.

0

Okay so I tried out what you said and it didn't work, but I did change some things. I'm keeping the interpolate, but I got rid of the renderStepped. I was thinking that using a renderStepped for calling the interpolation was a bit much. So now it's "while wait(.05) do". It looks like that got rid of some of the choppyness. I noticed that if I disable the camera script while there was lag so the ca

0

Did my script not run at all or did it just not solve your lag problem?

0

It did run but it acted a little weird if the ball is moving too fast. The camera would completely "flip" kinda. The lag was still there though

0

I understand. Thanks for getting back to me.

0

Try this instead (remove the campos variable since it's unnecessary, replace line 30 from my original script): cam.CoordinateFrame = CFrame.new(CurrentTarget.Position + Vector3.new(0, 50, 0), CurrentTarget.Position)

1

Oh sorry I didn't see your message. I don't think I'm going to try it, but only because I've come to the conclusion that the lag isn't from the camera. Thanks for everything though. I have implemented some of the things that you suggested.

0

ok, thanks.

This discussion is preserved as it was. New answers, comments, and votes are closed.