Forum rules - please read before posting.

Timing two animations together

Hello everyone,
I have a question that seems like it would come up often in adventure game creation, but have not seen it answered anywhere. I have an animation that plays continuously on a loop (NPC throwing an object up in the air and catching it), and I want my character to to be able to use a colander to catch it. The issue is that depending on when in the original animation the player uses the item, it doesn't necessarily line up in terms of timing. What I am looking for is a way to tell the program not to initiate my player character's animation until the NPC loop finishes its cycle, so that the timing can be controlled. Does anyone know of a way to do that?

Thanks so much,
Adam

Comments

  • edited November 2020

    My background is mainly 2d related.
    Don't use on the loop in your case like this.
    Create variable ColanderUse, use actionlist to check for that variable if it is 1 play animation with colander, if not play your old animation and send call back to check varaible.
    Hope this helps.

  • I meant: Don't use on the loop in your case like that (like you do).
    :)

  • edited November 2020

    I guess the solution could be something like the PlayFootstep function called by an Animation Event? Link @ 1:03:17:

  • Interesting problem.

    Using animation events would be one way to solve it, but it'd be tricky to place the game in "cutscene" mode while the game waits for the animation to reset.

    Another way would be to use a custom Action that simply waits for a given Animator to complete it's current cycle of whatever animation state it's currently playing. Try this:

    using UnityEngine;
    #if UNITY_EDITOR
    using UnityEditor;
    #endif
    
    namespace AC
    {
    
        [System.Serializable]
        public class ActionAnimWait : Action
        {
    
            public Animator animator;
            public int layer;
    
            public ActionAnimWait ()
            {
                this.isDisplayed = true;
                category = ActionCategory.Custom;
                title = "Wait for animation";
            }
    
            public override float Run ()
            {
                float totalLength = animator.GetCurrentAnimatorStateInfo (layer).length;
                float timeLeft = (1f - animator.GetCurrentAnimatorStateInfo (layer).normalizedTime) * totalLength;
                return timeLeft;
            }
    
            public override void Skip ()
            {}
    
            #if UNITY_EDITOR
    
            public override void ShowGUI ()
            {
                animator = (Animator) EditorGUILayout.ObjectField ("Animator:", animator, typeof (Animator), true);
                layer = EditorGUILayout.IntField ("Layer:", layer);
    
                AfterRunningOption ();
            }
    
            #endif
    
        }
    
    }
    

    See the Manual's "Custom Actions" for a guide to installing custom Action scripts. This'll then appear as a new Custom: Wait for animation Action that you can use before running the rest of the Interaction sequence.

  • Thank you @SkyTree and @Vacerias for your answers, and Thank you @ChrisIceBox for this custom scripting! I have gone through the Custom Action section of the Manual and the online tutorial, but am a little bit stuck. I copied and pasted the code you into a C# file, saved it in a folder called Custom Actions, and set the directory in the Actions Manager. However, the Wait for animation action does not appear under Custom, and I get the error message "Wait for animation.cs must derive from AC's Action class in order to be available as an action." Thanks so much for your help

  • edited November 2020

    The Action's filename must match its class name - rename it to ActionAnimWait.cs and it should install, though you may have to restart Unity.

  • As a scripting novice, thanks very much! I look forward to learning it better.

  • edited December 2020

    Hi @ChrisIceBox. I was finally able to test out the Custom Animation Script in a scene, and I haven't gotten it to work for me yet. The next animation plays upon the player arriving to their marker instead of waiting for the loop to complete. Here is a picture of my action list. I use the Wait for Animation script before running the two character/objects' animations in parallel. I left the Layer for the custom script at 0 because the animations are found on the animator's base layer. I also tried changing that to 1 but it had no effect. I am wondering if there's something I'm still missing. Thanks so much for your help!

  • Apologies @Adam_LM, I suspect my code was wrong.

    Try this:

    using UnityEngine;
    #if UNITY_EDITOR
    using UnityEditor;
    #endif
    
    namespace AC
    {
    
        [System.Serializable]
        public class ActionAnimWait : Action
        {
    
            public Animator animator;
            public int layer;
    
            public ActionAnimWait ()
            {
                this.isDisplayed = true;
                category = ActionCategory.Custom;
                title = "Wait for animation";
            }
    
            public override float Run ()
            {
                if (!isRunning)
                {
                    isRunning = true;
                    float totalLength = animator.GetCurrentAnimatorStateInfo (layer).length;
                    float timeLeft = (1f - animator.GetCurrentAnimatorStateInfo (layer).normalizedTime) * totalLength;
                    return timeLeft;
                }
    
                isRunning = false;
                return 0f;
            }
    
            public override void Skip ()
            {}
    
            #if UNITY_EDITOR
    
            public override void ShowGUI ()
            {
                animator = (Animator) EditorGUILayout.ObjectField ("Animator:", animator, typeof (Animator), true);
                layer = EditorGUILayout.IntField ("Layer:", layer);
    
                AfterRunningOption ();
            }
    
            #endif
    
        }
    
    }
    
  • Hi @ChrisIceBox, thanks for the updated code, but unfortunately it's still having the same problem. I'm happy to send further info if that'd be helpful.

  • edited December 2020

    I think the only thing for it is to PM me the scene itself. I'd need a .unitypackage file of your Managers, the scene, your character graphics, prefabs and Animator Controllers, as well as instructions to recreate.

  • Thanks for the package. The issue occurs when the animation has looped through at least once. The "normalizedTime" value includes the number of times it's been played to completion, so just needs to be reduced to be less than 1.

    This should do it:

    using UnityEngine;
    #if UNITY_EDITOR
    using UnityEditor;
    #endif
    
    namespace AC
    {
    
        [System.Serializable]
        public class ActionAnimWait : Action
        {
    
            public Animator animator;
            public int layer;
    
            public ActionAnimWait ()
            {
                this.isDisplayed = true;
                category = ActionCategory.Custom;
                title = "Wait for animation";
            }
    
            public override float Run ()
            {
                if (!isRunning)
                {
                    isRunning = true;
                    float totalLength = animator.GetCurrentAnimatorStateInfo (layer).length;
                    float normalizedTime = animator.GetCurrentAnimatorStateInfo (layer).normalizedTime;
                    while (normalizedTime > 1f) normalizedTime -= 1f;
                    float timeLeft = (1f - normalizedTime) * totalLength;
                    return timeLeft;
                }
    
                isRunning = false;
                return 0f;
            }
    
            public override void Skip ()
            {}
    
            #if UNITY_EDITOR
    
            public override void ShowGUI ()
            {
                animator = (Animator) EditorGUILayout.ObjectField ("Animator:", animator, typeof (Animator), true);
                layer = EditorGUILayout.IntField ("Layer:", layer);
    
                AfterRunningOption ();
            }
    
            #endif
    
        }
    
    }
    
  • Hi @ChrisIceBox, I just tried it out and it works perfectly. Thanks as always for your help!

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.