Camera offset doesn't work correctly when looking other directions

I’m working on an FPS game, and I’m trying to get the Player’s camera offset to match the position of their head using the humanoid camera offset.

It works fine until you look any other direction that isn’t the default axis.
(I am only trying to track the head on the X and Z axis.)

This is the code I’m using, I hope that somebody can help me with this.

local RunService = game:GetService("RunService")

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local RootPart = Character:WaitForChild("HumanoidRootPart")
local Head = Character:WaitForChild("Head")

RunService.RenderStepped:Connect(function()
	local OffsetX = (Head.CFrame.Position.X-RootPart.CFrame.Position.X) -- The offset for the X axis.
	local OffsetZ = (Head.CFrame.Position.Z-RootPart.CFrame.Position.Z) -- The offset for the Y axis.

	Humanoid.CameraOffset = Vector3.new(OffsetX,-1.25+math.cos(math.sin(tick())*.75),-1+OffsetZ)
end)
2 Likes

Humanoid.CameraOffset is relative to the HumanoidRootPart. You should replace OffsetX and OffsetZ with constants, probably both 0. This should fix your issue. Why are you using sin and cos?

1 Like

The offsets are supposed to dynamically change to match the head’s position which would be how far left/right it is and how far forward/back it is, using 0 would defeat the purpose. Also, I am using sin and cos as a sort of head bobble.

You need to get this offset in object space. Currently you are using world space, so when your character rotates 90 degrees for example, the world x axis becomes the local z axis and the world z axis becomes the local x axis. Try something like this:

local Offset = RootPart.CFrame:ToObjectSpace(Head.CFrame)
local OffsetX = Offset.Position.X
local OffsetZ = Offset.Position.Z
1 Like

Thank you! That seems to have done the trick!