[Unity]Unity ECS v1.3.2を使ってゲームを作ってみました (2)―Component編

[Unity]Unity ECS v1.3.2を使ってゲームを作ってみました (2)―Component編

第二事業部 エンジニアの孫(ソン)と申します。
Unity ECSで実戦的にゲームを組み立てた資料が少ないと感じたので、実際にゲームを作ってみた経験から共有させていただきます。
今回はEntityの生成方法とデータ周りの書き方をご紹介させていただきます。
[Unity]Unity ECS v1.3.2を使ってゲームを作ってみました (1)―紹介編の続きです。

対象読者

・ECSを用いたゲーム開発に興味を持っている方
・インゲームのアーキテクチャ設計が得意な方
・基本的なUnity ECSの概念を理解されている方

この記事を読むことで得られる知見

・ECSを用いて構築したゲームの一部を垣間見ることができる
・最新のUnity ECSの書き方
・ユニットを大量に出す方法

ECSの良さ

ECSは以前から存在する設計パターンですが、GDCでの「オーバーウォッチ」の発表によって注目を集めるようになりました。
ECSは完全にデータとロジックを完全に分離させるアーキテクチャです。
複雑なキャラクターロジックをデカップリング(分離)し、フレーム同期にも適した構造であることがそのメリットです。
Unity ECSで得られるメリットがこちらで確認できます。

ECSの基本構成

ECSは名前の通り、以下の3つを基本構成として持ちます。
Entity: IDを保持する構造体
Component: データを定義する型
System: 計算ロジックを実装する型
Unityは用途に応じて、より複雑なComponentやSystemのさまざまな派生型を用意しています。
自分がよく使う派生型をいくつかピックアップして紹介します。

Component系

IComponentData: structまたはclassでComponentを作成するためのインターフェース
IEnableableComponent: Component有効性を設定出来るようにするインターフェース
BlobArray: 大容量データを参照するための構造体で、データは動的に変更できない
DynamicBuffer: 可変サイズのリストにデータを格納するためのComponent
UnityObjectRef: structからMonoBehaviourやオブジェクトを参照するための構造体

System系

ISystem: structでインターフェースを実装し、アンマネージド型のデータを処理するために使われることが多い
SystemBase: class型SystemのUnityのAPIやクラスと連携する場合に使われる
IJobEntity: 一番簡潔なECS用JobSystemで、System系で並列にデータを処理するための型

実戦での書き方

Componentの構成

DOTSを効果的に活用するために、structを使用してComponentを作成する場合、classのようにvirtualやoverrideといった継承用の修飾子は使用できません。そのため、各機能を細かく分割してコンポーネントを作成し、ポリモーフィズム(多態性)を実現しています。
サンプルのEntityの構成では、プレイヤーと敵の共通仕様であるHPを抽出し、HPComponentとしてそれぞれのEntityに追加しました。



Entityの生成

Bakerを使用してSubsceneに集めたGameObjectから生成する方法がよく見られますが、使用するアセットをSubsceneに集約する必要があるというデメリットがあります。また、一般的に利用されるAddressablesの動的読み込みにも適していないと思います。
今回は、直接メッシュとマテリアルを使用してカスタマイズしたEntityプロトタイプから生成する方法を紹介します。この方法は、プレハブを作成してインスタンス化し、複数のコピーを生成するイメージです。
メリットは、同じシーンにAddressablesを使って動的にアセットを追加できる点です。
マスターデータに定義されたAddressablesアドレスや[SerializableField]など、馴染みのある読み込み方法を使用できます。読み込んだメッシュとマテリアルからRenderMeshArrayを作成し、RenderMeshUtilityに渡します。これによりEntities Graphicsが描画してくれます。
以下のコードでは動的に読み込んだメッシュなどからEntityを生成する例です。
1.新しいEntityを作成する
2.Renderer設定(Entities Graphicsパッケージを使用しない場合はスキップ可)
3.コンポーネントを追加する
4.Prefabタグを付与する

5.インスタンシエート
敵Entityの大量生成をインスタンシエートする例として、下図に示します。
EntityManager.Instantiate(Entity, NativeArray)を使用して、配列に格納する形でEntityを一気に生成します。

次回へ

今回の記事はここまでとなります。
次回の投稿[Unity]Unity ECS v1.3.2を使ってゲームを作ってみました (3)―System編ではSystemの書き方に移ります。
ソースコードが長いですが、興味を持った方は、ぜひお楽しみください。

参考資料

‘Overwatch’ Gameplay Architecture and Netcode
ECSの仕組みを理解し、使いどころを把握する
【Unity ECS 2023 のお勉強】サンプルソースを読む (EntitiesSamples)
Entities[1.3.2]Changelog
© Unity Technologies Japan/UCL