【Unity】ECSでエンティティを動的生成して物理演算や移動させる方法

どうも、だらはです。
今回は、ECSでエンティティを動的生成して物理演算や移動させる方法についてまとめます。
ECSについて知りたいという方は以下の記事をご確認ください。

スポンサーリンク

手順

早速ですが、スクリプトを記載します。
処理内容は、SpawnerからCubeを生成して移動させるというものです。
Hierarchyは図1を参考にしてください。

◆Spawner.cs

using Unity.Entities;
using Unity.Mathematics;

public struct Spawner : IComponentData
{
    public Entity prefab;
    public float3 spawnPos;
    public float timeMax;
}

◆SpawnerAuthoring.cs

using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;

class SpawnerAuthoring : MonoBehaviour
{
    [SerializeField] public GameObject prefab;
    [SerializeField] public float3 spawnPos = new float3(0, 0.5f, 0);
    [SerializeField] public float timeMax = 1.0f;
}

class SpawnerAuthoringBaker : Baker<SpawnerAuthoring>
{
    public override void Bake(SpawnerAuthoring authoring)
    {
        Entity entity = GetEntity(TransformUsageFlags.None);

        AddComponent(entity, new Spawner
        {
            prefab = GetEntity(authoring.prefab, TransformUsageFlags.Dynamic),
            spawnPos = authoring.spawnPos,
            timeMax = authoring.timeMax,
        });
    }
}

◆SpawnerSystem.cs

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;

partial struct SpawnerSystem : ISystem
{
    float timeCnt;

    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
        
    }

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        float deltaTime = SystemAPI.Time.DeltaTime;
        timeCnt += deltaTime;

        //Entityを直接生成せず、Bafferを使用して生成する。
        EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.Temp);

        //Entityの位置を更新
        foreach (var spawner in SystemAPI.Query<Spawner>())
        {
            //時間経過で敵を生成
            if (timeCnt > spawner.timeMax)
            {
                timeCnt = 0;
                Entity newEntity = ecb.Instantiate(spawner.prefab);
                ecb.SetComponent(newEntity, LocalTransform.FromPosition(spawner.spawnPos));

                //ランダム値を速度ゲインに指定
                float randomSpeedGain = UnityEngine.Random.Range(0, 3f);
                ecb.SetComponent(newEntity, new Enemy
                {
                    speed = 1f,
                    speedGain = randomSpeedGain,
                });
            }
        }

        // EntityCommandBufferの命令を実行
        ecb.Playback(state.EntityManager);
        ecb.Dispose();
    }

    [BurstCompile]
    public void OnDestroy(ref SystemState state)
    {
        
    }
}

◆Enemy.cs

using Unity.Entities;
using Unity.Mathematics;

public struct Enemy : IComponentData
{
    public float speed;
    public float speedGain;
}

◆EnemyAuthoring.cs

using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Tilemaps;

class EnemyAuthoring : MonoBehaviour
{

}

class EnemyAuthoringBaker : Baker<EnemyAuthoring>
{
    public override void Bake(EnemyAuthoring authoring)
    {
        Entity entity = GetEntity(TransformUsageFlags.Dynamic);

        AddComponent(entity, new Enemy
        {
            speed = 0f,
            speedGain = 0f,
        });
    }
}

◆EnemySystem.cs

using Unity.Burst;
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
using Unity.Collections;
using System.Diagnostics;
using static UnityEngine.EventSystems.EventTrigger;

partial struct EnemySystem : ISystem
{
    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
        
    }

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        float deltaTime = SystemAPI.Time.DeltaTime;

        //Entityの位置を更新
        foreach (var (enemy, localTransform) in SystemAPI.Query<Enemy, RefRW<LocalTransform>>())
        {
            float3 move = new float3(1f, 0, 0) * enemy.speed *enemy.speedGain * deltaTime;
            localTransform.ValueRW.Position += move;
        }
    }

    [BurstCompile]
    public void OnDestroy(ref SystemState state)
    {
        
    }
}

以上です。
スクリプトは前回のものと殆ど変わりないです。
エンティティをSpawnerとEnemyで分けたというところと、エンティティごとに速度が変わるような処理を加えています。

◆図1

図1の通り、物理処理にはPhysicsBodyやPhysicsShapeを使います。
PhysicsBodyやPhysicsShapeが見当たらない!という方はパッケージのインストールが必要になりますので以下の記事を参考にしてください。

最後に

今回は物理処理について書きました。
次は、NavMeshAgentあたりへの対応を書こうかな?調べるのはこれからですけど頑張ります!

以上、だらはでした。

スポンサーリンク

基礎

Posted by daraha_gm