Doers of Stuff.org

A place to Do Stuff and see Stuff Done…

Creating Enemy Explosions

Overconfidence is such a killjoy. We just started animating our game objects and it all seemed so easy. Then we decided to create an animated explosion when our enemy objects are destroyed, and it didn’t work. Duuuuude….

The problem of course is, as soon as we kick off the explosion animation, we destroy the object the animation is attached to which of course, destroys the animation before it can finish or even execute. The first thought you might have is to simply delay the Destroy(). We know the animation runs about 2.4 seconds. So, if we pass that value as the second parameter to the Destroy() call the animation has time to execute.

And then, the still exploding ship ran into our player and took one of its lives. Duuuuude….

Now arguably, this last might be acceptable. The game play could reasonably define running into the debris is the same as running into the ship itself. But I didn’t really like this for mine. I actually preferred the effect of pushing through the fireball. Visually, it was just more appealing. Now of course, we could opt for a more complex definition where the debris causes partial damage, but we’ll let that one go for now.

The problem is, we need to leave the enemy game object around long enough for the explosion animation to run, but somehow still act like it’s not really there and able to interact with other game objects.

To make this particular animation work we did have to do a few things different. We can’t really keep the animation from firing off, but we can put it in a holding pattern. In the Animator we add an empty state in between the entry point and the explosion animation.

We then add a trigger in the parameters tab which we can use in the transition from the Empty state to the EnemyDesrotyed_anim state. The OnEnemyDeath trigger can then be added as a condition on the transition.

With this setup, we can interact with the components in code.

    private void OnTriggerEnter2D(Collider2D other)
    {

        if (  other.tag == "Player"
           || other.tag == "Laser"
           ) { EnemyDeathScene(); }
    }

    private void EnemyDeathScene()
    {
        myExplosion_anim.SetTrigger("OnEnemyDeath");
        transform.GetComponent<Collider2D>().enabled = false;
        if (myPlayer != null) { myPlayer.EnemyDestroyed(); }
        Destroy(this.gameObject, 2.4f);
    }

Once the enemy game object collides, we can set the trigger. The next line is what keeps any other collisions from being triggered. We now have time for the explosion animation to complete and it no longer causes secondary collisions.

It would be nice if that were it, but it turns out there are a couple more quirks. First, there is an erratic delay in the animation. This turns out to be a configuration issue, not a coding one. In the Inspector, we see additional settings for the transition. The first is a checkbox, “Has Exit Time.” This tells the animation it must remain in its current state for the entire time prescribed in the “Exit Time.” But for us, this state is just a place holder, so it has no need to run to completion. So, we can uncheck it. Since we are also not blending this animation with another, we can set the “Transition Duration” to 0 as well.

Our animation will now exit the “Empty State” immediately, making the transition smooth and immediate.

The second quirk is a little less obvious and I almost didn’t catch it. If you destroy an enemy ship close enough to the bottom of the screen, the respawn logic will teleport it back to the top of the screen while it is still exploding. So, need to just throw a little bit more in to manage that possibility.

    [SerializeField] private bool imDead = false;

    private void Update()
    {
        transform.Translate(Vector3.down * Time.deltaTime * mySpeed);

        if (imDead) { return; }     // ensure an exploding enemy does not respawn at the top

        if (  transform.position.y < -8.0f )
            { transform.position = new Vector3(Random.Range(-10.0f, 10.0f), 8, 0); }
    }
    
    private void EnemyDeathScene()
    {
        imDead = true;
        myExplosion_anim.SetTrigger("OnEnemyDeath");
        transform.GetComponent<Collider2D>().enabled = false;
        if (myPlayer != null) { myPlayer.EnemyDestroyed(); }
        Destroy(this.gameObject, 2.4f);
    }

By adding a boolean to mark the object as dead, we can short circuit the Update method. This will allow the enemy object to keep moving but skip the respawn. Our animation is not complete.

Leave a Reply

Creating Enemy Explosions

by Robert time to read: 3 min
0