[英]How to fix these Unity errors?
我最近在我的大多數腳本中為列表切換了一些 arrays,因為它們更易於使用。 但問題是帶來了一些新的錯誤。 他們是:
根據錯誤,問題出在 Gorean Turret 的第 96 行和 POW_Camp 的第 37 行。 其他幾個腳本也有這個問題,但如果我弄清楚這兩個有什么問題,我應該能夠弄清楚如何修復 rest。
我搜索了如何處理這些錯誤並找到了幾個解決方案。 我將 foreach 循環更改為 for (var i=0;) 樣式循環。 這應該有效,但不幸的是沒有。
我的問題是如何修復這些錯誤。 我如何需要更改我的腳本以確保沒有錯誤。 作為旁注,如果您發現可以縮短的內容,請告訴我。 我有一種感覺,代碼也比它需要的長。
這是 POW_Camp 腳本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class POW_Camp : MonoBehaviour
{
public GameObject AmmunitionsDump;
public GameObject Explosion;
public GameObject Fences;
public List<GameObject> Prisoners;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (AmmunitionsDump.GetComponent<Health>().CurrentHealth<=0)
{
AmmunitionsDump.SetActive(false);
Explosion.SetActive(true);
}
//If the ammunitiondump is destroyed then destroy fences
if (AmmunitionsDump.activeSelf == false)
{
Destroy(Fences);
//Activate POWs
for (var i=0;i<Prisoners.Count; i++)
{
if (Prisoners[i] == null)
{
Prisoners.Remove(Prisoners[i]);
}
if (Prisoners[i] != null)
{
Prisoners[i].GetComponent<PlayerData>().Captured = false;
}
}
}
}
}
這是 GoreanTurret 腳本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GoreanTurret : MonoBehaviour
{
public GameObject Projectile;
public GameObject FiringPoint;
public GameObject GunTower;
public GameObject HealthBar;
public List<GameObject> TargetsWithinRange = new List<GameObject>();
public float FiringRange = 100;
public GameObject CurrentTarget;
public bool TargetLocked;
// Start is called before the first frame update
void Start()
{
InvokeRepeating("Shoot", 1, 0.5f);
HealthBar.GetComponent<Slider>().maxValue = gameObject.GetComponent<Health>().MaxHealth;
HealthBar.GetComponent<Slider>().value = gameObject.GetComponent<Health>().CurrentHealth;
}
// Update is called once per frame
void Update()
{
FindTargetsWithinRange(FiringRange, TargetsWithinRange);
TargetManager(TargetsWithinRange, FiringRange);
HealthBar.GetComponent<Slider>().value = gameObject.GetComponent<Health>().CurrentHealth;
//Look at Target if Target is Locked
if (TargetLocked)
{
GunTower.transform.LookAt(CurrentTarget.transform);
}
// If target is destroyed then set targetLocked to false and target to null;
if (CurrentTarget != null)
{
if (CurrentTarget.GetComponent<Health>().CurrentHealth <= 0)
{
TargetLocked = false;
CurrentTarget = null;
}
}
// If one of the targets in the target list is destroyed then remove that
foreach (GameObject possibleTarget in TargetsWithinRange)
{
if (possibleTarget == null || possibleTarget.GetComponent<Health>().CurrentHealth<=0 || possibleTarget.GetComponent<Health>()==null)
{
TargetsWithinRange.Remove(possibleTarget);
}
}
if (CurrentTarget == null)
{
TargetLocked = false;
CurrentTarget = null;
}
// If target is lost and there are still targets, then switch target
if (TargetLocked == false && (CurrentTarget == null || CurrentTarget.GetComponent<Health>().CurrentHealth<0) && TargetsWithinRange.Count>0)
{
if (TargetsWithinRange[0] != null)
{
CurrentTarget = TargetsWithinRange[0];
TargetLocked = true;
}
}
}
void FindTargetsWithinRange(float range, List<GameObject> TargetList)
{
Collider[] colliders = Physics.OverlapSphere(gameObject.transform.position, range);
foreach (Collider collider in colliders)
{
if (collider.gameObject.GetComponent<PlayerData>())
{
if (collider.gameObject.GetComponent<PlayerData>().Captured == false && TargetList.Contains(collider.gameObject) == false)
{
TargetList.Add(collider.gameObject);
}
}
}
}
void TargetManager(List<GameObject> TargetList, float MaxRange)
{
for (var i = 0; i < TargetList.Count; i++)
{
//If the Target is null or inactive then remove that target or if it has no health
if (TargetList[i] == null || TargetList[i].activeSelf == false || TargetList[i].GetComponent<Health>().CurrentHealth <= 0)
{
TargetList.Remove(TargetList[i]);
if (TargetList[i] == CurrentTarget)
{
TargetLocked = false;
}
}
//If the target is too far
if (Vector3.Distance(gameObject.transform.position, TargetList[i].transform.position) > MaxRange)
{
TargetList.Remove(TargetList[i]);
if (TargetList[i] == CurrentTarget)
{
CurrentTarget = null;
TargetLocked = false;
}
}
}
//If there is no target and the TargetLocked is false then Set a new target
if (CurrentTarget == null && TargetLocked == false && TargetList.Count > 0)
{
CurrentTarget = TargetList[0];
TargetLocked = true;
}
// If target is destroyed then set targetLocked to false and target to null;
if (CurrentTarget != null && CurrentTarget.activeSelf == true && CurrentTarget.GetComponent<Health>().CurrentHealth > 0)
{
if (CurrentTarget.GetComponent<Health>().CurrentHealth <= 0)
{
TargetLocked = false;
CurrentTarget = null;
}
}
}
public void Shoot()
{
if (TargetLocked == true)
{
Instantiate(Projectile, FiringPoint.transform.position, FiringPoint.transform.rotation);
}
}
}
在您的兩個類中,您都有循環,您在迭代它們時從 collections 中刪除元素。
第一個導致ArgumentOutOfRangeException
因為在刪除一定數量的元素后,您將迭代直到達到一個太高的索引,因為您的列表/數組現在更小了!
另一個例外是不言自明的:您在使用foreach
迭代集合時更改集合。
您可以使用Linq 解決這兩種情況, Where
為了過濾掉null
條目(需要using System.Linq;
在文件頂部)
// in general use the bool operator of UnityEngine.Object
// never do check for "== null" !
Prisoners = Prisoners.Where(p => p).ToList();
// This basically equals doing something like
//var p = new List<GameObject>();
//foreach(var prisoner in Prisoners)
//{
// if(prisoner) p.Add(prisoner);
//}
//Prisoners = p;
foreach (var prisoner in Prisoners.Count)
{
prisoner.GetComponent<PlayerData>().Captured = false;
}
完全相同的事情可以在你的第二個腳本中完成
// so first again we use the bool operator to check if the element target "existed
// then directly use TryGetComponent instead of GetComponent twice
// your order to check also made little sense ;) you should first Check
// the existence of the component before accessing a value
TargetsWithinRange = TargetsWithinRange.Where(target => target && target.TryGetComponent<Health>(out var health) && health.CurrentHealth > 0).ToList();
或者,如果集合本身保持相同的引用很重要,您可以使用RemoveAll
代替,例如
Prisoners.RemoveAll(prisoner => ! prisoner);
並相應地在您的其他腳本中
TargetsWithinRange.RemoveAll(target => !target || !target.TryGetComponent<Health>(out var h) || h.CurrentHealth <= 0);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.