您当前的位置: 首页 > 

CloudHu1989

暂无认证

  • 5浏览

    0关注

    89博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

ECS官方案例6. SpawnFromEntity

CloudHu1989 发布时间:2019-08-10 18:45:06 ,浏览量:5

基于Unity2019最新ECS架构开发MMO游戏笔记5
  • 官方案例解析6
    • 6. SpawnFromEntity
    • 小结
      • DOTS 逻辑图表
  • 更新计划
    • 作者的话
  • ECS系列目录
    • ECS官方示例1:ForEach
    • ECS官方案例2:IJobForEach
    • ECS官方案例3:IJobChunk
    • ECS官方案例4:SubScene
    • ECS官方案例5:SpawnFromMonoBehaviour
    • ECS官方案例6:SpawnFromEntity
    • ECS官方案例7:SpawnAndRemove
    • ECS进阶:FixedTimestepWorkaround
    • ECS进阶:Boids
    • ECS进阶:场景切换器
    • ECS进阶:MegaCity0
    • ECS进阶:MegaCity1
    • UnityMMO资源整合&服务器部署
    • UnityMMO选人流程
    • UnityMMO主世界

官方案例解析6

开始之前的准备工作: 0下载Unity编辑器(2019.1.0f1 or 更新的版本),if(已经下载了)continue; 1下载官方案例,打开Git Shell输入: git clone https://github.com/Unity-Technologies/EntityComponentSystemSamples.git --recurse or 点击Unity官方ECS示例下载代码 if(已经下载了)continue; 2用Unity Hub打开官方的项目:ECSSamples 3在Assets目录下找到HelloCube/6. SpawnFromEntity ,并打开6. SpawnFromEntity场景

6. SpawnFromEntity

这个案例演示了我们如何使用预设游戏对象来生成实体和组件,场景将由此生成一大堆旋转的方块对,貌似和上一个案例一样,实则不是,下面一起来一探究竟吧:

  • Main Camera ……主摄像机
  • Directional Light……光源
  • Spawner……旋转方块生成器

我们注意到这个Spawner生成器相对于案例5多了一个ConvertToEntity脚本,这个脚本是我们最早接触到的,还记得它的功能吗?就是把游戏对象转化成实体,由此我们就明白这个案例的用意了。相对于案例5的从游戏对象上生成实体,我们这一次先将Spawner转化成实体,再由实体来生成实体:

/// 
/// 先将自己转换成实体,再由预设生成新的实体
/// 
[RequiresEntityConversion]
public class SpawnerAuthoring_FromEntity : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
{
    public GameObject Prefab;
    public int CountX;
    public int CountY;

    // Referenced prefabs have to be declared so that the conversion system knows about them ahead of time
    /// 
    /// IDeclareReferencedPrefabs接口的实现,声明引用的预设,好让转化系统提前知道它们的存在
    /// 
    /// 引用的预设
    public void DeclareReferencedPrefabs(List referencedPrefabs)
    {
        referencedPrefabs.Add(Prefab);
    }

    // Lets you convert the editor data representation to the entity optimal runtime representation
    /// 
    /// 我们将编辑器的数据表述转化成实体最佳的运行时表述
    /// 
    /// 实体
    /// 目标实体管理器
    /// 转化系统
    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        var spawnerData = new Spawner_FromEntity
        {
            // The referenced prefab will be converted due to DeclareReferencedPrefabs.
            // So here we simply map the game object to an entity reference to that prefab.
            //被引用的预设因为做了声明将被转化成实体
            //所以我们这里只是将游戏对象标记到一个引用该预设的实体上
            Prefab = conversionSystem.GetPrimaryEntity(Prefab),
            CountX = CountX,
            CountY = CountY
        };
        dstManager.AddComponentData(entity, spawnerData);
    }
}

因为是将Spawner先转化成实体,再由Spawner实体来生成旋转方块儿实体,所以这里需要组件Spawner实体的ECS结构。

/// 
/// 我是Spawner的组件,我只储存数据
/// 
public struct Spawner_FromEntity : IComponentData
{
    public int CountX;
    public int CountY;
    public Entity Prefab;
}

Component和实体的代码都非常简单,所以后期开发的时候,我会写一个工具来自动生成代码,从而大大提高工作效率。既然我们是面向数据的编程模式,那么我认为可以直接通过策划的表格或数据库来直接生成实体和组件,我们要做的只是编写各种System系统。先这么构思好了,后面很快就能制作出对应的工具来的,我会把工具放到开发者联盟的群文件共享,如果有需要的话可以自行下载。稍后我会把制作代码生成工具排进计划中,不如明天好了。 跑题了,我们继续来看看Spawner的System脚本SpawnerSystem_FromEntity:

// JobComponentSystems can run on worker threads.
// However, creating and removing Entities can only be done on the main thread to prevent race conditions.
// The system uses an EntityCommandBuffer to defer tasks that can't be done inside the Job.
/// 
/// 任务组件系统(JobComponentSystems)可以在工作线程上运行,但是创建和移除实体只能在主线程上做,从而防止线程之间的竞争
/// Jobs系统使用一个实体命令缓存(EntityCommandBuffer)来延迟那些不能在任务系统内完成的任务。
/// 
[UpdateInGroup(typeof(SimulationSystemGroup))]//标记更新组为模拟系统组
public class SpawnerSystem_FromEntity : JobComponentSystem
{
    // BeginInitializationEntityCommandBufferSystem is used to create a command buffer which will then be played back
    // when that barrier system executes.
    // Though the instantiation command is recorded in the SpawnJob, it's not actually processed (or "played back")
    // until the corresponding EntityCommandBufferSystem is updated. To ensure that the transform system has a chance
    // to run on the newly-spawned entities before they're rendered for the first time, the SpawnerSystem_FromEntity
    // will use the BeginSimulationEntityCommandBufferSystem to play back its commands. This introduces a one-frame lag
    // between recording the commands and instantiating the entities, but in practice this is usually not noticeable.
    /// 
    /// 开始初始化实体命令缓存系统(BeginInitializationEntityCommandBufferSystem)被用来创建一个命令缓存,
    /// 这个命令缓存将在阻塞系统执行时被回放。虽然初始化命令在生成任务(SpawnJob)中被记录下来,
    /// 它并非真正地被执行(或“回放”)直到相应的实体命令缓存系统(EntityCommandBufferSystem)被更新。
    /// 为了确保transform系统有机会在新生的实体初次被渲染之前运行,SpawnerSystem_FromEntity将使用
    /// 开始模拟实体命令缓存系统(BeginSimulationEntityCommandBufferSystem)来回放其命令。
    /// 这就导致了在记录命令和初始化实体之间一帧的延迟,但是该延迟实际通常被忽略掉。
    /// 
    BeginInitializationEntityCommandBufferSystem m_EntityCommandBufferSystem;
    /// 
    /// 在这个字段中缓存BeginInitializationEntityCommandBufferSystem,这样我们就不需要每一帧去创建
    /// 
    protected override void OnCreate()
    {
        // Cache the BeginInitializationEntityCommandBufferSystem in a field, so we don't have to create it every frame
        m_EntityCommandBufferSystem = World.GetOrCreateSystem();
    }

    /// 
    /// 生成实体任务,实现了IJobForEachWithEntity接口
    /// 
    struct SpawnJob : IJobForEachWithEntity
    {
        /// 
        /// 当前实体命令缓存
        /// 
        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             
关注
打赏
1664096582
查看更多评论
0.2112s