我遇到了以上错误,我尝试使用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);
}
}
非常感谢您的帮助。我尝试搜索,但无法解决。
答案 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
}
}