godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.07k stars 69 forks source link

Add a more intuitive way to edit animation in `AnimationPlayer` #4368

Open RechieKho opened 2 years ago

RechieKho commented 2 years ago

Describe the project you are working on

I am currently making a 2D platformer + rhythm game in which the enemies attack in a level is animated using AnimationPlayer in order to sync to the background music.

I have more than 30 (and counting) EnemyHurtBox nodes in the scene. In order to inflict damage to the player in the hurt box, hurt() function need to be called. Since this is a rhythm game in which the enemy attacks are based on the music, the hurt() function need to be called according to the beat of the music. Thus, the best way to sync the attacks to the music is to use AnimationPlayer to animate it.

Describe the problem or limitation you are having in your project

Add “call method” track & method keys

If you have tried using “call method” tracks in AnimationPlayer, you'll know it is a pain to add the tracks and insert “method” keys. The only way is to add the tracks one at a time. If the scene only contains a few nodes, it is fine. But when the scene contains 100+ of nodes, selecting that one node to be added will inflict enormous pain to your eyes.

This picture best describe my pain:

AnimationPlayerAddTrack

When comes to adding “method” keys to the call method tracks, once again, the only way to add the key is to add it one by one.

InsertKey

The current way of adding call method track and insert method keys is so troublesome until it causes problem such as:

Repetitive pattern in calling methods

Furthermore, when animating methods, it is very likely to see repeating pattern. For instances, here is a timeline of a boss’s attack call animation.

UnGroupKeyframe_Normal

Usually, a group of keys is used to induce one action. In above example, one boss attack require start_cue(), stop_cue(), start_attack(), stop_attack(). You might be thinking that why don’t I just make a function that calls these method through coroutine. Well, it is really much better to put all the relevant information in one place. It would be a disaster that going back and forth from inspector and AnimationPlayer and calculate the duration between calls so the call won’t overlap.

Because if the groups of keys overlap, the action cannot be induced.

UnGroupedKeyframe_overlapped

The repetitive pattern not only occurs in animating methods, but also in other aspect. For instances, you are animating the glow of a star. The animation will be similar like below.

AnimatingCrystal

To make the effect of the star twinkles, the star’s modulate need to be from dark to bright, and dark again. This one sequence of changing of modulate is one action, one twinkle. And if it the action overlap, it becomes weirdly-timed twinkles.

So wouldn’t it be nice to group key? (foreshadowing)

General animation utility

Lastly, “transforming” selected keys is tedious. “Transforming” here refers to scaling and copy-pasting (moving keys is good).

Scaling keys are very cumbersome. Firstly, the scale option hides itself from the user in the “Edit” button. Second, prompts user to input scale factor is not user-friendly. There is no immediate visual feedback like scaling a Sprite.

ScalingCanvasItem

You can SEE how the scaling goes when scaling in the viewport.

ScaleInAnimation

But you CAN’T immediately SEE how the scale ratio affecting the keys.

Someone also faces this problem

For copy-pasting tracks, it is as cumbersome as animating methods. When copying tracks, you are bombarded with tracks.

CopyPain

It is abusing the user’s attention span.

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

Repetitive pattern in calling methods

I would like to start my discussion on this problem prior to Add “call method” track & method keys.

It is sensible to have a feature that groups keys together.

GroupedKey

Group cannot overlap each other. A group symbolizes one action. For a property, it is no good to see two actions overlapping each other (as it results weirdness). For calling methods, overlapping actions can means that the user disobey the single-responsible principle as doing two things at the same time mostly means the subject is having more than one responsibility.

If you scale the group (by dragging the handle at head or tail of group), the key will also scale. Moving the group will move the all the keys with it. The user still can adjust the position of the key in the group by just moving that single key.

ScalingGroup

For the user, to group the keys, it will be as easy as selecting the keys and press a “group” icon.

Add “call method” track & method keys

Making the user to choose the node through the dialog is a not the best and cumbersome. It is better to take advantage of the selected nodes from the tree rather than using dialog. When the user is editing an animation and selects a node or nodes. This “Animate Method” property appears in the inspector.

AnimateMethod

Through the “Choose Methods…” button, this dialog shows up.

AnimateMethodDialog

