unity3d 缺少引用异常:类型为“Attacker”的对象已被销毁,但您仍在尝试访问它

ftf50wuq  于 2022-12-27  发布在  其他
关注(0)|答案(4)|浏览(310)

我得到了上述错误,我试图使用debug.log打印错误所在。我正在创建一个类型的tank对象,它会触发一些示例化对象。示例化对象是攻击者。
在update中,我使用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);
            }
    }

非常感谢您的帮助。我尝试搜索,但无法解决此问题。

moiiocjp

moiiocjp1#

解决这个问题的最快捷的方法是使用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);
t2a7ltrp

t2a7ltrp2#

有很多方法可以解决这个问题。一个方法是当你编辑foreach循环的时候不要使用它。但是当你想保留foreach循环的时候,只要把对象保存在另一个列表中,然后在foreach循环之后销毁它们。
实施例1

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

实施例2

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

希望能帮到你

c9qzyr3d

c9qzyr3d3#

我将假设,在第一个坦克被摧毁后示例化另一个坦克时出现错误?所有坦克都是tank 1的克隆,所以当tank 1被摧毁时,你得到一个空指针,因为它试图示例化一个不再存在的对象。
两种解决方案...
A)丑陋:改变tank 1的初始位置到某个永远不会被摧毁的地方,比如说5000,5000,5000.因为tank 1不能被摧毁,所以它永远不会为空
B)明智、正确的方法:制作一个prefab.制作一个名为prefabs的文件夹,拖动tank 1到其中.选择你的脚本来生成坦克,并拖动tank 1的PREFAB副本到其中.现在你总是有一个tank 1的示例,并且你的空指针消失了!
我再怎么强调正确使用预制件的重要性也不为过,不仅是性能和可靠性,还有理智。

7xzttuei

7xzttuei4#

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

将返回数组,而不是对象,使用attackers[0]作为第一步或使用
第一个月
(will返回第一个找到的)。
使用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
                }
        }

相关问题