The function you want to use here is math.atan2. What you need to do is project the camera’s CFrame Look vector on to a flat plane, since the vertical direction doesn’t matter in this case.
Below is a more thorough explanation of the solution.
Using the helpful image from the atan2 Wikipedia article (image is also in the dropdown below) we can see that an angle θ between the X axis and a line to a point (x, y) on a 2D plane is calculated as atan2(y, x). Note that y comes first in the atan2 function.
Geometric representation of atan2
Now, we know that we can get a Vector3 representation of the camera’s direction using Camera.CFrame.LookVector
. As I already mentioned in the first paragraph, the vertical direction, in other words the Y component of the LookVector, does not matter. We can project the LookVector into a Vector2 on the XZ plane as (LookVector.X
, LookVector.Z
). For our purposes, we can pretend that the Z component is the Y axis on our 2D plane.
Finally, referring back to the image above, we can calculate the camera’s rotation as follows:
-- Assuming camera is defined
-- Remember that atan2 takes the y parameter first, then x.
local cameraAngle = math.atan2(camera.CFrame.LookVector.Z, camera.CFrame.LookVector.X)
If the camera is looking down the -Z axis, the resulting angle will be -90. However, in your example images the desired result for +Z would be 180 (or -180), and therefore the angle for -Z should be 0. We can fix this by adding an offset of +90 degrees to our final result.
The final script:
-- Assuming camera is defined
-- Remember that atan2 takes the y parameter first, then x.
local cameraAngle = math.atan2(camera.CFrame.LookVector.Z, camera.CFrame.LookVector.X)
cameraAngle += math.rad(90)
Note that math.atan2 returns the angle in radians. If you use it to rotate a UI element, convert the angle to degrees using math.deg(angle)
first.