MissingReferenceException:类型为“攻击者”的对象已被破坏,但您仍在尝试访问它

时间:2018-09-26 13:15:08

标签: c# unity3d 2d

我遇到了以上错误,我尝试使用debug.log打印错误所在。 我正在创建一种类型的Tank obj。触发某些实例化的obj。实例化的对象是攻击者。

在更新中,我使用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为null。我试图在控制台中打印出来。但不会在其他if语句中出现

{   //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 :(得分:5)

解决此问题的快速而肮脏的方法是使用DestroyImmediate函数而不是Destroy函数。使用DestroyImmediate(gameObject)将破坏该帧中的对象,并且FindObjectsOfType<Attacker>()无法找到它,因此将不会在foreach循环中对其进行访问。


正确的方法是在您的主代码中创建一个List来保存实例化的Attacker脚本:

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

实例化预制件时,将Attacker脚本 add 添加到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);

答案 1 :(得分:2)

有很多选项可以解决此问题。一种选择是在编辑循环时不要使用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);
        }

我希望能为您提供帮助

答案 2 :(得分:1)

我要假设,第一个坦克被摧毁后实例化另一个坦克时会显示错误?您所有的坦克都是tank1的克隆,所以当tank1被销毁时,您会得到一个空指针,因为它试图实例化一个不再存在的对象。

2个解决方案...

A)丑陋:将tank1的初始位置更改为永远不会被破坏的位置,例如5000,5000,5000。因为坦克不能被摧毁,所以永远不会为空

B)明智而正确的方法:制作预制件。制作一个名为prefabs的文件夹,将tank1拖入其中。选择生成坦克的脚本,然后将tank1的PREFAB副本拖到其中。现在,您始终拥有tank1的实例,并且空指针已消失!

我不能过分强调正确使用预制件的重要性,这不仅是为了提高性能和可靠性,还包括保持健康……

答案 3 :(得分:0)

FindObjectsOfType<Attacker>(); //returns an array

将返回一个数组,而不是一个对象,首先使用Attackers [0]或使用

FindObjectOfType<Attacker>()

(将返回找到的第一个)。

使用objectsOfType,您总是会有一个空数组,所以

if (attacker==null)

当然会返回false,因为数组不是null,而是空的。这就是为什么它不会出现在第二个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
                }
        }