性能优化:在Update()中进行空检查

时间:2019-02-27 14:09:36

标签: unity3d

我目前正在为我的太空射击项目中的敌人开发基本的AI。 在我的EnemyAI脚本中,我有一个实例化敌人时设置的public Transform target。在Update循环中,我正在查看目标,然后使用transform.towards移动,一切正常。问题是target可能会死亡,因此我需要在执行所有操作之前检查它是否不为null。问题是:显然做一个简单的if(target == null)确实是很糟糕的性能,我需要在Update中进行。在没有性能问题的情况下实现这一目标的最佳方法应该是什么(假设我一次要500个敌人)。我是否仍应在每个X帧中执行此操作,将目标的位置缓存到下一次检查,然后移向该缓存的结果?这可能有效,但如果两次检查之间的时间过长,则会引入抖动。

我找不到任何“简单”的方法,但我希望有一种方法,它看起来很简单,并且会引起很多麻烦:/

4 个答案:

答案 0 :(得分:2)

  • 空检查并不那么昂贵。
  • 协同程序可以帮助将负载分散到多个帧中。但是请仔细阅读它们的内存使用/垃圾回收问题。
  • 您可以结合使用ECS系统(实体组件系统)和C#Jobs(多线程)来加快速度
  • 使用Profiler(窗口-> Profiler)或(窗口->分析-> 2018.3中的Profiler)来分析实际花费的时间。
  • for-each与正常for相比是不好的(从垃圾回收角度来看)。
  • 如果您设置位置和旋转,请使用SetPositionAndRotation
  • 将这两个呼叫分组

答案 1 :(得分:0)

我检查并测试了它,是的,您可以使用回调函数来执行此操作,该回调函数将注册到目标的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);
}

5秒后,我用协程破坏了该物体。这实际上与您的情况无关。我采用了here中的这段代码。

答案 2 :(得分:0)

注意 UnityEngine.Object 子项的空检查不是标准的 C# 空检查。 Jetbrains 提供的与 Rider IDE 和分析工具相关的 description 深入了解了细节。基本思想是 C# 脚本将 null 检查交给底层 C++ 引擎结构。

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

答案 3 :(得分:-2)

您可以在逻辑上避免它,创建一个仅在分配目标时才运行的协程,如果目标为null,则结束协程,该协程应具有一个...

yield return new WaitForEndOfFrame();

那样,它将像一种LateUpdate一样。

然后检查每一帧...

while (target != null)

您仍将每个帧都检查为空,但只检查一次target = null