PrefabからEntityを生成(Entity Component System)
ECS(Entity Component System) 基礎中の基礎で作成したCubeを大量に生成します。
Script
Cube
CubeDataで使用するデータを定義しています。
using UnityEngine;
using Unity.Entities;
using Random = Unity.Mathematics.Random;
namespace EmptyCan
{
public struct CubeData : IComponentData
{
public float Speed;
public Vector3 Direction;
public Vector3 Axis;
public Quaternion Rotaiton;
public Quaternion InitRotation;
public float MaxRadius;
public static CubeData Set(uint seed, float max_radius)
{
float min_speed = 100f;
float max_speed = 10000f;
Random random = new Random(seed);
Quaternion rotation = Quaternion.Euler(random.NextFloat(0f, 360f), random.NextFloat(0f, 360f), random.NextFloat(0f, 360f));
float min_value = 1f / max_radius;
float t = random.NextFloat(min_value, 1f);
t = random.NextFloat(t, 1f); //原点付近で生成される数を減らすため
float radius = t * max_radius;
Vector3 direction = rotation * Vector3.up * radius;
Vector3 axis = rotation * Vector3.forward;
Quaternion init_rotation = Quaternion.FromToRotation(Quaternion.FromToRotation(Vector3.forward, axis) * Vector3.up, -direction);
return new CubeData()
{
Speed = random.NextFloat(min_speed, max_speed),
Direction = direction,
Axis = axis,
Rotaiton = rotation,
InitRotation = init_rotation,
MaxRadius = max_radius
};
}
}
}
Entityの取得及びComponentの追加を行っています。
using Unity.Entities;
using UnityEngine;
using Unity.Mathematics;
namespace EmptyCan
{
public class CubeAuthoring : MonoBehaviour
{
public uint Seed;
public float MaxRadius;
class Baker : Baker<CubeAuthoring>
{
public override void Bake(CubeAuthoring authoring)
{
CubeData data = CubeData.Set(math.max(1, authoring.Seed), math.max(1f, authoring.MaxRadius));
Entity entity = GetEntity(TransformUsageFlags.Dynamic);
AddComponent(entity, data);
}
}
}
}
Cubeを動かすための処理です。今回は大量にCubeを動かすのでJobSytemを使用して並列に実行しています。
using Unity.Burst;
using Unity.Entities;
using Unity.Transforms;
using UnityEngine;
namespace EmptyCan
{
public partial struct CubeSystem : ISystem
{
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
CubeUpdateJob job = new CubeUpdateJob() { Elapsed = (float)SystemAPI.Time.ElapsedTime };
job.ScheduleParallel();
}
}
[BurstCompile]
partial struct CubeUpdateJob : IJobEntity
{
public float Elapsed;
void Execute(in CubeData cube, ref LocalTransform xform)
{
float radius = cube.MaxRadius;
float angle = cube.Speed / radius * Elapsed;
Vector3 direction = cube.Direction;
Vector3 axis = cube.Axis;
Quaternion init_rotation = cube.InitRotation;
Vector3 position = Quaternion.AngleAxis(angle, axis) * direction;
xform.Position = position;
Quaternion quaternion = init_rotation * Quaternion.FromToRotation(Vector3.forward, axis);
quaternion = Quaternion.AngleAxis(angle, axis) * quaternion;
xform.Rotation = quaternion;
}
}
}
Cubeの生成
Prefabを使用してCubeを生成します。以下のScriptはCubeを生成する際に使用するデータを定義しています。
using Unity.Entities;
namespace EmptyCan
{
public struct Config : IComponentData
{
public Entity Prefab;
public int SpawnCount;
public uint RandomSeed;
}
}
Cubeを生成するためのEntityの取得とComponentの追加を行っています。
using Unity.Entities;
using UnityEngine;
using Unity.Mathematics;
namespace EmptyCan
{
public class ConfigAuthoring : MonoBehaviour
{
public GameObject Prefab;
public int SpawnCount;
public uint RandomSeed;
class Baker : Baker<ConfigAuthoring>
{
public override void Bake(ConfigAuthoring authoring)
{
Config data = new Config()
{
Prefab = GetEntity(authoring.Prefab, TransformUsageFlags.Dynamic),
SpawnCount = authoring.SpawnCount,
RandomSeed = math.max(1, authoring.RandomSeed)
};
AddComponent(GetEntity(TransformUsageFlags.None), data);
}
}
}
}
Cubeを生成するためのSystemです。
- RequireForUpdate
SubScene内に指定したComponentがないとSystemが起動しないようにできます。よって、このSystemはConfigが存在しない場合は実行されません。 - SystemAPI.GetSingleton
Componentを一つだけ取得できます。これを利用してConfigを取得します。 - state.EntityManager.Instantiate
指定した数だけPrefabからEntityを生成します。 - state.Enabled = false
Systemを無効にします。これにより、Systemが一度だけ実行されるようにしています。
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Random = Unity.Mathematics.Random;
namespace EmptyCan
{
[UpdateInGroup(typeof(InitializationSystemGroup))]
public partial struct SpawnSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<Config>(); //Configが存在しない場合、Systemは実行されない
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
Config config = SystemAPI.GetSingleton<Config>();
//SpawnCountだけEntityを取得
NativeArray<Entity> entities = state.EntityManager.Instantiate(config.Prefab, config.SpawnCount, Allocator.Temp);
//取得したEntityのデータを設定
Random random = new Random(config.RandomSeed);
foreach (Entity entity in entities)
{
RefRW<CubeData> cube = SystemAPI.GetComponentRW<CubeData>(entity);
cube.ValueRW = CubeData.Set(random.NextUInt(), cube.ValueRO.MaxRadius);
}
state.Enabled = false; //Systemを止める
}
}
}
設定と実行結果
CubeAuthoringを追加したPrefabを作成します。

空のGameObjectを作成し、ConfigAuthoringを追加します。これをSubScene内へ移動します。今回はSpawnCount=5000、RandomSeed=10としました。

これを実行すると以下のように、回転するCubeが大量に生成されます。

参考ページ
-
前の記事
ECS(Entity Component System) 基礎中の基礎 2025.01.09
-
次の記事
InputSystemで入力を取得(Entity Component System) 2025.01.18
コメントを書く