Let’s say I have a tween of a part moving from point A to point B that loops indefinitely. Well, what if point A and point B change while the tween is being played? How can my tween be updated smoothly to transition into following a new point?
As I move the red part, the tween does not follow the new position of the red part, but it instead follows the old position. This is what I want to change. In other words, I want my tween to start following the new position.
So what approach can I take to update the tween while it is being played? Or is tweening unsuitable for this purpose? I’m not really looking for a code sample answer, just trying to understand what approach I can use to achieve what I want.
Here is the code I’m using for reference. Should be quite simple.
local target = partA
local TweenService = game:GetService("TweenService")
local part = partB
part.Anchored = true
local goal = target
local tweenInfo = TweenInfo.new(
2, -- Time
Enum.EasingStyle.Linear, -- EasingStyle
Enum.EasingDirection.Out, -- EasingDirection
-1, -- RepeatCount (when less than zero the tween will loop indefinitely)
true, -- Reverses (tween will reverse once reaching it's goal)
0 -- DelayTime
)
local tween = TweenService:Create(part, tweenInfo, {Position = target.Position})
tween:Play()
Ok oh a good one so this is what you need to do you need to make a function within that function you need to have both the tween play and the targets so like this.
local target = partA
local TweenService = game:GetService("TweenService")
local part = partB
part.Anchored = true
local goal = target
local tweenInfo = TweenInfo.new(
2, -- Time
Enum.EasingStyle.Linear, -- EasingStyle
Enum.EasingDirection.Out, -- EasingDirection
-1, -- RepeatCount (when less than zero the tween will loop indefinitely)
true, -- Reverses (tween will reverse once reaching it's goal)
0 -- DelayTime
)
function MovePart()
target = partA
part = partB
TweenService:Create(part, tweenInfo, {Position = target.Position})
end
MovePart()
You’re most likely better off using a custom lerp instead of TweenService, as you cannot directly change the goal, especially if you use Reverse. The below code will move towards the endGoal by 5% of it’s distance every wait() interval.
If you want it to take a specific time, then you can use an event loop and the delta as this is just an example. To do the reverses effect, you’ll have to change the goal position once within a certain distance.
You can make it go a specific studs per second using (studsPerSecond / distBetweenGoal) * timeDelta
local endGoal = workspace.Target;
local item = workspace.Root;
while true do
item.CFrame = CFrame.new(item.Position:Lerp(endGoal.Position, .05));
wait();
end
This might be what you’re looking for, but if it’s not then you’re going to have to write your own tweening function like @fireboltofdeath said.
while wait(2) do
local target = partA
local TweenService = game:GetService("TweenService")
local part = partB
part.Anchored = true
local goal = target
local tweenInfo = TweenInfo.new(
2, -- Time
Enum.EasingStyle.Linear, -- EasingStyle
Enum.EasingDirection.Out, -- EasingDirection
0, -- RepeatCount (when less than zero the tween will loop indefinitely)
true, -- Reverses (tween will reverse once reaching it's goal)
0 -- DelayTime
)
local tween = TweenService:Create(part, tweenInfo, {Position = target.Position})
tween:Play()
end
Basically what I did here was tell TweenService to only do the tween once but then encase the code inside a loop so it will update for any new positions.
Alternatively, you can look into using BodyPositions if you want something that changes in real-time.
local tween -- predefine it because you need a reference to it
...
-- in function
if tween then
tween:Cancel() -- do this, then create a new one
end
-- ^ like i said
local tweenInfo = TweenInfo.new(
2, -- Time
Enum.EasingStyle.Linear, -- EasingStyle
Enum.EasingDirection.Out, -- EasingDirection
-1, -- RepeatCount (when less than zero the tween will loop indefinitely)
true, -- Reverses (tween will reverse once reaching it's goal)
0 -- DelayTime
)
tween:Create(part, tweenInfo, {Position = target.Position})
This solution will achieve what you’re looking for. If you want it to be perfectly smooth or otherwise have more specific control over the tween, you can use a custom implementation of Penner’s original easing formulas: easing/lib/easing.lua at master · EmmanuelOga/easing · GitHub
Can’t you just loop a position check and stop the old tween/start a new tween when the part moves? If it reaches the goal before the part moves a Tween.Completed event will fire letting you know to stop checking the position of the part.
Thanks for the link, it’s a nice resource to have. What do you mean with ‘perfectly smooth’, though? Are you suggesting that the other methods have a particular disadvantage and if so, what is it?
I see. I thought about writing a custom lerp but that does mean doing a lot of work which tweening already does, doesn’t it? So it would be quite a shame.
You’re only using a linear lerp, so it’s not any issue. However, if you want different tweening styles, you can simply use TweenService:GetValue() which takes in an alpha just like Vector3:lerp() so it should work just as well.