How to get a CFrame's angles

I actually am going to use your method because it says it is more accurate.

local Angle = Vector3.new(Camera.CFrame - Camera.CFrame.Position)
Angle = Vector3.new(math.deg(Angle.X), math.deg(Angle.Y), math.deg(Angle.Z))

I have this but it is just giving me 0,0,0 every time I print that angle…

4 Likes

The XYZ properties are always going to be the position coordinates, not rotation. The rotation is derived from the rest of the CFrame matrix.

I’m not very good with that stuff, but there’s a way to use some trig functions to reconstruct the rotational XYZ from the other CFrame components. However, I think that’s exactly what ToEulerAnglesYXZ() is doing.

2 Likes
if (input.UserInputType == Enum.UserInputType.MouseButton1) then
			if (self.CanFire == false or self.FPS.IsSprinting) then return end
			
			self.CanFire = false
			
			self.Recoil.angularFrequency = 20
--			local x, y, z = Camera.CFrame:ToEulerAnglesYXZ()
--			local OriginalCameraAngle = Vector3.new(math.deg(x),math.deg(y),math.deg(z))
--			local sx, sy, sz, m00, m01, m02, m10, m11, m12, m20, m21, m22 = Camera.CFrame:GetComponents()
--			local x = math.atan2(-m12, m22)
--			local y = math.asin(m02)
--			local z = math.atan2(-m01, m00)
--			local OriginalCameraAngle = Vector3.new(y,z,0)
--			local Angle = Vector3.new(Camera.CFrame - Camera.CFrame.Position)
--			Angle = Vector3.new(math.deg(Angle.X), math.deg(Angle.Y), math.deg(Angle.Z))
			
			local x, y, z = Camera.CFrame:ToEulerAnglesYXZ()
			local Angle = Vector3.new(math.deg(x),math.deg(y),math.deg(z))
			
			print(Angle)
			
			if (self.FireType == "Auto") then
				while (UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1)) do
					self:Fire()
				end
			elseif (self.FireType == "Semi") then
				self:Fire()
			elseif (self.FireType == "Burst") then
				self:Fire()
				wait(.1)
				self:Fire()
				wait(.1)
				self:Fire()
			end
			
			self.Recoil.angularFrequency = 10
			self.Recoil.p = Angle
			
			self.CanFire = true
		end

Hmmm… what I am trying to do is have a gun, when it is done firing, return the camera to it’s original rotation.

This is what is looks like…
https://gyazo.com/d2dfe96601ca58990bb86e5b239e22ad

The angle gets applied like this:

Camera.CFrame = Camera.CFrame * CFrame.fromEulerAnglesYXZ(self.Recoil.p.y, self.Recoil.p.z, 0)

Am I missing something?

3 Likes

First, make sure when you using math.rad(radius) when using CFrame.Angles(). Math.rad is basically a function that takes the a number and makes it to an angle. Using this, when you do something like

part.CFrame = part.CFrame * CFrame.Angles()

you can change the angle of the part by doing

CFrame.Angles(math.rad(90),0,math.rad(180))

Switching it from CFrame.fromEulerAnglesYXZ() to CFrame.Angles does not make any difference.

That is not what math.rad function does. rad takes an angle given in degrees, and converts it to an angle given in radians. It’s a simple conversion with the following formula:

function rad(x)
    return x * math.pi / 180
end

Likewise, math.deg is its counterpart for converting angles given in radians to angles given in degrees.

3 Likes

Ahh this is a classic example of an X/Y problem.

You are trying to use a mathematical spring for rotational camera recoil. You are asking how to convert the spring to angles, but you should be asking how to interpolate a cframe with the spring code you have.

Speaking of which thats not particularly easy to do so i rcmd trying a different approach. I have a FPS guide somewhere on the devforum with an example placefile. That may help!

8 Likes

I have seen your example place file. It doesn’t have anything for the recoil returning to the original camera position.

It was awhile ago but im pretty sure in the most recent placefile i added at the bottom there’s something in there for recoil.

2 Likes

I’m not having a problem with the recoil. I need the gun to return to the original angle that was before the gun was fire, when the gun is done firing.

1 Like

You could try running a for loop twice (first for recoil, second for recovery) or you could try repeatedly using Lerp() to take the camera where you want to go.

An example of lerp would be


local angle = 0.2

for i = 1,5 do
workspace.Camera.CFrame = workspace.Camera.CFrame:Lerp(workspace.Camera.CFrame * CFrame.Angles(angle,0,0), 0.05)
wait()
end


