godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
86.49k stars 19.27k forks source link

Swapping textures between animations in AnimationPlayer shows frame 0 for a split second before playing the animation #46022

Open Kikasuru opened 3 years ago

Kikasuru commented 3 years ago

Godot version:

v3.2.3

Issue description:

Explained in this link, still happens today. https://godotengine.org/qa/26173/swapping-textures-animations-animationplayer-animation

Calinou commented 3 years ago

@Kikasuru Please upload a minimal reproduction project to make this easier to troubleshoot.

Kikasuru commented 3 years ago

@Kikasuru Please upload a minimal reproduction project to make this easier to troubleshoot.

Well now the bug doesn't want to work in the project I made, even though it still happens in another one I'm working on... strange...

Kikasuru commented 3 years ago

Never mind, found out exactly how to reproduce it, it only happens when the sheet that you load into has more frames than the one that was just loaded.

Minimal reproduction project can be found here, press space to change the sprite.

kleonc commented 3 years ago

The cause of this issue is that animation tracks are being updated in top to bottom fashion. So when you're changing frame property it takes into account not yet updated values of vframes and hframes. In this case it results in index out of bounds error which is being printed to the console (so error is not hidden):

E 0:00:02.917 set_frame: Index p_frame = 24 is out of bounds (vframes * hframes = 4). <C++ Source> scene/2d/sprite.cpp:261 @ set_frame()

The solution is to change the order of the animation tracks so vframes and hframes will be updated before frame:

Godot_v3 2 3-stable_win64_wzN6Vd3XrH

I'd say it's not a bug and this behaviour is expected. Not sure if it's documented though.

maranr commented 2 years ago

The cause of this issue is that animation tracks are being updated in top to bottom fashion. So when you're changing frame property it takes into account not yet updated values of vframes and hframes. In this case it results in index out of bounds error which is being printed to the console (so error is not hidden):

E 0:00:02.917 set_frame: Index p_frame = 24 is out of bounds (vframes * hframes = 4). <C++ Source> scene/2d/sprite.cpp:261 @ set_frame()

The solution is to change the order of the animation tracks so vframes and hframes will be updated before frame:

Godot_v3 2 3-stable_win64_wzN6Vd3XrH

I'd say it's not a bug and this behaviour is expected. Not sure if it's documented though.

Thanks so much for this. It was driving me crazy. Once I changed all my animations to have vframe and hframe on top it stopped the errors.

romhenri commented 12 months ago

Two years later and it saved me.

Proggle commented 8 months ago

The cause of this issue is that animation tracks are being updated in top to bottom fashion. So when you're changing frame property it takes into account not yet updated values of vframes and hframes. In this case it results in index out of bounds error which is being printed to the console (so error is not hidden):

E 0:00:02.917 set_frame: Index p_frame = 24 is out of bounds (vframes * hframes = 4). <C++ Source> scene/2d/sprite.cpp:261 @ set_frame()

The solution is to change the order of the animation tracks so vframes and hframes will be updated before frame:

Godot_v3 2 3-stable_win64_wzN6Vd3XrH

I'd say it's not a bug and this behaviour is expected. Not sure if it's documented though.

It looks like this behavior is no longer functioning properly in the latest build of 4.2. It does not appear to do it in 4.1.2 so that should narrow it down.

My animations occasionally flicker to the wrong frame (even in the editor), and I keep getting errors about the frames being out of bounds which show that it's trying to set the frame before setting hframes and vframes.

E 0:00:20:0979   Sprite2D::set_frame: Index p_frame = 7 is out of bounds (vframes * hframes = 4).
  <C++ Source>   scene\2d\sprite_2d.cpp:235 @ Sprite2D::set_frame()

If it were following a proper top-to-bottom order this wouldn't happen, so something must have broken.

https://github.com/godotengine/godot/assets/89282845/f97449a8-09b4-43d2-8d02-8e92f6b4d161

Ingame the situation is even worse, it goes through two incorrect frames before landing on the proper one.

https://github.com/godotengine/godot/assets/89282845/a5e1023b-03af-422c-8a55-b963fc223e67

Proggle commented 8 months ago

Checked 4.1.3 and it works fine there, I think this regression is part of https://github.com/godotengine/godot/issues/83401

TokageItLab commented 8 months ago

Since the iterate order is fixed in the order of the first cache created, it may be necessary to specify the order with the top most animation that may be blended in a list such as RESET. Or #84106 may be relevant.

elbroandrew commented 6 months ago

Godot 4.2.1 v4.2.1.stable.official [b09f793f5] win 64. I'm loading two sheets, first one is 3 frames x 1 row for 'idle' anim, second one is 5 frames x 1 row for 'attack' anim. When I connect them in Anim Tree, I'm getting 'Frame' and 'Frame Coords' values in the editor running in the loop. When I run the scene, an error occurs: "E 0:00:06:0792 set_frame: Index p_frame = 4 is out of bounds (vframes * hframes = 3). <C++ Source> scene/2d/sprite_2d.cpp:235 @ set_frame()".

TokageItLab commented 6 months ago

As I commented above, after 4.2 the order in which tracks are processed depends on the order in which the cache is created; For technical reasons, it do not look at the order of tracks when processing animations since it is not possible to determine priority when animations of different order are blended/xfaded.

The order of cache creation may not match the order of the animation tracks to be played. It means that the values may not be updated in the order of the animation tracks to be played.

Also, at that time, AnimationPlayer/AnimationTree iterates through all the animation list it has when it is activated and creates a cache, so the order in which the animations play is irrelevant, only the order of the animation list is relevant.


For example:

If you have two animations in the animation list like below, if A is cached first and B is cached later, the cache order will be frames, vframes, hframes. Even if you play B, the process order does not change from frames, vframes, hframes.

As I remember, the RESET animation is probably cached first, so you should be able to fix the cache order by having a RESET animation with the following track order.


I guess the cache order will probably match in that RESET animation's track order as long as it exists. But probably to handle this correctly, we need to add a property somewhere to indicate the priority of the track processing.