其他分享
首页 > 其他分享> > Unity ECS+Jobs System笔记 案例解析3(十二)

Unity ECS+Jobs System笔记 案例解析3(十二)

作者:互联网

本章节为大家解析ECS案例,资源来自,大家自行获取:
https://github.com/Unity-Technologies/EntityComponentSystemSamples

5、SubScene——新的场景工作流

在这里插入图片描述
这个案例演示了SubScene的工作流,SubScene提供了一个更加有效的在Unity内编辑和加载场景的方式
这个案例使用了HelloCube中IJobForEach的Components和Systems,这个场景包括了一对正在旋转的Cube,而它们是在开始之后自动从一个SubScene中加载的

创建方式

在Unity的Hierarchy面板创建一个GameObject,添加SubScene组件,在SceneAsset中选择需要加载的场景,然后点击Rebuild Entity Cache(如果有警告就点击Clear),通过Edit按钮可以进入便编辑模式,按Close退出,使用Save保存场景,使用Load和Unload选择是否加载资源

6、SpawnFromMonoBehaviour

 	public GameObject Prefab;
    public int CountX = 100;
    public int CountY = 100;

    void Start()
    {
        Entity prefab = GameObjectConversionUtility.ConvertGameObjectHierarchy(Prefab, World.Active);
        EntityManager entityManager = World.Active.EntityManager;

        for (var x = 0; x < CountX; x++)
        {
            for (var y = 0; y < CountY; y++)
            {
                var instance = entityManager.Instantiate(prefab);

                float3 position = transform.TransformPoint(new float3(x * 1.3F, noise.cnoise(new float2(x, y) * 0.21F) * 2, y * 1.3F));
                entityManager.SetComponentData(instance, new Translation {Value = position});
            }
        }
    }

这个案例和案例2一样,通过GameObjectConversionUtility.ConvertGameObjectHierarchy函数将Prefab转化成Entity,然后使用EntityManager克隆

7、SpawnFromEntity——之后还会研究

这个案例是通过生成一个Entity,然后使用这个Entity的组件数据来生成其他Entity,可以说第一个生成的实体是一个实体生成器

7.1、组件

using Unity.Entities;
public struct Spawner_FromEntity : IComponentData
{
    public int CountX;
    public int CountY;
    public Entity Prefab;
}

组件中的数据分别代表生成的位置和预制体,这很简单

7.2、预制体生成器

using System;
using System.Collections.Generic;
using Unity.Entities;
using UnityEngine;

[RequiresEntityConversion]
public class SpawnerAuthoring_FromEntity : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
{
    public GameObject Prefab;
    public int CountX;
    public int CountY;
    public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
    {
        referencedPrefabs.Add(Prefab);
    }

实现IDeclareReferencedPrefabs接口,预先声明了Prefab的参考,让转换系统能够预先知道它

    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        var spawnerData = new Spawner_FromEntity
        {
            Prefab = conversionSystem.GetPrimaryEntity(Prefab),
            CountX = CountX,
            CountY = CountY
        };
        dstManager.AddComponentData(entity, spawnerData);
    }
}

因为需要引用的Prefab是基于DeclareReferencedPrefabs的,所以这里我们简单地将游戏对象映射到该预制件的引用上
并且这边会因为Convert To Entity组件调用Convert函数,然后添加上7.1中的组件

7.3、生成系统

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

这里首先要说明一下,JobComponentSystems可以在工作线程上运行,但是添加和删除实体的操作只能在主线程上执行——为了避免线程上的冲突,因此在这里需要使用EntityCommandBuffer(实体指令缓冲)来延迟进行这些操作

[UpdateInGroup(typeof(SimulationSystemGroup))]

我们把这个Job放入SimulationSystemGroup组中

public class SpawnerSystem_FromEntity : JobComponentSystem
{
    BeginInitializationEntityCommandBufferSystem m_EntityCommandBufferSystem;
    protected override void OnCreate()
    {
        m_EntityCommandBufferSystem = World.GetOrCreateSystem<BeginInitializationEntityCommandBufferSystem>();
    }

BeginInitializationEntityCommandBufferSystem可以创建一个命令缓存系统在阻塞系统被执行的时候运行,虽然这个初始化命令在SpawnJob中被记录下来,但是它并不会真正地被执行直到相应的实体命令缓存系统更新

(可能不太恰当)我现在缓存了一个“给我苹果”的操作,直到我执行了“我想吃苹果”这个操作,我发现我没有苹果,我就会执行缓存的操作,然后我就有苹果吃了

那么我们就得先声明变量并初始化

    struct SpawnJob : IJobForEachWithEntity<Spawner_FromEntity, LocalToWorld>
    {
        public EntityCommandBuffer.Concurrent CommandBuffer;

声明实体指令缓冲

        public void Execute(Entity entity, int index, [ReadOnly] ref Spawner_FromEntity spawnerFromEntity, [ReadOnly] ref LocalToWorld location)
        {
            for (var x = 0; x < spawnerFromEntity.CountX; x++)
            {
                for (var y = 0; y < spawnerFromEntity.CountY; y++)
                {
                    var instance = CommandBuffer.Instantiate(index, spawnerFromEntity.Prefab);

                    var position = math.transform(location.Value,
                        new float3(x * 1.3F, noise.cnoise(new float2(x, y) * 0.21F) * 2, y * 1.3F));
                    CommandBuffer.SetComponent(index, instance, new Translation {Value = position});
                }
            }
            CommandBuffer.DestroyEntity(index, entity);
        }
    }

缓冲“生成预制体,然后销毁自己”这个指令

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        var job = new SpawnJob
        {
            CommandBuffer = m_EntityCommandBufferSystem.CreateCommandBuffer().ToConcurrent()
        }.Schedule(this, inputDeps);
        m_EntityCommandBufferSystem.AddJobHandleForProducer(job);
        return job;
    }
}

将缓冲指令作为参数传入,然后在缓冲区添加Job句柄

4.4、小结

8、SpawnAndRemove

这个案例是之前的综合案例,非常类似案例7,重点在于LifeTime,也就是在LifeTime小于0之后销毁实例,其实也是通过命令缓冲执行的,这里就不再赘述了

标签:Prefab,Jobs,System,SubScene,Entity,Unity,using,public
来源: https://blog.csdn.net/qq_43500611/article/details/99733978