unity2019 ECS入門例項:建立一個Entity

tinySnailer發表於2020-10-24

Unity2019 ECS 入門例項:建立一個Entity

一. 前言

本篇要實現建立一個實體,並將這個Entity在場景中顯示出來,用ECS框架來解釋就是建立一個Entity,併為這個Entity新增ComponentData從而完成上述功能.

  1. 按我的理解Entity≠GameObject,而 GameObject = (Entity + Component(data) +System)
  2. 想要在場景中顯示物體肯定要有Mesh(形狀)Material(材質),所以我們要做的是為Entity新增這些Component(資料)
  3. 這個案例沒有編寫System(行為)

二. 搭建環境

  1. 我的Unity版本:Unity2019.4.7LTS
  2. 使用Window->PackageManage 搜尋Entities,點選Install,記得勾選 show preview packages
  3. 同理安裝Jobs,Mathematics,Hybrid Render
  4. 安裝完成後即可開始編碼了,以上步驟有問題可以自行搜尋對應的問題或者留言

三. 編碼實現建立一個Entity,並在場景中顯示

在Unity中,提供了很多方法去建立或者將GameObject轉換成Entity,這裡我們主要採用建立的方式,在新建的專案中,建立一個指令碼CreateEntity.cs

CreateEntity.cs

using Unity.Entities;
using Unity.Rendering;
using Unity.Transforms;
using UnityEngine;

public class CreateEntity : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        manager = World.DefaultGameObjectInjectionWorld.EntityManager;//獲取預設世界的實體管理器
        CreateEntityObj();
    }

    // Update is called once per frame
    void Update()
    {
        
    }


    private EntityManager manager;
    private void CreateEntityObj()
    {
        //在EntityManager中提供了public Entity CreateEntity(EntityArchetype archetype);方法
        //在此之前,我們需要一個
        //同樣在EntityManager中,有一個 CreateArchetype(params ComponentType[] types);方法
        var archeType = manager.CreateArchetype
        (
            //以下等於規定了Entity中一系列資料型別
            ComponentType.ReadWrite<LocalToWorld>(),
            ComponentType.ReadWrite<Translation>(),
            ComponentType.ReadOnly<RenderMesh>()
        );

        var entity = manager.CreateEntity(archeType);//到此我們就建立了一個entity
        manager.SetName(entity, "cube");//設定一個名字方便觀察

        //需要為Entity設定位置,形狀,材質等資訊,這裡的資訊可以使用公有變數在檢視皮膚中設定
        //此處直接使用一個標準的資料
        var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);

        //為實體設定資料
        manager.SetComponentData<LocalToWorld>(entity, new LocalToWorld() { Value = Unity.Mathematics.float4x4.zero });
        manager.SetComponentData<Translation>(entity, new Translation() { Value = new Unity.Mathematics.float3(0, 0, 0) });
        manager.SetSharedComponentData<RenderMesh>(entity, new RenderMesh()
        {
            material = cube.GetComponent<MeshRenderer>().material,
            mesh = cube.GetComponent<MeshFilter>().sharedMesh,
            subMesh = 0,
            castShadows = UnityEngine.Rendering.ShadowCastingMode.On,
            receiveShadows = true,
            needMotionVectorPass = true
        });

        Destroy(cube);//臨時使用的cube進行銷燬
    }
}

但是!掛載執行後在在場景中並沒有找到我我們想要的那個Cube,但是在Entity Debugger中可以看到那個Entity確實已經存在了,那就說明場景中應該是有的,只能說我們沒找到。

四. 問題解決

Entity Debugger中有,場景中看不到,那就說明為他設定位置的資料有問題。

  1. 在場景中新建一個Cube,並新增ConvertToEntity指令碼
  2. 執行然後開啟Entity Debugger,檢視轉換成的Entity,發現多了幾個資料,資料型別都是render bounds相關的
  3. Entity新增RenderBounds資料

第一次執行,Entity的資訊
新增Renderbounds後

修改後的CreateEntity.cs

using Unity.Entities;
using Unity.Rendering;
using Unity.Transforms;
using UnityEngine;

public class CreateEntity : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        manager = World.DefaultGameObjectInjectionWorld.EntityManager;//獲取預設世界的實體管理器
        CreateEntityObj();
    }

    // Update is called once per frame
    void Update()
    {
        
    }


    private EntityManager manager;
    private void CreateEntityObj()
    {
        //在EntityManager中提供了public Entity CreateEntity(EntityArchetype archetype);方法
        //在此之前,我們需要一個
        //同樣在EntityManager中,有一個 CreateArchetype(params ComponentType[] types);方法
        var archeType = manager.CreateArchetype
        (
            //以下等於規定了Entity中一系列資料型別
            ComponentType.ReadWrite<LocalToWorld>(),
            ComponentType.ReadWrite<Translation>(),
            ComponentType.ReadOnly<RenderMesh>(),
            ComponentType.ReadWrite<RenderBounds>()
        );

        var entity = manager.CreateEntity(archeType);//到此我們就建立了一個entity
        manager.SetName(entity, "cube");//設定一個名字方便觀察

        //需要為Entity設定位置,形狀,材質等資訊,這裡的資訊可以使用公有變數在檢視皮膚中設定
        //此處直接使用一個標準的資料
        var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);

        //為實體設定資料
        RenderBounds rb = new RenderBounds()
        {
            Value = new Unity.Mathematics.AABB()
            {
                Center = new Unity.Mathematics.float3(0, 0, 0),
                Extents = new Unity.Mathematics.float3(0.5f,0.5f,0.5f)
            }
        };
        manager.SetComponentData<RenderBounds>(entity,rb)//只需新增archerType即可,不需要手動設定資料
        manager.SetComponentData<LocalToWorld>(entity, new LocalToWorld() { Value = Unity.Mathematics.float4x4.zero });
        manager.SetComponentData<Translation>(entity, new Translation() { Value = new Unity.Mathematics.float3(0, 0, 0) });
        manager.SetSharedComponentData<RenderMesh>(entity, new RenderMesh()
        {
            material = cube.GetComponent<MeshRenderer>().material,
            mesh = cube.GetComponent<MeshFilter>().sharedMesh,
            subMesh = 0,
            castShadows = UnityEngine.Rendering.ShadowCastingMode.On,
            receiveShadows = true,
            needMotionVectorPass = true
        });

        Destroy(cube);//臨時使用的cube進行銷燬
    }
}

歡迎訪問我的個人部落格 Snail’s Blog

相關文章