How can I make my camera-tilting smoother?

Hi! I made this custom camera script for my RTS-Style game, I tried mimicking the camera from this video as much as possible (I am still working on the camera rotation though).

local UserInputService = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")
local Player = game.Players.LocalPlayer
local cam = game.Workspace.CurrentCamera
local mouse = Player:GetMouse()
local scrollspeed = 1
local rotateRatio = 20
local pressed = UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton2)
game.Workspace.Camera.FieldOfView = 70

--Zoom
local max = 80
local min = 7

local focusLevel = 20

-- place the camera high in the air, looking down at the ground
local startingPos = Vector3.new(0, 60, 50)
local angle = 60
local downwardLookAngle =  CFrame.Angles(-math.rad(angle), 0, 0)
cam.CFrame = CFrame.new(startingPos) * downwardLookAngle

-- create a function that moves the camera around
local moveDir = Vector3.new(0, 0, 0) -- we'll use this vector to control our movement
local moveSpeed = 0.5
spawn(function()
	while true do
		-- animate the camera movement
		local c = game.Workspace.CurrentCamera.CFrame
		game.Workspace.CurrentCamera.CFrame = CFrame.new(c.Position) * CFrame.new(moveDir) * downwardLookAngle
		wait(0.01)
	end
end)

-- create a function to handle keyboard inputs
local function onKeyPress(actionName, userInputState, inputObject)
	-- when a key is pressed, modify our moveDir vector so our camera moves

	-- W key input
	if actionName == "moveCameraForward" then
		if userInputState == Enum.UserInputState.Begin then
			moveDir = Vector3.new(moveDir.X, moveDir.Y, -moveSpeed)
		elseif userInputState == Enum.UserInputState.End then
			moveDir = Vector3.new(moveDir.X, moveDir.Y, 0)
		end

		-- A key input
	elseif actionName == "moveCameraLeft" then
		if userInputState == Enum.UserInputState.Begin then
			moveDir = Vector3.new(-moveSpeed, moveDir.Y, moveDir.Z)
		elseif userInputState == Enum.UserInputState.End then
			moveDir = Vector3.new(0, moveDir.Y, moveDir.Z)
		end

		-- S key input
	elseif actionName == "moveCameraBackward" then
		if userInputState == Enum.UserInputState.Begin then
			moveDir = Vector3.new(moveDir.X, moveDir.Y, moveSpeed)
		elseif userInputState == Enum.UserInputState.End then
			moveDir = Vector3.new(moveDir.X, moveDir.Y, 0)
		end

		-- D key input
	elseif actionName == "moveCameraRight" then
		if userInputState == Enum.UserInputState.Begin then
			moveDir = Vector3.new(moveSpeed, moveDir.Y, moveDir.Z)
		elseif userInputState == Enum.UserInputState.End then
			moveDir = Vector3.new(0, moveDir.Y, moveDir.Z)
		end
	end
end

-- Zoom in and zoom out
mouse.WheelForward:Connect(function() -- Zoom in
	if game.Workspace.CurrentCamera.CFrame.Y >= min or game.Workspace.CurrentCamera.CFrame.Y == min then
		game.Workspace.CurrentCamera.CFrame = CFrame.new(game.Workspace.CurrentCamera.CFrame.Position) * CFrame.new(0,-scrollspeed,0) * downwardLookAngle
	else
		-- Do nothing
	end
	scrollspeed = game.Workspace.CurrentCamera.CFrame.Y/10
	
	if game.Workspace.CurrentCamera.CFrame.Y <= focusLevel and angle >= 15 then
		--angle = angle - 5
		
		downwardLookAngle =  CFrame.Angles(-math.rad(angle), 0, 0)
	else
		--Do nothing again
	end
end)

