How can I play an animation backwards?

@Straafe and @Bunny83
Unity 2019 has updated a few things which changed what this generates. Can you provide an update?

Unity gives me the warning:
Assets\Editor\ReverseAnimationContext.cs(25,22): warning CS0618: ‘AnimationUtility.GetAllCurves(AnimationClip, bool)’ is obsolete: ‘GetAllCurves is deprecated. Use GetCurveBindings and GetObjectReferenceCurveBindings instead.’

Hi @BellBlitzKing ,

I updated the script above to use the newer functions and no longer use the deprecated one. It also now supports multiple animation clips at a time, so you can shift-click or ctrl-click multiple clips and reverse them all at once.

You can find it here (haven’t done much testing, so let me know if there’s a problem):

I also added a couple more scripts there, one to add a default empty state to an AnimationController and one to unloop AnimationClips which default to looped most of the time. Both of those also support multi select and have helped me a lot in some situations. Still not perfect, but it works.

https://github.com/Straafe/unity-editor-tools

@Kybernetik I got it to work with multiple clips at once, but please improve it!

8 Likes

Thank you @Straafe ! Get it while it’s fresh, @Elin42 @rudehouse , @pinaeong , @thierry_unity , @vladk ,

ReverseAnimationContext.cs allows you to easily reverse animation clips:

1 Like

Thank you @Straafe , this is really amazing, unity should integrate this feature by default. You saved us a lot of time.

1 Like

@Straafe you are amazing thank you so much. You saved my day

1 Like

Hi.
At the moment it does not seem to work with sprites, but it still helped me with my animated colliders etc.

would it be possible to have this work for sprites as well?

Anyway still Thanks @Straafe as it saved me hand setting collider animations :slight_smile:

Hi @Djaydino , I almost exclusively work with 3D models and 3D scenes, so I haven’t done much in 2D with sprite or sprite animations. Do they still use Animation Clips? In theory it should work with anything that uses clips.

Hi.
Thank for your reply.

Yes they are within the clip and on a older version i copied from here they where disappeared after reversed.
Then i tried with the github version and with this version they do not disappear, but they are also not reversing.

But i think it is probably not possible.
If you select a clip directly from project then you are not able to add sprites, only move/remove.

@Straafe Please tell me how I should attribute you since I want to use this in production. At the moment, I want to provide your user handle and the link to this post on the top of the code.

My only complaint is that AnimationUtility.GetAllCurves is deprecated now.

@Vivraan Hey, that sounds perfectly fine to me. I believe I updated it to not use the deprecated functions here: unity-editor-tools/ReverseAnimationContext.cs at master · Straafe/unity-editor-tools · GitHub

Alright, so I modified the script to be a bit more “modern” (if at the lack of compatibility) and replaced the GetAllCurves method with the editor bindings API.

@Straafe could you comment on the shortcomings of this edit I made?

(See below for updated script.)

1 Like

Really like the multiple clips reversal context, although I believe just reversing one at a time would suffice! (We seriously need our animators to make reversed versions since this isn’t Godot :p)

The corrected version is:

using UnityEditor;
using UnityEngine;
using System.IO;
using System.Linq;

namespace Helpers
{
    /// Originally from Straafe
    /// From https://discussions.unity.com/t/678635/10
    public static class ReverseAnimationContext
    {
        [MenuItem("Assets/Create Reversed Clip", false, 14)]
        private static void ReverseClip()
        {
            string path = AssetDatabase.GetAssetPath(Selection.activeObject);
            string directoryPath = Path.GetDirectoryName(path);
            string fileName = Path.GetFileName(path).Split('.')[0];
            string fileExtension = Path.GetExtension(path);
            string copiedFilePath = Path.Combine(directoryPath, $"{fileName}_Reversed{fileExtension}");
            AssetDatabase.CopyAsset(path, copiedFilePath);

            var clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(copiedFilePath);

            if (clip == null)
            {
                return;
            }

            float clipLength = clip.length;
            var editorBindings = AnimationUtility.GetCurveBindings(clip);

            foreach (var binding in editorBindings)
            {
                var curve = AnimationUtility.GetEditorCurve(clip, binding);
                var keys = curve.keys;

                var postWrapmode = curve.postWrapMode;
                curve.postWrapMode = curve.preWrapMode;
                curve.preWrapMode = postWrapmode;

                for (int i = 0; i < keys.Length; i++)
                {
                    var K = keys[i];
                    K.time = clipLength - K.time;

                    var tmp = -K.inTangent;
                    K.inTangent = -K.outTangent;
                    K.outTangent = tmp;

                    keys[i] = K;
                }

                curve.keys = keys;
                clip.SetCurve(binding.path, binding.type, binding.propertyName, curve);
            }

            var events = AnimationUtility.GetAnimationEvents(clip);
            foreach (var @event in events)
            {
                @event.time = clipLength - @event.time;
            }
            AnimationUtility.SetAnimationEvents(clip, events);

            Debug.Log("Animation reversed!");
        }

        [MenuItem("Assets/Create Reversed Clip", true)]
        private static bool ReverseClipValidation() => Selection.activeObject is AnimationClip;

        private static AnimationClip SelectedClip => Selection.GetFiltered<AnimationClip>(SelectionMode.Assets).FirstOrDefault();
    }
}
5 Likes

Hi everyone!

in Unity (until 2020) I just typed:
animator.speed = -1f;

in Unity 2020 (and above) I need to enter:
animator.StartPlayback ();
animator.speed = -1f;

It works for me!!!

8 Likes

I agree, negative speed has worked for some time now??

animator.speed = -1f;

gives me

Animator.speed can only be negative when Animator recorder is enabled. Animator.recorderMode != AnimatorRecorderMode.Offline

Are you setting the speed on the state or the whole animator?

Of the animator (GetComponent())

Property or indexer 'AnimatorStateInfo.speed' cannot be assigned to -- it is read only

Why are you suggesting this?
Do you know another way through “state”? Which state do you mean?
Do you have code showing this?

In the animator statemachine, select the state and in the inspector set the speed to -ve. I.e. each state plays its animation at a specific speed.

Thanks so much for the script I would have sat there for days without it