protected override void OnUpdate() { Entities.ForEach((Entity e, SpawnRandomInSphere spawner, ref LocalToWorld localToWorld) => { int toSpawnCount = spawner.Count; var spawnPositions = new NativeArray <float3>(toSpawnCount, Allocator.TempJob); GeneratePoints.RandomPointsInUnitSphere(spawnPositions); // Calling Instantiate once per spawned Entity is rather slow, and not recommended // This code is placeholder until we add the ability to bulk-instantiate many entities from an ECB var entities = new NativeArray <Entity>(toSpawnCount, Allocator.Temp); for (int i = 0; i < toSpawnCount; ++i) { entities[i] = PostUpdateCommands.Instantiate(spawner.Prefab); } for (int i = 0; i < toSpawnCount; i++) { PostUpdateCommands.SetComponent(entities[i], new LocalToWorld { Value = float4x4.TRS( localToWorld.Position + (spawnPositions[i] * spawner.Radius), quaternion.LookRotationSafe(spawnPositions[i], math.up()), new float3(1.0f, 1.0f, 1.0f)) }); } PostUpdateCommands.RemoveComponent <SpawnRandomInSphere>(e); spawnPositions.Dispose(); entities.Dispose(); }); }
protected override void OnUpdate() { Entities.ForEach((Entity e, SpawnRandomInSphere spawner, ref LocalToWorld localToWorld) => { int toSpawnCount = spawner.Count; // Using a .TempJob instead of a .Temp for `spawnPositions`, because the method // `RandomPointsInUnitSphere` passes this NativeArray into a Job var spawnPositions = new NativeArray <float3>(toSpawnCount, Allocator.TempJob); GeneratePoints.RandomPointsInUnitSphere(spawnPositions); // Calling Instantiate once per spawned Entity is rather slow, and not recommended // This code is placeholder until we add the ability to bulk-instantiate many entities from an ECB var entities = new NativeArray <Entity>(toSpawnCount, Allocator.Temp); for (int i = 0; i < toSpawnCount; ++i) { entities[i] = PostUpdateCommands.Instantiate(spawner.Prefab); } for (int i = 0; i < toSpawnCount; i++) { PostUpdateCommands.SetComponent(entities[i], new LocalToWorld { Value = float4x4.TRS( localToWorld.Position + (spawnPositions[i] * spawner.Radius), quaternion.LookRotationSafe(spawnPositions[i], math.up()), new float3(1.0f, 1.0f, 1.0f)) }); } // Using 'RemoveComponent' instead of 'DestroyEntity' as a safety. // Removing the SpawnRandomInSphere component is sufficient to prevent the spawner // from executing its spawn logic more than once. The spawner may have other components // that are relevant to ongoing processing; this system doesn't know about them & shouldn't // assume the entity is safe to delete. PostUpdateCommands.RemoveComponent <SpawnRandomInSphere>(e); spawnPositions.Dispose(); entities.Dispose(); }); }
protected override void OnUpdate() { var uniqueTypes = new List <SpawnRandomInSphere>(10); EntityManager.GetAllUniqueSharedComponentData(uniqueTypes); int spawnInstanceCount = 0; for (int sharedIndex = 0; sharedIndex != uniqueTypes.Count; sharedIndex++) { var spawner = uniqueTypes[sharedIndex]; m_MainGroup.SetFilter(spawner); var entityCount = m_MainGroup.CalculateLength(); spawnInstanceCount += entityCount; } if (spawnInstanceCount == 0) { return; } var spawnInstances = new NativeArray <SpawnRandomInSphereInstance>(spawnInstanceCount, Allocator.Temp); { int spawnIndex = 0; for (int sharedIndex = 0; sharedIndex != uniqueTypes.Count; sharedIndex++) { var spawner = uniqueTypes[sharedIndex]; m_MainGroup.SetFilter(spawner); if (m_MainGroup.CalculateLength() == 0) { continue; } var entities = m_MainGroup.ToEntityArray(Allocator.TempJob); var localToWorld = m_MainGroup.ToComponentDataArray <LocalToWorld>(Allocator.TempJob); for (int entityIndex = 0; entityIndex < entities.Length; entityIndex++) { var spawnInstance = new SpawnRandomInSphereInstance(); spawnInstance.sourceEntity = entities[entityIndex]; spawnInstance.spawnerIndex = sharedIndex; spawnInstance.position = localToWorld[entityIndex].Position; spawnInstances[spawnIndex] = spawnInstance; spawnIndex++; } entities.Dispose(); localToWorld.Dispose(); } } for (int spawnIndex = 0; spawnIndex < spawnInstances.Length; spawnIndex++) { int spawnerIndex = spawnInstances[spawnIndex].spawnerIndex; var spawner = uniqueTypes[spawnerIndex]; int count = spawner.count; var entities = new NativeArray <Entity>(count, Allocator.Temp); var prefab = spawner.prefab; float radius = spawner.radius; var spawnPositions = new NativeArray <float3>(count, Allocator.TempJob); float3 center = spawnInstances[spawnIndex].position; var sourceEntity = spawnInstances[spawnIndex].sourceEntity; GeneratePoints.RandomPointsInUnitSphere(spawnPositions); EntityManager.Instantiate(prefab, entities); for (int i = 0; i < count; i++) { EntityManager.SetComponentData(entities[i], new LocalToWorld { Value = float4x4.TRS( center + (spawnPositions[i] * radius), quaternion.LookRotationSafe(spawnPositions[i], math.up()), new float3(1.0f, 1.0f, 1.0f)) }); } EntityManager.RemoveComponent <SpawnRandomInSphere>(sourceEntity); spawnPositions.Dispose(); entities.Dispose(); } spawnInstances.Dispose(); }
// This is (most times) a trigger: see https://forum.unity.com/threads/onupdate-method-in-componentsystems.541647/ for when it's called protected override void OnUpdate() { var uniqueTypes = new List <SpawnRandomInSphere>(10); // We have (by default) 2 BoidFishSpawners in the scene (if not modified). These have 3 attributes. If both spawners have EXACTLY the same values (whether its reference or value type) // they will be "fused" in uniqueTypes.Count, so uniqueTypes.Count will be 2, otherwise it'll be 3. The reason is that the first seems to be a default one (see link below) EntityManager.GetAllUniqueSharedComponentData(uniqueTypes); int spawnInstanceCount = 0; // https://forum.unity.com/threads/question-about-getalluniquesharedcomponentdata.545945/ // Since the 0 is the default, why not start at 1, does not make any difference since when filtering by the 0 uniqueType, it's being ignored for (int sharedIndex = 0 /* 1 */; sharedIndex != uniqueTypes.Count; sharedIndex++) { var spawner = uniqueTypes[sharedIndex]; // this is filtering the "groups of instances" that have the same values m_MainGroup.SetFilter(spawner); // we're counting them var entityCount = m_MainGroup.CalculateLength(); // so this is the overall number of instances wether or not they have the same values spawnInstanceCount += entityCount; } if (spawnInstanceCount == 0) { return; } var spawnInstances = new NativeArray <SpawnRandomInSphereInstance>(spawnInstanceCount, Allocator.Temp); { int spawnIndex = 0; for (int sharedIndex = 0; sharedIndex != uniqueTypes.Count; sharedIndex++) { var spawner = uniqueTypes[sharedIndex]; m_MainGroup.SetFilter(spawner); // this would never be 0 if the previous loop started at 1 I guess if (m_MainGroup.CalculateLength() == 0) { continue; } // 1+1 entities (if any value differs, and it is the default scene, 2 spawners overall) var entities = m_MainGroup.ToEntityArray(Allocator.TempJob); var localToWorld = m_MainGroup.ToComponentDataArray <LocalToWorld>(Allocator.TempJob); // convenient way of storing the 2 (if default) spawners info for (int entityIndex = 0; entityIndex < entities.Length; entityIndex++) { var spawnInstance = new SpawnRandomInSphereInstance(); spawnInstance.sourceEntity = entities[entityIndex]; spawnInstance.spawnerIndex = sharedIndex; spawnInstance.position = localToWorld[entityIndex].Position; spawnInstances[spawnIndex] = spawnInstance; spawnIndex++; } entities.Dispose(); localToWorld.Dispose(); } // for more info about ISharedComponentData see: https://docs.unity3d.com/Packages/[email protected]/manual/shared_component_data.html } // now for every spawner for (int spawnIndex = 0; spawnIndex < spawnInstances.Length; spawnIndex++) { int spawnerIndex = spawnInstances[spawnIndex].spawnerIndex; var spawner = uniqueTypes[spawnerIndex]; int count = spawner.count; var prefab = spawner.prefab; float radius = spawner.radius; float3 center = spawnInstances[spawnIndex].position; var sourceEntity = spawnInstances[spawnIndex].sourceEntity; var spawnPositions = new NativeArray <float3>(count, Allocator.TempJob); var entities = new NativeArray <Entity>(count, Allocator.Temp); // prepare the positions to spawn the fishes and instantiate them GeneratePoints.RandomPointsInUnitSphere(spawnPositions); EntityManager.Instantiate(prefab, entities); for (int i = 0; i < count; i++) { // set the fishes entities data EntityManager.SetComponentData(entities[i], new LocalToWorld { // the center is the spawner GameObject center // radius is the sphere radius Value = float4x4.TRS( center + (spawnPositions[i] * radius), quaternion.LookRotationSafe(spawnPositions[i], math.up()), new float3(1.0f, 1.0f, 1.0f)) }); } // the system does not need it anymore, get rid of it EntityManager.RemoveComponent <SpawnRandomInSphere>(sourceEntity); spawnPositions.Dispose(); entities.Dispose(); } spawnInstances.Dispose(); }