見出し画像

Unity DOTS 入門 (10) - 他のエンティティのコンポーネントデータへのアクセス

これまで、エンティティ自身のコンポーネントデータにアクセスしてきました。今回は、他のエンティティのコンポーネントデータへのアクセスする方法を説明します。

・Unity 2019.3.14.f1
・Entities 0.11.1

1. 他のエンティティのコンポーネントデータへのアクセス

Unity DOTS 入門 (9)」のサンプルを改良して、キー操作で動く立方体「Cube」の後ろを、立方体「Chaser」が追いかけるようにします。

(1) 「Unity DOTS 入門 (9)」のサンプルの「PlayerTag」のないCubeを1つだけ残し、名前を「Chaser」とし、Transformを以下のように設定。

Translate = (-2, 0, 0)
Rotation = (0, 0, 0)
Scale = (0.8, 0.8, 0.8)

画像1

(2) 「Chaser」にタグ「ChaserTag」を追加。

using Unity.Entities;

[GenerateAuthoringComponent]
public struct ChaserTag : IComponentData
{
}

画像2

(3) 「Chaser」にスクリプト「ChaserData」を追加。
以下の2つのフィールドを保持します。

・アクセス対象となるエンティティの参照(正確にはID)。
・アクセス対象となるエンティティ取得する位置。
using Unity.Entities;
using Unity.Mathematics;

[GenerateAuthoringComponent]
public struct ChaserData : IComponentData
{
    public Entity targetEntity; // アクセス対象となるエンティティの参照(正確にはID)
    public float3 targetTranslation; // アクセス対象となるエンティティ取得する位置
}

(4) コンポーネント「ChaserData」の「Target Entity」に「Cube」(ConvertToEntityを持つGameObject)をドラッグ&ドロップ。

画像3

(5) Projectウィンドウにスクリプト「ChaserSystem」を追加。

using UnityEngine;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
using System;

public class ChaserSystem : SystemBase
{
    protected override void OnUpdate()
    {
        float deltaTime = Time.DeltaTime;
        float speed = 3f;

        // ターゲット位置の取得
        Entities.
            WithAll<ChaserTag>().
            ForEach((ref ChaserData chaserData) =>
        {
            // Translationコンポーネント群の取得
            ComponentDataFromEntity<Translation> allTranslations =
                GetComponentDataFromEntity<Translation>(true);
            if (!allTranslations.Exists(chaserData.targetEntity))
            {
                return;
            }
            Translation targetPos = allTranslations[chaserData.targetEntity];

            // ターゲット位置の保持
            chaserData.targetTranslation = targetPos.Value;
        }).Schedule();

        // チェイサーの移動
        Entities.
            WithAll<ChaserTag>().
            ForEach((ref Translation translation, in ChaserData chaserData) =>
        {
            float dx = (chaserData.targetTranslation.x - translation.Value.x);
            float dz = (chaserData.targetTranslation.z - translation.Value.z);
            translation.Value.x += dx * deltaTime * speed;
            translation.Value.z += dz * deltaTime * speed;
        }).Schedule();
    }
}

◎ GetComponentDataFromEntity<T>()
GetComponentDataFromEntity<T>()
でTranslationコンポーネント群を取得します。引数のtrue/falseは「読み込み専用」かどうかで、未設定時はfalseになります。

◎ ターゲット位置の取得とチェイサーの移動を分ける
「ターゲット位置の取得」で同時にチェイサーの移動を行うため、ForEachに「ref Translation translation」を付加すると、次のようなエラーがでまします。

Entities.ForEachは、GetComponentDataFromEntity()読み書き可なラムダ関数のパラメータで同じコンポーネント種別を使うことはできません。

そこで分けましたが、もっとスマートな方法あるかも。

(6) 実行。
「Cube」を「Chaser」が追いかけることを確認できます。

画像4


この記事が気に入ったらサポートをしてみませんか?