【问题标题】:How do you move 500 Rigidbody cubes without slowing to 0.3 FPS?如何在不减慢到 0.3 FPS 的情况下移动 500 个刚体立方体?
【发布时间】:2019-07-13 01:03:09
【问题描述】:

过去几周我一直在试验 Unity;我还是新人。我稍微涉足 ECS、计算着色器等,但如果由于复杂性而没有必要,我真的不想实现这些解决方案。

默认的 Unity 物理引擎真的不能同时使用刚体处理移动 500 个立方体实例吗?还是我做事的方式对性能特别不利?

这是我正在使用的代码;它只是一个空游戏对象上的一个脚本。实例化 500 个立方体时,它会减慢到 16FPS,然后通过 Rigidbody MoveTowards 一次移动它们时减慢到 0.3 FPS。

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

public class SpawnAndMove : MonoBehaviour
{
    public TargetCube TargetCube;
    public GameObject CubePrefab;
    public Vector3 brickPosition = new Vector3(10, 0, 0);
    GameObject[] objects;
    int moveCubeInstances;

    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(Countdown());
    }

    IEnumerator Countdown()
    {
        yield return new WaitForSeconds(3f);
        for (int i = 0; i < 500; i++)
        {
            var cubeClone = Instantiate(CubePrefab, transform.position + brickPosition, transform.rotation);
            cubeClone.tag = "CubeInstance";
        }

        objects = GameObject.FindGameObjectsWithTag("CubeInstance");

        yield return new WaitForSeconds(3f);
        moveCubeInstances = 1;

        while (moveCubeInstances == 1)
        {
            for (int i = 0; i < 500; i++)
            {
                objects[i].GetComponent<Rigidbody>().transform.position =
                            Vector3.MoveTowards(objects[i].GetComponent<Rigidbody>().transform.position, TargetCube.transform.position, 12f);
            }
            yield return new WaitForFixedUpdate();
        }

        print("exited while loop");
    }
}

感谢您在此提供的任何帮助。

【问题讨论】:

  • GetComponent 是一项昂贵的操作。避免每次固定更新调用 1000 次

标签: c# performance unity3d instance frame-rate


【解决方案1】:
  • 您对 FindGameObjectsWithTag 的调用会进行额外搜索,不仅针对新的 500 个对象,还针对该场景中的所有其他对象
  • transform 已经是缓存字段并且调用它你不需要做GetComponent&lt;&gt;
  • Instantiate 是一个非常困难的操作,最好提前做,甚至可以将它分成每帧几个调用,例如,每个调用 50 个,但绝对不是一帧 500 个,而是使用池化 (https://docs.unity3d.com/Manual/MobileOptimizationPracticalScriptingOptimizations.html)

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class SpawnAndMove : MonoBehaviour
    {
        public TargetCube TargetCube;
        public Rigidbody CubePrefab;
        public Vector3 brickPosition = new Vector3(10, 0, 0);
        Rigidbody[] objects;
        int moveCubeInstances;
    
        void Start()
        {
            StartCoroutine(Countdown());
        }
    
        IEnumerator Countdown()
        {
            yield return new WaitForSeconds(3f);
            objects = new Rigidbody[500];
            for (int i = 0 ; i < 500 ; i++)
            {
                Rigidbody cubeClone = Instantiate(CubePrefab, transform.position + brickPosition, transform.rotation);
                cubeClone.tag = "CubeInstance";
                objects[i] = cubeClone;
                if (i % 50 == 0)
                {
                    yield return new WaitForFixedUpdate();
                }
            }
    
            yield return new WaitForSeconds(3f);
            moveCubeInstances = 1;
    
            while (moveCubeInstances == 1)
            {
                for (int i = 0 ; i < 500 ; i++)
                {
                    objects[i].transform.position =
                            Vector3.MoveTowards(objects[i].transform.position, TargetCube.transform.position, 12f);
                }
                yield return new WaitForFixedUpdate();
            }
    
            print("exited while loop");
        }
    }
    

【讨论】:

  • 可以缓存转换。所以数组可以是变换,而不是对象,以保存对每个 ... 对象的变换的访问。在 Unity 中查找/获取/访问变换的速度并不快。
  • @Confused 我完全同意你的观点,我以为作者一旦使用Rigitbody,就会转向他,但如果不是,那么最好使用Transform
  • 很棒的解决方案。使我达到数百个 FPS。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-17
  • 2015-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多