godotengine / godot

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

looped animations give unexpected results #959

Closed adolson closed 7 years ago

adolson commented 9 years ago

If you loop an animation and use the continuous interpolation mode, after the last keyframe in a track, things get wonky. If you have a keyframe at the very end of the animation's length, the value will loop back to 0 immediately. If you have a keyframe earlier, it'll count down from that keyframe back to the first keyframe in the track.

I've never seen a loop behave like this before. I tested this in v0.99.3653-pre-beta from January 3rd, and get the same behavior, so this isn't a regression, by the look of it.

Here's a video showing how to reproduce this, in case it's not clear what I'm saying: http://youtu.be/Ti0OBfWR4a8

I can't see why anyone in their right mind would WANT this behavior to happen automatically, since they could simply keyframe back down at the end of the animation. But those of us who don't want this behavior don't have any option unless we want to insert keyframes for EVERY value... Which is simply making things far more tedious than need be. Even extending the animation a bit, inserting a duplicate keyframe there, then setting the length back to the desired value doesn't prevent this from happening (keyframe past length is just ignored, as would logically be expected).

Ace-Dragon commented 9 years ago

As things work right now, if you extend the animation beyond the last keyframe, then you will get a smooth transition back to the first one.

But I can see your point, it would be nice to have an option for the animation to backtrack along every key to the beginning when it reaches the end (which does a virtual extension of the animation with a mirror of the keys).

godotengine commented 9 years ago

frames appear as default as discrete for this same reason, they will be interpolated otherwise maybe there should be an extra interpolation mode, that does not blend begining to end?

On Thu, Dec 11, 2014 at 4:18 PM, Ace-Dragon notifications@github.com wrote:

As things work right now, if you extend the animation beyond the last keyframe, then you will get a smooth transition back to the first one.

But I can see your point, it would be nice to have an option for the animation to backtrack along every key to the beginning when it reaches the end (which does a virtual extension of the animation with a mirror of the keys).

— Reply to this email directly or view it on GitHub https://github.com/okamstudio/godot/issues/959#issuecomment-66672075.

OkamStudio

godotengine commented 9 years ago

er, i mean end to begining

On Thu, Dec 11, 2014 at 4:40 PM, Juan Linietsky juan@okamstudio.com wrote:

frames appear as default as discrete for this same reason, they will be interpolated otherwise maybe there should be an extra interpolation mode, that does not blend begining to end?

On Thu, Dec 11, 2014 at 4:18 PM, Ace-Dragon notifications@github.com wrote:

As things work right now, if you extend the animation beyond the last keyframe, then you will get a smooth transition back to the first one.

But I can see your point, it would be nice to have an option for the animation to backtrack along every key to the beginning when it reaches the end (which does a virtual extension of the animation with a mirror of the keys).

— Reply to this email directly or view it on GitHub https://github.com/okamstudio/godot/issues/959#issuecomment-66672075.

OkamStudio

OkamStudio

adolson commented 9 years ago

@Ace-Dragon even if the keyframe is at the length of the animation, things get weird because it sets the frame back to 0 instead of whatever the keyframe is. It might not be noticeable in all cases, but I definitely notice it in some.

@okamstudio I'd agree with an extra interpolation mode that doesn't blend beginning to end. would appreciate if it's the default as well, since it's the normal behavior.

reduz commented 9 years ago

you would be surprised but as far as artists here and other projects i've worked with, i changed that behavior and made it default because they all requested it, so i guess it should stay default, but i will made the other one as optional

On Thu, Dec 11, 2014 at 4:46 PM, adolson notifications@github.com wrote:

@Ace-Dragon https://github.com/Ace-Dragon even if the keyframe is at the length of the animation, things get weird because it sets the frame back to 0 instead of whatever the keyframe is. It might not be noticeable in all cases, but I definitely notice it in some.

@okamstudio https://github.com/okamstudio I'd agree with an extra interpolation mode that doesn't blend beginning to end. would appreciate if it's the default as well, since it's the normal behavior.

— Reply to this email directly or view it on GitHub https://github.com/okamstudio/godot/issues/959#issuecomment-66676436.

adolson commented 9 years ago

Why doesn't it interpolate back down unless you have it set to looping? If you design your animation and it looks good, and then you enable looping, suddenly it gets all screwy because of that feature. Isn't this at least considered unexpected behavior? Shouldn't it interpolate back down even when not looped, or just not interpolate back down at all? Just looking for some consistency here...

