How do I make animations finish playing?

I have a level with a fairly large number of doors (around 50, all up). I have gone through and created an "open" and a "close" animation for each door using the Unity animation editor. I have then gone through and created triggers for each door. OnTriggerEnter() queues up the associated open animation, while OnTriggerExit() queues the close animation.

So far, so good. I can now run around the level and doors open when I get close, and close when I move away. My problem is that the the doors do not always completely open when I get close, nor close when I move away. The last few frames of the animation are not always being properly played.

I'm at something of a loss as to why this is occurring or how to fix it. The animations are quite simple - basically just a keyframe at frame 0 with the door closed; keyframe at frame 30 with the door open. I've tried adding an additional keyframe at frame 31 that duplicates the keyframe at frame 30, but this doesn't seem to help.

I also tried changing WrapMode to ClampForever. This is promising, except it breaks animation queuing - presumably because the first open animation on each door never ends, so the door never closes.

Sooo...now what? How can I make sure that when my close animations finish playing the door is actually closed as per the final keyframe of the animation?

Update: This problem should be fixed in Unity 3.2


We are aware of this problem and we are working on fixing it.

In the mean time, there are a couple of workarounds:

  • You can make the animation a bit longer, with the last few frames being identical. You wrote that this didn't work for you, but try with a few extra frames and see if that works better.

  • You can make your own logic for controlling the animation playback instead of using the built-in queuing. By implementing your own logic you can use WrapMode.ClampForever and manually keep track of when the time of the animation has exceeded the length of the clip.

I actually opted to solve this slightly differently. I decided the animation was so simple I didn't need animation curves at all, and so just controlled door rotation programatically. On the offchance it helps anyone else, here is my eventual solution to the problem. :)

using UnityEngine;
using System.Collections;

public class DoorBehaviour : MonoBehaviour
{
    public float DoorRotation;

    bool needOpen;
    bool needClose;

    Quaternion closedRotation;
    Quaternion openRotation;

    IEnumerator Start()
    {
        needOpen = false;
        needClose = false;
        closedRotation = transform.rotation;

        while (true) {
            if (needOpen)
            {
                yield return StartCoroutine(OpenDoor());
                needOpen = false;
            }

            if (needClose)
            {
                yield return StartCoroutine(CloseDoor());
                needClose = false;
            }

            yield return 1;
        }
    }

    public void Open()
    {
        needOpen = true;
        openRotation = Quaternion.AngleAxis(DoorRotation,Vector3.up);
    }

    public void Close()
    {
        needClose = true;
    }

    IEnumerator OpenDoor()
    {
        Quaternion targetRotation = transform.rotation * openRotation;

        while (Quaternion.Angle(transform.rotation, targetRotation)>1)
        {
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f);
            yield return 1;
        }
    }

    IEnumerator CloseDoor()
    {
        while (Quaternion.Angle(transform.rotation, closedRotation) > 1)
        {
            transform.rotation = Quaternion.Slerp(transform.rotation, closedRotation, Time.deltaTime * 5f);
            yield return 1;
        }
    }
}

Usage is fairly obvious. Drop this on a door and set the DoorRotation variable to be the number of degrees to rotate when it opens. (i.e., -90 means the door rotates 90 degrees counterclockwise to open.) Create a trigger that calls the Open() and Close() functions as appropriate.

Coroutines are used so the door doesn't do anything crazy like queue up open and close movements, or open a second time when it's already open. Probably not the best solution in the world, but it seems to work for me. :)

Has anyone tested force playing the last frame of animation again? Is this possible? Im just a basic scripter so far, but i figure you could:

play animation x
{
  if (animation x is playing yield)
   {
      play last frame of animation x again

i dont know how to do this exactly but this was my best workaround i could think of at this point. If it would even accomplish what we want that is.

I have the same issue, I'm just going to add extra frames at the end of my animations.

Hello, I came across the same issue today and I have unity version 3.1.0f4. I wanted to know what is the status on fixing bug since it seems that it is almost one year old. Anyway I could work around it by also adding frames at the end of my animation clip, but it's not a very pretty solution. Thank you and keep up the good work!

You can make your own logic for controlling the animation playback instead of using the built-in queuing

I used this method for one of my games and it is working well. A beneficial side effect is that now I can use Time.realtimeSinceStartup to manage my animations. This allows me to create a Pause Screen where I set Time.timeScale to 0 to halt everything but my manual Pause Screen animations...