案例二:PureECS(纯ECS)动态创建指定数量的小球Entity(实体)(Scne3)
脚本:PureMain
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Collections;
using Unity.Rendering;
using Unity.Transforms;
public class PureMain : MonoBehaviour
{
public int entityCount = 1000; //动态生成实体数量
public int entityRange = 100; // 生成实体的范围乘值
public Mesh mymesh; // 实体的 网格
public Material mymaterial; // 实体的材质
void Start()
{
this.CreatePureMain();
}
void CreatePureMain()
{
#region 1.创建本地实体数组
// 世界自动创建的唯一实体管理器
EntityManager entityManager = World.Active.EntityManager;
// 创建一个原型模型(可以类比 GameObject.CreatePrimitive ), 函数参数代表该实体有哪些组件(注意要想实体在场景中显示必须有 Translation,RenderMesh,LoalToWorld这三个组件)
EntityArchetype entityArchetype = entityManager.CreateArchetype
(
typeof(Translation),
typeof(RenderMesh),
ComponentType.ReadWrite<LocalToWorld>() // 实体的矩阵,
);
NativeArray<Entity> entities = new NativeArray<Entity>(entityCount, Allocator.Temp);
entityManager.CreateEntity(entityArchetype, entities);
#endregion
#region 2.初始化数组中的实体数据
for (int i = 0; i < entityCount; i++)
{
Translation translation = new Translation();
translation.Value = Random.insideUnitSphere * entityRange; // 设置位置为随机的球体
entityManager.SetComponentData<Translation>(entities[i], translation); // 设置位置信息
// 给所有实体 设置网格 和材质 信息 这些UnityECS做了优化处理,使用共享网格材质的函数进行添加
entityManager.SetSharedComponentData<RenderMesh>(entities[i], new RenderMesh { mesh = mymesh, material = mymaterial });
}
entities.Dispose(); // 这里把内存缓冲区释放掉
#endregion
}
}
如上图,动态创建了10万个小球实体,Unity的FPS才70。
第一步,创建本地实体数组,通过unity提供的API创建,原型类型组件LoalToWrold包含了该物体的矩阵信息(个人觉得该矩阵信息主要用来进行坐标系(相机,本地,屏幕坐标系)的转变使用),而translation只存储了在世界(wrold)的坐标信息。
Unity提供了一套内置缓冲区的概念,上篇只是提到。
首先翻译官方的解释:NativeArray将本地内存的缓冲区公开给托管代码,从而使托管和本地之间共享数据成为可能,而无需花费任何成本。在后台,NativeArrays提供的系统使它们可以安全地与作业一起使用,并自动跟踪内存泄漏。
这里涉及到两个知识点:
1. 托管代码和非托管代码
大概就是 托管内存受c#内存管理机制控制,自动释放。
非托管内存必须得手动进行释放。
详情参考:http://blog.sina.com.cn/s/blog_3e51bb390102vv6b.html
2.为啥么使用缓冲区可以提高性能
这个涉及到cpu硬件的存读方式,可以记住按照Unity指定的格式存储,这样程序访问的数据会更快。
详情参考:https://zhuanlan.zhihu.com/p/44851549 这篇写的很详细
第二步,初始化数组中的实体数据
Unity并不能直接访问本地缓存的实体,必须通过EntityManager(实体管理类)提供的方法进行数据初始化,比如初始化位置信息。另外,Unity还提供了对数据量级的相同实体使用共享的网格和材质信息,从而对游戏进行优化处理。
远程仓库(github):https://github.com/h1031464180/UnityECS