I will close my pull request since you want to keep the current behavior.

In any case, hopefully you can add the option sooner than later.

Cybolic commented 9 years ago

Argh, so this is why my animation looks strange! I stumbled on to this bug report through a Google search, not even looking for the issue; up until now I had just assumed I was a lousy animator. Can we please have a toggle for this behaviour?

reduz commented 9 years ago

it does not interpolate back unless it is set to looping you mean looping without interpolating back? i guess it could be made optional

On Mon, Apr 27, 2015 at 1:07 PM, Christian Dannie Storgaard < notifications@github.com> wrote:

Argh, so this is why my animation looks strange! I stumbled on to this bug report through a Google search, not even looking for the issue; up until now I had just assumed I was a lousy animator. Can we please have a toggle for this behaviour?

— Reply to this email directly or view it on GitHub https://github.com/okamstudio/godot/issues/959#issuecomment-96726138.

Cybolic commented 9 years ago

I don't mind interpolating back (though I think it should be optional), my issue is when for example the last keyframe is set to frame 10, but it actually plays frame 0.

adolson commented 9 years ago

If there is a frame keyframe at the very end of the animation track, the expected behavior is that it won't interpolate when it loops, so it should disable automatically in those cases. However, I'd prefer it as an option anyhow, because I can see other use cases where interpolation is only desired inside the iteration and not between loops. On Apr 27, 2015 12:17 PM, "Christian Dannie Storgaard" < notifications@github.com> wrote:

I don't mind interpolating back (though I think it should be optional), my issue is when for example the last keyframe is set to frame 10, but it actually plays frame 0.

— Reply to this email directly or view it on GitHub https://github.com/okamstudio/godot/issues/959#issuecomment-96729151.

adolson commented 9 years ago

Will this be fixed in 1.2?

akien-mga commented 8 years ago

What's the status on this issue? I actually never noticed it, I guess I'll have to check my animations to see if they are not actually behaving as I intended them to (though I think I have a keyframe at the very end of each animation so I might be exempt from this bug/feature).

adolson commented 8 years ago

I haven't had time to test recently. I did try opening a project but there are too many changes so I'd have to find some time to specifically do some testing in the current version. However, as several of the comments stated, it didn't matter if you had a keyframe at the end, the buggy look still persisted. Some animations it was a lot more noticeable than others, though. That being said, @reduz said it's not a bug, it's by design. So the question is, has he added any options to how looping / interpolation happens?

vnen commented 8 years ago

I think I noticed some weird behavior on animations though I attributed it to myself as a no-artist that I am. From what I can tell, it seems that the keyframe at the end of the animations seems to be ignored (does it make any difference?). The interpolation should happen, as it's a nice feature, but it's not natural in the way it's working last time I checked.

ghost commented 8 years ago

it does not interpolate back unless it is set to looping you mean looping without interpolating back? i guess it could be made optional

@reduz See my bug report here as well #4681

I sincerely ask you, please give us an option to disable the resetting back to frame 0 on loop. Take this spritesheet we have for our game:

image

When looping is enabled on continuous, as you can see via my screen screenshot on my issue (second one), it gets reset back to zero right before it's done animating. This makes it so the loop is not looped correctly, it's basically creating an illusion of a frame that lasts for milliseconds (that is detectable by the human eye, and makes the loop not fluid).

I have hundreds of sprites that are like this and will use the continuation method. I have fallen in love with Godot, Please accept a PR that implements an option to disable this, thank you.

--Nick

Argh, so this is why my animation looks strange! I stumbled on to this bug report through a Google search, not even looking for the issue; up until now I had just assumed I was a lousy animator. Can we please have a toggle for this behaviour?

@Cybolic I'm trying! :8ball:

adolson commented 8 years ago

If there were a PR to merge, I'm sure it would be in by now. My PR, which I closed, fixed the problem completely. But in doing so, it removed this faulty behavior, which Juan wants to keep for some reason. So I closed it.

slapin commented 8 years ago

Any links to the discussion for reference?

On Tue, May 17, 2016 at 8:39 AM, Dana Olson notifications@github.com wrote:

If there were a PR to merge, I'm sure it would be in by now. My PR, which I closed, fixed the problem completely. But in doing so, it removed this faulty behavior, which Juan wants to keep for some reason. So I closed it.

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/godotengine/godot/issues/959#issuecomment-219624265

adolson commented 8 years ago

Scroll up?

punto- commented 8 years ago

