Unity3d 性能优化:空签入更新()

Unity3d 性能优化:空签入更新(),unity3d,Unity3d,我目前正在为我的太空射手项目中的敌人开发一种基本的人工智能。 在我的EnemyAI脚本中,我在实例化敌人时设置了一个公共转换目标。在更新循环中,我查看目标,然后使用transform.to移动,一切正常。问题是,目标可能会死掉,因此在执行所有操作之前,我需要检查它是否为null。问题是:显然,如果(target==null)执行一个简单的,在性能方面是非常糟糕的,我需要在Update中执行它。在没有性能问题的情况下实现这一目标的最佳方法应该是什么(假设我一次想要500个敌人)。我是否仍应该每X帧

我目前正在为我的太空射手项目中的敌人开发一种基本的人工智能。 在我的EnemyAI脚本中,我在实例化敌人时设置了一个
公共转换目标。在更新循环中,我查看目标,然后使用
transform.to
移动,一切正常。问题是,
目标
可能会死掉,因此在执行所有操作之前,我需要检查它是否为null。问题是:显然,如果(target==null)
执行一个简单的
,在性能方面是非常糟糕的,我需要在Update中执行它。在没有性能问题的情况下实现这一目标的最佳方法应该是什么(假设我一次想要500个敌人)。我是否仍应该每X帧执行一次,缓存目标的位置,直到下一次检查并向缓存的结果移动?这可能会起作用,但如果两次检查之间的时间过长,则会引入抖动

我找不到任何“简单”的方法,但我希望有一种,它看起来非常简单,而且会引起很多麻烦://p>
  • 空检查并不昂贵
  • 协同路由可以帮助将负载分散到多个帧上。但请仔细阅读他们的内存使用/垃圾收集问题
  • 您可以将ECS系统(实体组件系统)与C#Jobs(多线程)结合使用来加快速度
  • 使用探查器(Window->Profiler)或(Window->Analysis->Profiler in 2018.3)分析实际花费的时间
  • 与正常的for相比,for-each是不好的(垃圾收集方面)
  • 如果设置了位置和旋转,请使用
      • 空检查并不昂贵
      • 协同路由可以帮助将负载分散到多个帧上。但请仔细阅读他们的内存使用/垃圾收集问题
      • 您可以将ECS系统(实体组件系统)与C#Jobs(多线程)结合使用来加快速度
      • 使用探查器(Window->Profiler)或(Window->Analysis->Profiler in 2018.3)分析实际花费的时间
      • 与正常的for相比,for-each是不好的(垃圾收集方面)
      • 如果设置了位置和旋转,请使用

        • 您可以从逻辑上避免它,创建一个仅在分配目标时运行的协同路由,如果目标为空,则结束协同路由,该协同路由应具有

          yield return new WaitForEndOfFrame();
          
          这样,它将充当一种
          最新更新

          检查每一帧

          while (target != null)
          

          您仍然会检查每一帧的空值,但您只会检查一次
          target=null

          您可以从逻辑上避免这种情况,创建一个只在分配目标时运行的协程,如果目标为空,则结束协程,该协程应具有

          yield return new WaitForEndOfFrame();
          
          这样,它将充当一种
          最新更新

          检查每一帧

          while (target != null)
          

          您仍将检查每一帧的空值,但只检查一次
          target=null

          我查找并测试了它,是的,您可以使用回调函数执行此操作,该函数将注册到目标的
          ondestory
          方法。您的
          Player脚本
          应该访问目标脚本并按如下方式委派方法:

          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");
          }
          
          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);
          }
          

          我用了一个协同程序在5秒后销毁了这个对象。这实际上与你的情况无关。我采用了这个代码

          我查找并测试了它,是的,您可以使用一个回调函数来执行此操作,该函数将注册到目标的
          ondestory
          方法中。您的
          Player脚本
          应该访问目标脚本并按如下方式委派方法:

          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");
          }
          
          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);
          }
          

          我用了一个协同程序在5秒后销毁了这个对象。这实际上与你的情况无关。我采用了这个代码

          注意UnityEngine的空检查。对象子对象不是标准的C#空检查。Jetbrains提供的与Rider IDE和分析工具相关的信息将深入到细节中。基本的想法是C脚本将空校验交给底层C++引擎结构。
          我不需要它,但我看过别人的代码,它保存了一个简单的UnityEngine.Object引用列表。创建对象时,它们会将对象的引用添加到列表中。然后将其从销毁列表中删除。Update()然后可以使用列表中更快的测试。在速度至关重要的地方,您只需测试列表,而不是对象。当然,可以使用列表以外的方法。

          注意UnityEngine的空检查。对象子对象不是标准的C#空检查。Jetbrains提供的与Rider IDE和分析工具相关的信息将深入到细节中。基本的想法是C脚本将空校验交给底层C++引擎结构。
          我不需要它,但我看过别人的代码,它保存了一个简单的UnityEngine.Object引用列表。创建对象时,它们会将对象的引用添加到列表中。然后将其从销毁列表中删除。Update()然后可以使用列表中更快的测试。在速度至关重要的地方,您只需测试列表,而不是对象。当然,可以使用列表以外的方法。

          您从哪里知道检查空指针是一项昂贵的操作?我对C#的内部结构了解不多,但对于大多数编程语言来说,它与整数比较一样快(可能更快)。。。任何空检查都非常便宜。您可以每帧执行数百次此问题涉及Unity对象,空比较并不快。我相信你可以通过一个回调来解决这个问题,这个回调在销毁时注册到目标。我不知道这要花多少钱though@AliKanat这是一个很好的提示!我会调查的谢谢你你从哪里知道检查空指针是一个昂贵的操作?我不太了解C#的内部结构,但对于大多数程序来说