How can I play an animation backwards?

I’ve added an animation to my timeline, but the timescale on that animation won’t let me specify a negative number. How can I play the animation in reverse? (Speed -1).

2 Likes

Hi,
Unfortunately, right now there is no way to play an animation in reverse inside timeline. It’s something that came up a couple of time but there is no easy way to do it. Only solution I can give you is to duplicate your clip and inside the animation window, using the box tool, you could reverse the 2nd clip.

4 Likes

Ah damn, that’s really disappointing!

Thanks for your answer.

1 Like

could you please explain how to do it? What’s a box tool?

What about this?

I this it should allow you to play it backwards from the coroutine or update.

Timeline can’t currently play animations backwards.

To fix this, you can duplicate your animation in the project window, and then create a reversed copy in “Keys” view by dragging right to its end then scaling negatively, which works, but is a pain on large animations as the Animation UI becomes quite unresponsive.

Or, you can clone your anim and run this script:

Both confirmed working in 2017.4, but the script version is much less hassle.

It would be nice to be able to create the reversed animation clip at runtime, but I believe that’s not possible until 2018.2 (?)

3 Likes

Is this now possible?

Not yet

:cry:

If it helps anyone else, I modified the script above to be inside the context menu when you right click on an animation clip. It also automatically creates the copy and adds “_Reversed” to the name so you don’t have to copy it first. Not perfect, but it saves me some time.

using UnityEditor;
using UnityEngine;
using System.IO;

public static class ReverseAnimationContext
{

    [MenuItem("Assets/Create Reversed Clip", false, 14)]
    private static void ReverseClip()
    {
        string directoryPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(Selection.activeObject));
        string fileName = Path.GetFileName(AssetDatabase.GetAssetPath(Selection.activeObject));
        string fileExtension = Path.GetExtension(AssetDatabase.GetAssetPath(Selection.activeObject));
        fileName = fileName.Split('.')[0];
        string copiedFilePath = directoryPath + Path.DirectorySeparatorChar + fileName + "_Reversed" + fileExtension;
        var clip = GetSelectedClip();

        AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(Selection.activeObject), copiedFilePath);

        clip  = (AnimationClip)AssetDatabase.LoadAssetAtPath(copiedFilePath, typeof(AnimationClip));

        if (clip == null)
            return;
        float clipLength = clip.length;
        var curves = AnimationUtility.GetAllCurves(clip, true);
        clip.ClearCurves();
        foreach (AnimationClipCurveData curve in curves)
        {
            var keys = curve.curve.keys;
            int keyCount = keys.Length;
            var postWrapmode = curve.curve.postWrapMode;
            curve.curve.postWrapMode = curve.curve.preWrapMode;
            curve.curve.preWrapMode = postWrapmode;
            for (int i = 0; i < keyCount; i++)
            {
                Keyframe K = keys[i];
                K.time = clipLength - K.time;
                var tmp = -K.inTangent;
                K.inTangent = -K.outTangent;
                K.outTangent = tmp;
                keys[i] = K;
            }
            curve.curve.keys = keys;
            clip.SetCurve(curve.path, curve.type, curve.propertyName, curve.curve);
        }
        var events = AnimationUtility.GetAnimationEvents(clip);
        if (events.Length > 0)
        {
            for (int i = 0; i < events.Length; i++)
            {
                events[i].time = clipLength - events[i].time;
            }
            AnimationUtility.SetAnimationEvents(clip, events);
        }
        Debug.Log("Animation reversed!");
    }

    [MenuItem("Assets/Create Reversed Clip", true)]
    static bool ReverseClipValidation()
    {
        return Selection.activeObject.GetType() == typeof(AnimationClip);
    }

    public static AnimationClip GetSelectedClip()
    {
        var clips = Selection.GetFiltered(typeof(AnimationClip), SelectionMode.Assets);
        if (clips.Length > 0)
        {
            return clips[0] as AnimationClip;
        }
        return null;
    }

}
53 Likes

Your Script is Amazing, it is working fine, Thanks for sharing

1 Like

Such a useful function. This should be in unity by default, if there is no easy way to reverse a clip in Timeline.

4 Likes

@Straafe Thank you!

1 Like

@Straafe You could change the menu path to “CONTEXT/AnimationClip/Create Reversed Clip” to make it a context menu function on the AnimationClip asset instead. Give it a “MenuCommand command” parameter and use “command.context” to access the clip it’s being called on instead of “Selection.activeObject”. That way you could select multiple clips and run the function for all of them at once (and it isn’t taking up space in the main Assets menu).

3 Likes

@Straafe You are so amazing!! Thank you so much. Can I post your code on my blog? Of course, I’ll write where it came from and who wrote it. Thank you!

Sure, please do. @pinaeong

sorry but where exactly do i place this code? thanks

Thank you @Straafe for this script !!!

( @steveh2112 : put it into an folder named Editor, also make sure that the file is named ReverseAnimationContext.cs )

2 Likes

In this video the man change the speed to negative and the animation starts playing backwards

6 Likes
1 Like