Possible to loop position with Tween in object space while also moving object in world space?

It looks like TweenService tweens can only be used with global positions. Is that correct? There’s no way to use relative change in position and employ the same tween from different places when position is being modified? Or, parent a tweened object to something else and have the changes happen in local space? I’m trying to do a short, loopable animation that includes rotation and small position changes (picture a skater spinning in circles while her position wobbles around in a small area–I’m not applying this to a character, that’s just a variation of the problem for illustration).

I can re-create the tween with new position a number of times in a loop.
Or do it all with CFrame lerp + RenderStepped.(:nauseated_face:)

Am I missing some easy/effective way to handle this kind of thing–like a way to move an object that has a looping tween which includes local translations? Maybe I’m just tired and it’s something obvious. Thanks for your thoughts.

3 Likes

I have come across this problem many times with doors. I am certain there is a MUCH better way than I am using, but what I do is this:

if object.Orientation.Y >= 90 then
    thisTween:Play();
else
    thisTween2:Play();
end

I am making sure to use the Z axis instead of the X when the orientation ‘if’ statement is met.

1 Like

Thanks for sharing that. I’ll play around with the orientation trigger idea and see if I can get something workable while I’m mulling it over. The actual problem is a wall (actually several at once) that grows and at it’s leading edge is an animation of a section rotating and sliding into place. This happens quickly and repeatedly as the wall grows almost like a line of doors shutting and sliding forward in sequence (the first way I thought to describe this didn’t make nearly as much sense…hence the skater thing). Appreciate your thoughts. The rotating step and the sliding step would be easily handled as you described. Although, I’d have to recreate the sliding into place tween as I move the position of the leading edge. I may have to go with only rotation and do away with the sliding into place bit. Not nearly as cool.

Unfortunately I can’t offer a better solution until I experiment with the TweenService more than just with positions. Hopefully another dev can help.

1 Like

No worries. I’m happy to have another perspective on things. Is easy to get locked into one way of thinking about it and completely miss something obvious.

By relative position do you mean something like this:

A part is in position X and you want to tween it to X + 10, no matter the value of X?

So essentially move something in a vector, rather than to a specific destination?

1 Like

Yes, exactly.

If you want to position part A relative to part B, then you can weld A to B, and tween the C0/C1 of that weld to whatever offset you want. This only works if A is not Anchored, though. The offset will also be in object space (relative to B), not in world space. A will also need to have a root priority lower than B. Other than that, I can’t think of another solution :frowning:

1 Like

I think you can do this pretty well by just doing some math. All you need to do is calculate the global position of the relative distance you want to use.

For example, here’s a function for what you could do:

function tweenRelative(Instance part, Vec3 relativeDistance)
    local globalPos = part.CFrame + relativeDistance

    -- Here you can handle using the tween service to simply tween to that global position

So, all that code will do is calculate the global position based on a relative vector 3 you provided.

1 Like

Ahh. Tween the offset. That might be what I’m looking for. I hadn’t thought to look at that. Thanks!

@CodeNinja16 Creating a new tween each time the object changes location (prior to running the tween)?

Thanks all. I’ll run with some of these ideas in the morning and see if I can get it to work like I want.

Yes, unfortunately. Judging by the documentation for the tweenservice’s create function, you can’t change the values of a tween, meaning you need to create a new one when you want to tween.

With this solution, there are a few problems, not just with anchored parts as you said. For example, if you want to then rotate the part, it will be a real headache with removing welds, changing orientation, then welding again to the face nearest to the part tweened from. Also, it assumes that you have an instance to tween from. You can’t just work with CFrame values.

You could just convert any relevant vectors to object space and work in object space. Is that what you’re asking?

Say I have a spinning coin pickup that I want to animate. I could tween the rotation and loop it and place the coin anywhere I want, and it would behave as expected without requiring any changes to the tween. Then, let’s say I decide to change the animation to bob up and down while spinning, I could also do this with a tween (the same one since it’s a new parameter on the same object), but the animation would do the wrong thing if I tried moving the coin to a new place because the position values given to tween:create for the bob movement are all in world space. I’d need to rebuild the tween every time I moved the coin. I’m essentially asking if there is some way that I’m not seeing to do the spin+bob using tweens (without having to rebuild the tween all the time for what I’m doing).

