Hi, I’m still learning a lot about ECS. I am trying to spawn a whole lot of entities to see how well it performs, they are essentially just cubes with physics bodies.
This is what I’m using to spawn them:
public class EnemySpawner : MonoBehaviour
{
public int sizeX;
public int sizeY;
[SerializeField]
private GameObject _enemyPrefab;
[SerializeField]
private Vector3 _spawnPosition;
[SerializeField]
private float _spawnTime;
[SerializeField]
private bool _enabled;
EntityManager entityManager;
BlobAssetStore blob;
Entity prefab;
// Start is called before the first frame update
void Start()
{
blob = new BlobAssetStore();
var settings = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, blob);
prefab = GameObjectConversionUtility.ConvertGameObjectHierarchy(_enemyPrefab, settings);
entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
StartCoroutine(SpawnEnemiesCR());
}
private void OnDestroy()
{
blob.Dispose();
}
private IEnumerator SpawnEnemiesCR()
{
while (_enabled)
{
SpawnEnemy(sizeX, sizeY, prefab);
yield return new WaitForSeconds(_spawnTime);
}
}
private void SpawnEnemy(int chunkX, int chunkY, Entity prefab)
{
for (int x = 0; x < chunkX; x++)
{
for (int y = 0; y < chunkY; y++)
{
var instance = entityManager.Instantiate(prefab);
Vector3 position = new Vector3(_spawnPosition.x + x, _spawnPosition.y, _spawnPosition.z + y);
entityManager.SetComponentData(instance, new Translation { Value = position });
}
}
}
}
And this is what’s happening:
5ab7at
As you can see my framerate is dropping significantly.
In the entity debugger I am noticing that there is one chunk that has one of these cubes, and another chunk that has all the rest of them. I’m not sure what I’m doing wrong, I think I would need to have multiple chunks with a limited number of cubes in each, but I’m not sure how to achieve this. Any help would be greatly appreciated.
So the lone entity in it’s chunk probably is your prefab. That is normal.
The chunks count will increase as they get full.
For the frame drop it seems to be related to 2 things.
1 your instantiate your prefab one by one. You could look at the other methods that allows you to spawn several entities at a time and return a native array of entities. Then you can use a job to set the position of each entities.
2 you spawn your prefab in waves in the same location. This,I think, gives a hard time to the physics system which as to solve overlapping bodies. You could try spawning your entities at some height so that they don’t overlap when spawning.
Thanks for the suggestion.
I looked around and found a more optimal way of spawning these cubes within a system using the EntityCommandBuffer. It is looking much better! It can easily handle about 10k cubes, however really struggles starting at 50-60k cubes, I guess it has to have a limit and for my PC this was it.
As for spawning them in the same location and that giving the physics system a hard time, I’ve been playing around with this, it does seem to struggle to handle that many collisions at once so I’ve tried spawning one cube at a time in the same location instead of multiple at once and it seems to be handling it much better.
fxj27s
One important thing to note, which really helped me out, is that I didn’t have a Physics Step component in the scene. Once I added that and switched to Havok Physics and checked the multi-threaded box it was running much more smoothly. Hope this can help anyone else who was having the same struggle. This is my spawner system
using Unity.Burst;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
[UpdateInGroup(typeof(SimulationSystemGroup))]
public partial class EnemySpawnerSystem : SystemBase
{
BeginSimulationEntityCommandBufferSystem m_EntityCommandBufferSystem;
protected override void OnCreate()
{
m_EntityCommandBufferSystem = World.GetOrCreateSystem<BeginSimulationEntityCommandBufferSystem>();
}
protected override void OnUpdate()
{
var cmdBuffer = m_EntityCommandBufferSystem.CreateCommandBuffer().AsParallelWriter();
Entities
.WithName("Spawner")
.WithAll<SpawnerData>()
.WithBurst(FloatMode.Default, FloatPrecision.Standard, true)
.ForEach((Entity e, int entityInQueryIndex, in SpawnerData spawnerData, in LocalToWorld location) =>
{
for (int x = 0; x < spawnerData.x; x++) {
for(int y = 0; y < spawnerData.y; y++)
{
Entity instance = cmdBuffer.Instantiate(entityInQueryIndex, spawnerData.prefab);
float3 pos = math.transform(location.Value,
new float3(x * 2f, 0.5f, y * 2f));
cmdBuffer.SetComponent(entityInQueryIndex, instance, new Translation { Value = pos });
}
}
}).ScheduleParallel();
m_EntityCommandBufferSystem.AddJobHandleForProducer(this.Dependency);
}
}