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