The user can input the method call (with its argument) with auto-completion though the LineEdit. Auto-completion will show the common methods of the nodes. Only common methods is accepted. When the advance toggle is turned on, the LineEdit will be replaced by a list of methods like below.

AnimateMethodDialogAdvance

The user can add or remove methods in the list. The timeline will shows each method key in the specified time frame (in the above dialog, the time frame is 2 seconds). The “Ease graph” gives the user fun ways to arrange the methods in the time frame. For an instances,

Ease graph: EaseCurve

Method keys: EaseAnimation **Just think that the balls are the method keys

Users can still edit the keys manually, but it will disable the “Ease graph”, and enable “Ease graph” will apply the arrangement back to the method keys (and the user’s edit will be gone... Well, still can CTRL-Z if it is accidental).

After the user is done with the settings, hit “Apply”. Now, the dialog is gone. Nothing change, not until the user hit the “key” icon. As soon as the user hit the “key” icon, voilà! The method keys are inserted just as the settings.

The method keys will automatically grouped together so when the user spams the “key” icon, instead of overlapping the methods keys, the grouped method keys are pushed back.

If the advance toggle is turned off, only one method call is used and inserted (without grouping) when the “key” icon is pressed.

General animation utility

This feature is heavily depends on the solution mentioned in Repetitive pattern in calling methods. There will be two type of editing tools, key editing and group editing.

Key editing

For key editing, it is for editing key (of course). When in key editing mode, the user cannot select keys through groups. If the user move a key into a group, then the key is in the group. if a key is moved out from a group, the key is not in the group (and the group will shrink).

CTRL + left click or dragging is still the same as current version (selecting multiple keys). When multiple keys in a same track are selected, there will be a pseudo-group that groups the multiple keys selected for each track.

Pseudo-group is not a group, it is temporary in will disappear when there is no multiple keys selected in a track. The purpose of this is to allow the user scale the selected keys only (by dragging the handle). They will all scale together when the user drags one of the handles.

When copy-pasting or duplicating, it's still behave the same (copy-paste or duplicate key to the current animation time)

Group editing

For group editing, it is for editing group. When in group editing mode, the user can only select or deselect a group or groups before doing any further operation. After at least one group is selected, the user can edit the key inside the group. Moving other keys (that is not belong to a group) on the same track will cause the group selected expands and reach the key. If multiple group is selected, only the last selected group will expands. Clicking other group will select the clicked group and deselect the current group. Clicking any place in the timeline that is not the above mentioned items (other keys that is not belong to a group and on the same track, other group) will deselect the group.

CTRL + left click or dragging is now for selecting multiple groups. CTRL+ left click will set the last selected group. The groups will scale together if the user drags one of the handles of the selected group.

SelectedGroup

When copy-pasting or duplicating, instead of keys, it copy-pasting or duplicating group.

For copy-pasting tracks, add a “Clipboard” icon next to the “trash” icon in a track. Clicking the “Clipboard” icon will result the icon turns to a “tick”, indicating that it is copied, clicking the tick again will make the “tick” returns back to “Clipboard” icon, indicating that it is not copied.

If there is copied track, then there will be a “Paste” option in the right-click menu. As soon as the user clicks the “Clipboard” icon of a track in different animation, the previous track selected to be copied will be deselected.

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

All the mock-ups and diagrams are in the above sections.

For selecting common methods, my plan is to find out the common classes between the selected nodes, then prepare a list of methods (with its parameter) from the classes.

For grouping, make a KeyGroup class that stores the keys and the ratio (duration from start of group to the key / the total duration). When the group scales, just:

key_offset = group.offset + group.get_key().ratio * group.duration
# key_offset means the duration between the key and the start of the animation

Most of the GUI are designed to be similar to the godot's GUI. So it reduces complexity.

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

There is no workaround that only need few lines of script.

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

Why not a good, user-friendly, animation editor out of the box?

Mickeon commented 2 years ago

I feel like this one is related to an Animation Editor overhaul: https://github.com/godotengine/godot-proposals/issues/3950

The current Animation Editor is generally feature complete, but it's so clunky to make changes on, it completely discouraged me from making actual use of it. Most starting users experimenting with the Godot Editor may feel the same, too.