Larr Bear
Larr Bear

Reputation: 93

GameObject counted as destroyed but not really destroyed

I am currently making a Breakout style game and have a problem with destroying bricks when there are more than 5 or 6 balls in play (there is no solid number that recreates this bug, it just happens when there are a lot of balls in play). There is a double and triple ball power up so the number of balls can increase very quickly in a short amount of time.

In my GameManager Script I keep track of the initial number of bricks at the start of the scene and subtract 1 everytime a ball comes into contact with a brick. After the number of Bricks is zero the player wins and the game is over. The game works with a small number of balls however the process seems to break down when too many balls get involved.

Relevant code for GameManager.cs:

void Start()
{
    livesText.text = "Lives: " + Lives;
    numOfBalls = GameObject.FindGameObjectsWithTag("Ball").Length;
    numOfBricks = GameObject.FindGameObjectsWithTag("Brick").Length;
    //Debug.Log(numOfBalls);
}

public void UpdateBrickNumber()
{
    numOfBricks--;
    if(numOfBricks <= 0)
    {
        numOfBricks = 0;
        GameOver();
    }
}

void GameOver()
{
    gameOver = true;
    if(numOfBricks == 0)
    {
        WinPanel.SetActive(true);
    }
    else
    {
        GameOverPanel.SetActive(true);
    }
}
...

Ball code for handling Collisions:

void OnCollisionEnter2D(Collision2D collision)
{
    if (collision.transform.CompareTag("Brick"))
    {
        Debug.Log("Brick Hit");
        //Chance of powerup to spawn
        int rand = Random.Range(1, 101);
        //Chance of each power up
        int rand2 = Random.Range(1, 101);



        if (rand < 7)
        {
            if (rand2 >=1 && rand2<=20) {
                Instantiate(SpeedBall, collision.transform.position, collision.transform.rotation);
                //Debug.Log(" Speed Power Up Created ");
            }
            ...
            Rest of  power ups
            ...
        }
        Transform newExplosion = Instantiate(explosion, collision.transform.position, collision.transform.rotation);
        Destroy(newExplosion.gameObject, 2f);
        gm.UpdateBrickNumber();
        Destroy(collision.gameObject);
    }
}

The Debug log does show that the correct number of bricks were hit but I think some balls are hitting the same brick before it has a chance to be destroyed. How can I make sure the bricks are destroyed before another ball hits the collider on the brick?

The bug in action: Picture of the bug in action

Upvotes: 1

Views: 161

Answers (2)

Mars
Mars

Reputation: 2572

Going off the hunch that you're getting multiple collisions in a frame, resulting in a lower brick count than remaining number of bricks, this should fix it:

void OnCollisionEnter2D(Collision2D collision)
{   //Check if the brick has already been processed
    if (collision.transform.CompareTag("Brick") && collision.collider.enabled) 
    {
        Debug.Log("Brick Hit");
        //Chance of powerup to spawn
        int rand = Random.Range(1, 101);
        //Chance of each power up
        int rand2 = Random.Range(1, 101);



        if (rand < 7)
        {
            if (rand2 >=1 && rand2<=20) {
                Instantiate(SpeedBall, collision.transform.position, collision.transform.rotation);
                //Debug.Log(" Speed Power Up Created ");
            }
            ...
            Rest of  power ups
            ...
        }
        Transform newExplosion = Instantiate(explosion, collision.transform.position, collision.transform.rotation);
        Destroy(newExplosion.gameObject, 2f);
        gm.UpdateBrickNumber();
        //Mark the brick as hit already so other balls can't hit it!
        collision.collider.enabled = false; 
        Destroy(collision.gameObject);
    }
}

Explanation

From the documentation:

Actual object destruction is always delayed until after the current Update loop, but will always be done before rendering.

Destroy is not instant. It will take place after the update loop, meaning if two balls hit in the same frame, you're reducing your count by two, but only destroying one brick.

Upvotes: 2

umlcat
umlcat

Reputation: 4143

Quick Short Answer

In C# and Java, objects aren´t destroyed right-away, they put in a process to be removed, and sometimes occurs inmediatly, sometimes not.

Sometimes, other objects still reference them. The solution is to removed those references before.

void OnCollisionEnter2D(Collision2D collision)
{
        ...

        Transform newExplosion = Instantiate(explosion, collision.transform.position,     collision.transform.rotation);


        // notify other objects that reference "newExplosion.gameObject"
        Destroy(newExplosion.gameObject, 2f);

        newExplosion.gameObject = null;


        gm.UpdateBrickNumber();

        // notify other objects that reference "collision.gameObject"
        Destroy(collision.gameObject);

        collision.gameObject = null;

        ...
}  // void OnCollisionEnter2D(...)

Cheers.

Upvotes: 0

Related Questions