Reputation: 21
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
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
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