Lerp Camera to player's head

Hey folks,

I was working on an Over-The-Shoulder Gun system for a game I work on, when I came across the problem of resetting the character’s camera (Through animating w/ lerp). Let me explain:

This is where the camera is positioned when you are aiming down a sight,
image

It’s a little offset, I’ll include the values below.

local CameraOffset = Vector3.new(2,1,8)

Mouse.Button2Down:Connect(function()
	if Equipped == false or Reloading == true or Aiming == true then return end
	Aiming = true
	local Humanoid = SelfPlayer.Character.Humanoid
	local HumanoidRootPart = SelfPlayer.Character.HumanoidRootPart

	local Tween = TweenService:Create(Camera, TweenInfo.new(0.4, Enum.EasingStyle.Quint, Enum.EasingDirection.Out), {FieldOfView = OriginFieldOfView - 30})
	Tween:Play()

	Camera.CameraType = Enum.CameraType.Scriptable


	RunService:BindToRenderStep("OTS", Enum.RenderPriority.Camera.Value, function()
		local StartingCFrame = CFrame.new((HumanoidRootPart.CFrame.p + Vector3.new(0,2,0))) * CFrame.Angles(0, math.rad(CameraAngleX), 0) * CFrame.Angles(math.rad(CameraAngleY), 0 ,0)
		local CameraCFrame = StartingCFrame + StartingCFrame:VectorToWorldSpace(Vector3.new(CameraOffset.X, CameraOffset.Y, CameraOffset.Z))
		local CameraFocus = StartingCFrame + StartingCFrame:VectorToWorldSpace(Vector3.new(CameraOffset.X, CameraOffset.Y, -50000))

		if Initial == false then
			Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(CameraCFrame.p, CameraFocus.p), 0.4)
			if OtherDebounce2 == false then
				OtherDebounce2 = true
				spawn(function()
					wait(0.4)
					Initial = true
				end)
			end
		else
			print("h")
			UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter

			Camera.CFrame = CFrame.new(CameraCFrame.p, CameraFocus.p)
			HumanoidRootPart.CFrame = CFrame.new(HumanoidRootPart.CFrame.p, HumanoidRootPart.CFrame.p + Vector3.new(Camera.CFrame.LookVector.X, 0, Camera.CFrame.LookVector.Z))


			ConnectionAlpha = Mouse.WheelForward:Connect(function()
				if CameraOffset.Z > 1 then
					CameraOffset = Vector3.new(CameraOffset.X, CameraOffset.Y, CameraOffset.Z - 1)
				end
			end)
			ConnectionBeta = Mouse.WheelBackward:Connect(function()
				if CameraOffset.Z < 9 then
					CameraOffset = Vector3.new(CameraOffset.X, CameraOffset.Y, CameraOffset.Z + 1)
				end
			end)

			ContextActionService:BindAction("CameraMovement", function(_,_,Input)
				CameraAngleX = CameraAngleX - Input.Delta.x * 0.4
				CameraAngleY = math.clamp(CameraAngleY - Input.Delta.y * 0.4, -65, 65)
			end, false, Enum.UserInputType.MouseMovement)

		end

	end)

end)

However, the problem lies in actually resetting the camera to the character. Right now, if I were to stop aiming, my camera would show up like this:


Then when I unequip it, it ends up like this:

Follows my character’s head completely instead of making it the free-moving camera it usually is.

Here are both the unequip and the stop aiming event blocks:

Mouse.Button2Up:Connect(function()
	if Equipped == false or Reloading == true or Aiming == false then return end
	
	local Tween = TweenService:Create(Camera, TweenInfo.new(0.4, Enum.EasingStyle.Quint, Enum.EasingDirection.Out), {FieldOfView = OriginFieldOfView})
	Tween:Play()

	RunService:BindToRenderStep("FixCamera", Enum.RenderPriority.Camera.Value, function()
		Camera.CFrame = Camera.CFrame:Lerp(SelfPlayer.Character.Head.CFrame, 0.4)
		if Camera.CFrame == SelfPlayer.Character.Head.CFrame then
			RunService:UnbindFromRenderStep("FixCamera")
			Camera.CameraType = Enum.CameraType.Custom
			Camera.CameraSubject = SelfPlayer.Character.Humanoid
		end
	end)


	Initial = false

	if ConnectionAlpha then
		ConnectionAlpha:Disconnect()
	end
	if ConnectionBeta then
		ConnectionBeta:Disconnect()
	end


	ContextActionService:UnbindAction("CameraMovement")
	RunService:UnbindFromRenderStep("OTS")
	
	Aiming = false
	
end)

