如何在不减慢到 0.3 FPS 的情况下移动 500 个刚体立方体?

How do you move 500 Rigidbody cubes without slowing to 0.3 FPS?

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

默认的 Unity 物理引擎真的不能一次处理移动 500 个带有 RigidBodies 的立方体实例吗?还是我做事的方式对性能特别不利?

这是我正在使用的代码;它只是空游戏对象上的一个脚本。它在实例化 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");
    }
}

在此感谢您的帮助。

  • 您对 FindGameObjectsWithTag 的调用会进行额外的搜索,不仅针对新的 500 个对象,而且针对此场景中的所有其他对象
  • transform 已经是缓存字段,调用它不需要 GetComponent<>
  • Instantiate是一个非常难的操作,最好提前做好,甚至可以分解成每帧调用几次,比如每次调用50次,但绝对一帧不是 500,而是使用 Pooling (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");
        }
    }