How to create camera like this

so i want to create a camera like this:


i know humanoid.CameraOffset exists, but camera offset looks awkward especially when your moving around, however in the video, it shows how you can go all around the character, its a little offset to the right.

1 Like

Hey again lol

I think you can make this with kind of an orbit camera with an offset and multiply the CFrame of your character to this every frame.

btw I’ll have to look at CameraOffset to make sure I’m not suggesting a more complicated version of the property.

You’d need to make a custom camera by setting the camera’s type to Scriptable then updating the camera’s position every frame (using the RunService’s RenderStepped or BindToRenderStep) based on user input.

To get a CFrame behind the character and to the right, you can just take the CFrame of the HRP and add something like:

humanoidRootPart.CFrame.LookVector*(-distanceBehind) + humanoidRootPart.CFrame.RightVector*(distanceRight)

Then camera bobble can be calculated with some modules/math. There’s an FPS tutorial that on the forums that explains camera bobble well.

something like this? :

local cam = workspace.CurrentCamera
local runService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local humanoidRootPart = char:WaitForChild("HumanoidRootPart")
task.wait()
cam.CameraType = Enum.CameraType.Scriptable
runService.RenderStepped:Connect(function()
	cam.CFrame =   humanoidRootPart.CFrame.LookVector*(-10) + humanoidRootPart.CFrame.RightVector*(10)
end)

and i get this error: invalid argument #3 (CFrame expected, got Vector3) also the camera cannot be moved since its set to scriptable (also i dont care about the camera bob, just the movement and position)

2 Likes

Yep! Just like that. You just need to add in the humanoidRootPart’s CFrame:

local cam = workspace.CurrentCamera
local runService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local humanoidRootPart = char:WaitForChild("HumanoidRootPart")
task.wait()
cam.CameraType = Enum.CameraType.Scriptable
runService.RenderStepped:Connect(function()
	cam.CFrame = humanoidRootPart.CFrame + humanoidRootPart.CFrame.LookVector*(-10) + humanoidRootPart.CFrame.RightVector*(10)
end)

Setting the camera to scriptable allows scripts to move the camera. Setting it to scriptable stops the default camera scripts from moving it too, which can seem a little weird.

Edit:
Oh I see, you also want the mouse to be able to rotate the camera. That’s a little complicated:

  • Lock the mouse using UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
  • Every frame:
    • Get the mouse movement using UserInputService:GetMouseDelta()
    • Calculate the rotation using the mouse delta
    • Rotate the camera

Here is some example code:

local cam = workspace.CurrentCamera
local runService = game:GetService("RunService")
local userInputService = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local humanoidRootPart = char:WaitForChild("HumanoidRootPart")
task.wait()
cam.CameraType = Enum.CameraType.Scriptable
cam:GetPropertyChangedSignal("CameraType"):Connect(function()
	cam.CameraType = Enum.CameraType.Scriptable
	cam.CameraSubject = nil
end)

local _, cameraRotation, _ = humanoidRootPart.CFrame.Rotation:ToEulerAnglesXYZ()
local rotationSensitivity = 1/4
local offsetForwards = -10

local function updateCamera()
	userInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
	cameraRotation += rotationSensitivity * userInputService:GetMouseDelta().X
	
	local cframe = CFrame.Angles(0, math.rad(cameraRotation), 0) + (humanoidRootPart.Position)
	cframe += cframe.LookVector*offsetForwards + cframe.RightVector*offsetRight
	cam.CFrame = cframe
end

runService.RenderStepped:Connect(function()
	updateCamera()
end)
1 Like

got this error: invalid argument #1 (Vector2 expected, got number)

1 Like

I accidently made a few mistakes in the code. I fixed them and updated the code block above. Sorry about that!

1 Like

is it possible in the script to change where the camera is in the Y axis

cause this is X and Z axis but the mouse only seems to move along the X axis, is it possible to make it slightly move along the Y too? and one more thing: the camera is inverted with the mouse, how could it be un-inverted? Thanks! (also the camera is looking really good rn :slight_smile: )

1 Like

Yep, just add a vector3 to the final camera position. I added a universal offset variable below to do that:

local cam = workspace.CurrentCamera
local runService = game:GetService("RunService")
local userInputService = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local humanoidRootPart = char:WaitForChild("HumanoidRootPart")
task.wait()
cam.CameraType = Enum.CameraType.Scriptable
cam:GetPropertyChangedSignal("CameraType"):Connect(function()
	cam.CameraType = Enum.CameraType.Scriptable
	cam.CameraSubject = nil
end)

local _, cameraRotation, _ = humanoidRootPart.CFrame.Rotation:ToEulerAnglesXYZ()
local rotationSensitivity = 1/4
local offsetForwards = -10
local offsetRight = 5
local universalOffset = Vector3.new(0, 2, 0)

local function updateCamera()
	userInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
	cameraRotation += rotationSensitivity * userInputService:GetMouseDelta().X
	
	local cframe = CFrame.Angles(0, math.rad(cameraRotation), 0) + (humanoidRootPart.Position)
	cframe += cframe.LookVector*offsetForwards + cframe.RightVector*offsetRight + universalOffset
	cam.CFrame = cframe
end

runService.RenderStepped:Connect(function()
	updateCamera()
end)
1 Like

i forgot to say that i actually already found out how to change the Y axis, but what i meant is this: The mouse can only move along X axis, how could i make it so the mouse can slightly move along the Y axis too? And also the mouse is inverted, how could i un-invert it? Thanks!!

1 Like

Change the camera sensitivity to a negative number to flip the controls on the x-axis.

To move it on the y axis, you can create a second camera rotation variable, then update it like this:

-- Need to define some new vars above
cameraRotationY += rotationSensitivityY * userInputService:GetMouseDelta().Y

Then you need to rotate the CFrame on it’s relative X axis.

Edit:

@F0xBirdmansBFF - Here’s some code:

local cam = workspace.CurrentCamera
local runService = game:GetService("RunService")
local userInputService = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local humanoidRootPart = char:WaitForChild("HumanoidRootPart")
task.wait()
cam.CameraType = Enum.CameraType.Scriptable
cam:GetPropertyChangedSignal("CameraType"):Connect(function()
	cam.CameraType = Enum.CameraType.Scriptable
	cam.CameraSubject = nil
end)

local _, cameraRotation, _ = humanoidRootPart.CFrame.Rotation:ToEulerAnglesXYZ()
local rotationSensitivity = -1/4
local rotationSensitivityVertical = -1/8
local verticalRotationLimit = 20
local offsetForwards = -10
local offsetRight = 5
local universalOffset = Vector3.new(0, 2, 0)

local cameraRotationVertical = 0

userInputService.MouseBehavior = Enum.MouseBehavior.LockCenter

local function updateCamera()
	
	cameraRotation += rotationSensitivity * userInputService:GetMouseDelta().X
	cameraRotationVertical += rotationSensitivityVertical * userInputService:GetMouseDelta().Y
	cameraRotationVertical = math.clamp(cameraRotationVertical, -verticalRotationLimit, verticalRotationLimit)

	local cframe = CFrame.Angles(0, math.rad(cameraRotation), 0)
	cframe = cframe:ToWorldSpace(CFrame.Angles(math.rad(cameraRotationVertical), 0, 0))
	cframe += humanoidRootPart.Position
	cframe += cframe.LookVector*offsetForwards + cframe.RightVector*offsetRight + universalOffset
	
	cam.CFrame = cframe
end

runService.RenderStepped:Connect(function()
	updateCamera()
end)
4 Likes