ichiyamanのブログ

基本Tech Logです

写経:WAYN Games (DOTS 基礎編)

はじめに

この記事は以下の動画を写経したものです。

WAYN Games - YouTube

DOTS101-DOTS111 シンプルなTowerDeffenceのモックをDOTSで構築する方法を学びます。

できたもの

  • 基本的な構造の理解
  • Object を いくつかPointに沿って移動させる
  • Object に モーション付き 3D モデルを使用する
  • Entity の InstantiateとDestroy
  • 基本的な Collision 判定

成果物

各動画

DOTS101

https://www.youtube.com/watch?v=N-xoBFi2YF0

この動画では、DOTSのInstallとWindowの説明です。ごくごく基本的な解説でCodeは作成しません。

※後に version up して、これらの手順や install するpackageは1部変更されます。

DOTS102

https://www.youtube.com/watch?v=FXgVuewJ_qU

この動画では SystemBase が解説されます。 既存のUnityでは、ScriptはなんらかのGameObjectにAttachしなければ動作しませんでしたが、これらのClassはただ書くだけで実行されます。 感の良い人はこの動画の時点でデータ指向はそういうことかとわかると思います。 BOX Objectを2つ表示してそれぞれ違うSpeedで移動させています。

DOTS103

https://www.youtube.com/watch?v=uXvuFMlBI3Y

この動画では、DynamicBuffer が解説されます。 複数のPointを配置されたGameObjetから取得し順番に移動させます。

DOTS104

https://www.youtube.com/watch?v=iDPfH0cCPuY

Version up された entities の install方法と ISystemが解説されます。 既存の code の修正方法などの説明があります。 この動画中のソースに TransformAspect が使用されている部分がありますが、 entities ver1.0.0 pre 63 で remove されます。最新版では代わりににLocalTransformを使用します。

  • TransfomrAspect -> LocalTransform

※TransformAspectのmethodを使用している場合は、それぞれの方法で実装が必要です。

※ここでめでたいことに entitiesが’1.0.0に大幅 Version up され、正式リリースとなります。

DOTS105

https://www.youtube.com/watch?v=nXcLOnRGG0w&t=203s

この動画では、Baker が解説されます

Authoring -> Baking - > Runtime の図はとてもわかりやすいので必見です 4:00 くらいから始まります。

DOTS106

https://www.youtube.com/watch?v=uIfdINDCstQ

この動画では ISystem が解説されます。

DOTS107

https://www.youtube.com/watch?v=_35CzCxPqTg

この動画では IAspect が解説されます。

DOTS108

https://www.youtube.com/watch?v=n2NvbNtzkCE

この動画では Entity を Instantiateする方法などが解説されます。 Fee Asset モーション付き 3D model を表示させる方法などが解説されます。 この動画からぐっと見栄えが派手になります。 メモ:URPじゃないアセットのMaterialをURPように変換するコマンド

Edit > Rendering > Materials > Convert Selected build-in Materials to URP

DOTS109

https://www.youtube.com/watch?v=vs6h4waQpPA

DOTS上でモーション付きモデルを表示させる方法について解説されます。 EntitiyのInstatiateとDestroyまでの流れも解説され、ようやくゲームっぽい感じになってきます。 以下のようなQueryを使うことによって、オブジェクトを横断して共通なComponentを取得することなどがコードから理解出来るようになります。

foreach (var entity in SystemAPI.Query<Speed>() {
  // do something
}

DOTS110

https://www.youtube.com/watch?v=YzezqDqr7RM

MouseでClickした箇所にTowerを配置する方法が解説されます。

DOTS111

https://www.youtube.com/watch?v=YzezqDqr7RM

Towerから弾を発射し、EnemyにHitしたらEnemyのHelthを減少させ、Healthが0以下になったら削除する。 といった一連の流れが解説されます。 この動画から動画中のソースと実行画面の不整合が発生しはじめ写経ポイントです!

  • PhysicsCategory Assetsが突然現れる

Create -> Unity Physics -> Physics category name で作成可能です。

  • 弾が配置されない!

以下のように修正する必要があります。 ProjectileSystem.cs

                       ecbBOS.SetComponent(e, new Translation() { Value = towerPosition });

vvv

                        ecbBOS.SetComponent(e, new LocalTransform
                        {
                            Position = towerPosition,
                            Rotation = quaternion.identity,
                            Scale = 1
                        });

こちらも先述したTransfomrAspect の removeの影響です

  • 敵にあたらない弾が消えない 動画中だと消えているように見えるのですが、おそらく次の動画で説明するソースにCodeが記述されているようです。 この動画までの記事にしたいので自前で実装します。

Target.cs

public struct Target : IComponentData
{
    public Entity Value;
    public float timeLife;  // << 追加
}

ProjectileSystem.cs

                 ....

                    ecbBOS.AddComponent(e,
                        new Target()
                            { Value = closestHitCollector.ClosestHit.Entity});

                 ....

        foreach(var (speed,target,transform,entity ) in SystemAPI.Query<RefRO<Speed>, RefRO<Target>, RefRW<LocalTransform>>().WithEntityAccess())
        {
            //Debug.Log($"HasComponent:{positionLookup.HasComponent(target.ValueRO.Value)},{target.ValueRO.timeLife},{Time.time}"); 
            if(positionLookup.HasComponent(target.ValueRO.Value) )
            {
                 ....

vvv

                 ....

                    ecbBOS.AddComponent(e,
                        new Target()
                            { Value = closestHitCollector.ClosestHit.Entity, timeLife = Time.time+ 3.0f });

                 ....

        foreach(var (speed,target,transform,entity ) in SystemAPI.Query<RefRO<Speed>, RefRO<Target>, RefRW<LocalTransform>>
().WithEntityAccess())
        {
            //Debug.Log($"HasComponent:{positionLookup.HasComponent(target.ValueRO.Value)},{target.ValueRO.timeLife},{Time.time}"); 
            if(positionLookup.HasComponent(target.ValueRO.Value) && target.ValueRO.timeLife > Time.time)
            {
                 ....

最後に

各動画のソースは branch に分かれて公開されているので、どうしても動かないという方は各 package の version を揃えてそちらも参考にしてみると良いと思います。素晴らしいですね。

https://github.com/WAYN-Games/DOTS-Training/tree/main

これはもう別Engineなんじゃない?というくらい書き方変わりますが、プログラマ的にはごりごりに最適化出来そうなので ボクハエガカケナイ という方は全力でいくのもアリなんじゃないでしょうか。 STGを書くのが楽しそうです。Collider周りも大きく変更されているので、それはまた別の記事で。

Thanks ! WAYN Games