godotengine / godot-proposals

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

Add an AnimationPlayer method to get the current frame of the timeline position #9267

Open ThiagoMoraesGD opened 4 months ago

ThiagoMoraesGD commented 4 months ago

Describe the project you are working on

Adventure game with battle system

Describe the problem or limitation you are having in your project

Cannot implement logic, like damage count, properly. Time position is not reliable

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

A method to access frame position of the current animation using gdscript API. This information is only avaiable through GUI panel

134523454262456345

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

AnimationPlayer.current_animation_frame()

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

I didn't find a work around for this

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

Involves changing the gdscript api and it is mandatory for most modern games.

AThousandShips commented 4 months ago

The frame is, as far as I know, just a feature of the editor to help with editing, animations and the player doesn't have frames, it operates on time, in seconds

ThiagoMoraesGD commented 4 months ago

I see. Even if its not an actual frame, i think would be good to have access to this information at game runtime.

AThousandShips commented 4 months ago

It doesn't change anything in the animation data, so that would be impossible, it's just like the grid in the 2D editor

ThiagoMoraesGD commented 4 months ago

Maybe replicate the logic that build that UI "frames" in AnimationPlayer class?

AThousandShips commented 4 months ago

But why? It's not relevant for the code, just compute it yourself instead by dividing what ever your frame rate is, that's a simple workaround

ThiagoMoraesGD commented 4 months ago

Why getting the frame position is relevant to code in 2D (there's a method for it) but its not relevant for 3D?

AThousandShips commented 4 months ago

There isn't a 2D animation player? The animation class isn't just 3D, so I'm not sure what you mean?

ThiagoMoraesGD commented 4 months ago

You assume that is not relevante for the code. My point is that is relevant the same way. A person can compute it yourself the actual frame of a animated sprite, can compute yourself the render process, etc...

AThousandShips commented 4 months ago

There's no 2D animation though, do you mean AnimatedSprite2D? That's not the same thing, it works completely differently (and isn't just 2D, there's AnimatedSprite3D too) No part of the animation system uses frames, not 2D, not 3D

It isn't relevant as the animation just doesn't deal with frames, it doesn't matter to it, and most people don't use it, if you do need it you can just work around it by doing maths on it :) Doesn't need to be added as it's not relevant for most users and is simple to do

So to be clear: Animation and AnimationPlayer doesn't use frames, at all, they are only a tool to help when editing in the editor, they don't matter anywhere else, if you do need them you can just compute them, but adding it to the engine itself when it doesn't do anything isn't worth it IMO if you can just do it yourself easily with just a single line of code

ThiagoMoraesGD commented 4 months ago

Animation process in general deal with frames. You mean the godot API doesn't and i think it should. Its a common feature in all modern engines. Having a reliable way to determine and trigger code/events in a specific moment of the animation, maybe not using "frames" (i just thought that is the easyest way to implement it). FPS isn't fixed and "do the math on your own" can be applied to any requested feature.

AThousandShips commented 4 months ago

It uses time, not frames, animation in general doesn't use frames, can you show me other engine that use frames and not time? (Unity doesn't)

Having a reliable way to determine and trigger code/events in a specific moment of the animation

You mean like using method tracks? You really shouldn't be checking the time of an animation and relying on it, you should use the features that are available

FPS isn't fixed

So now we're not talking about the frames in the animation as the editor uses it, but rendering FPS in the game? Those are two different things, please be clear about what you are talking about. The animation will progress the same way regardless of the game FPS, it doesn't work based on just frames rendered, nothing in the engine does

and "do the math on your own" can be applied to any requested feature.

Not at all, but when you can do it the solution is to do it, that's how feature proposals work, if it can be worked around and isn't needed a lot then there's no reason to add a feature

ThiagoMoraesGD commented 4 months ago

Using the UI to set this isn't a good workflow. Facing the following scenario (that is pretty common when developing a real game):

I import a file to godot, with dozen maybe hundred of animations. Need to set a script to run only when a specific stage of some animations is reached. Do i have to do this manually, on every single animation that need it? Do this again whenever i update the animation? Would not be better if i can set this programatically?

In unity we don't have frames but we have a method that returns the actual progress of the current animation.

In unreal: https://docs.unrealengine.com/5.3/en-US/BlueprintAPI/Animation/GetCurrentFrame/

ThiagoMoraesGD commented 4 months ago

The method for Skeletal Animations (Animation Sequence) is this -> https://docs.unrealengine.com/4.26/en-US/BlueprintAPI/AnimationBlueprintLibrary/Helpers/GetFrameatTime/ As you can see, it works backwards, you give the Time and it returns the Frame. This illustrates what AThousandShips was telling you, frames are not "first class" for animation at run-time.

But my point here was not to determine if frames are first class or not. Just that the frames are considered in animation process by other engines. The fact is, unreal api have a method that return the animation frame and i can use it on my logic. Godot don´t. Btw AnimNotify is avaiable through unreal API.

In my opinion, no. But different people think differently.

Can you share your opinion? Why is better do this manually on every animation and not programatically?

You can still do it programatically if you want using current_animation_position as explained in the proposal description.

In fact i can't and thats why i came up with the proposal.

AThousandShips commented 4 months ago

I reiterate that you shouldn't really use the time or frame etc. to detect things from scripts, you should use property or method tracks to do that, you can't rely on specific time points or frames being hit when your script fired, depending on how it's done you can miss it because of frame rates, especially with lag

ThiagoMoraesGD commented 4 months ago

Or maybe they are named with some kind of pattern on export?

Simple as that. Just work with patterns.

When in a team, the person doing this is most always not a programmer, but a designer/animator/fx/sfx. If not in a team, you still keep your options open to have someone that is not coder help you out.

But the person who does the animation doesn't need to be a programmer at all. Just send the animations and the programmer take care of logic and where to put triggers or not.

..you can't rely on specific time points or frames being hit when your script fired, depending on how it's done you can miss it because of frame rates, especially with lag

I agree. Like i describe in the "problem" session, time position isn't reliable and theres no "frame check" option. The only way is method track, that work in most cases but can be a waste of time doing repeteadly tasks that a simple algorythm could do.

Kakiroi commented 4 months ago

Why not just call timer or wrap the animation player with other animation player? I'm assuming your animations are like "soldier_attack", "dog_attack","king_attack" and you match keyword like "attack" to discern it's a attack animation, and you want to call "damage" function on same frame time because you don't want to set same time frame for all those attack animation? You will have to play around with strings since animation names are stringnames, but it's reasonably simple to set it up.

ThiagoMoraesGD commented 3 months ago

Why relying on workarounds to get a feature that is native on another engines? I dont have any idea on how to "wrap the animation player with other animation player" to get what i need but sounds like over complicating a simple task. Having only one way to do this, exclusively on UI, isn't the best solution. Workarounds won't be tested by the community.

TokageItLab commented 2 months ago

As mentioned above, Animation has no frame, only time as a double, so if you expect it to always return an integer, this is never possible.

If you do not need exact frame, you can calculate the result of floor() the result of multiplying the FPS (int) by the current_pos (double that accumulates the delta), but aside from the physics process, the idle process, however, has a variable frame rate and may not get the correct fps in some environments.

In other words, all you can do for this is always to use the physics process and calculate the result by floor() the result of multiplying the fps by the current_pos.