I have updated the code for anyone that wants to use it, and I also made it as a module so you can Start()
and Stop()
the camera script, however, there is a bug where the camera no longer moves after un-focusing the window.
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Camera = Workspace.CurrentCamera
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local Head = Character:WaitForChild("Head")
local OrbitalCamera = {
settings = {
popper = false,
sensitivity = Vector2.new(120, 120),
offset = CFrame.new(2, 3, 15),
verticalLimit = NumberRange.new(-5 * math.pi / 12, 5 * math.pi / 12),
combinations = {
{true, false, false, false, 0, 0},
{true, true, false, false, math.pi / 4},
{false, true, false, false, math.pi / 2},
{false, true, true, false, 3 * math.pi / 4},
{false, false, true, false, math.pi},
{false, false, true, true, 5 * math.pi / 4},
{false, false, false, true, 3 * math.pi / 2},
{true, false, false, true, 7 * math.pi / 4}
}
}
}
local DeltaX = 0
local DeltaY = 0
local AngleH = 0
local AngleV = 0
local W = false
local A = false
local S = false
local D = false
local RenderStepped = nil
local InputChanged = nil
local InputBegan = nil
local InputEnded = nil
function OrbitalCamera:Start()
Humanoid.AutoRotate = false
Camera.CameraType = Enum.CameraType.Scriptable
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
RenderStepped = RunService.RenderStepped:Connect(function()
AngleH = AngleH - DeltaX / self.settings.sensitivity.X
DeltaX = 0
AngleV = math.clamp(AngleV - DeltaY / self.settings.sensitivity.Y, self.settings.verticalLimit.Min, self.settings.verticalLimit.Max)
DeltaY = 0
local finalCFrame = CFrame.new(HumanoidRootPart.Position) * CFrame.Angles(0, AngleH, 0) * CFrame.Angles(AngleV, 0, 0) * self.settings.offset
if self.settings.popper then
local direction = (finalCFrame.Position - Head.Position).Unit * ((self.settings.offset.Position).Magnitude)
local raycastResult = Workspace:Raycast(Head.Position, direction)
if raycastResult then
local distance = (raycastResult.Position - finalCFrame.Position).Magnitude
finalCFrame = finalCFrame * CFrame.new(0, 0, -distance)
end
end
Camera.CFrame = finalCFrame
if W or A or S or D then
for _, value in pairs(self.settings.combinations) do
if value[1] == W and value[2] == A and value[3] == S and value[4] == D then
local directionVector = Camera.CFrame.LookVector
local targetCFrame = CFrame.new(HumanoidRootPart.Position, HumanoidRootPart.Position + Vector3.new(directionVector.X, 0, directionVector.Z))
HumanoidRootPart.CFrame = HumanoidRootPart.CFrame:Lerp(targetCFrame * CFrame.Angles(0, value[5], 0), 0.25)
end
end
end
end)
InputChanged = UserInputService.InputChanged:Connect(function(input, gameProcessedEvent)
if not gameProcessedEvent then
if input.UserInputType == Enum.UserInputType.MouseMovement then
if DeltaX ~= input.Delta.X then
DeltaX = input.Delta.X
end
if DeltaY ~= input.Delta.Y then
DeltaY = input.Delta.Y
end
end
end
end)
InputBegan = UserInputService.InputBegan:Connect(function(input, gameProcessedEvent)
if not gameProcessedEvent then
if input.KeyCode == Enum.KeyCode.W then
W = true
elseif input.KeyCode == Enum.KeyCode.A then
A = true
elseif input.KeyCode == Enum.KeyCode.S then
S = true
elseif input.KeyCode == Enum.KeyCode.D then
D = true
end
end
end)
InputEnded = UserInputService.InputEnded:Connect(function(input, gameProcessedEvent)
if not gameProcessedEvent then
if input.KeyCode == Enum.KeyCode.W then
W = false
elseif input.KeyCode == Enum.KeyCode.A then
A = false
elseif input.KeyCode == Enum.KeyCode.S then
S = false
elseif input.KeyCode == Enum.KeyCode.D then
D = false
end
end
end)
end
function OrbitalCamera:Stop()
Humanoid.AutoRotate = true
Camera.CameraType = Enum.CameraType.Custom
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
if RenderStepped then RenderStepped:Disconnect() end
if InputChanged then InputChanged:Disconnect() end
if InputBegan then InputBegan:Disconnect() end
if InputEnded then InputEnded:Disconnect() end
end
return OrbitalCamera
Example
local OrbitalCamera = require(script:WaitForChild("OrbitalCamera"))
OrbitalCamera:Start()