Unity中FindObjectsOfType无法统计实例化对象,现有代码仅识别初始对象
问题与解决方案
问题现状
当前使用的敌方最近目标检测代码仅能识别场景初始加载的Enemy对象,无法捕获运行时动态实例化的Enemy,但这是目前唯一能正常运行的版本。
原代码
void Update() { FindClosestEnemy(); } public void FindClosestEnemy() { float distanceToClosestEnemy = Mathf.Infinity; Enemy closestEnemy = null; Enemy[] allEnemies = GameObject.FindObjectsOfType<Enemy>(); foreach (Enemy currentEnemy in allEnemies) { float distanceToEnemy = (currentEnemy.transform.position - this.transform.position).sqrMagnitude; if (distanceToEnemy < distanceToClosestEnemy) { distanceToClosestEnemy = distanceToEnemy; closestEnemy = currentEnemy; } } }
问题原因分析
GameObject.FindObjectsOfType<Enemy>()本身是可以识别运行时实例化对象的,出现遗漏通常是以下原因:
- 运行时实例化的Enemy对象被设置为非激活状态(
SetActive(false)),该方法默认只检索激活状态的对象 - 实例化的预制体未正确挂载Enemy组件,或者组件在运行时被移除
- Enemy组件所在的GameObject未处于激活状态
修复与优化方案
方案1:兼容非激活对象
如果需要包含非激活的Enemy实例,只需修改FindObjectsOfType的调用,传入第二个参数true:
Enemy[] allEnemies = GameObject.FindObjectsOfType<Enemy>(true);
方案2:维护全局Enemy列表(推荐)
每帧调用FindObjectsOfType性能开销较高,且容易出现状态遗漏问题,建议通过Enemy自身的生命周期事件维护全局列表:
- 修改Enemy脚本,添加注册/注销逻辑:
public class Enemy : MonoBehaviour { // 全局维护所有Enemy实例 public static List<Enemy> AllEnemies = new List<Enemy>(); void OnEnable() { if (!AllEnemies.Contains(this)) { AllEnemies.Add(this); } } void OnDisable() { AllEnemies.Remove(this); } }
- 修改原检测脚本的
FindClosestEnemy方法,直接遍历全局列表:
void Update() { FindClosestEnemy(); } public void FindClosestEnemy() { float distanceToClosestEnemy = Mathf.Infinity; Enemy closestEnemy = null; foreach (Enemy currentEnemy in Enemy.AllEnemies) { float distanceToEnemy = (currentEnemy.transform.position - transform.position).sqrMagnitude; if (distanceToEnemy < distanceToClosestEnemy) { distanceToClosestEnemy = distanceToEnemy; closestEnemy = currentEnemy; } } // 此处可添加对closestEnemy的后续处理逻辑,如锁定目标、显示距离等 }
该方案的优势:
- 性能更优,避免每帧执行高开销的对象查找
- 实时响应Enemy的实例化、销毁、激活/禁用状态变化
- 彻底解决对象遗漏问题
内容的提问来源于stack exchange,提问作者Asker
相关产品推荐
相关产品推荐

