godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.13k stars 93 forks source link

Allow to reuse Tweens #8966

Open KoBeWi opened 8 months ago

KoBeWi commented 8 months ago

Describe the project you are working on

Godot, including the Tween system.

Describe the problem or limitation you are having in your project

The new Tween system in Godot 4 works in fire-and-forget manner. Make a Tween, it animates and dies, the engine cleans up the remains. This allows to use Tweens anywhere in a very convenient way. The caveat is that once a Tween finishes, you need to make a new one. In practice this simply means that the code defining animation needs to be part of the code that starts the Tween.

The only real drawback it causes is that a new Tween needs to be allocated and set up per each animation. It does not really cause visible performance problems, but if you are tweening something each frame, allocating and de-allocating memory is just inefficient.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

My idea to allow reusing Tweens is to add 2 new methods:

The first one can be used to preserve the Tween after it finishes animating. However this means that the Tween will exist until you kill it manually (though it's automatic for Tweens bound to a Node). The second one will stop the Tween from autostarting, making reusing easier.

This means that if you want to create a Tween for later use, you'd do:

create_tween().set_autostart(false).set_autokill(false)

While this does look verbose, it can be wrapped in a method or even a class:

class_name TweenNode extends Node

var tween: Tween

func _init():
    tween = create_tween().set_autostart(false).set_autokill(false)

func _ready():
    pass # override to define animation

func start():
    tween.start()

etc...

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Add the two methods mentioned above. autokill and autostart would be internal (C++) properties of Tween.

If this enhancement will not be used often, can it be worked around with a few lines of script?

Well it can be actually worked around quite easily.

set_autokill(false) can be achieved with

tween.finished.connect(tween.stop)

set_autostart(false) can be achieved with

var tween = create_tween()
tween.stop()

In fact this was more or less documented until https://github.com/godotengine/godot/pull/74258 Users kept running into problems, because the system wasn't really designed for that. While you can somewhat reuse Tweens, it's easy to make a mistake if you don't know how it works.

Is there a reason why this should be core and not an add-on in the asset library?

tbh I'll just make an addon. Adding this to core is opening a can of worms, based on my past experience with this topic. I'm mostly opening the proposal to see how many people actually care about it.

EDIT: The addon: https://github.com/KoBeWi/Godot-Tween-Suite

passivestar commented 8 months ago

I'm mostly opening the proposal to see how many people actually care about it

I care about tweens. I would love to see them catch up with DOTween. Speaking of which I also care about #7807 or anything that would help with tweening using a curve

On the topic of reusable tweens - a common usecase for them is to play the same tween in two different directions on mouseover/mouseout. This is useful for UI transitions. Both DOTween and Unreal's Timeline node allow playing tweens backwards (and from the current time) and it's very useful. Perhaps this is something that can be discussed in a separate proposal

Reusing the same tween for both directions would also remove the necessity for if tween: tween.stop() checks

KoBeWi commented 8 months ago

I care about tweens.

I also care about tweens, I was referring to reusing tweens, by which I mean being able to replay tween after it has finished, as opposed to creating a new one. Reversing a tween is a separate thing and indeed would require a separate proposal (although a true reversing is difficult to achieve with how tweens are structured).

KoBeWi commented 8 months ago

Here's the promised addon: https://github.com/KoBeWi/Godot-Tween-Suite

For the purpose of this proposal, there is TweeNode, which internally uses reusable Tween, or you can use its static method create_reusable_tween() that creates a Tween which will not go invalid by itself.

Cool stuff, but I'd rather keep it off core, because it's a lower maintenance burden this way.

passivestar commented 8 months ago

Here's the promised addon: https://github.com/KoBeWi/Godot-Tween-Suite

Looks like you've created and entire alternative animation system

What's the advantage over AnimationPlayer? An easier way to define a sequence of actions?

I can't help but think that some kind of a nonlinear animation system (like in blender or maya) where you group keyframes into clips and can then reorder and mix those clips on a timeline would solve the same problem but also give you the best of two worlds (which is flexibility of keyframes + higher level "clips" that can offset values by relative amounts, loop, extrapolate, adjust playback speed, be stacked on top of each other, etc)

KoBeWi commented 8 months ago

What's the advantage over AnimationPlayer?

Not much tbh, other than the animations are more portable and arguably lighter. It's the same old Tween, but with more options. Some people requested a way to edit Tweens from the editor, some want the Tween node back, some don't like that Tweens are getting invalidated. This addon addresses all of these problems.

The AnimationPlayer editor is easier to use due to having timeline, but it still doesn't support relative values and animations starting from an arbitrary value (there are Capture tracks, but they are not as flexible and currently not even working).

thygrrr commented 7 months ago

I'm mostly opening the proposal to see how many people actually care about it

I care about tweens. I would love to see them catch up with DOTween. Speaking of which I also care about #7807 or anything that would help with tweening using a curve

DOTween is not a good pattern. It's very ancient and not very clear to use.

I recommend looking at https://github.com/jeffreylanters/unity-tweens (api version 3) for a much better, "value-type" and callback based tween approach that's incredibly expressive and separates code from configuration. (a "fluent" type API does not achieve this)

z4gon commented 3 months ago

It would be very useful to have a method like stop() but to cancel any ongoing Tweeners. Then be able to .tween_property() again and keep going.

I'm firing a tween on each frame now and I feel it is really inefficient like you said.

cristiadu commented 3 months ago

As a web developer it feels weird to create a new variable each time I need to use the Tween, specially as in my case is a card click and mouseOut kind of logic, so two tweens objects being created each time the person clicks a card