MissingReferenceException: объект типа «Атакующий» был уничтожен, но вы все еще пытаетесь получить к нему доступ - PullRequest
0 голосов
/ 26 сентября 2018

Я получаю вышеуказанную ошибку, и я попытался использовать debug.log для печати, где ошибка.Я создаю тип танка объект.который огонь в какой-то конкретный объект.Созданный объект является атакующим.

В обновлении я использую цикл foreach для циклического прохождения всех созданных объектов.Если объект найден и объект находится в зоне пожара.

void Update () {


        if (attacker!= null  )
        {
            //Debug.Log("inside att");
            attacker = FindObjectsOfType<Attacker>();
        }

        // fire only if attacker is in range 

        if (IfInRange() && attacker!= null && running)
        {

            faceTowardTarget();
            Fire();
        }


    }
    bool IfInRange()
    {// run through all the instantiated attacker
        foreach (Attacker currentAttacker in attacker)

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

{   //if attacker is in range

            if (attacker != null )
                {

                    Debug.Log(currentAttacker.GetComponent<Health>().isAlive);

                    if (Vector2.Distance(transform.position, currentAttacker.transform.position) < minDistance)               
                    {

                        attackerPos = currentAttacker.transform;

                        return true;
                    }
                }
                if (currentAttacker == null)
                {
                    Debug.Log("curre Attacker null");
                    running = false;
                    return false;
                }

             }return false;
        }

У атакующего есть простой сценарий здоровья, который наносит урон при попадании снаряда.

Void update()
    {
     if (health <= 0)
            {
**is there any better way to destroy an obj. If i destroy gameObject that error appear and it get stuck in foreach loop**
               // Destroy(gameObject);
                noOfKilled++;
                isAlive = false;
                scoreHolder.addScore(scoreValue);
            }
    }

Большое спасибоза помощь.Я пытался найти, но не смог решить эту проблему.

Ответы [ 4 ]

0 голосов
/ 26 сентября 2018

Я собираюсь предположить, ошибка появляется при создании другого танка после уничтожения первого танка?все ваши танки являются клонами танка1, поэтому, когда танк1 уничтожен, вы получаете нулевой указатель, потому что он пытается создать объект, которого больше нет.

2 решения ...

AУЖАСНО: измените начальную позицию tank1 так, чтобы она никогда не была уничтожена, скажем, 5000, 5000, 5000.так как танк не может быть уничтожен, он никогда не будет нулевымсоздайте папку с именем prefabs, перетащите в нее tank1.выберите свой сценарий, который порождает танки, и перетащите в него PREFAB копию tank1.теперь у вас всегда есть экземпляр tank1, и ваш нулевой указатель пропал!

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

0 голосов
/ 26 сентября 2018

Быстрый и грязный способ исправить это - использовать функцию DestroyImmediate вместо функции Destroy.Использование DestroyImmediate(gameObject) уничтожит объект в этом кадре, а FindObjectsOfType<Attacker>() не сможет его найти, поэтому к нему не будет обращаться в цикле foreach.


Правильный способ для этого - создатьList в вашем основном коде для хранения экземпляра сценария Attacker:

public GameObject attackerPrefab;
public List<Attacker> attacker = new List<Attacker>();

Когда вы создаете экземпляр префаба, добавляет сценарий Attacker к List:

//Instantiate
GameObject obj = Instantiate(attackerPrefab);
//Get Attacker component 
Attacker tempAttacker = obj.GetComponent<Attacker>();
//Add Attacker component to List
attacker.Add(tempAttacker);

Наконец, когда вы хотите уничтожить объект атакующего в вашем скрипте здоровья, удалите его из List и затем уничтожьте его.Удалив его из List до его уничтожения, вы не сможете получить доступ к объекту, помеченному как уничтоженный.

//Get the script that stores the List of Attacker
Test otherScript = GameObject.Find("NameOfGameObjectYourScriptIsAttachedTo").GetComponent<Test>();
//Remove from the List
otherScript.attacker.Remove(gameObject.GetComponent<Attacker>());
//Now, destroy this gameObject
Destroy(gameObject);
0 голосов
/ 26 сентября 2018
FindObjectsOfType<Attacker>(); //returns an array

вернет массив, а не объект, используйте нападающие [0] для первого или используйте

FindObjectOfType<Attacker>()

(вернет первый найденный).

Используя objectsOfType, у вас всегда есть пустой массив, поэтому

if (attacker==null)

, конечно, вернет false, поскольку массив не равен нулю, он просто пуст.Вот почему он не входит в ваш второй оператор if;

Также

void update()
        {
         if (health <= 0)
                {
    **is there any better way to destroy an obj. If i destroy gameObject that error appear and it get stuck in foreach loop**

                    noOfKilled++;
                    isAlive = false;
                    scoreHolder.addScore(scoreValue);
                    Destroy(gameObject);// destroy it after at the end, not before it have something else to do
                }
        }
0 голосов
/ 26 сентября 2018

Есть много вариантов решения этой проблемы.Один из вариантов - не использовать цикл foreach при редактировании цикла.Но когда вы хотите сохранить цикл foreach, просто сохраните объекты в другом списке и уничтожьте их после цикла foreach.

Example1

for(int i = 0; i < attackers.Count; i++)
            {
                //if in range
                attackers.RemoveAt(i);
                i--;
            }

Example2

List<string> attackers = new List<string>();
        List<string> _shootAt = new List<string>();
        foreach(string attacker in attackers)
        {
            //if in range
            _shootAt.Add(attacker);
        }

        foreach (string attacker in _shootAt)
        {
            //if in range
            attackers.Remove(attacker);
        }

Я надеюсь, что это может помочь вам

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...