Making a part face another whilst moving in its direction using tweens

Heya!

  1. What do you want to achieve?
    I’m trying to make some sort of planet selection system thing and I’d like the red part (in the picture) to face the planet it’s currently moving towards.

  2. What is the issue?
    I can’t seem to get the rotation right. If I use CFrame.LookAt() it just breaks completely

  3. What solutions have you tried so far?
    This how my system currently works:

local travelTime = (ship.PrimaryPart.Position -planetModel.PrimaryPart.Position).Magnitude / 70
    local newCFrame = CFrame.new(planetModel.PrimaryPart.Position + Vector3.new(3, 0, 2.5))
	
	local shipTween = tweenService:Create(ship.PrimaryPart, TweenInfo.new(travelTime, Enum.EasingStyle.Linear), {CFrame = newCFrame})
	shipTween:Play()

As you can see, I’m using a tween to move the ship to the correct location, although I’d like it to face towards the planet as well.

Ship when spawned

Ship when moved to the next planet (not facing the planet)

Any help would be appreciated!!!

hi for rotation to be preserve, newCframe should be
local newCframe = Cframe.new(offset) * PrimaryPart.CFrame

The reason how this works is cuz Cframe is stores both position and rotation data. Reason for CFrame offset to be first before Part’s Cframe is so that offset is relative to world ( I assume you want that ).

I hope this help!

You need to construct the tween end CFrame using the direction to the target position, like CFrame.lookAlong(targetPosition, travelDirection)

So something like:

local startCFrame = ship:GetPivot() -- this is the ship's current cframe 
local targetPosition = planetModel:GetPivot().Position + Vector3.new(3, 0, 2.5) -- this is the target position 

-- you want to get the direction for the ship to travel along 
local travelDirection = targetPosition - startCFrame.Position 

local travelStartCFrame = CFrame.lookAlong(startCFrame.Position, travelDirection)
local travelEndCFrame = CFrame.lookAlong(targetPosition, travelDirection)

-- then to tween:
-- first set the ship to the start cframe, this is just a rotation
ship:PivotTo(travelStartCFrame)

-- then tween
local shipTween = tweenService:Create(ship.PrimaryPart, TweenInfo.new(travelTime, Enum.EasingStyle.Linear), {CFrame = travelEndCFrame})
shipTween:Play()

Woah that works really well already, thanks!
But is there a way to incorporate the rotation change of the ship into the tween / make it happen smoothly because rn it’s really snappy and doesn’t look that good.

Thanks!

You can tween the rotation first

local rotateTween = TweenService:Create(ship.PrimaryPart, TweenInfo.new(rotateDuration), {CFrame = travelStartCFrame})
rotateTween:Play()
rotateTween.Completed:Wait() -- wait for the tween to finish first 

Is there an issue in using IKControl for this? If not, I feel like that would be a better option.

Well you can definitely do that, but you’d have to rig up the ship and stuff. If you’re not familiar with how to do all that it’d just end up being more complicated when a simple (and intuitive) sequence of tweens

1 Like

Yea thad’d work. One last question; Is it possible to combine both tweens into one?

In this case… no. Because if you want to smoothly rotate the ship to face towards the planet while moving it at the same time, it’s not possible. You’d have to create two separete tweens, one for handling the rotation and the other handling the position, and call them at the same time.

I decided to go with a much different approach, attempting to combine both the tweens.
The first tween works fine, but the second one really doesn’t lol.
I’m quite terrible with CFrames so I can’t really find a fix.

local offset = Vector3.new(3, 0, 2.5)
	
	local Angle = CFrame.new(ship.PrimaryPart.Position,Vector3.new(planetModel.PrimaryPart.Position.X,ship.PrimaryPart.Position.Y,planetModel.PrimaryPart.Position.Z)+offset) - CFrame.new(ship.PrimaryPart.Position,Vector3.new(planetModel.PrimaryPart.Position.X,ship.PrimaryPart.Position.Y,planetModel.PrimaryPart.Position.Z)+offset).Position
	
	local Goal = {CFrame = ((CFrame.new(ship.PrimaryPart.CFrame.Position) * Angle):Lerp(CFrame.new(planetModel.PrimaryPart.Position+ offset)*Angle, 0.3))}
	local Tween = tweenService:Create(ship.PrimaryPart,TweenInfo.new(travelTime/10*3, Enum.EasingStyle.Quad, Enum.EasingDirection.In),Goal)
	Tween:Play()
	Tween.Completed:Connect(function()

		local Goal = {CFrame = CFrame.new(ship.PrimaryPart.Position+ offset)*Angle}
		local Tween = tweenService:Create(ship.PrimaryPart,TweenInfo.new(travelTime/10*7, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),Goal)
		Tween:Play()
		
		Tween.Completed:Connect(function()
			allowedToMove = true
		end)
	end)

My planet’s primary parts are Rotating cubes. Idk if the rotation of them matters.

Thanks!

1 Like

To create a new CFrame, where the CFrame has a start position and you want it to ‘look at’ another position, you do this!

local lookAtCFrame = CFrame.new(position, lookAtPosition)

So in the case of wanting your ship to face the planet, you’ll do this:

local tweenGoal = {CFrame = CFrame.new(shipPosition, planetPosition)}

Hey thanks for your reply!
I tried something like this but it looked really bad because the ship only finished its turning when reaching the target. My reply above has a solution for this but I can’t get it to work quite well.

2 Likes