Hide GameObject after Animation

Hello!

I have a gameObject with an animator and a script that plays different animations based on player input.

Everything works great and it cycles through the animations just how I intend.

For the last animation, once the animation is complete I would like to simply set the gameObject.active to false, effectively ‘hiding’ the game object, until it is needed again.

In my code, I have my if conditional which interacts with the player, containing two simple lines of code. The first plays the last animation, and the second sets the gameObject.active to false.

The issue I am having is the last animation never gets to play, when the conditional is true the gameobject just disappears.

So I guess what I would like to do, is have it disappear but not until the last animation is done playing.

I read a few other threads that said to use parameters inside the controller, but I really have no idea how to do this.

Any help would be very much appreciated guys! Thanks so much!

the easiest and simple way is when you call the last animation, call to invoke some function that will occur X seconds later, where X is the duration of the animation. And in that function disable the gameobject.

If this is in a coroutine, you could play the animation, yield for that duration, and then disable it.

I thought about using some kind of timer, the only issue I had with that was what if it doesn’t run the same across different strength pc’s. Or is there a way to standardize the timer?

Using Invoke or a coroutine normalizes for all strengths of PCs.

If you needed to tally up time that also worked across all computers, you’d use Time.deltaTime.

Okay this is what I currently have.

It seems to still just skip right over some animation and the object disappears. This is JS. The final animation is anim_2 and it is 2.7 seconds long.

var anim : Animator;
var someBool:boolean = false;
var timer : float = Time.time;


function Update ()
{

   
  if(onTrigger && !someBool)
  {
     anim.Play("anim_1", 0);
     someBool = true;
  }
   
  if(onTrigger && someBool)
  {
     anim.Play("anim_2", 0);
     
     var interval : float = Time.time - timer;
   
     if(interval >= 2.7)
     {

       gameObject.active = false;
     
       timer = Time.time;
     }
     
  }
   
}

your timer is set to ‘Time.time’ when this script is first loaded. This could have been any amount of time prior to ‘onTrigger’ flagging.

Try using ‘Invoke’:

Or BETTER use coroutines:

Example, rearranging your code as a coroutine:

var anim : Animation;

//instead of setting 'onTrigger' true, call this function... your bool approach is archaic!
public function SetTrigger()
{
    StartCoroutine(PerformAnimRoutine());
}

private function PerformAnimRoutine()
{
    //here we're going to use PlayQueued to get the animstate, with that we can determine some info about the anim
    var state:AnimationState = anim.PlayQueued("anim_1", QueueMode.PlayNow, PlayMode.StopSameLayer); //0 from Play is StopSameLayer... use the enums, they're more explicit

    yield WaitForSeconds(state.length);

    state = anim.PlayQueued("anim_2", QueueMode.PlayNow, PlayMode.StopSameLayer);

    yield WaitForSeconds(state.length);

    gameObject.active = false;
}

In this instead of setting some bool ‘onTrigger’ to true when you want the sequence to play. We instead call the method ‘SetTrigger’. This will start the sequence.

In our sequence we use a coroutine to order the sequence.

We first play ‘anim_1’, and we do so with PlayQueued. The reason I do this is because if you use that function it returns the AnimationState for the anim we played. With that state information we can get the length of the animation from its property… no longer needing to hardcode the wait duration.

Next we yield a WaitForSeconds instruction saying to wait the duration of that animation.

Now we play “anim_2”, getting the state again, note I reuse the variable because no reason to make a new one… old anim is complete.

We again wait for the duration of the animation.

And NOW we disable the gameObject.

What’s nice about coroutines is that each line of code reads in the sequence of events that is actually going…

play
wait
play
wait
disable

NOTE… I don’t usually write unityscript/javascript, I’m a C# guy… so this was written right here in the browser. No guarantee it’ll work directly. I may have mispelled this that or the other.

Here it is in C#:

using UnityEngine;
using System.Collections;

public class ExampleScript : MonoBehaviour
{

    public Animation anim;

    public void SetTrigger()
    {
        this.StartCoroutine(this.PerformAnimRoutine());
    }
 
    private IEnumerator PerformAnimRoutine()
    {
        var state = anim.PlayQueued("anim_1", QueueMode.PlayNow, PlayMode.StopSameLayer);
     
        yield return new WaitForSeconds(state.length);
     
        state = anim.PlayQueued("anim_2", QueueMode.PlayNow, PlayMode.StopSameLayer);
 
        yield return new WaitForSeconds(state.length);
     
        this.gameObject.active = false;
    }

}

There, much more familiar.

Okay cool!

Using your JS code I get some strange issues:

‘No appropriate version of ‘UnityEngine.Animator.Play’ for the argument list ‘(String, UnityEngine.QueueMode, UnityEngine.PlayMode)’ was found.’ Looks like it is mad at the line that defines ‘state’

like i said, I may have mispelled some lines.

and sure enough, the second ‘PlayQueued’, I typed only ‘Play’, but treated it with the parameters expected by ‘PlayQueued’.

edited/fixed

1 Like

Okay cool thank you very much!

So I would just call SetTrigger then?

When I call it I get the following error:

‘MissingMethodException: Unity.Engine.Animator.PlayQueued
Boo.Lang.Runtime.DynamicDispatching.MethodDispatcherFactory.ProduceExtensionDispatcher()’

Oh… lol. Just noticed you’re using the Mecanim Animator.

I programmed this like you were using legacy Animation.

I don’t usually use Mecanim, and I have my own custom Animation system called SPAnimator, that I didn’t think nothing of the variable ‘anim’ typed as Animator.

Usually with Mecanim you don’t call specific animations, you let the Animator take care of it, and you merely signal to the Animator what to do. And then in the last animation you can wire up an event that calls a function back to your script to then disable the gameObject.

Doing all this requires the Mecanim Animator editor. It’s not something easily demonstrated via text on the forums.

There’s usually not as much code as you’re original post, nor my post, when you use Mecanim. You merely define flags and triggers on the animator state machine, and you trigger them through code in a single line of code.

If you switched to legacy Animation, and renamed ‘Animator’ to ‘Animation’ in my code. It’d work correctly.

Okay thank you so much!

My whole project uses Mecanim so I would like to stick with it. I still am not entirely sure how to set flags from the Mecanim Animator editor. This is probably the only case in my game where I would like to know when the animation is done playing, all I want to do is make the object vanish once it finishes playing but I have no experience doing that with mecanim.

With Mecanim, you’re animator can send messages to the GameObject the Animator is connected to. You’d wire up Mecanim to play the sequence in order just using the nodes. And the last node would send the message calling a function in your script that disabled it.

This is 95% all in the visual mecanim editor. So sorry I can’t really ‘show’ you how to do it. You need to go read the mecanim documentation to know how to use that thing: