MarcoBot
MarcoBot

Reputation: 21

Unity - Space Shooter 2D - Ignore OnTriggerEnter when game object gets destroyed

I'm new to Unity and created a little space shooter game in 2D.

When the player shoots an enemy with a bolt, the enemy object get's destroyed and the player receives 1 point.

When the player collects a power up he can shoot 2 bolts at the same time. If those 2 bolts hit the enemy, the player receives 2 points instead of 1 point unfortunately. The method OnTriggerEnter in the attached script "DestroyByContact" of the enemy gets called twice.

How can I ignore OnTriggerEnter if the game object gets destroyed? Maybe someone can help me out.

I added the code for the OnTriggerEnter method below.

private void OnTriggerEnter(Collider other)
{
    switch (gameObject.tag)
    {
        case "Player":
            {
                if (other.CompareTag("Asteroid"))
                {
                    if (playerController.HasShield())
                    {
                        Destroy(other.gameObject); // Asteroid

                        Instantiate(asteroidExplosion, other.transform.position, other.transform.rotation);
                        playerController.RemoveShield();
                    }
                    else
                    {
                        Destroy(other.gameObject); // Asteroid
                        Destroy(gameObject); // Player

                        Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
                        gameController.GameOver();
                    }
                }
                if (other.CompareTag("Enemy"))
                {
                    if (playerController.HasShield())
                    {
                        Destroy(other.gameObject); // Enemy

                        Instantiate(enemyExplosion, other.transform.position, other.transform.rotation);
                        playerController.RemoveShield();
                    }
                    else
                    {
                        Destroy(other.gameObject); // Enemy
                        Destroy(gameObject); // Player

                        Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
                        gameController.GameOver();
                    }
                }
                if (other.CompareTag("BoltEnemy"))
                {
                    if (playerController.HasShield())
                    {
                        Destroy(other.gameObject); // BoltEnemy

                        playerController.RemoveShield();
                    }
                    else
                    {
                        Destroy(other.gameObject); // BoltEnemy
                        Destroy(gameObject); // Player

                        Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
                        gameController.GameOver();
                    }
                }
                if (other.CompareTag("Boss"))
                {
                    // if player ship hits the boss, player gets destroyed, no matter if he has a shield left or not
                    if (playerController.HasShield())
                    {
                        playerController.RemoveShield();
                    }
                    Destroy(gameObject); // Player

                    Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
                    gameController.GameOver();
                }
                if (other.CompareTag("PowerUpBolt"))
                {
                    Destroy(other.gameObject); // PowerUpBolt

                    audioPowerUp.Play();
                    playerController.IncreaseShotSpawns();
                }
                if (other.CompareTag("PowerUpHealth"))
                {
                    Destroy(other.gameObject); // PowerUpHealth

                    audioPowerUp.Play();
                    if (!playerController.HasShield())
                    {
                        playerController.AddShield();
                    }
                }
            }
            break;
        case "Asteroid":
            {
                if (other.CompareTag("BoltPlayer"))
                {
                    Destroy(other.gameObject); // BoltPlayer
                    Destroy(gameObject); // Asteroid

                    Instantiate(asteroidExplosion, other.transform.position, other.transform.rotation);
                    gameController.AddScore(scoreValueAsteroid);
                }
            }
            break;
        case "Enemy":
            {
                if (other.CompareTag("BoltPlayer"))
                {
                    Destroy(other.gameObject); // BoltPlayer
                    Destroy(gameObject); // Enemy

                    Instantiate(enemyExplosion, other.transform.position, other.transform.rotation);
                    gameController.AddScore(scoreValueEnemy);
                    gameController.SpawnPowerUp(other.transform);
                }
            }
            break;
        case "Boss":
            {
                if (other.CompareTag("BoltPlayer"))
                {
                    Destroy(other.gameObject); // BoltPlayer
                    bossController.GotHit();

                    if (bossController.IsDefeated())
                    {
                        Destroy(gameObject); // Boss

                        Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
                        gameController.Success();
                    }
                }
            }
            break;
    }
}

Upvotes: 0

Views: 356

Answers (2)

Jay
Jay

Reputation: 2946

As mentioned in other answers, Destroy() will destroy an object at the end of the current frame, and so as your script is getting called twice in the same frame you'll gain two points.
Luckily Unity has a feature to avoid this this, if you increment your score in OnDestroy() then it is guaranteed to only happen once.

void OnDestroy(){
    player.IncrementScore();
}

Upvotes: 0

Kacper
Kacper

Reputation: 598

After the call to Destroy Unity marks given object for destruction, but it is not destroyed until the next frame. To avoid calling your method twice simply add bool variable to your enemy class and check it inside OnTriggerEnter

It could look like this

bool isDestroyed = false;

void OnTriggerEnter(Collider other)
{
    if (isDestroyed) return;
    else
    {
        isDestroyed = true;
        Destoy(gameObject);
        // whatever else should happen
    }
}

Upvotes: 1

Related Questions