【问题标题】:MissingReferenceException: The object of type 'Attacker' has been destroyed but you are still trying to access itMissingReferenceException:“攻击者”类型的对象已被破坏,但您仍在尝试访问它
【发布时间】:2018-09-26 13:15:07
【问题描述】:

我收到上述错误,我尝试使用 debug.log 打印错误所在。 我正在创建一种坦克 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 最终为空。我试图在控制台中打印它。但它不会出现在其他 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);
            }
    }

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

【问题讨论】:

  • 你能发布整个堆栈跟踪吗?
  • 好吧,你有很多自高自大的逻辑。在您的Update()if 检查中,交换IsInRange()attacker != null。如果没有,您将使用null 攻击者(可能)进入IsInRange()。现在,您可以删除 IsInRange() 中的攻击者空检查,这可能会使您的 foreach 循环弹出。此外,currentAttacker 不会为空,它不会出现在您的列表中。你需要维护一个标志
  • 非常感谢您找出错误。谢谢,游戏开发是我这辈子唯一想做的事。没有你们的帮助,我做不到。因为一个人做所有的事情真的有点困难。谢谢。
  • @jiveturkey 感谢 jiveturkey 的帮助。在你的帮助下,我能够制作我的第三场比赛。我在描述中提到了你的名字,希望你不介意。 lifeisjourney.itch.io/snowman
  • 非常感谢您的赞誉。

标签: c# unity3d 2d


【解决方案1】:

解决此问题的快速而肮脏的方法是使用DestroyImmediate 函数而不是Destroy 函数。使用DestroyImmediate(gameObject) 将破坏该帧中的对象,FindObjectsOfType&lt;Attacker&gt;() 找不到它,因此不会在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);

【讨论】:

  • 非常感谢您解决了我的很多问题。谢谢你。我真的很感谢你们帮助像我这样的人。谁知道很少的编程和梦想有一天成为一名游戏开发者。早些时候我在编程中不使用列表,但现在我真的很喜欢它。我已经更改了我的代码 a 但是并使用该列表并从该列表中获取 obj 。好干净。谢谢。
  • 很高兴能够提供帮助
  • 感谢您的帮助。在你的帮助下,我能够制作我的第三场比赛。我在描述中提到了你的名字,希望你不介意。 lifeisjourney.itch.io/snowman
  • 完全没问题。否则你需要装配雪人,盯着一个只有变换动作的静态角色很无聊。装配后,为其创建一个空闲和移动的动画。它会让它看起来更好。请参阅this 教程以开始使用。
  • 非常感谢现在会尝试一些事情......:) 谢谢你的帮助。
【解决方案2】:

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

希望对你有帮助

【讨论】:

  • 非常感谢您帮助 Z3RP。没有你们的帮助,我无法解决这些仅由我自己创建的错误。谢谢谢谢。你们都是英雄。
  • 感谢 Z3RP 的帮助。在你的帮助下,我能够制作我的第三场比赛。我在描述中提到了你的名字,希望你不介意。 lifeisjourney.itch.io/snowman
【解决方案3】:

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

2 个解决方案...

A) UGLY:将 tank1 的初始位置更改为永远不会被摧毁的位置,例如 5000,5000,5000。由于坦克不能被摧毁,它永远不会为空

B) 聪明、正确的方法:制作预制件。创建一个名为 prefabs 的文件夹,将 tank1 拖入其中。选择生成坦克的脚本,然后将 tank1 的 PREFAB 副本拖入其中。现在你总是有一个 tank1 的实例,你的空指针不见了!

我不能足够强调正确使用预制件的重要性,不仅仅是为了性能和可靠性,还有理智......

【讨论】:

  • 非常感谢 Vanethrane。我会和 B 一起去。我正在努力变得聪明。但是现在我写的代码很丑,但是在你们的帮助下学习会让我和我的代码变得聪明。一天。希望如此。:)
  • 感谢 Vanethrane 的帮助。在你的帮助下,我能够制作我的第三场比赛。我在描述中提到了你的名字,希望你不介意。 lifeisjourney.itch.io/snowman
  • 感谢好友的提及!好游戏!我试了一下,很享受。很高兴为您提供帮助
【解决方案4】:
FindObjectsOfType<Attacker>(); //returns an array

将返回一个数组,而不是一个对象,使用攻击者[0]作为第一个或使用

FindObjectOfType&lt;Attacker&gt;()

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

使用 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
                }
        }

【讨论】:

  • 谢谢胜利者。我使用过 List,现在我认为使用它确实是一件好事。 :)
  • 感谢 victor dabija 的帮助。在你的帮助下,我能够制作我的第三场比赛。我在描述中提到了你的名字,希望你不介意。 lifeisjourney.itch.io/snowman
猜你喜欢
  • 2012-04-30
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多