Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First frame is played of first animation when starting second animation #25

Closed
jj-jabb opened this issue Feb 16, 2020 · 7 comments
Closed
Labels
Bug Something isn't working Solved A solution is available here (but may not yet be included in the latest release)

Comments

@jj-jabb
Copy link

jj-jabb commented Feb 16, 2020

Given the following code, where there is no fade duration , the first frame of anim1 is played beore anim2 is played. anim2 is a looping clip, while anim1 is not.

// play the non-looping clip
var state = character.Animancer.Play(anim1);
state.Events.OnEnd = () => {
    // play the looping clip
    // the first frame of anim1 is played before anim2 is played
    character.Animancer.Play(anim2);
};

I have smooth transitions between anim1 and anim2 - i.e. the last frame of anim1 is the same as the first frame of anim2. But sometimes when playing in the editor, the sequence looks like

  • last frame of anim1 is played
  • first frame of anim1 is played
  • first frame of anim2 is played

When building (for PC), this sequence always occurs.

The expected sequence is

  • last frame of anim1 is played
  • first frame of anim2 is played

Should I be doing something in addition to what I have here to prevent this?

EDIT: I can send you a minimal example if necessary. I'm using Animancer Pro 4, I have clips edited with UMotion @ 30fps, and I have a simple stateless state machine where states are ScriptableObjects that reference the clips in question, so maybe there's something in there that's causing issues if you can't reproduce the issue.

Also this is with 2019.3.0f6

@KybernetikGames KybernetikGames added the Bug Something isn't working label Feb 17, 2020
@KybernetikGames
Copy link
Owner

Well the good news is that I can replicate the issue and the bad news is that I can also replicate it in a runtime build so it's not just in the Editor. Actually that's probably both bad news since it would be much easier if you were just doing something wrong.

If you need an immediate workaround, you can simply play the next animation from outside the end event:

private bool _AnimationEnded;

public void PlayAnimation()
{
    var state = animancer.Play(anim1);
    state.Events.OnEnd = () =>
    {
        _AnimationEnded = true;
    };
}

private void Update()
{
    if (_AnimationEnded)
    {
        _AnimationEnded = false;
        animancer.Play(anim2);
    }
}

This seems like a fairly major issue so I'll start working on a proper fix ASAP. I'm fairly certain I know the cause of the problem, but it might require some significant restructuring to solve.

@jj-jabb
Copy link
Author

jj-jabb commented Feb 17, 2020

OK, thanks for the quick response!

FYI, I am unable to reproduce this problem in 3.1, if that helps at all.

@KybernetikGames
Copy link
Owner

KybernetikGames commented Feb 17, 2020

Yeah, the whole system was entirely different and much simpler in v3.1 because it only had end events.

Turns out it was easier to fix than I expected. The problem was that events are triggered at a point in the update process where times can be changed but weights cannot, so playing a new animation during an event would stop the old animation and set its time back to 0 and cause it to get rendered on its first frame before the next update comes along to apply its weight at 0 (so it stops affecting the output).

So the solution is a couple of simple modifications to AnimancerState (in Assets/Plugins/Animancer/Internal/Core).

Add a field to indicate when the time needs to be set:

private bool _MustSetTime;

Change the bottom of the Time setter to use that field:

_Time = value;
// Don't set NewTime = value;
_MustSetTime = true;
Root.RequireUpdate(this);
if (_EventUpdatable != null)
    _EventUpdatable.OnTimeChanged();

Then apply the time at the bottom of the Update method:

if (_MustSetTime)
{
    _MustSetTime = false;
    NewTime = _Time;
}

I'll submit an update to the store soon so hopefully it should be up in a couple of days.

@KybernetikGames KybernetikGames added the Solved A solution is available here (but may not yet be included in the latest release) label Feb 17, 2020
@jj-jabb
Copy link
Author

jj-jabb commented Feb 17, 2020

Great, thanks! RawTime isn't a member of AnimancerState in the current version that I have, but I can wait for the update.

Thanks for taking care of this so quickly!

@KybernetikGames
Copy link
Owner

My bad, I renamed it from NewTime.

@jj-jabb
Copy link
Author

jj-jabb commented Feb 17, 2020

Perfect, the fix works like a charm - thanks!

@KybernetikGames
Copy link
Owner

This is now fixed in Animancer v4.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something isn't working Solved A solution is available here (but may not yet be included in the latest release)
Projects
None yet
Development

No branches or pull requests

2 participants