【Unity】ついにECSがリリースされたので触ってみた
はじめに
こんにちは。ホンジョウです。今回はUnity 2022 LTSがリリースされてから初めてのUnityの記事ということで、Unity 2022 LTSの目玉機能のひとつであるUnity ECSについて書いていこうと思います。
思えば、Unity 2018.2あたりからベータ版として提供され、いつ正式リリースするのかしばらく静観する状態が続いていましたが、
いよいよリリースしたということで個人的に盛り上がっています。
動作環境
- MacBook Pro macOS Ventura 13.4
- Unity 2022.2.21
- (Unity Packuage) Burst 1.8.4
- (Unity Packuage) Entities 1.0.10
- (Unity Packuage) Entities Graphics 1.0.10
- (Unity Packuage) Universal RP 14.0.7
作るもの
今回はUnity ECSの公式ドキュメントの例にあるSpawner Exampleを元に、動くところまで進めていこうと思います。Spawner Example
プロジェクトの準備
まずは新しいプロジェクトを作成します。Unity Hubで「新しいプロジェクト」からテンプレート「3D(URP)」を選択します。デフォルトのプロジェクトをURP対応にすることもできますが、マテリアルの置き換えなどが少々面倒なので、テンプレートから選択する方が楽でした。
サブシーンの作成
ECSはSceneの代わりとしてSub Sceneを利用してオブジェクトを管理していくようです。Hierarchy上で右クリックして「New Sub Scene」→「Empty Scene」を選択します。
作成したサブシーンには「Spawner」という空オブジェクトを作成しておきます。
Spawnerコンポーネントの作成
Entityを生成するSpawnerのためのコンポーネントを作成します。従来のUnityプロジェクトと同じように、C#ファイルを追加して以下のように書きます。
using Unity.Entities;
using Unity.Mathematics;
public struct Spawner : IComponentData
{
public Entity Prefab;
public float3 SpawnPosition;
public float NextSpawnTime;
public float SpawnRate;
}
Spawner Entityの作成
SpawnerAuthoringコンポーネントを作成します。作成したコンポーネントはサブシーンに配置する空オブジェクトにアタッチします。
using UnityEngine;
using Unity.Entities;
class SpawnerAuthoring : MonoBehaviour
{
public GameObject Prefab;
public float SpawnRate;
}
class SpawnerBaker : Baker<SpawnerAuthoring>
{
public override void Bake(SpawnerAuthoring authoring)
{
var entity = GetEntity(TransformUsageFlags.None);
AddComponent(entity, new Spawner
{
Prefab = GetEntity(authoring.Prefab, TransformUsageFlags.Dynamic),
SpawnPosition = authoring.transform.position,
NextSpawnTime = 0.0f,
SpawnRate = authoring.SpawnRate
});
}
}
Prefabには適当なオブジェクトを登録しておきましょう。私の場合はSphereオブジェクトをPrefabにして登録しました。
Spawnerシステムの作成
Spawnerシステムを作成します。今回は先ほどのSpawnerAuthoringで設定した、SpawnRateごとにPrefabを生成するシステムを作ります。新しいC#ファイル SpawnerSystemを作成します。
using Unity.Entities;
using Unity.Transforms;
using Unity.Burst;
[BurstCompile]
public partial struct SpawnerSystem : ISystem
{
public void OnCreate(ref SystemState state) { }
public void OnDestroy(ref SystemState state) { }
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
foreach (RefRW<Spawner> spawner in SystemAPI.Query<RefRW<Spawner>>())
{
ProcessSpawner(ref state, spawner);
}
}
private void ProcessSpawner(ref SystemState state, RefRW<Spawner> spawner)
{
if (spawner.ValueRO.NextSpawnTime < SystemAPI.Time.ElapsedTime)
{
Entity newEntity = state.EntityManager.Instantiate(spawner.ValueRO.Prefab);
state.EntityManager.SetComponentData(newEntity, LocalTransform.FromPosition(spawner.ValueRO.SpawnPosition));
spawner.ValueRW.NextSpawnTime = (float)SystemAPI.Time.ElapsedTime + spawner.ValueRO.SpawnRate;
}
}
}
このコードは特にどこかにアタッチしなくても勝手に動作します。
実行してEntities Hierarchyを確認してみると、確かにSphereが生成されていることがわかります。
シーン上でもわかりやすいように、SphereにRigidBodyをアタッチして、生成されてから落ちていくようにしてみます。
Entityとして生成されたオブジェクトでも従来の物理挙動が使えるというのは不思議な感じがしますね。
最後に
はじめてECSに触れてみましたが、確かにこれまでとは全体的な概念が大きく異なるようで少々戸惑いました。しかし、これでアプリケーションの高速化が図れるならば十分に学習の価値はありそうです。引き続き調査を進めてみます。
参考資料