Tool.Unequipped:Connect(function()
	Equipped = false
	Firing = false
	Reloading = false
	Aiming = false

	ClearGunAnimations()

	local Tween = TweenService:Create(Camera, TweenInfo.new(0.4, Enum.EasingStyle.Quint, Enum.EasingDirection.Out), {FieldOfView = OriginFieldOfView})
	Tween:Play()
	
	Camera.CameraType = Enum.CameraType.Custom
	
	RunService:BindToRenderStep("FixCamera", Enum.RenderPriority.Camera.Value, function()
		Camera.CFrame = Camera.CFrame:Lerp(SelfPlayer.Character.Head.CFrame, 0.4)
		if Camera.CFrame == SelfPlayer.Character.Head.CFrame then
			RunService:UnbindFromRenderStep("FixCamera")
			Camera.CameraType = Enum.CameraType.Custom
			Camera.CameraSubject = SelfPlayer.Character.Humanoid
		end
	end)

	Initial = false

	if ConnectionAlpha then
		ConnectionAlpha:Disconnect()
	end
	if ConnectionBeta then
		ConnectionBeta:Disconnect()
	end


	ContextActionService:UnbindAction("CameraMovement")
	RunService:UnbindFromRenderStep("OTS")

	Aiming = false
	GunModel.Parent = Tool
	AmmoGui.Parent = Folder
	ReplicatedStorage.DisconnectM6D:FireServer()
end)

I’m really confused where I went wrong. It may just be that I’m tired, but does anyone have an idea?

1 Like

oh perhaps at the end of your unequip function set the player camera back to
cameraType “custom”

1 Like

Doesn’t seem to work.
It’s been a while since I posted this, and I’ve done a bunch of changes, so I’ll throw in the updated code here.

Mouse.Button2Up:Connect(function()
	CameraOffset = Vector3.new(2,1,8)
	if Equipped == false or Reloading == true or Aiming == false then return end

	ClearGunAnimations()

	local Tween = TweenService:Create(Camera, TweenInfo.new(0.4, Enum.EasingStyle.Quint, Enum.EasingDirection.Out), {FieldOfView = OriginFieldOfView})
	Tween:Play()

	PlayAnimation(SelfPlayer.Character.Humanoid, AnimationsFolder.GunHolster)


	RunService:BindToRenderStep("FixCamera", Enum.RenderPriority.Camera.Value, function()
		Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(OriginCameraCFrame.p, OriginCameraFocus.p), 0.4)
		if Camera.CFrame == CFrame.new(OriginCameraCFrame.p, OriginCameraFocus.p) then
			RunService:UnbindFromRenderStep("FixCamera")
		end
	end)
	Camera.CameraType = Enum.CameraType.Custom
	Camera.CameraSubject = SelfPlayer.Character.Humanoid
	Camera.CFrame = SelfPlayer.Character.Head.CFrame


	Initial = false
	OtherDebounce2 = false

	if ConnectionAlpha then
		ConnectionAlpha:Disconnect()
	end
	if ConnectionBeta then
		ConnectionBeta:Disconnect()
	end


	ContextActionService:UnbindAction("CameraMovement")
	RunService:UnbindFromRenderStep("OTS")

	Aiming = false
	Camera.CameraType = Enum.CameraType.Custom
end)

Tool.Unequipped:Connect(function()
	CameraOffset = Vector3.new(2,1,8)
	Equipped = false
	Firing = false
	Reloading = false
	Aiming = false

	ClearGunAnimations()

	local Tween = TweenService:Create(Camera, TweenInfo.new(0.4, Enum.EasingStyle.Quint, Enum.EasingDirection.Out), {FieldOfView = OriginFieldOfView})
	Tween:Play()
	
	RunService:BindToRenderStep("FixCamera", Enum.RenderPriority.Camera.Value, function()
		Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(OriginCameraCFrame.p, OriginCameraFocus.p), 0.4)
		if Camera.CFrame == CFrame.new(OriginCameraCFrame.p, OriginCameraFocus.p) then
			RunService:UnbindFromRenderStep("FixCamera")
		end
	end)
	
	Camera.CameraType = Enum.CameraType.Custom
	Camera.CameraSubject = SelfPlayer.Character.Humanoid
	Camera.CFrame = SelfPlayer.Character.Head.CFrame

	Initial = false
	OtherDebounce2 = false

	if ConnectionAlpha then
		ConnectionAlpha:Disconnect()
	end
	if ConnectionBeta then
		ConnectionBeta:Disconnect()
	end


	ContextActionService:UnbindAction("CameraMovement")
	RunService:UnbindFromRenderStep("OTS")

	Aiming = false
	GunModel.Parent = Tool
	AmmoGui.Parent = Folder
	ReplicatedStorage.DisconnectM6D:FireServer()
end)

Updated result:
image
Camera disconnects from the player, and only moves slighly with it.

1 Like

If it isn’t too much of a hassle, maybe consider this module? I modified it to allow for accepting new camera settings, and independent lerp speeds via (remote) events I’m sure you could do something similar

1 Like

I’ve seen it around, but honestly I want to figure out my own way to make a system like this. If all else fails, I’ll consider it though.

1 Like

Finally figured it out. Apparently I don’t even need to wait for it to match.

RunService:BindToRenderStep("FixCamera", Enum.RenderPriority.Camera.Value, function()
		Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(SelfPlayer.Character.Head.CFrame.p, SelfPlayer.Character.Head.CFrame.p + SelfPlayer.Character.HumanoidRootPart.CFrame.LookVector), .1)
		wait(0.4)
		RunService:UnbindFromRenderStep("FixCamera")
	end)
3 Likes