内存块(IJobChunk),这个块是被一开始基于相同原型分配好了的,也就是说,如果实体有相同的组件,那么他们会被紧密的安排在一块内存中,从而方便处理器进行操作。这是相对于面向对象的散列内存而言的,在面向对象中要操作内存中的某个对象时,你不得不在整个内存中寻找它,这样会降低读取速度,也不方便批量操作。ECS则会非常紧密地分配实体在内存中的位置,相同的组件会被统一放在块中,读取速度快,也方便批量操作。
块的概念必读:http://www.benmutou.com/archives/2805
案例十:Job使用内存块(JobChunk)来模拟雨滴下落(Scne11)
注意:在使用哪个场景的使用将其 ComponentSystem的 [DisableAutoCreation] 去掉,这个是同来停止 系统功能的!
脚本:IJobChunk_DropData
using Unity.Entities;
public struct IJobChunk_DropData : IComponentData
{
public float delay;
public float velocity;
}
脚本:IJobChunk_Main
using UnityEngine;
using Unity.Entities;
using Unity.Collections;
using Unity.Transforms;
public class IJobChunk_Main : MonoBehaviour
{
public int entityCount = 1000;
public int entityRange = 100;
public GameObject prefab;
private EntityManager entityManager;
private NativeArray<Entity> entityArray;
void Start()
{
this.CreatePureMain();
}
void CreatePureMain()
{
entityManager = World.Active.EntityManager;
entityArray = new NativeArray<Entity>(entityCount, Allocator.Persistent);
Entity entity = GameObjectConversionUtility.ConvertGameObjectHierarchy(this.prefab, World.Active);
entityManager.Instantiate(entity, entityArray);
for (int i = 0; i < entityCount; i++)
{
// 初始化位置信息
Translation translation = new Translation();
translation.Value = Random.insideUnitSphere * entityRange; // 设置位置为随机的球体
translation.Value.y = 0;
entityManager.SetComponentData<Translation>(entityArray[i], translation); // 设置位置信息
// 初始化延迟时间
entityManager.AddComponentData<IJobChunk_DropData>(entityArray[i], new IJobChunk_DropData { delay=5, velocity=10});
}
}
private void OnDestroy()
{
entityArray.Dispose(); // 这里把内存缓冲区释放掉
}
}
脚本:IJobChunk_TranJobComponent
using UnityEngine;
using UnityEngine.Jobs;
using Unity.Entities;
using Unity.Jobs;
using Unity.Transforms;
using Unity.Collections;
using Unity.Burst;
[DisableAutoCreation]
public class IJobChunk_TranJobComponent : JobComponentSystem
{
EntityQuery entityQuery;
protected override void OnCreate()
{
entityQuery = this.GetEntityQuery(typeof(Translation), typeof(IJobChunk_DropData));
}
[BurstCompile]
struct TranslateJob : IJobChunk
{
[ReadOnly]
public float deltaTime;
[ReadOnly]
public int minHeight;
[ReadOnly]
public float velocity;
[ReadOnly]
public float delay;
public ArchetypeChunkComponentType<Translation> archetypeTranslation;
public ArchetypeChunkComponentType<IJobChunk_DropData> archetypeDropData;
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
{
// 通过原型从块里获取对应的实体数组
var tranArray = chunk.GetNativeArray<Translation>(archetypeTranslation);
var dropArray = chunk.GetNativeArray<IJobChunk_DropData>(archetypeDropData);
for (int i = 0; i < chunk.Count; i++)
{
var dropData = dropArray[i];
var translation = tranArray[i];
if (dropData.delay > 0)
{
dropData.delay -= deltaTime;
}
else
{
if (translation.Value.y < minHeight)
{
translation.Value.y = 0;
dropData.velocity = velocity;
dropData.delay = delay;
}
else
{
translation.Value.y -= dropData.velocity * deltaTime;
}
}
dropArray[i] = dropData;
tranArray[i] = translation;
}
}
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
// 获取相对应组件的原型
var tranArchetype = this.GetArchetypeChunkComponentType<Translation>();
var dropArachetype = this.GetArchetypeChunkComponentType<IJobChunk_DropData>();
TranslateJob translateJob = new TranslateJob()
{
deltaTime = Time.deltaTime,
minHeight = -70,
archetypeTranslation = tranArchetype,
archetypeDropData = dropArachetype,
delay = UnityEngine.Random.Range(1, 10),
velocity = UnityEngine.Random.Range(1, 10),
};
// 注意这里的筛选器中对应的组件必须和job中对应的相同
JobHandle outputDeps = translateJob.Schedule(entityQuery, inputDeps);
return outputDeps;
}
}
IJobChunk使用的时候是在OnUpdate中是对块进行赋值操作的,而IJobForEach是对每个实体进行操作的,从而提高游戏性能!IJobChunk帧率更高一些。
本文参考:https://blog.csdn.net/qq_30137245/article/details/99068336
远程项目仓库(github):https://github.com/h1031464180/UnityECS