性能优化:null null in update()



我目前正在为我的太空射击项目中的敌人提供基本的AI。在我的Eneyai脚本中,当我实例化敌人时,我设置了一个public Transform target。在更新循环中,我正在查看目标,然后使用transform.towards移动,一切正常。问题是,target可能会死亡,因此我需要在完成所有操作之前检查它是否不是零。问题是:显然,做一个简单的if(target == null)确实是糟糕的性能,我需要在更新中进行。在没有绩效问题的情况下,应该是实现这一目标的最佳方法(假设我要一次想要500名敌人)。我是否还应该在每个X框架上进行此操作,缓存目标的位置,直到下次检查并向该缓存结果移动?这可能会起作用,但是如果两个检查时间太长,则会引入抖动。

我找不到任何"简单"的方式,但我希望有一个,看起来很简单,并且造成了很多麻烦:/

  • null检查不是昂贵的。
  • Coroutines可以帮助将负载扩散到多个帧上。但是仔细阅读了他们的内存使用情况/垃圾收集问题。
  • 您可以使用ECS系统(实体组件系统)与C#作业(多线程)
  • 结合使用加速加速
  • 使用Profiler(窗口 -> profiler)或(窗口 ->分析 -> 2018.3中的Profiler)分析实际花费的时间很长。
  • 的正常人相比
  • 如果设置位置和旋转,请使用setPosition andRotation分组两个调用

注意null与UnityEngine。对象儿童不是标准的C#NULL检查。Jetbrains提供的有关骑手IDE和分析工具的描述介绍了细节。基本想法是,C#脚本将零检查删除到基础C 发动机结构。

我没有需要它,但是我看到了其他代码,可以保留一个简单的UnityEngine.Object参考。他们在创建对象的对象中添加了对对象的引用。然后将其从毁灭性的列表中删除。然后,update()可以在列表中使用更快的测试。速度至关重要的地方,您只需测试列表而不是对象即可。当然,可以使用列表以外的其他方法。

我查找并测试了它,是的,您可以使用回调函数进行此操作,该回调功能将注册到您的目标OnDestroy方法中。您的Player script应访问目标脚本并委派这样的方法:

public GameObject target;
private TargetScript myTargetScript;
void Start () {
    myTargetScript = target.GetComponent<TargetScript>();
    myTargetScript.OnDestroyEvnt += OnDestroyListener;
}
private void OnDestroyListener(MonoBehaviour instance)
{
    Debug.Log("Callback is called");
}

Target script也应该像这样:

public event OnDestroyDelegate OnDestroyEvnt;
public delegate void OnDestroyDelegate(MonoBehaviour instance);
void Start () {
    StartCoroutine(DestroyCoroutine());
}   
private void OnDestroy()
{
    if (this.OnDestroyEvnt != null)
    {
        this.OnDestroyEvnt(this);
    }
}
IEnumerator DestroyCoroutine()
{
    yield return new WaitForSeconds(5);
    Destroy(gameObject);
}

我用coroutine在5秒后摧毁该物体。在您的情况下,这实际上是无关紧要的。我从这里采用了此代码。

您可以避免逻辑上的逻辑,制作仅在分配目标时运行的coroutine,如果目标为null,则结束Coroutine,该coroutine应该具有...

yield return new WaitForEndOfFrame();

这样,它将充当LateUpdate

并检查每个帧...

while (target != null)

您仍将检查每个帧的每个帧,但是您只会检查一次target = null

最新更新