Im trying to create a custom camera system for my directional gravity controller. As part of this, I need a “facingCFrame” CFrame that has the upvector of gravity but faces in the direction of the camera, this is used by the camera is it’s own math and referenced in the character controller. The problem is, I’m using springs in the camera to make it smoother, but the yaw rotation from the facingCFrame is adding to the spring rotation, causing my camera to rotate much faster than intended. In the following video, there is a blue part with an arrow. The GOAL is that the arrow should always point in the direction of the camera (while maintaining the same upvector as gravity), it represents the “self._facingCFrame” variable. You will also see me rotating a purple part and changing the direction of gravity.
Video:
Code:
-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local PlayerService = game:GetService("Players")
local UIS = game:GetService("UserInputService")
-- Essentials
local Utility = ReplicatedStorage.Modules.Utility
local Spring = require(Utility.Spring)
local Mouse = PlayerService.LocalPlayer:GetMouse()
local Camera = workspace.CurrentCamera
local AdjustCFrameUp = require(script.Parent.Parent.AdjustCFrameUp)
-- CONSTANTS
local ZERO_VECTOR2 = Vector2.zero
local ZERO_VECTOR3 = Vector3.zero
local MAX_UP_ANGLE = math.rad(80)
local MAX_DOWN_ANGLE = math.rad(-80)
local MAX_ZOOM_DISTANCE = 20
local MIN_ZOOM_DISTANCE = 4
local DEFAULT_ZOOM_DISTANCE = 8
local SENSITIVITY = 0.007
local ZOOM_SENSITIVITY = 1.6
local MAX_MOUSE_DELTA = 0.4
local ZOOM_SPRING_SPEED = 20
local ZOOM_SPRING_DAMPER = 0.8
local ROT_SPRING_SPEED = 30
local ROT_SPRING_DAMPER = 0.8
local CAMERA_OFFSET = Vector3.new(0, 2, 0)
-- Module
type main = {
Player : Player,
Character : Model,
Humanoid : Humanoid,
HRP : BasePart,
Attachment : Attachment,
_characterMass : number,
_gravityStrength : number,
_upVector : Vector3,
_gravityForce : Vector3,
_negateForce : Vector3,
_totalForce : Vector3,
Physics : typeof(require(script.Parent.Parent.Physics))
}
local CameraController = {}
CameraController.__index = CameraController
function CameraController.new(main : main)
local self = setmetatable({}, CameraController)
self.Main = main
self.FirstPerson = false
self._smoothedUpVector = main._upVector
self._facingCFrame = CFrame.new(ZERO_VECTOR3)
self._targetRotX = 0
self._targetRotY = 0
self._rotSpringX = Spring.new(0)
self._rotSpringY = Spring.new(0)
self._rotSpringX.Speed = ROT_SPRING_SPEED
self._rotSpringX.Damper = ROT_SPRING_DAMPER
self._rotSpringY.Speed = ROT_SPRING_SPEED
self._rotSpringY.Damper = ROT_SPRING_DAMPER
self._targetZoom = DEFAULT_ZOOM_DISTANCE
self._zoomSpring = Spring.new(0)
self._zoomSpring.Speed = ZOOM_SPRING_SPEED
self._zoomSpring.Damper = ZOOM_SPRING_DAMPER
self._cameraPos = ZERO_VECTOR3
self._runConnection = nil
self:_init()
--self:_update()
return self
end
-- Private methods
function CameraController:_init()
self._facingCFrame = AdjustCFrameUp(self.Main.HRP.CFrame, self.Main._upVector).Rotation
self._runConnection = RunService.RenderStepped:Connect(function()
self:_update()
end)
UIS.InputChanged:Connect(function(input, gpe)
if gpe or input.UserInputType ~= Enum.UserInputType.MouseWheel then return end
self._targetZoom = math.clamp(self._targetZoom - input.Position.Z * ZOOM_SENSITIVITY, MIN_ZOOM_DISTANCE, MAX_ZOOM_DISTANCE)
end)
end
function CameraController:_getTargetPos()
return (self.Main.HRP.CFrame * CFrame.new(CAMERA_OFFSET)).Position
end
function CameraController:_update()
Camera.CameraType = Enum.CameraType.Custom
local mouseDelta = ZERO_VECTOR3
if Mouse.Button2Down or self.FirstPerson or self.ShiftLocked then
mouseDelta = Vector2.new(
math.clamp(UIS:GetMouseDelta().X * SENSITIVITY, -MAX_MOUSE_DELTA, MAX_MOUSE_DELTA),
math.clamp(UIS:GetMouseDelta().Y * SENSITIVITY, -MAX_MOUSE_DELTA, MAX_MOUSE_DELTA) / 1.6
)
end
self._targetRotX -= mouseDelta.X
self._targetRotY = math.clamp(self._targetRotY - mouseDelta.Y, MAX_DOWN_ANGLE, MAX_UP_ANGLE)
self._smoothedUpVector = self._smoothedUpVector:Lerp(self.Main._upVector, 0.1)
self._facingCFrame *= CFrame.Angles(0, -mouseDelta.X, 0)
self._facingCFrame = AdjustCFrameUp(self._facingCFrame, self._smoothedUpVector)
self._rotSpringX.Target = self._targetRotX
self._rotSpringY.Target = self._targetRotY
self._zoomSpring.Target = self._targetZoom
self._cameraPos = self:_getTargetPos()
workspace.FacePart.CFrame = self.Main.HRP.CFrame * self._facingCFrame
Camera.CFrame = CFrame.new(self._cameraPos)
* self._facingCFrame
* CFrame.Angles(0, self._rotSpringX.Position, 0)
* CFrame.Angles(self._rotSpringY.Position, 0, 0)
* CFrame.new(0, 0, self._zoomSpring.Position)
end
return CameraController