How to clamp a part's rotation to +/-30 of the character's rotation without flipping at 0/360?

  1. What do you want to achieve?
    I’m making a custom camera for boss fights in my game. I have the player only able to move left/right while facing a center point and keeping a consistent distance from that center point. I also have a camera part in front of the player with the camera style set to Attach and the camera subject set to that camera part. I want the camera part to rotate such that when the player moves left, the camera part will rotate counter clock wise to provide a different angle of the boss fight. When the player moves right, the camera part will rotate clock wise. I want this camera part’s Y orientation to be clamped to 30 degrees higher or lower than the character’s Y orientation.

  2. What is the issue?
    When the character’s Y orientation crosses 0/360 degrees, math.clamp doesn’t account for this properly and the camera part suddenly flips 180 degrees.

  3. What solutions have you tried so far?
    I’ve looked for solutions on the forums and tried ChatGPT but all of the solutions have the same problem.

See the attached project and hit play. Rotate the character around 360 degrees by moving left and right and you will see the camera part’s rotation flip when the player rotation crosses 0/360.

BossCameraTest.rbxl (82.2 KB)

Here is the full script:

local Control = require(game.Players.LocalPlayer:WaitForChild("PlayerScripts"):WaitForChild("PlayerModule"):WaitForChild("ControlModule"))

local camera = workspace.CurrentCamera
local character = script.Parent
local root = character.PrimaryPart
local center = workspace.SpawnLocation.Position
local distanceFromCenter = 40
local cameraRotationLimit = 30

local cameraPart = Instance.new("Part")
cameraPart.Transparency = 0
cameraPart.Massless = true
cameraPart.Anchored = false
cameraPart.CanTouch = false
cameraPart.CanQuery = false
cameraPart.CanCollide = false

cameraPart:PivotTo(root.CFrame:ToWorldSpace(CFrame.new(0,0,-7)) * CFrame.Angles(0,math.rad(25),0))

local weld = Instance.new("WeldConstraint")
weld.Parent = cameraPart
weld.Part0 = root
weld.Part1 = cameraPart

cameraPart.Parent = root

camera.CameraType = Enum.CameraType.Attach
camera.CameraSubject = cameraPart

local prevCameraY = 0

while true do
	local inputVector = Control:GetMoveVector()
	
	local directionToCenter = (root.Position - center).unit
	local desiredPosition = center + directionToCenter * distanceFromCenter
	character:PivotTo(CFrame.new(desiredPosition, center))

	local cameraY = math.clamp(cameraPart.Orientation.Y - inputVector.X, root.Orientation.Y - 30, root.Orientation.Y + 30)
	cameraPart.Orientation = Vector3.new(0, cameraY, 0)
	
	task.wait()
end
1 Like

For any future searches looking for an answer to this problem, it was very obvious all along, and that was to remove the weld and use the same formula I use to place the cameraPart initially, which positions and rotates the cameraPart relative to the humanoid root part using :ToWorldSpace()

local inputVector = Control:GetMoveVector()
local cameraY = math.clamp(prevCameraY - inputVector.X, -30, 30)
cameraPart:PivotTo(root.CFrame:ToWorldSpace(CFrame.new(0,0,-7)) * CFrame.Angles(0,math.rad(cameraY),0))	
prevCameraY = cameraY

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