How do I make custom orbital camera control?

I want to make something like the Orbital CameraType using a custom script for finer control. Here’s what I have so far, but it is not quite smooth/accurate because RenderStepped is independent of InputChanged. Does anyone have an idea how to script a camera that orbits an object while allowing smooth left/right control of the orbit position?

local UserInputService = game:GetService("UserInputService")

local RunService = game:GetService("RunService")

local Camera = workspace.CurrentCamera

local X, Y, Z = 0, 5, 0

workspace:WaitForChild("Map")

UserInputService.InputChanged:Connect(function(Input)

X = 15*math.sinh(Input.Position.X)

Z = 15*math.cosh(Input.Position.Y)

end)

RunService.RenderStepped:Connect(function()

print(X,Y,Z)

Camera.CFrame = CFrame.lookAt(Vector3.new(workspace.Map.GolfBall.Position.X+X, workspace.Map.GolfBall.Position.Y+Y, workspace.Map.GolfBall.Position.Z+Z), workspace.Map.GolfBall.Position)

end)

you can try tween service
https://developer.roblox.com/en-us/api-reference/class/TweenService

1 Like

This isn’t perfect but its a start. Here’s an orbital camera that points at a part and has some smooth deceleration. This post helped: https://scriptinghelpers.org/questions/62897/custom-orbital-camera-rotation

local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Camera = workspace.CurrentCamera

Camera.CameraSubject = workspace.Part --The part you want to orbit around
local CameraAngle = 0

local function SetCameraAngle() --You don't have to pass in your part's position through CameraSubject, but I think it's convenient
	Camera.CFrame = CFrame.new(workspace.CurrentCamera.CameraSubject.Position) * CFrame.Angles(0,CameraAngle,0) * CFrame.new(0,5,7):ToWorldSpace(CFrame.Angles(math.rad(-30),0,0))
end

RunService:BindToRenderStep("CustomOrbitalCamera", Enum.RenderPriority.Camera.Value, SetCameraAngle)

local BeganConnection
local ChangedConnection
local EndedConnection
BeganConnection = UserInputService.InputBegan:Connect(function()
	local FormerTime = os.clock()
	RunService:UnbindFromRenderStep("CameraPan")
	if ChangedConnection then ChangedConnection:Disconnect() end
	if EndedConnection then EndedConnection:Disconnect() end
	local AngleVelocity = 0
	ChangedConnection = UserInputService.InputChanged:Connect(function(Input)
		local CurrentTime = os.clock()
		local AngleDelta = math.atan2(Input.Position.Y - Camera.ViewportSize.Y / 2, Input.Position.X - Camera.ViewportSize.X / 2) - math.atan2(Input.Position.Y - Camera.ViewportSize.Y / 2 - Input.Delta.Y, Input.Position.X - Camera.ViewportSize.X / 2 - Input.Delta.X)
		CameraAngle = (CameraAngle + AngleDelta) % (math.pi * 2)
		AngleVelocity = (AngleDelta) / (CurrentTime - FormerTime)
		if AngleVelocity > 0 then AngleVelocity = math.min(13, AngleVelocity) end --maximum angular velocity to decelerate from, in radians. The velocity isn't 100% accurate and can be too fast, like hundreds of radians per second
		if AngleVelocity < 0 then AngleVelocity = math.max(-13, AngleVelocity) end
		FormerTime = os.clock()
	end)
	EndedConnection = UserInputService.InputEnded:Connect(function(Input)
		local function CameraPan(TimeDelta)
			AngleVelocity /= 1.05 --increase to make camera decelerate faster
			local AngleDelta = AngleVelocity * TimeDelta
			if -0.001745 < AngleDelta and AngleDelta < 0.001745 then --smallest rotational increment before stopping, in radians
				AngleVelocity = 0
				RunService:UnbindFromRenderStep("CameraPan")
			end
			CameraAngle = (CameraAngle + AngleDelta) % (math.pi * 2)
		end
		RunService:BindToRenderStep("CameraPan", Enum.RenderPriority.Camera.Value, CameraPan)
	end)
end)
4 Likes