I have a version that changes the tween every time the object’s position changes, but I need to do this kind of thing a fair number of times in a short span of time with several objects at once, and the end result has me re-creating a lot of tweens on every loop of the animation. It seems excessive and cludgy for what I’m trying to do.

Before abandoning the nice and simple tweens, I wanted to see if anyone knew of a way to either parent the tweened object to another object so it could have local translations as part of the animation and also be moved to another location, or somehow get the tween object to allow secondary motions

So you basically want to tween something reletavistically from a part without having to create multiple tweens to use absolute coordinates?

So like tween three studs forward, instead of tween to CFrame of the position three studs forward

Yes, basically. Picture moving an object 3 studs forward and collapsing it back three studs in a loop (as a local movement) while also moving the root of the tween/animation globally by 3 studs each time it loops so that the effect is something not unlike an inchworm crawling. It looks like I wouldn’t be able to use that inner loop at all; I’d have to rebuild the tween for each iteration.

In other contexts I would have done this kind of thing by animating the back and forth loop in the object space of one node and then parent that to another node in order to do the global placement. Since it doesn’t look like tweening works on anything but world space, I think I’m stuck using another approach. :confused:

Sorry if this is an obvious question, but what do you mean by “local movement”. As in here:

Relative to the object’s frame of reference rather than the global frame (world space).

Okay, understood.

Well, sadly, that means that my previous solution doesn’t work. Did you try out the solution with tweening a part’s offset from a weld? That might do what you want.

Your warnings about potential problems with that approach plus the idea of managing several of these things attached to RenderStepped had me looking at other options, so no. I haven’t yet. I went a completely different path and set it up as a model with hinge and prismatic constraint servos. It has some benefits such as the leading edge animation travels with the growing wall without doing anything extra, but those constraints are a little finicky. I’m also concerned about the whole thing getting out of sync if there are any hiccups with playback speed. And, I’m having trouble getting it to play as quickly as I’d like.

I’ll mess with that a bit more and then try the weld offset idea and CFraming.

You can tween objects relatively by tweening a CFrameValue by itself, and assigning the object’s CFrame to the value’s CFrame multiplied by whatever the CFrame is supposed to be relative to, and this happens every time the value’s .Changed event fires:

local RelPart = path.to.Part1
local RelativeCF = Instance.new("CFrameValue")
RelativeCF.Value = CFrame.new()

local RelativeTo = path.to.Part2 -- or just a cframe by itself i guess

TweenService:Create( --tween to new cframe
    RelativeCF,
    TweenInfo.new(...),
    {Value = ...}
):Play()

RelativeCF.Changed:Connect(function() -- move part whenever this cframe changes, basically throughout the tween
    RelPart.CFrame = RelativeTo.CFrame * RelativeCF.Value
end)

Hopefully, that helps. It was written hastily, so expect logic errors or stuff of the sort.

Edit:

In your example from Post #16, you could probably use two tweens at the same time, one moving forward linearly and another moving back and forth in a loop.

local tweeninfo1 = TweenInfo.new(
    10, -- time
    Enum.EasingStyle.Linear,
    Enum.EasingDirection.Out,
    0, -- loop for
    false, -- reverses
    0 -- delay
)
local tweeninfo2 = TweenInfo.new(
    1,
    Enum.EasingStyle.Quad,
    Enum.EasingDirection.InOut,
    15, -- or 30? Something like that...
    true,
    0
)

local part = path.to.Part

local CF1 = Instance.new("CFrameValue")
CF1.Value = part.CFrame
local CF2 = Instance.new("CFrameValue")
CF2.Value = CFrame.new()

TweenService:Create(
    CF1,
    tweeninfo1, -- makes the value tween linearly from current position to 30 studs ahead on the Z-axis
    {Value = CF1.Value * CFrame.new(0,0,30)}
):Play()
TweenService:Create(
    CF2,
    tweeninfo2, -- makes the value tween from left to right on the X-axis
    {Value = CFrame.new(3,0,0)}
):Play()

CF1.Changed:Connect(function()
    part.CFrame = CF1.Value * CF2.Value
end)

Written a bit more thoughtfully, hopefully that helps again…

5 Likes