Have first person camera follow player's head, similar to pressure

I am basically trying to get a First Person Camera to follow the head position. Looking up will cause the player’s character to look up physically, same for looking down.

I got it working to the point where I have the character looking up and down physically. (Another issue is the new rotation not updating server side/other players…)
image image
Basically where the head is facing and positioned, i want the camera to be facing and looking there. The issue i have is when I set the camera’s CFrame to the head’s position, the character spins uncontrollably.

Currently each render stepped, I am getting the UpperTorso and it’s Waist (Motor6D) child and setting the rotation of C1 property based on the rotation of the camera. Something like this here:

motor6d.C1 = CFrame.new(motor6d.C1.Position) * CFrame.Angles(-Camera.CFrame.LookVector.Y, 0, 0)

I have tried using things like this to get it working but it causes the player to spin:

Camera.CFrame = CFrame.new(head.CFrame.Position) * Camera.CFrame.Rotation

One thing to know is: yes I am using first person camera mode. (set within starter player, under camera section.)

This problem stumpped me for a bit now, and idk what to try next…

[EDIT]: I also forgot to mention but I do want something that can possibly work with platforms such as mobile or even console.

1 Like

Video
CameraMovment.wmv (1.1 MB)

This script may help. I created it(ChatGPT did) when I was trying to recreate the camera effect of Hellmet. It can be switched into first person.

local Player = game.Players.LocalPlayer
local character = Player.Character or Player.ChildAdded:Wait()
local UserInputService = game:GetService("UserInputService")
local camera = game.Workspace.CurrentCamera
local runService = game:GetService("RunService")

local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
local rootJoint = humanoidRootPart:FindFirstChild("RootJoint")
local peekAngle = math.rad(35)  -- Adjust the peek angle as needed
local isPeekingLeft = false
local isPeekingRight = false
local offset = CFrame.new(2,0.5,2) -- hmet
--local offset = CFrame.new(1.5,0.5,4) -- seperate
--local offset = CFrame.new(0,0.15,1) --fps

local originalRootJointC1 = rootJoint and rootJoint.C1 or CFrame.new()

local Mouse = Player:GetMouse()

local RC1 = CFrame.new(-.5, .5, 0, 0, 0, 1, 0, 1, 0, -1, 0, 0)
local LC1 = CFrame.new(.5, .5, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0)

local Right = true
UserInputService.InputBegan:Connect(function(input, gamepr)
	if gamepr then return end
	if input.KeyCode == Enum.KeyCode.F then
		character["Torso"].Transparency = 0
		character["Head"].Transparency = 0
	if Right then
		Right = false
		offset = CFrame.new(-2, 0.5, 2) -- hmet
	else
		Right = true
			offset = CFrame.new(2, 0.5, 2) -- hmet
		end	
	end
	
	if input.KeyCode == Enum.KeyCode.V then
		offset = CFrame.new(0,0.15,1)
		character["Torso"].Transparency = 1
		character["Head"].Transparency = 1
	end
end)

local function Begin(Char)
	UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
	humanoidRootPart = character:WaitForChild("HumanoidRootPart")
	rootJoint = humanoidRootPart:FindFirstChild("RootJoint")
	local head = character:WaitForChild("Head")
	local torso = character:WaitForChild("Torso")
	local neck = torso:WaitForChild("Neck")
	local LeftShoulder = torso:WaitForChild("Left Shoulder")
	local RightShoulder = torso:WaitForChild("Right Shoulder")
	local Humanoid = character:WaitForChild("Humanoid")
	camera.CameraType = Enum.CameraType.Scriptable
	local cameraRotation = CFrame.new()
	local verticalAngle = 0
	local smoothVerticalAngle = 0
	local maxVerticalAngle = math.rad(80)
	local minVerticalAngle = math.rad(-80)
	local originalNeckC1 = neck and neck.C1 or CFrame.new()
	-- Arm movement setup
	local RC1 = CFrame.new(-.5, .5, 0, 0, 0, 1, 0, 1, 0, -1, 0, 0)
	local LC1 = CFrame.new(.5, .5, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0)
	if offset == CFrame.new(0,0.15,1) then
		character["Torso"].Transparency = 1
		character["Head"].Transparency = 1
	end

	runService.RenderStepped:Connect(function()
		
		-- Camera movement
		local mouseDelta = UserInputService:GetMouseDelta()
		local horizontalRotationChange = CFrame.Angles(0, -mouseDelta.X * 0.002, 0)
		cameraRotation = cameraRotation * horizontalRotationChange

		verticalAngle = math.clamp(verticalAngle - mouseDelta.Y * 0.002, minVerticalAngle, maxVerticalAngle)
		smoothVerticalAngle = smoothVerticalAngle + (verticalAngle - smoothVerticalAngle)-- Smoothing factor

		local verticalRotation = CFrame.Angles(smoothVerticalAngle, 0, 0)
		local ForwardHead = CFrame.new(0, -smoothVerticalAngle/3.2, 0)

		-- Sway factor
		local swayIntensity = 0
		local horizontalSway = math.sin(smoothVerticalAngle) * swayIntensity
		local verticalSway = math.cos(smoothVerticalAngle) * swayIntensity
		local sway = CFrame.new(horizontalSway, verticalSway, 0)

		local newOrientation = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + cameraRotation.LookVector)
		humanoidRootPart.CFrame = newOrientation
		if neck and neck:IsA("Motor6D") then
			neck.C1 = originalNeckC1 * verticalRotation  -- Apply the peek adjustment here
		end
		camera.CFrame = character:WaitForChild("Head").CFrame * offset

		local cf = workspace.CurrentCamera.CFrame.lookVector.Y

		local Kek = CFrame.Angles(0, 0, math.asin(Mouse.Origin.lookVector.Y))
		RightShoulder.C1 = RC1 * Kek:inverse()
		LeftShoulder.C1 = LC1 * Kek

	end)
	
end

Begin()

Hope this helps.

1 Like

It will help, but i do wonder…
does it support mobile and/or other platforms such as console?

I don’t know if it works for other platforms.

The camera offset in the script is different for different screen sizes but if the camera offset is set to (0,0,0). it should be fine for different sized monitors.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.