You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity脚本导致编辑器无响应卡顿问题排查求助

Unity脚本卡顿问题排查

问题描述

我写了一个脚本,功能是先禁用所有名为“target”的对象,再随机激活其中一个,让NavMeshAgent移动到该目标;当NavMeshAgent到达当前激活的目标后,会禁用这个目标并切换激活新的随机目标。但进入PlayMode测试时,Unity直接卡顿、无响应,只能用任务管理器强制关闭;停用这个脚本后游戏运行完全正常。之前还出现过错误提示:LS Allocator ALLOC_TEMP_TLS, underlying allocator ALLOC_TEMP_MAIN has unfreed allocations, size 560,但卡顿后这个错误就不再出现了。我附上了初始脚本和优化后的脚本,希望能找出卡顿的原因,我编程经验不多。

初始脚本

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class TargetManager : MonoBehaviour
{
    public Transform[] targets;

    private void Start()
    {
        // 获取所有子物体的Transform
        targets = GetComponentsInChildren<Transform>();
        // 移除第一个元素(自身Transform)
        targets = targets.Skip(1).ToArray();

        // 初始时禁用所有目标
        foreach (Transform target in targets)
        {
            target.gameObject.SetActive(false);
        }

        // 激活随机目标
        ActivateRandomTarget();
    }

    public void ActivateRandomTarget()
    {
        // 禁用所有目标
        foreach (Transform target in targets)
        {
            target.gameObject.SetActive(false);
        }

        // 随机选择索引并激活目标
        int randomIndex = Random.Range(0, targets.Length);
        targets[randomIndex].gameObject.SetActive(true);
    }
}

优化后脚本

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class TargetManager : MonoBehaviour
{
   public List<GameObject> targets = new List<GameObject>();

    private int currentTargetIndex = -1;

    private void Start()
    {
        // 初始时禁用所有目标
        foreach (GameObject target in targets)
        {
            target.SetActive(false);
        }

        // 激活随机目标
        ActivateRandomTarget();
    }

    public void ActivateRandomTarget()
    {
        if (targets.Count == 0)
        {
            Debug.LogWarning("未找到目标,请在Inspector中添加目标对象到列表。");
            return;
        }

        // 禁用当前激活的目标
        if (currentTargetIndex >= 0 && currentTargetIndex < targets.Count)
        {
            targets[currentTargetIndex].SetActive(false);
        }

        // 随机选择索引并激活新目标
        int randomIndex = Random.Range(0, targets.Count);
        targets[randomIndex].SetActive(true);

        // 更新当前目标索引
        currentTargetIndex = randomIndex;
    }
}

卡顿原因分析

  • 初始脚本的核心问题:

    1. 若ActivateRandomTarget()被高频调用(比如NavMeshAgent到达逻辑错误,导致每帧都调用),每次调用都要遍历所有目标执行SetActive(false),大量的对象激活/禁用操作会触发Unity频繁刷新对象状态,直接阻塞主线程。
    2. targets.Skip(1).ToArray()每次都会创建新数组,增加GC压力,但这一般不会直接导致卡死。
  • 优化后脚本的潜在残留问题:
    优化后的脚本已经减少了SetActive的调用次数(只禁用当前目标),但如果NavMeshAgent的到达检测逻辑有问题,导致ActivateRandomTarget()被无限循环调用(比如目标位置与Agent位置重叠,触发到达后立刻切换新目标,新目标又瞬间被判定为到达),依然会占满主线程导致卡顿。

  • 关于内存分配错误:
    那个unfreed allocations错误属于Unity内部临时内存未释放,和你的脚本关联不大,卡顿后错误消失是因为Unity卡死时无法输出日志。

解决建议

  1. 检查到达触发逻辑:不要在Update里每帧调用ActivateRandomTarget(),改用NavMeshAgent的isStopped状态,或者设置合理的距离阈值(比如距离目标大于0.5f时才移动,到达后仅调用一次切换方法)。
  2. 添加调试日志:在ActivateRandomTarget()开头加Debug.Log("切换目标"),查看方法调用频率,若每秒调用几十次以上,说明触发逻辑有问题。
  3. 确认目标列表赋值:在Inspector中确保targets列表正确添加了所有目标对象,避免空列表的无效调用。
  4. 避免重复切换相同目标:可以在随机选索引时,判断是否和当前索引相同,若相同则重新随机,减少不必要的SetActive操作。

内容的提问来源于stack exchange,提问作者JoseaRegbla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 19:15:36