Unity跨脚本获取组件变量时触发引擎崩溃问题求助
问题根因
你的代码存在4个直接导致引擎崩溃、逻辑失效的核心问题:
- 语法错误直接触发编译崩溃:Food生成脚本最后一行
foodobject.name = "AppleObject";存在引号不匹配问题,C#编译器解析未闭合字符串时会抛出严重语法错误,直接导致Unity编译进程崩溃。 - 空引用未防护引发运行时崩溃:Hunter的Update逻辑中没有判断
ScannerEyes.foundobject是否为null——游戏启动初期扫描器未检测到苹果时,foundobject默认是null,直接访问.transform会每帧抛出空引用异常,异常堆栈持续堆积会直接卡死引擎。另外你写的GameObject.FindGameObjectsWithTag("Food") != null判断完全无效:该方法无论场景内是否存在对应标签物体,都会返回数组对象(无对应物体时返回长度为0的空数组,永远不会返回null),根本无法拦截空引用。 - 组件获取逻辑错误:你提到ScannerEyes挂载在Hunter的子对象上,但
GetComponent<ScannerEyes>()只会搜索Hunter物体自身挂载的组件,不会遍历子物体,因此你拿到的组件引用本身就是null,访问null对象的属性必然触发异常。 - 扫描逻辑单次生效:ScannerEyes第一次扫到苹果后就会把扫描球缩为0,终止扫描流程,如果当前锁定的苹果被其他猎人吃掉/销毁,猎人会永久丢失目标,不会重新搜索新的苹果。
额外存在两个影响稳定性的问题:每帧调用GetComponent获取组件会产生不必要的性能开销;扫描扩张速度没有乘以Time.deltaTime,会导致扫描速度受帧率影响波动。
修复方案
按以下逻辑修改代码即可解决所有问题:
- 修复Food脚本的语法错误,补全正确的字符串引号。
- 在Hunter初始化阶段缓存子对象上的ScannerEyes组件引用,不要每帧重复查找。
- 所有访问可能为null的对象前,先做非空校验。
- 给ScannerEyes增加重置逻辑:锁定的苹果被销毁后,自动重启扫描流程。
- 移动逻辑指定使用世界坐标,避免物体自身旋转导致移动方向偏移。
修正后的Hunter脚本代码
// 缓存组件和参数 private ScannerEyes myScanner; public Transform Target; public float Speed = 5f; public float StopDistance = 1f; public int reproducerate = 0; void Start() { // GetComponentInChildren会遍历自身和所有子物体的组件,正确拿到子对象上的ScannerEyes myScanner = GetComponentInChildren<ScannerEyes>(); } void Update() { if (reproducerate < 1) { // 仅当扫描器找到目标、且目标未被销毁时执行移动逻辑 if (myScanner.found && myScanner.foundobject != null) { Target = myScanner.foundobject.transform; Vector3 moveDir = (Target.position - transform.position).normalized; if (Vector3.Distance(transform.position, Target.position) > StopDistance) { // 指定Space.World保证移动方向不受物体自身旋转影响 transform.Translate(moveDir * Time.deltaTime * Speed, Space.World); } } } } public void OnCollisionEnter(Collision collision) { if (collision.gameObject.CompareTag("Food")) { reproducerate += 1; Destroy(collision.gameObject); // 吃到苹果后重置扫描器,搜索下一个目标 myScanner.ResetScan(); Debug.Log(reproducerate); } }
修正后的ScannerEyes脚本代码
public bool found = false; public GameObject foundobject; public float maxScanSize = 10f; public float scanSpeed = 2f; private float currentSize = 0f; void Update() { // 扫描球未到最大范围、且未找到目标时持续扩张 if (currentSize < maxScanSize && !found) { transform.localScale = new Vector3(currentSize, currentSize, currentSize); currentSize += scanSpeed * Time.deltaTime; } if (found) { transform.localScale = Vector3.zero; // 锁定的目标被销毁时自动重置扫描 if (foundobject == null) { ResetScan(); } } } // 对外提供重置扫描的方法 public void ResetScan() { found = false; foundobject = null; currentSize = 0f; } private void OnTriggerEnter(Collider other) { // 未找到目标时才响应Food触发,避免重复覆盖目标 if (other.gameObject.CompareTag("Food") && !found) { Debug.Log("Found target"); foundobject = other.gameObject; Debug.Log("Target position: " + foundobject.transform.position); found = true; } }
修正后的Food生成脚本代码
private GameObject foodobject; public GameObject Foodprefab; private float xSpawn; private float zSpawn; void Start() { Debug.Log("Food spawner active"); for (int i = 0; i < 2; i++){ xSpawn = Random.Range(-4, 4); zSpawn = Random.Range(-4, 4); Debug.Log(xSpawn + " , " + zSpawn); foodobject = Instantiate(Foodprefab, new Vector3(xSpawn, 1.4f, zSpawn), Quaternion.identity); // 修复引号不匹配的语法错误 foodobject.name = "AppleObject"; } }
配置注意事项
- 确保scannereyes子对象的Collider组件勾选了
Is Trigger选项,否则OnTriggerEnter事件不会触发 - Rigidbody组件挂载在Hunter父物体上即可,不要给扫描球单独加Rigidbody,避免物理计算异常
- 所有Apple预制体必须正确设置
Food标签,否则扫描逻辑无法识别目标
内容的提问来源于stack exchange,提问作者Hymandois
相关产品推荐
相关产品推荐