mouse.WheelBackward:Connect(function() -- Zoom out
	if game.Workspace.CurrentCamera.CFrame.Y <= max or game.Workspace.CurrentCamera.CFrame.Y == max then
		game.Workspace.CurrentCamera.CFrame = CFrame.new(game.Workspace.CurrentCamera.CFrame.Position) * CFrame.new(0,scrollspeed,0) * downwardLookAngle
	else
		-- Do nothing
	end
	scrollspeed = game.Workspace.CurrentCamera.CFrame.Y/10

	if game.Workspace.CurrentCamera.CFrame.Y <= focusLevel and angle <= 60 then
		
		--angle = angle + 5
		
		downwardLookAngle =  CFrame.Angles(-math.rad(angle), 0, 0)
	else
		--Do nothing again
	end
end)

UserInputService.TouchPinch:Connect(function(touchPositions, scale, velocity, state, gameProcessedEvent)
	if game.Workspace.CurrentCamera.CFrame.Y <= max and game.Workspace.CurrentCamera.CFrame.Y >= min then
		game.Workspace.CurrentCamera.CFrame = CFrame.new(game.Workspace.CurrentCamera.CFrame.Position) * CFrame.new(0,scale,0) * downwardLookAngle
	else
		-- Do nothing
	end
end)

-- listen for keyboard input that moves the camera
game.ContextActionService:BindAction("moveCameraForward",  onKeyPress, false, Enum.KeyCode.W)
game.ContextActionService:BindAction("moveCameraLeft",     onKeyPress, false, Enum.KeyCode.A)
game.ContextActionService:BindAction("moveCameraBackward", onKeyPress, false, Enum.KeyCode.S)
game.ContextActionService:BindAction("moveCameraRight",    onKeyPress, false, Enum.KeyCode.D)

It’s an incredibly messy script since i am quite new to scripting but this is the most important part for my question:

-- Zoom in and zoom out
mouse.WheelForward:Connect(function() -- Zoom in
	if game.Workspace.CurrentCamera.CFrame.Y >= min or game.Workspace.CurrentCamera.CFrame.Y == min then
		game.Workspace.CurrentCamera.CFrame = CFrame.new(game.Workspace.CurrentCamera.CFrame.Position) * CFrame.new(0,-scrollspeed,0) * downwardLookAngle
	else
		-- Do nothing
	end
	scrollspeed = game.Workspace.CurrentCamera.CFrame.Y/10
	
	if game.Workspace.CurrentCamera.CFrame.Y <= focusLevel and angle >= 15 then
		--angle = angle - 5
		
		downwardLookAngle =  CFrame.Angles(-math.rad(angle), 0, 0)
	else
		--Do nothing again
	end
end)

mouse.WheelBackward:Connect(function() -- Zoom out
	if game.Workspace.CurrentCamera.CFrame.Y <= max or game.Workspace.CurrentCamera.CFrame.Y == max then
		game.Workspace.CurrentCamera.CFrame = CFrame.new(game.Workspace.CurrentCamera.CFrame.Position) * CFrame.new(0,scrollspeed,0) * downwardLookAngle
	else
		-- Do nothing
	end
	scrollspeed = game.Workspace.CurrentCamera.CFrame.Y/10

	if game.Workspace.CurrentCamera.CFrame.Y <= focusLevel and angle <= 60 then
		
		--angle = angle + 5
		
		downwardLookAngle =  CFrame.Angles(-math.rad(angle), 0, 0)
	else
		--Do nothing again
	end
end)

As you can see I rotate the camera forwards when the camera is certain distance from the ground, however, because I change the angle by 5 every time you move the mouseweel, this rotation isn’t smooth at all.

I have tried using Tweenservice, but you can only tween a instance’s properties and not a value. I have also tried using the :Lerp function, everytime you used the scroll wheel I would lerp the angle value to angle + 5. this didn’t work because if you scrolled fast enough you could be out of the focuslevel before the camera returned to normal.
If anyone knows how to make this rotation more smooth please let me know, thanks!

2 Likes

I know you mentioned using TweenService and it not working, but maybe you should try that again. How about trying to tween the value as an attribute to the script, and have the function update as the value changes?

local TS,TI = game:GetService("TweenService"),TweenInfo.new()
local Value = script:GetAttribute("RotateRatio") -- Something like this

Thanks! I’ve never used attributes before but I will look into it.

1 Like