ECS(Entity Component System) 基礎中の基礎
原点回りにCubeが回転するだけの単純なサンプルです。
Script
CubeDataで使用するデータを定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
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 }; } } } |
CubeAuthoringではEntityを取得し、そのEntityにCubeData Componentを追加しています。よって、CubeAuthoringにはCubeを動かすための処理はありません。また、GetEntityでTransformUsageFlags.Dynamicを指定した場合、LocalToWorldとLocalTransform Componentが追加されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
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); //Entityを取得 AddComponent(entity, data); } } } } |
Cubeを動かすための処理は以下のScriptで行います。このように、ECSではデータと処理を分けて記述する必要があります。また、このSystemは動かすために何かする必要はなく、自動的に実行されます。Cubeを動かすためにはCubeDataとLocalTransformの取得を行い、CubeDataをもとに計算を行いLocalTransformを変更する必要があります。よって、SystemAPI.QueryでこれらのComponentを取得します。SystemAPI.Query内のRefROは読み取り専用、RefRWは読み込みだけではなく書き込みができることを示します。そして、Componentから値を取得する場合はValueRO、書き込みを行う場合はValueRWを使用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
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) { //CubeDataとLocalTransformをもつ場合にComponentを取得 foreach(var (cube, xform) in SystemAPI.Query<RefRO<CubeData>, RefRW<LocalTransform>>()) { float radius = cube.ValueRO.MaxRadius; float angle = cube.ValueRO.Speed / radius * (float)SystemAPI.Time.ElapsedTime; Vector3 direction = cube.ValueRO.Direction; Vector3 axis = cube.ValueRO.Axis; Quaternion init_rotation = cube.ValueRO.InitRotation; Vector3 position = Quaternion.AngleAxis(angle, axis) * direction; xform.ValueRW.Position = position; Quaternion quaternion = init_rotation * Quaternion.FromToRotation(Vector3.forward, axis); quaternion = Quaternion.AngleAxis(angle, axis) * quaternion; xform.ValueRW.Rotation = quaternion; } } } } |
SystemAPI.Queryについて
SystemAPI.Queryでは指定したComponentを有するEntityのComponentを取得できます。複数のComponentを指定した場合、それらを有するEntityのComponentのみを取得します。
例としてEntityを作成する際にTransformUsageFlags.Dynamicを指定したCubeAとTransformUsageFlags.Noneを指定したCubeBを使用します。(Burstを利用する場合はstringが使用できないのでFixedStringを使っています。)
1 2 3 4 5 6 |
//CubeA CubeData data = CubeData.Set( math.max(1, authoring.Seed), math.max(1f, authoring.MaxRadius), new FixedString32Bytes(authoring.name)); Entity entity = GetEntity(TransformUsageFlags.Dynamic); |
1 2 3 4 5 6 |
//CubeB CubeData data = CubeData.Set( math.max(1, authoring.Seed), math.max(1f, authoring.MaxRadius), new FixedString32Bytes(authoring.name)); Entity entity = GetEntity(TransformUsageFlags.None); |
TransformUsageFlags.DynamicはLocalTransformが追加されますが、TransformUsageFlags.Noneは追加されません(Colliderがある場合は自動的にLocalTransformが追加されます)。この条件でSystemAPI.QueryへCubeDataのみ指定するとConsoleにはCubeAとCubeBが表示されます。
1 2 3 4 |
foreach (var cube in SystemAPI.Query<RefRO<CubeData>>()) { Debug.Log(cube.ValueRO.Name); } |
次に、SystemAPI.QueryにLocalTransformを追加します。
1 2 3 4 |
foreach (var (cube, xform) in SystemAPI.Query<RefRO<CubeData>, RefRW<LocalTransform>>()) { Debug.Log(cube.ValueRO.Name); } |
これを実行すると、LocalTransformを持たないCubeBは除外されるため、ConsoleにはCubeAのみ表示されます。
設定と実行結果
以上のScriptを利用してCubeを回転させます。始めに、SubSceneを作成します。作成したSubSceneの横に表示されているチェックボックスにチェックを入れます。
次に、Cubeを作成し、SubSceneへ移動させます。
最後に、作成したCubeへCubeAuthoringを追加します。
実行すると以下のように、原点回りにCubeが回転します。
参考ページ
-
前の記事
三次ベジェ曲線の最接近点(近似二次ベジェ曲線を利用) 2023.12.10
-
次の記事
PrefabからEntityを生成(Entity Component System) 2025.01.13
コメントを書く