Отсутствует ссылочное исключение в Unity после создания нескольких префабов GameObject и удаления оригинала - PullRequest
1 голос
/ 06 июня 2019

В настоящее время я делаю игру в стиле Breakout, и у меня есть два "бонуса", которые доставляют мне некоторые проблемы.У меня есть бонусы с двойным и тройным шариками, которые создают 1 или 2 дополнительных шарика из оригинального сборного мяча.

Все работает хорошо, пока оригинальный шарик все еще находится на сцене, но после оригинальногошарик со сцены удаляется (шарик уничтожается после того, как он достигнет нижней части экрана, но игра продолжается, если клонированные шарики все еще находятся в игре, а "Ball Count" не равен 0) Я получаю следующую ошибку в строках, содержащихфункция Instantiate в случаях двойного и тройного включения питания:

MissingReferenceException: объект типа 'Transform' был уничтожен, но вы все еще пытаетесь получить к нему доступ.

Часть моего кода весла обрабатывает полномочия при столкновении между веслом и включением питания следующим образом:

void OnTriggerEnter2D(Collider2D collision)
{
    GameObject[] ArrayOfBalls = GameObject.FindGameObjectsWithTag("Ball");

    switch (collision.tag)
    {
        case "Life Powerup" :
            Debug.Log("hit " + collision.name);
            gm.UpdateLives(1);
            Destroy(collision.gameObject);
            break;

        case "Speed PowerUp":

            for (int i = 0; i<ArrayOfBalls.Length; i++)
            {
                ball ballscript = ArrayOfBalls[i].GetComponent < ball>();
                if (ballscript.rb.velocity.magnitude > 7.5f)
                {
                    CancelInvoke("NormalSpeed");
                    Invoke("NormalSpeed", 5f);

                }
                else if (ballscript.rb.velocity.magnitude <= 7.5f)
                {
                    ballscript.rb.velocity = new Vector2(ballscript.rb.velocity.x * 1.5f, ballscript.rb.velocity.y * 1.5f);
                    Invoke("NormalSpeed", 5f);
                }

            }

            //If another powerup is collected call to function to slow down is cancelled and started with new delay


            Debug.Log("hit " + collision.name);
            Destroy(collision.gameObject);
            break;

        case "Shrink PowerDown":

            gameObject.transform.localScale = new Vector3( 0.25f, 0.4f, 1f);
            Invoke("NormalSize", 15);

            Debug.Log("hit " + collision.name);
            Destroy(collision.gameObject);
            break;

        case "Expand PowerUp":

            gameObject.transform.localScale = new Vector3( 0.55f, 0.4f, 1f);
            Invoke("NormalSize", 5f);
            Debug.Log("hit " + collision.name);
            Destroy(collision.gameObject);
            break;

        case "Double PowerUp":
            for (int i = 0; i < ArrayOfBalls.Length; i++)
            {
                ball ballscript = ArrayOfBalls[i].GetComponent<ball>();
                Transform Doubleclone = Instantiate(PrefabBall, new Vector3(ballscript.rb.position.x + 0.1f, ballscript.rb.position.y + 0.1f, 0f), Quaternion.identity);
                Doubleclone.GetComponent<Rigidbody2D>().velocity = new Vector2(ballscript.rb.velocity.x, ballscript.rb.velocity.y);
                gm.UpdateBallCount(1);


            }
            Debug.Log("hit " + collision.name);
            Destroy(collision.gameObject);
            break;

        case "Triple PowerUp":
            for (int i = 0; i < ArrayOfBalls.Length; i++)
            {

                ball ballscript = ArrayOfBalls[i].GetComponent<ball>();
                Transform Tripleclone = Instantiate(PrefabBall, new Vector3(ballscript.rb.position.x + 0.1f, ballscript.rb.position.y + 0.1f, 0f), Quaternion.identity);
                Transform Tripleclone2 = Instantiate(PrefabBall, new Vector3(ballscript.rb.position.x - 0.1f, ballscript.rb.position.y - 0.1f, 0f), Quaternion.identity);
                Tripleclone.GetComponent<Rigidbody2D>().velocity = new Vector2(ballscript.rb.velocity.x, ballscript.rb.velocity.y);
                Tripleclone2.GetComponent<Rigidbody2D>().velocity = new Vector2(ballscript.rb.velocity.x, ballscript.rb.velocity.y);
                gm.UpdateBallCount(2);

            }

            Debug.Log("hit " + collision.name);
            Destroy(collision.gameObject);
            break;

    }

Я не знаю, как это исправить, и ценю любые идеи!

1 Ответ

3 голосов
/ 06 июня 2019

Я не вижу код, где шары уничтожены, или ваши настройки, но в вашем вопросе это звучит для меня как в PrefabBall, на который вы ссылались на оригинальный шар из Сцены .

Так что, когда вы Destroy(), тогда PrefabBall будет null конечно.


Как насчет того, чтобы иметь фактический префаб в Assets вместо ссылки на объект Scene? Я полагаю, вы этого не делали, потому что вы хотели напрямую клонировать его текущие свойства, полученные из бонусов вместе с ним. Но для этого есть и другие варианты (например, копирование их, как вы делали с настройками жесткого тела, или сохранение бонусов в виде значений static)


В качестве альтернативы можно отключить только «потерянные» шары

ball.gameObject.SetActive(false);

вместо того, чтобы уничтожать их. Таким образом, он остается неизменным, но больше не доступен для игры. Вам только нужно убедиться, что включены инстанцированные шары, такие как

Doubleclone.gameObject.SetActive(true);

Как замечание, есть также некоторые проблемы с эффективностью, которые я хотел бы отметить здесь

Вы все время пользуетесь

ball ballscript = ArrayOfBalls[i].GetComponent<ball>();

Было бы гораздо эффективнее вместо этого напрямую использовать

ball[] ArrayOfBalls = FindObjectsOfType<ball>();

или в качестве полной альтернативы Find используйте

public static readonly List<ball> ArrayOfBalls = new List<ball>();

сделать тип PrefabBall скорее ball, и теперь каждый раз, когда вы создаете новый шар, добавляйте его в список

ball Doubleclone = Instantiate(PrefabBall, ....);
ArrayOfBalls.Add(Doubleclone);

и каждый раз до вы Destroy() мяч удаляете его из списка frist

ArrayOfBalls.Remove(ball);
Destroy(ball.gameObject);

Таким образом, ваш ArrayOfBalls всегда обновляется сам по себе.

И Вы можете легко получить текущий глобальный счетчик шаров:

YourScriptType.ArrayOfBalls.Count
...