Soy nuevo en Unity y creé un pequeño juego de disparos espaciales en 2D.

Cuando el jugador dispara a un enemigo con un rayo, el objeto enemigo se destruye y el jugador recibe 1 punto.

Cuando el jugador acumula un poder, puede disparar 2 rayos al mismo tiempo. Si esos 2 rayos alcanzan al enemigo, el jugador recibe 2 puntos en lugar de 1 punto desafortunadamente. El método OnTriggerEnter en el script adjunto "DestroyByContact" del enemigo se llama dos veces.

¿Cómo puedo ignorar OnTriggerEnter si el objeto del juego se destruye? Quizás alguien pueda ayudarme.

Agregué el código para el método OnTriggerEnter a continuación.

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;
    }
}
-1
MarBot 23 abr. 2020 a las 21:18

2 respuestas

La mejor respuesta

Después de la llamada a Destroy Unity marca el objeto dado para su destrucción, pero no se destruye hasta el siguiente marco. Para evitar llamar a su método dos veces, simplemente agregue la variable bool a su clase enemiga y verifíquelo dentro de OnTriggerEnter

Podría verse así

bool isDestroyed = false;

void OnTriggerEnter(Collider other)
{
    if (isDestroyed) return;
    else
    {
        isDestroyed = true;
        Destoy(gameObject);
        // whatever else should happen
    }
}
1
Kacper 23 abr. 2020 a las 18:31

Como se mencionó en otras respuestas, Destroy() destruirá un objeto al final del cuadro actual, y así como se llama a tu script dos veces en el mismo cuadro, ganarás dos puntos.
Afortunadamente, Unity tiene una función para evitar esto, si incrementa su puntaje en OnDestroy(), entonces se garantiza que solo sucederá una vez.

void OnDestroy(){
    player.IncrementScore();
}
0
Jake 23 abr. 2020 a las 18:39