Can you try this branch? https://github.com/punto-/godot/tree/floor (the only change should be 1 line in variant_op.cpp, but I don't know how up to date it is with master).

The idea is that the current time offset on a looping animation should be "time modulo length", so a keyframe at the very end of the timeline and a keyframe at the very beginning are essentially at the same time, which is

  1. If your last keyframe is in the middle of the animation, it will interpolate with the next one, which is the first one if the animation loops, but that shouldn't be an issue, you can just duplicate that keyframe at the end if you don't want it to interpolate looping. So if there's a bug, it would be interpolating those 2 keyframes that are at the same point in time.

This patch removes the rounding in int interpolation, which will cause the 1st and last frame of your sprite to be shorter than the rest, maybe that's the issue here?

On 17 May 2016 at 03:05, Dana Olson notifications@github.com wrote:

Scroll up?

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/godotengine/godot/issues/959#issuecomment-219627423

punto- commented 8 years ago

BTW with this patch, your last keyframe has to be the number of frames in the sprite, so if there's 20 frames, the last keyframe should be 20, which is an invalid frame, but the idea is that the last frame will stay at 19 (because it's not rounding anymore), and when it gets to the end it loops back to 0.

On 17 May 2016 at 03:40, Ariel Manzur ariel@godotengine.org wrote:

Can you try this branch? https://github.com/punto-/godot/tree/floor (the only change should be 1 line in variant_op.cpp, but I don't know how up to date it is with master).

The idea is that the current time offset on a looping animation should be "time modulo length", so a keyframe at the very end of the timeline and a keyframe at the very beginning are essentially at the same time, which is

  1. If your last keyframe is in the middle of the animation, it will interpolate with the next one, which is the first one if the animation loops, but that shouldn't be an issue, you can just duplicate that keyframe at the end if you don't want it to interpolate looping. So if there's a bug, it would be interpolating those 2 keyframes that are at the same point in time.

This patch removes the rounding in int interpolation, which will cause the 1st and last frame of your sprite to be shorter than the rest, maybe that's the issue here?

On 17 May 2016 at 03:05, Dana Olson notifications@github.com wrote:

Scroll up?

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/godotengine/godot/issues/959#issuecomment-219627423

Cybolic commented 8 years ago

Seeing as the problem with merging adolson's fix seems to be that the current behaviour is also wanted, I adapted the code into a toggle button, so everyone can be happy :)

akien-mga commented 8 years ago

Reopening as the fix was actually reverted. This should be fixed once and for all for 3.0, we can now break compatibility all we want.

reduz commented 7 years ago

This was fixed already for the never released 2.2, as you can now select the loop mode per track: image closing..

lverona commented 6 years ago

In the Facebook post, referenced by Dillybob1992 we talk of two workarounds:

  1. Add a useless frame and keyframe to this last useless frame. Then looping will be correct.
  2. Add more length to the animation or move the last node to a moment in time before the end of the animation. For instance, if I have 4 frames over a second, the last node should be at 0.75. This will give even time to each frame.

What seems to be happening is this.

  1. Our expectation is that when you keyframe frame 0 and then frame 3, Godot should understand this as the length of the animation being evenly divided between the four frames.

  2. In reality, Godot keyframes a switch to a frame. Which means that when we keyframe the last frame by the end of the length of the animation, it does exactly that - switches to last frame at the last milisecond. In looped mode it probably means that the switch just never shows up.

Before fixing this situation, I would seriously think about what Godot does and how is the current behavior used in other animation cases. Maybe, our expectations are actually not reasonable. Or maybe this is indeed a special case that needs to be handled automatically.

vnen commented 6 years ago

Note that problem is with integers. If you are animating a floating point value, doesn't really matter if it got to 1.0 or to 0.999. But with integers it matters if it got to 10 or to 9. The "evenly divided" works great for integers, but I'm not sure if it'll look good for floating point values.

RandomShaper commented 6 years ago

I think workaround 2 in @Iverona's comment is the right thing to do. It seems some users find confusing how integral values are animated along continuous time, but once you get it it makes full sense. Maybe a quick tip about this could be added to the docs.

lverona commented 6 years ago

And am I correct in understanding that if I need several separate animations, then I actually need a single sprite sheet that I have to animate, which has columns and rows? I.e., it is not possible to add several textures to one sprite?

RandomShaper commented 6 years ago

As far as I know you can switch between spritesheets by setting keys for the texture property.

If after auto-atlasing on export they end up in the same image resource, the penalty at runtime should be negligible.