GameObject 算作已销毁但并未真正销毁

GameObject counted as destroyed but not really destroyed

我目前正在制作 Breakout 风格的游戏,当游戏中的球超过 5 或 6 个时,我会遇到破坏砖块的问题(没有可靠的数字可以重现此错误,它只会在有很多球时发生比赛中的球)。有双球和三球能量提升,因此球的数量可以在短时间内迅速增加。

在我的 GameManager 脚本中,我在场景开始时跟踪初始砖块数量,并在每次球与砖块接触时减去 1。积木数为零后,玩家获胜,游戏结束。该游戏适用于少量球,但是当涉及太多球时,该过程似乎会中断。

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);
    }
}
...

处理碰撞的球代码:

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);
    }
}

调试日志确实显示了正确数量的砖块被击中,但我认为有些球在有机会被摧毁之前就击中了同一块砖块。我怎样才能确保在另一个球撞到砖块上的对撞机之前砖块被摧毁?

实际错误:

消除了你在一个框架中遇到多次碰撞的预感,导致砖块数量低于剩余砖块数量,这应该可以解决这个问题:

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);
    }
}

说明

来自documentation

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

Destroy 不是即时的。它将在更新循环之后发生,这意味着如果两个球在同一帧中击中,您的计数将减少 2,但只会摧毁一块砖。

快速简短回答

在 C# 和 Java 中,对象不会被销毁 right-away,它们会放入要删除的进程中,有时会立即发生,有时不会。

有时,其他对象仍然引用它们。解决方案是删除之前的那些引用。

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(...)

干杯。