for i = 1,5 do -- return camera to original position
workspace.Camera.CFrame = workspace.Camera.CFrame:Lerp(workspace.Camera.CFrame * CFrame.Angles(-angle,0,0), 0.05)
wait()
end

or simply

for i = 1,5 do -- return camera to original position
workspace.Camera.CFrame = workspace.Camera.CFrame * CFrame.Angles(angle,0,0)
wait()
end


for i = 1,5 do -- return camera to original position
workspace.Camera.CFrame = workspace.Camera.CFrame * CFrame.Angles(-angle,0,0)
wait()
end

Maybe you could store the original CFrame in a Variable then when the recoil is done use :Lerp function to restore it to normal

1 Like

That wouldn’t always work, the player is constantly moving their camera as well as the recoil.

I know this is a very old post, and I found it actually just looking for a way to mirror a cframe’s roation around a single axis… however, after reading all the posts…

What would probably work is having 2 CFrames for the camera, one is the Actual camera cframe, and one is the Visual camera cframe

Visual is what you will see, actual is where the camera ‘should’ be looking.
Both of these CFrames get upated every time the mouse is moved
However for recoil, only the visible cframe is given a rotation around the x? to move the view upwards
Have the view cframe always trying to lerp its way back to the actual cframe

So that as you look around, even during recoil, you will still end up with the camera returning to where the player is more currently looking.

You could also add a way to ‘unhook’ the trying to sync up the view and actual cframes, so that you could have a sort of ‘look over your shoulders’ effect, for games that might have a more ‘fixed’ actual cframe

3 Likes

been melting my brain for the past 2 or so hours trying to understand how quaternion rotations work just to do what you just said. you are a true life saver g

3 Likes

oh whoops, I thought the post was bumped already… my bad!

It’s okay! It’s Recommended to check it first though.

Also, is this question solved yet?

I’m a little confused. Why is it ToEulerAnglesYXZ when you’re doing local x, y, z? Why is it not ToEulerAnglesXYZ?
Is it because of complicated math stuff?

1 Like

idk if this has been solved yet, but I’ve worked on sophisticated systems for recoil and recoil return.

What you want to do is add more clarity to your recoil system. I mean like add a table containing your recoil pattern. It could look something like this:

myRecoilPattern = {
 {10, {.2,0,.8},{-.2,0} },
 {20, {.5,0,.5},{-.5,0} },
 {30, {.4,0,.5},{-.4,0} },
}

--// for each index in myRecoilPattern, below is the template
--// {tillWhichBullet, {upRecoil, rightRecoil, forHowLong}, {upReturn, rightReturn, forHowLong?} }

so what you could do in your self.Recoil:Fire() line is

local function getCalculatedRecoil(whichBullet) --// note that this number depends on the burstCount, not the position of the bullet in the magazine.
 for _, recoilTable do
  if whichBullet < recoilTable[1] then
   return recoilTable
  end
 end
end

while mouseHeld do
 if fireRateChecksOut then
  self.Recoil:Fire(getCalculatedRecoil())
 end
 runS:Wait()
end

--// then wherever you are receiving that signal,

local recoilTable = --//receive this through signal

local timePassed = 0
local direction = 0
local myRecoilLoop = runS.OnRenderStep:Connect(function(dt)
 timePassed += dt
 if timePassed > recoilTable[2][3] then
  direction += 1
 end
 if direction == 0 then
  cam.CFrame *= CFrame.Angles(recoilTable[2][1] * dt,recoilTable[2][2] * dt)
 elseif direction == 1 then
  cam.CFrame *= CFrame.Angles(recoilTable[3][1] * dt, recoilTable[3][2] * dt)
 end
end)

this is only to show you the general structure of more sophisticated recoil systems. I’m sure you can add more to it yourself.

Have Fun!

ALSO REMEMBER TO DISCONNECT THE RENDERSTEP AFTER USE myRecoilLoop:Disconnect()

1 Like

There are 2 ways:
• You could use CFrame - CFrame.Position if you want the Cframe without its position.
• You can use local X, Y, Z = CFrame:ToOrientation() if you need the values for mirroring or printing them etc. !

Also no need for math.deg() etc. you can just grab one of the angles and do something like this:

local X, Y, Z = MyCFrame:ToOrientation()
print(X / math.pi * 180, Y / math.pi * 180, Z / math.pi * 180)

And if you need it as a vector just do this:

local Rot = Vector3.new(MyCFrame:ToOrientation()) / math.pi * 180
print(Rot)
2 Likes