Orient a part's top face toward another object

  1. What do you want to achieve? I have an arrow system where multiple arrows are spawed in and move toward the player in a matter of 10 seconds. The arrow moves toward the player fine, but I want the top face of the arrow to face the player.

  2. What is the issue? This code only moves the arrow toward the player, but doesn’t change the orientation to face the player

Video:

  1. What solutions have you tried so far? I looked on YT and other devforum posts. The only thing I can find is orienting other faces using CFrame.lookAt() and using CFrame.Angles, which I’m not sure how I could implement into this script. (I tried)
function tweenToMovingPart(movePart, targetPart, duration)
	local startCFrame = movePart.CFrame
	local startTime = os.clock()
	local connection = nil
	connection = game:GetService('RunService').Heartbeat:Connect(function()
		local t = math.clamp((os.clock()-startTime)/duration, 0 ,1)
		if movePart and movePart.Parent and targetPart and targetPart.Parent then
			movePart.CFrame = startCFrame:Lerp(targetPart.CFrame, t)
		end
		if t == 1 then
			connection:Disconnect()
			connection = nil
		end
	end)
end
1 Like

CFrame.lookAt() should change the orientation, you may be doing it wrong.

maybe take a reread on the documentation

1 Like

Even after reading this again, all my attempts of CFrame.lookAt() orients the arrow’s front face to the player

EDIT: I think I might have found a solution - nevermind

1 Like

I think I might have worded it weirdly. CFrame.lookAt() did change the orientation, but it changed the front face toward the player. I am looking to change the top face to look at the player.

1 Like

You could use CFrame.lookAt() multiplied with another CFrame.Angles() to fix this. This might not work, but just test other axes.

arrow.CFrame = CFrame.lookAt(arrow, plrPart) * CFrame.Angles(math.rad(90), 0, 0) -- rotates 90 degrees on the x axis
2 Likes

This works really good, thank you!

Keep in mind that this code won’t work very well if both of the objects are in the same position. A better way to do this would be to use the code from the following post:

1 Like

Right now I disconnect and destroy the arrow once it gets in the correct position, but do you know what the normalId stands for?

I don’t know what it means, but you can the function just how you use CFrame.lookAt(). Like this:

local UNIT_X = Vector3.new(1, 0, 0)
local UNIT_Y = Vector3.new(0, 1, 0)
local UNIT_Z = Vector3.new(0, 0, 1)
local IDENTITYCF = CFrame.new()

local function lookAt(eye, target, normalId)
	local cf = IDENTITYCF
	local forward = target - eye
	
	-- technically returns 0, 1, 0, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN
	if (forward:Dot(forward) == 0) then
		return IDENTITYCF + eye
	end
	
	-- calculate needed rotation for adjusting face
	if (normalId and normalId ~= Enum.NormalId.Front) then
		local face = Vector3.FromNormalId(normalId)
		local axis = math.abs(face.z) >= 1 and UNIT_Y or UNIT_Z:Cross(face)
		local theta = math.acos(-face.z)
		cf = CFrame.fromAxisAngle(axis, theta)
	end
	
	-- return the CFrame
	forward = forward.Unit
	if (math.abs(forward.y) >= 0.9999) then
		return CFrame.fromMatrix(eye, -math.sign(forward.y) * UNIT_Z, UNIT_X) * cf
	else
		local right = forward:Cross(UNIT_Y).Unit
		local up = right:Cross(forward).Unit
		return CFrame.fromMatrix(eye, right, up) * cf
	end
end
workspace.Part1.CFrame = lookAt(workspace.Part1.Position, workspace.Part2.Position)

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