How to "normalize" an angle

Hello, i’m having problems with a custom shiftlock system i’m trying to make.

local RS = game:GetService("RunService")
local UIS = game:GetService("UserInputService")
local ShiftLock = false
local Camera = workspace.CurrentCamera
local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Zoom = 5
local RY = 0
local RX = 0
RS.RenderStepped:Connect(function()
	if ShiftLock then
		local delta = UIS:GetMouseDelta()
		local X,Y,Z = Camera.CFrame:ToEulerAnglesXYZ()
		local YDeg = math.deg(Y)
		local CX,CY,CZ = Character.PrimaryPart.CFrame:ToEulerAnglesXYZ()
		Character:SetPrimaryPartCFrame(CFrame.new(Character.PrimaryPart.Position) * CFrame.Angles(CX,Y,CZ))
		
		local Y1 = delta.Y
		local X1 = delta.X
		RY += Y1
		RX += X1
		print(Zoom)
		local CF = (Character.PrimaryPart.CFrame * CFrame.Angles(math.rad(RY),math.rad(RX),0)) * CFrame.new(-Character.PrimaryPart.CFrame.LookVector*Zoom) 
		Camera.CFrame = CF
	end
end)
UIS.InputBegan:Connect(function(key)
	if key.KeyCode == Enum.KeyCode.LeftShift then
		ShiftLock = not ShiftLock
		if ShiftLock then
			Camera.CameraType = Enum.CameraType.Scriptable
			UIS.MouseBehavior = Enum.MouseBehavior.LockCenter
		else
			Camera.CameraType = Enum.CameraType.Custom
			UIS.MouseBehavior = Enum.MouseBehavior.Default
		end
	end
end)
UIS.InputChanged:Connect(function(inp)
	if inp.UserInputType == Enum.UserInputType.MouseWheel then
		if inp.Position.Z == 1 then
			Zoom = math.clamp(Zoom + 5,5,100)
		else
			Zoom = math.clamp(Zoom - 5,5,100)
		end
	end
end)

Here’s what happens.

1 Like

CFrame * CFrame results in a CFrame that is the first one, transformed by the second one, relative to the first one. So if the second one is a rotation, the result will be the first one rotated relative to the first one. You get that result because you’re rotating the camera on it’s local Y axis. “normal” fps cameras generally rotate on the world-space Y axis.

To get the correct result you’ll have to pitch (rotate on X axis) relative to the camera and yaw (rotate on Y axis) relative to the world. You can convert from the world-space Y axis to the camera’s current object space coordinates using VectorToObjectSpace and then create a rotation CFrame using fromAxisAngle.

Here’s an example script showing exactly how to do it:

local InputS = game:GetService("UserInputService")

local cam = game.Workspace.CurrentCamera

cam:GetPropertyChangedSignal("CameraType"):Connect(function()
	if cam.CameraType ~= Enum.CameraType.Scriptable then
		--Needed because there's a bug with the Roblox engine or some built-in script causing CameraType to be reset after LocalScripts run
		cam.CameraType = Enum.CameraType.Scriptable
		print(":D")
	end
end)
cam.CameraType = Enum.CameraType.Scriptable

InputS:GetPropertyChangedSignal("MouseBehavior"):Connect(function()
	if InputS.MouseBehavior ~= Enum.MouseBehavior.LockCenter then
		--Needed because there's a bug with the Roblox engine or some built-in script causing MouseBehavior to be reset after LocalScripts run
		InputS.MouseBehavior = Enum.MouseBehavior.LockCenter
		print(":3")
	end
end)
InputS.MouseBehavior = Enum.MouseBehavior.LockCenter

cam.CFrame = CFrame.new(0, 20, 0)

InputS.InputChanged:Connect(function(input)
	cam.CFrame *= CFrame.Angles(-input.Delta.Y * 0.01, 0, 0)
	cam.CFrame *= CFrame.fromAxisAngle( cam.CFrame:VectorToObjectSpace(Vector3.yAxis), -input.Delta.X * 0.01 )
end)
1 Like