如何在不减慢到 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");
}
}
过去几周我一直在尝试使用 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"); } }