Make part rotate on only 1 axis

Ok, so I am using CFrame.lookAt to make a part face another part. This works fine, but the part is rotating on all axes to face the other part. I want it to just rotate on the Y axis, not the X and Z. How could I do this?

1 Like

The way I would do it is:

After setting the part’s CFrame to the lookAt CFrame, we need to figure out how to offset the orientation X and the orientation Z of the CFrame to turn it into 0, so only our orientation Y of our CFrame will be changed while the X & Z are 0. This requires some math and ToWorldSpace.

First, we’re gonna get the orientation X and the orientation Z of our part.

part1.CFrame = CFrame.lookAt(part1.Position, part2.Position)

local orientationX = part1.Orientation.X
local orientationZ = part1.Orientation.Z

Next, we need to calculate how much we need to increase or decrease our orientation X & Z to make it 0.

Therefore, the offset we need to add/subtract is just the opposite sign (+/-) of our orientation X and Z because we need to cancel out our orientation X and Z. Don’t get me? Here’s an example:

If the Orientation X is at 30, we take the opposite sign of 30, which is -30. This is what we’ll add to our Orientation X to make it 0.

30 + (-30) = 0

Same rules apply for negative orientations, for example, if our Orientation Z is at -60, we take the opposite sign of -60, which is +60.

-60 + (+60) = 0

Now that we know this, we just need to figure out how to take the opposite sign of both of our orientation X & Z independently. We can do this by multiplying each of them by -1.

part1.CFrame = CFrame.lookAt(part1.Position, part2.Position)

local orientationX = part1.Orientation.X
local orientationZ = part1.Orientation.Z

local orientationXOffset = orientationX * -1
local orientationZOffset = orientationZ * -1

We can create a new orientation CFrame with these values (which will serve how much we are offsetting the X and the Z), with the orientation Y being 0 because we are not offsetting the Y, only the X and the Z.

part1.CFrame = CFrame.lookAt(part1.Position, part2.Position)

local orientationX = part1.Orientation.X
local orientationZ = part1.Orientation.Z

local orientationXOffset = orientationX * -1
local orientationZOffset = orientationZ * -1

local orientationOffsetCFrame = CFrame.Angles(math.rad(orientationXOffset), 0, math.rad(orientationZOffset))

Finally, we can use ToWorldSpace, which is a CFrame method to offset our current CFrame’s orientation by another CFrame’s orientation (in this case, our orientationOffsetCFrame).

part1.CFrame = CFrame.lookAt(part1.Position, part2.Position)

local orientationX = part1.Orientation.X
local orientationZ = part1.Orientation.Z

local orientationXOffset = orientationX * -1
local orientationZOffset = orientationZ * -1

local orientationOffsetCFrame = CFrame.Angles(math.rad(orientationXOffset), 0, math.rad(orientationZOffset))

part1.CFrame = part1.CFrame:ToWorldSpace(orientationOffsetCFrame)

And you’re done.
If you have any questions, let me know!

I am testing this now, thanks for the informative reply!

is there a way I can get the orientationX and orientationY without setting the CFrame of the part? I need this because I am intending to tween the part to this position, instead of setting it instantly. Thanks!

What are you making specifically? Is it for some sort of power or animation?

This took me way too long to figure out :sweat_smile:

Instead of changing the part’s CFrame immediately to the lookAt CFrame, we can instead store it into a variable.

local lookAtCFrame = CFrame.lookAt(part1.Position, part2.Position)

Next, instead of getting the part’s orientation X and Z, you can use ToOrientation() to get all of the orientation axes.

local lookAtCFrame = CFrame.lookAt(part1.Position, part2.Position)

local orientationX, orientationY, orientationZ = lookAtCFrame:ToOrientation()

Then, since we’re getting the orientation from the CFrame instead of the part directly, we need to convert the X and Z into degrees using math.deg().

local lookAtCFrame = CFrame.lookAt(part1.Position, part2.Position)

local orientationX, orientationY, orientationZ = lookAtCFrame:ToOrientation()

local orientationXOffset = math.deg(orientationX) * -1
local orientationZOffset = math.deg(orientationZ) * -1

The rest is the same, except for the fact that since you’re tweening it, we’ll just save the final CFrame to a variable!

local lookAtCFrame = CFrame.lookAt(part1.Position, part2.Position)

local orientationX, orientationY, orientationZ = lookAtCFrame:ToOrientation()
	
local orientationXOffset = math.deg(orientationX) * -1
local orientationZOffset = math.deg(orientationZ) * -1

local orientationOffsetCFrame = CFrame.Angles(math.rad(orientationXOffset), 0, math.rad(orientationZOffset))

local finalCFrame = lookAtCFrame:ToWorldSpace(orientationOffsetCFrame)

There you go! :grin:

3 Likes

Seen someone else make this look rather simple.

local cframe = CFrame.lookAt(part1.Position, Vector3.new(part2.Position.X, part1.Position.Y, part2.Position.Z)) 

This should remove pitch from the equation without relying on orientation → cframe calculations.

3 Likes

Wow, it worked! Thank you for the help!

2 Likes

This is a way better solution honestly, I overcomplicated things too much :flushed:

didn’t work for me, so i used yours

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