What do you want to achieve? Keep it simple and clear!
I want help in finding a solution to my problem.
What is the problem? Include screenshots/videos if possible.
I made a third person shoulder camera system for my project. It works fine, but there’s a big problem, when facing the camera or any direction that’s not forward, it rotates the camera based on the HumanoidRootPart CFrame. This causes the camera to sometimes turn 180*.
Here is a video of the problem occurring: Watch issue | Streamable
What solutions have you tried so far?
ChatGPT, Claude.ai, x.ai, reading the forum posts, nothing seems to work.
local uis = game:GetService("UserInputService")
local camera = workspace.CurrentCamera
local char = script.Parent
local humanoid = char:WaitForChild("Humanoid")
local hrp = char:WaitForChild("HumanoidRootPart")
local runService = game:GetService("RunService")
local x = 0
local y = 0
local offset = Vector3.new(2.5, 2.1, 7)
local isActive = false
local canZoom = false
local defaultCameraType = camera.CameraType
local defaultAutoRotate = humanoid.AutoRotate
local minZoom = 2
local maxZoom = 20
local lastCameraRotation = CFrame.identity
local cameraLerpAlpha = 0
local cameraLerpSpeed = 5
local transitioningToCamera = false
local transitioningToDefault = false
local deactivationLerpAlpha = 0
local defaultCameraOffset
local function lerp(a, b, t)
return a + (b - a) * t
end
local function enableCameraControl()
local hrpCFrame = hrp.CFrame
local cameraCFrame = camera.CFrame
defaultCameraOffset = hrpCFrame:ToObjectSpace(cameraCFrame)
isActive = true
transitioningToCamera = true
transitioningToDefault = false
cameraLerpAlpha = 0
local _, currentY, _ = camera.CFrame:ToOrientation()
x = math.deg(currentY)
lastCameraRotation = CFrame.Angles(0, math.rad(x), 0) * CFrame.Angles(math.rad(y), 0, 0)
camera.CameraType = Enum.CameraType.Scriptable
humanoid.AutoRotate = false
uis.MouseBehavior = Enum.MouseBehavior.LockCenter
end
local function disableCameraControl()
isActive = false
transitioningToCamera = false
transitioningToDefault = true
deactivationLerpAlpha = 0
end
local function adjustCameraForCollisions(targetPosition, lookTarget)
local rayOrigin = hrp.Position
local rayDirection = targetPosition - rayOrigin
local rayLength = rayDirection.Magnitude
local rayUnit = rayDirection.Unit
local rayDistance = math.min(rayLength, maxZoom)
local ignoreList = {char}
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = ignoreList
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local raycastResult = workspace:Raycast(rayOrigin, rayUnit * rayDistance, raycastParams)
if raycastResult then
local hitPoint = raycastResult.Position
local wallOffset = 0.5
local adjustedPosition = hitPoint - (rayUnit * wallOffset)
local distanceToCharacter = (adjustedPosition - rayOrigin).Magnitude
if distanceToCharacter < minZoom then
adjustedPosition = rayOrigin + rayUnit * minZoom
end
return CFrame.new(adjustedPosition, lookTarget)
else
return CFrame.new(targetPosition, lookTarget)
end
end
uis.InputBegan:Connect(function(input, processed)
if processed then return end
if input.UserInputType == Enum.UserInputType.MouseButton2 then
enableCameraControl()
end
end)
uis.InputEnded:Connect(function(input, processed)
if processed then return end
if input.UserInputType == Enum.UserInputType.MouseButton2 then
disableCameraControl()
end
end)
uis.InputChanged:Connect(function(input, processed)
if input.UserInputType == Enum.UserInputType.MouseWheel and isActive and canZoom then
offset = Vector3.new(
offset.X,
offset.Y,
math.clamp(offset.Z - input.Position.Z * 2, minZoom, maxZoom)
)
end
if processed then return end
if input.UserInputType == Enum.UserInputType.MouseMovement and isActive then
x -= input.Delta.X
y = math.clamp(y - input.Delta.Y * 0.4, -75, 75)
lastCameraRotation = CFrame.Angles(0, math.rad(x), 0) * CFrame.Angles(math.rad(y), 0, 0)
end
end)
local renderConnection = runService.RenderStepped:Connect(function(dt)
dt = math.min(dt, 0.1)
if isActive then
if humanoid.AutoRotate then
humanoid.AutoRotate = false
end
local currentCFrame = hrp.CFrame
hrp.CFrame = CFrame.new(currentCFrame.Position) * CFrame.Angles(0, math.rad(x), 0)
local startCFrame = CFrame.new(hrp.Position) * lastCameraRotation
local cameraCFrame = startCFrame:ToWorldSpace(CFrame.new(offset.X, offset.Y, offset.Z))
local cameraDirection = startCFrame:ToWorldSpace(CFrame.new(offset.X, offset.Y, -10000))
local adjustedCameraCFrame = adjustCameraForCollisions(cameraCFrame.Position, cameraDirection.Position)
if transitioningToCamera then
cameraLerpAlpha = math.clamp(cameraLerpAlpha + dt * cameraLerpSpeed, 0, 1)
camera.CFrame = camera.CFrame:Lerp(adjustedCameraCFrame, cameraLerpAlpha)
if cameraLerpAlpha >= 1 then
transitioningToCamera = false
end
else
camera.CFrame = adjustedCameraCFrame
end
elseif transitioningToDefault then
local targetCameraCFrame = hrp.CFrame * defaultCameraOffset
deactivationLerpAlpha = math.clamp(deactivationLerpAlpha + dt * cameraLerpSpeed, 0, 1)
camera.CFrame = camera.CFrame:Lerp(targetCameraCFrame, deactivationLerpAlpha)
if deactivationLerpAlpha >= 1 then
transitioningToDefault = false
camera.CameraType = defaultCameraType
camera.CameraSubject = humanoid
humanoid.AutoRotate = defaultAutoRotate
uis.MouseBehavior = Enum.MouseBehavior.Default
local heartbeatConnection
heartbeatConnection = runService.Heartbeat:Connect(function()
camera.CameraType = defaultCameraType
camera.CameraSubject = humanoid
heartbeatConnection:Disconnect()
end)
end
end
end)
char.Destroying:Connect(function()
if renderConnection then
renderConnection:Disconnect()
end
uis.MouseBehavior = Enum.MouseBehavior.Default
camera.CameraType = defaultCameraType
camera.CameraSubject = humanoid
humanoid.AutoRotate = defaultAutoRotate
end)