Unity ECS Sample解析(1)

资料来源:https://github.com/Unity-Technologies/EntityComponentSystemSamples

使用工具:Unity,vscode,dnSPy

Unity版本:2020.1.0.f1

研究目的:研究ECS的工作原理

BoidSchool

用来生成鱼群的ECS结构

BoidSchool中的Prefab是名为TestBoidFish和TestBoidFish 1的Prefab.

BoidSchoolSpawnSystem利用了场景中的BoidSchool类型,使用Entities.WithStructuralChanges().ForEach便利BoidSchool.

然后再生成boidSchool.Count条鱼,利用SetBoidLocalToWorld设置具体位置.

namespace Samples.Boids
{public struct BoidSchool : IComponentData{public Entity Prefab;public float InitialRadius;public int Count;}public class BoidSchoolSpawnSystem : SystemBase{[BurstCompile]struct SetBoidLocalToWorld : IJobParallelFor{[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction]public ComponentDataFromEntity<LocalToWorld> LocalToWorldFromEntity;public NativeArray<Entity> Entities;public float3 Center;public float Radius;public void Execute(int i){var entity = Entities[i];var random = new Random(((uint)(entity.Index + i + 1) * 0x9F6ABC1));var dir = math.normalizesafe(random.NextFloat3() - new float3(0.5f, 0.5f, 0.5f));var pos = Center + (dir * Radius);var localToWorld = new LocalToWorld{Value = float4x4.TRS(pos, quaternion.LookRotationSafe(dir, math.up()), new float3(1.0f, 1.0f, 1.0f))};LocalToWorldFromEntity[entity] = localToWorld;}}protected override void OnUpdate(){Entities.WithStructuralChanges().ForEach((Entity entity, int entityInQueryIndex, in BoidSchool boidSchool, in LocalToWorld boidSchoolLocalToWorld) =>{var boidEntities = new NativeArray<Entity>(boidSchool.Count, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);Profiler.BeginSample("Instantiate");EntityManager.Instantiate(boidSchool.Prefab, boidEntities);Profiler.EndSample();var localToWorldFromEntity = GetComponentDataFromEntity<LocalToWorld>();var setBoidLocalToWorldJob = new SetBoidLocalToWorld{LocalToWorldFromEntity = localToWorldFromEntity,Entities = boidEntities,Center = boidSchoolLocalToWorld.Position,Radius = boidSchool.InitialRadius};Dependency = setBoidLocalToWorldJob.Schedule(boidSchool.Count, 64, Dependency);Dependency = boidEntities.Dispose(Dependency);EntityManager.DestroyEntity(entity);}).Run();}}
}

我们再来看通过语法糖生成的IL逆向代码:

namespace Samples.Boids
{public class BoidSchoolSpawnSystem : SystemBase{protected override void OnUpdate(){ForEachLambdaJobDescription entities = base.Entities;BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0 <>c__DisplayClass_OnUpdate_LambdaJob = default(BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0);<>c__DisplayClass_OnUpdate_LambdaJob.ScheduleTimeInitialize(this);base.CompleteDependency();EntityQuery query = this.<>OnUpdate_LambdaJob0_entityQuery;this.<>OnUpdate_LambdaJob0_profilerMarker.Begin();try{<>c__DisplayClass_OnUpdate_LambdaJob.Execute(this, query);}finally{this.<>OnUpdate_LambdaJob0_profilerMarker.End();}}protected internal override void OnCreateForCompiler(){base.OnCreateForCompiler();this.<>OnUpdate_LambdaJob0_entityQuery = BoidSchoolSpawnSystem.<>GetEntityQuery_ForOnUpdate_LambdaJob0_From(this);this.<>OnUpdate_LambdaJob0_profilerMarker = new ProfilerMarker("OnUpdate_LambdaJob0");}public static EntityQuery <>GetEntityQuery_ForOnUpdate_LambdaJob0_From(ComponentSystemBase componentSystem){EntityQueryDesc[] array = new EntityQueryDesc[1];EntityQueryDesc entityQueryDesc = new EntityQueryDesc();array[0] = entityQueryDesc;entityQueryDesc.All = new ComponentType[]{ComponentType.ReadOnly<BoidSchool>(),ComponentType.ReadOnly<LocalToWorld>()};return componentSystem.GetEntityQuery(array);}private EntityQuery <>OnUpdate_LambdaJob0_entityQuery;private ProfilerMarker <>OnUpdate_LambdaJob0_profilerMarker;[BurstCompile]private struct SetBoidLocalToWorld : IJobParallelFor{public void Execute(int i){Entity entity = this.Entities[i];Unity.Mathematics.Random random = new Unity.Mathematics.Random((uint)((entity.Index + i + 1) * 167160769));float3 dir = math.normalizesafe(random.NextFloat3() - new float3(0.5f, 0.5f, 0.5f), default(float3));float3 pos = this.Center + dir * this.Radius;LocalToWorld localToWorld = new LocalToWorld{Value = float4x4.TRS(pos, quaternion.LookRotationSafe(dir, math.up()), new float3(1f, 1f, 1f))};this.LocalToWorldFromEntity[entity] = localToWorld;}[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction]public ComponentDataFromEntity<LocalToWorld> LocalToWorldFromEntity;public NativeArray<Entity> Entities;public float3 Center;public float Radius;}[DOTSCompilerGenerated]private struct <>c__DisplayClass_OnUpdate_LambdaJob0{public void OriginalLambdaBody(Entity entity, int entityInQueryIndex, [In] ref BoidSchool boidSchool, [In] ref LocalToWorld boidSchoolLocalToWorld){this.hostInstance.<OnUpdate>b__1_0(entity, entityInQueryIndex, boidSchool, boidSchoolLocalToWorld);}public unsafe static void PerformLambda(void* jobStructPtr, void* runtimesPtr, Entity entity){ref BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders.Runtimes ptr = UnsafeUtility.AsRef<BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders.Runtimes>(runtimesPtr);Entity entity2 = ptr.runtime_entity.For(entity);int entityInQueryIndex = ptr.runtime_entityInQueryIndex.For(entity);BoidSchool boidSchool2;BoidSchool boidSchool = ptr.runtime_boidSchool.For(entity, out boidSchool2);LocalToWorld localToWorld2;LocalToWorld localToWorld = ptr.runtime_boidSchoolLocalToWorld.For(entity, out localToWorld2);UnsafeUtility.AsRef<BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0>(jobStructPtr).OriginalLambdaBody(entity2, entityInQueryIndex, ref boidSchool, ref localToWorld);}public unsafe void Execute(ComponentSystemBase componentSystem, EntityQuery query){BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders.Runtimes runtimes = this._lambdaParameterValueProviders.PrepareToExecuteWithStructuralChanges(componentSystem, query);this._runtimes = &runtimes;runtimes._entityProvider.IterateEntities((void*)(&this), (void*)this._runtimes, BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0._performLambdaDelegate);}public void ScheduleTimeInitialize(BoidSchoolSpawnSystem componentSystem){this.hostInstance = componentSystem;}public BoidSchoolSpawnSystem hostInstance;private BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders _lambdaParameterValueProviders;[NativeDisableUnsafePtrRestriction]private unsafe BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders.Runtimes* _runtimes;public static StructuralChangeEntityProvider.PerformLambdaDelegate _performLambdaDelegate = new StructuralChangeEntityProvider.PerformLambdaDelegate(BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.PerformLambda);private struct LambdaParameterValueProviders{public void ScheduleTimeInitialize(BoidSchoolSpawnSystem componentSystem){this.forParameter_entity.ScheduleTimeInitialize(componentSystem, true);this.forParameter_entityInQueryIndex.ScheduleTimeInitialize(componentSystem, true);this.forParameter_boidSchool.ScheduleTimeInitialize(componentSystem, true);this.forParameter_boidSchoolLocalToWorld.ScheduleTimeInitialize(componentSystem, true);}public BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders.Runtimes PrepareToExecuteWithStructuralChanges(ComponentSystemBase p0, EntityQuery p1){BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders.Runtimes result = default(BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders.Runtimes);result._entityProvider.PrepareToExecuteWithStructuralChanges(p0, p1);result.runtime_entity = this.forParameter_entity.PrepareToExecuteWithStructuralChanges(p0, p1);result.runtime_entityInQueryIndex = this.forParameter_entityInQueryIndex.PrepareToExecuteWithStructuralChanges(p0, p1);result.runtime_boidSchool = this.forParameter_boidSchool.PrepareToExecuteWithStructuralChanges(p0, p1);result.runtime_boidSchoolLocalToWorld = this.forParameter_boidSchoolLocalToWorld.PrepareToExecuteWithStructuralChanges(p0, p1);return result;}[ReadOnly]private LambdaParameterValueProvider_Entity forParameter_entity;[ReadOnly]private LambdaParameterValueProvider_EntityInQueryIndex forParameter_entityInQueryIndex;[ReadOnly]private LambdaParameterValueProvider_IComponentData<BoidSchool> forParameter_boidSchool;[ReadOnly]private LambdaParameterValueProvider_IComponentData<LocalToWorld> forParameter_boidSchoolLocalToWorld;public struct Runtimes{public StructuralChangeEntityProvider _entityProvider;public LambdaParameterValueProvider_Entity.StructuralChangeRuntime runtime_entity;public LambdaParameterValueProvider_EntityInQueryIndex.StructuralChangeRuntime runtime_entityInQueryIndex;public LambdaParameterValueProvider_IComponentData<BoidSchool>.StructuralChangeRuntime runtime_boidSchool;public LambdaParameterValueProvider_IComponentData<LocalToWorld>.StructuralChangeRuntime runtime_boidSchoolLocalToWorld;}}}}
}

Onupdate

我们可以了解到IL的代码已经和源码天壤之别,现在来分析下

IL逆向

     protected override void OnUpdate(){ForEachLambdaJobDescription entities = base.Entities;BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0 <>c__DisplayClass_OnUpdate_LambdaJob = default(BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0);<>c__DisplayClass_OnUpdate_LambdaJob.ScheduleTimeInitialize(this);base.CompleteDependency();EntityQuery query = this.<>OnUpdate_LambdaJob0_entityQuery;this.<>OnUpdate_LambdaJob0_profilerMarker.Begin();try{<>c__DisplayClass_OnUpdate_LambdaJob.Execute(this, query);}finally{this.<>OnUpdate_LambdaJob0_profilerMarker.End();}}

源码

        protected override void OnUpdate(){Entities.WithStructuralChanges().ForEach((Entity entity, int entityInQueryIndex, in BoidSchool boidSchool, in LocalToWorld boidSchoolLocalToWorld) =>{var boidEntities = new NativeArray<Entity>(boidSchool.Count, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);Profiler.BeginSample("Instantiate");EntityManager.Instantiate(boidSchool.Prefab, boidEntities);Profiler.EndSample();var localToWorldFromEntity = GetComponentDataFromEntity<LocalToWorld>();var setBoidLocalToWorldJob = new SetBoidLocalToWorld{LocalToWorldFromEntity = localToWorldFromEntity,Entities = boidEntities,Center = boidSchoolLocalToWorld.Position,Radius = boidSchool.InitialRadius};Dependency = setBoidLocalToWorldJob.Schedule(boidSchool.Count, 64, Dependency);Dependency = boidEntities.Dispose(Dependency);EntityManager.DestroyEntity(entity);}).Run();}

看起来已经不是同一份代码了,Entities.WithStructuralChanges().ForEach和lamda表达式到哪里去了.

答案就在<>c__DisplayClass_OnUpdate_LambdaJob.Execute(this, query);中

         public unsafe void Execute(ComponentSystemBase componentSystem, EntityQuery query){BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders.Runtimes runtimes = this._lambdaParameterValueProviders.PrepareToExecuteWithStructuralChanges(componentSystem, query);this._runtimes = &runtimes;runtimes._entityProvider.IterateEntities((void*)(&this), (void*)this._runtimes, BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0._performLambdaDelegate);}

IterateEntities函数说明了这里并不是多线程处理的,使用时要多加注意.

     public unsafe void IterateEntities(void* jobStruct, void* runtimes, StructuralChangeEntityProvider.PerformLambdaDelegate action){try{int entityCount = this.EntityCount;for (int i = 0; i != entityCount; i++){Entity entity = this.For(i);bool flag = entity != Entity.Null;if (flag){action(jobStruct, runtimes, entity);}}}finally{this._query.ReleaseGatheredEntities(ref this._gatherEntitiesResult);}}

其中_performLambdaDelegate就是下面函数

         public unsafe static void PerformLambda(void* jobStructPtr, void* runtimesPtr, Entity entity){ref BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders.Runtimes ptr = UnsafeUtility.AsRef<BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders.Runtimes>(runtimesPtr);Entity entity2 = ptr.runtime_entity.For(entity);int entityInQueryIndex = ptr.runtime_entityInQueryIndex.For(entity);BoidSchool boidSchool2;BoidSchool boidSchool = ptr.runtime_boidSchool.For(entity, out boidSchool2);LocalToWorld localToWorld2;LocalToWorld localToWorld = ptr.runtime_boidSchoolLocalToWorld.For(entity, out localToWorld2);UnsafeUtility.AsRef<BoidSchoolSpawnSystem.<>c__DisplayClass_OnUpdate_LambdaJob0>(jobStructPtr).OriginalLambdaBody(entity2, entityInQueryIndex, ref boidSchool, ref localToWorld);}

可以看到其中OriginalLambdaBody就是lamda表达式

         public void OriginalLambdaBody(Entity entity, int entityInQueryIndex, [In] ref BoidSchool boidSchool, [In] ref LocalToWorld boidSchoolLocalToWorld){this.hostInstance.<OnUpdate>b__1_0(entity, entityInQueryIndex, boidSchool, boidSchoolLocalToWorld);}

这里可以看到b__1_0这个函数,可惜dnspy并没有解析出来.

直接去看il2cpp output的代码:

// System.Void Samples.Boids.BoidSchoolSpawnSystem::<OnUpdate>b__1_0(Unity.Entities.Entity,System.Int32,Samples.Boids.BoidSchool&,Unity.Transforms.LocalToWorld&)
IL2CPP_EXTERN_C IL2CPP_METHOD_ATTR void BoidSchoolSpawnSystem_U3COnUpdateU3Eb__1_0_mD857D466DB5D861FD717ABADB04442458A302DC1 (BoidSchoolSpawnSystem_tE41A950D814AC56EA06ED2356EAC22C71348012E * __this, Entity_tA8DE691EC83EB40E80A611C2E6D8C90C3C97AAF4  ___entity0, int32_t ___entityInQueryIndex1, BoidSchool_t0E6F71F9F614EFCD375DFBA4BBC9A4CCA94361E7 * ___boidSchool2, LocalToWorld_t9CECB89076D428C856FD9BE65391C0DE94B65290 * ___boidSchoolLocalToWorld3, const RuntimeMethod* method)
{static bool s_Il2CppMethodInitialized;if (!s_Il2CppMethodInitialized){il2cpp_codegen_initialize_method (BoidSchoolSpawnSystem_U3COnUpdateU3Eb__1_0_mD857D466DB5D861FD717ABADB04442458A302DC1_MetadataUsageId);s_Il2CppMethodInitialized = true;}NativeArray_1_t587B0E555A435D1A1EACD16A8F3C3EBCF3497F5E  V_0;memset((&V_0), 0, sizeof(V_0));ComponentDataFromEntity_1_t4BFB53C0F238D124D1498C4139A2699C220B890E  V_1;memset((&V_1), 0, sizeof(V_1));SetBoidLocalToWorld_t825819EB0518E866FCB687E2533FFCFCB0EB19B1  V_2;memset((&V_2), 0, sizeof(V_2));EntityManager_t375E301E0D409D57A32EB6EEFEE4DCFA936B3FD0  V_3;memset((&V_3), 0, sizeof(V_3));SetBoidLocalToWorld_t825819EB0518E866FCB687E2533FFCFCB0EB19B1  V_4;memset((&V_4), 0, sizeof(V_4));LocalToWorld_t9CECB89076D428C856FD9BE65391C0DE94B65290  V_5;memset((&V_5), 0, sizeof(V_5));{// var boidEntities = new NativeArray<Entity>(boidSchool.Count, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);BoidSchool_t0E6F71F9F614EFCD375DFBA4BBC9A4CCA94361E7 * L_0 = ___boidSchool2;int32_t L_1 = L_0->get_Count_2();NativeArray_1__ctor_mC76CAC41CA00C16A626EB0CDAE4684A692566BE2((NativeArray_1_t587B0E555A435D1A1EACD16A8F3C3EBCF3497F5E *)(&V_0), L_1, 3, 0, /*hidden argument*/NativeArray_1__ctor_mC76CAC41CA00C16A626EB0CDAE4684A692566BE2_RuntimeMethod_var);// Profiler.BeginSample("Instantiate");Profiler_BeginSample_m72E4BD9503BC991BAFAED992FF1CA4504C741865_inline(_stringLiteralD517C7CD0B15AC7D7FED8521FC3CE0FC3C729432, /*hidden argument*/NULL);// EntityManager.Instantiate(boidSchool.Prefab, boidEntities);EntityManager_t375E301E0D409D57A32EB6EEFEE4DCFA936B3FD0  L_2 = ComponentSystemBase_get_EntityManager_mEA56D9178F087FFF35990C12D2195FF634413AA5(__this, /*hidden argument*/NULL);V_3 = L_2;BoidSchool_t0E6F71F9F614EFCD375DFBA4BBC9A4CCA94361E7 * L_3 = ___boidSchool2;Entity_tA8DE691EC83EB40E80A611C2E6D8C90C3C97AAF4  L_4 = L_3->get_Prefab_0();NativeArray_1_t587B0E555A435D1A1EACD16A8F3C3EBCF3497F5E  L_5 = V_0;EntityManager_Instantiate_m1B56A6484833CE1493E4D08D41E9A3F35376D8A9((EntityManager_t375E301E0D409D57A32EB6EEFEE4DCFA936B3FD0 *)(&V_3), L_4, L_5, /*hidden argument*/NULL);// Profiler.EndSample();Profiler_EndSample_m78C76E709113E225D47687E26EA320E4FC548B71(/*hidden argument*/NULL);// var localToWorldFromEntity = GetComponentDataFromEntity<LocalToWorld>();ComponentDataFromEntity_1_t4BFB53C0F238D124D1498C4139A2699C220B890E  L_6 = SystemBase_GetComponentDataFromEntity_TisLocalToWorld_t9CECB89076D428C856FD9BE65391C0DE94B65290_m22498B916F710E6FF82B815A6FE06558D1996E9C(__this, (bool)0, /*hidden argument*/SystemBase_GetComponentDataFromEntity_TisLocalToWorld_t9CECB89076D428C856FD9BE65391C0DE94B65290_m22498B916F710E6FF82B815A6FE06558D1996E9C_RuntimeMethod_var);V_1 = L_6;// var setBoidLocalToWorldJob = new SetBoidLocalToWorld// {//     LocalToWorldFromEntity = localToWorldFromEntity,//     Entities = boidEntities,//     Center = boidSchoolLocalToWorld.Position,//     Radius = boidSchool.InitialRadius// };il2cpp_codegen_initobj((&V_4), sizeof(SetBoidLocalToWorld_t825819EB0518E866FCB687E2533FFCFCB0EB19B1 ));ComponentDataFromEntity_1_t4BFB53C0F238D124D1498C4139A2699C220B890E  L_7 = V_1;(&V_4)->set_LocalToWorldFromEntity_0(L_7);NativeArray_1_t587B0E555A435D1A1EACD16A8F3C3EBCF3497F5E  L_8 = V_0;(&V_4)->set_Entities_1(L_8);LocalToWorld_t9CECB89076D428C856FD9BE65391C0DE94B65290 * L_9 = ___boidSchoolLocalToWorld3;LocalToWorld_t9CECB89076D428C856FD9BE65391C0DE94B65290  L_10 = (*(LocalToWorld_t9CECB89076D428C856FD9BE65391C0DE94B65290 *)L_9);V_5 = L_10;float3_t9500D105F273B3D86BD354142E891C48FFF9F71D  L_11 = LocalToWorld_get_Position_m8FB60CB9859C480CEB3F9E8BDF5BCF5053B2135F((LocalToWorld_t9CECB89076D428C856FD9BE65391C0DE94B65290 *)(&V_5), /*hidden argument*/NULL);(&V_4)->set_Center_2(L_11);BoidSchool_t0E6F71F9F614EFCD375DFBA4BBC9A4CCA94361E7 * L_12 = ___boidSchool2;float L_13 = L_12->get_InitialRadius_1();(&V_4)->set_Radius_3(L_13);SetBoidLocalToWorld_t825819EB0518E866FCB687E2533FFCFCB0EB19B1  L_14 = V_4;V_2 = L_14;// Dependency = setBoidLocalToWorldJob.Schedule(boidSchool.Count, 64, Dependency);SetBoidLocalToWorld_t825819EB0518E866FCB687E2533FFCFCB0EB19B1  L_15 = V_2;BoidSchool_t0E6F71F9F614EFCD375DFBA4BBC9A4CCA94361E7 * L_16 = ___boidSchool2;int32_t L_17 = L_16->get_Count_2();JobHandle_t8AEB8D31C25D7774C71D62B0C662525E6E36D847  L_18 = SystemBase_get_Dependency_m5F571303CFE0102AB40DF9277BBECA28CE052FAC(__this, /*hidden argument*/NULL);JobHandle_t8AEB8D31C25D7774C71D62B0C662525E6E36D847  L_19 = IJobParallelForExtensions_Schedule_TisSetBoidLocalToWorld_t825819EB0518E866FCB687E2533FFCFCB0EB19B1_mB9CD7D6F6010ADF5D28188B90014249EEB09EAE3(L_15, L_17, ((int32_t)64), L_18, /*hidden argument*/IJobParallelForExtensions_Schedule_TisSetBoidLocalToWorld_t825819EB0518E866FCB687E2533FFCFCB0EB19B1_mB9CD7D6F6010ADF5D28188B90014249EEB09EAE3_RuntimeMethod_var);SystemBase_set_Dependency_m46343983A977DE641677E0C7032FE7ACCE4169D6(__this, L_19, /*hidden argument*/NULL);// Dependency = boidEntities.Dispose(Dependency);JobHandle_t8AEB8D31C25D7774C71D62B0C662525E6E36D847  L_20 = SystemBase_get_Dependency_m5F571303CFE0102AB40DF9277BBECA28CE052FAC(__this, /*hidden argument*/NULL);JobHandle_t8AEB8D31C25D7774C71D62B0C662525E6E36D847  L_21 = NativeArray_1_Dispose_mD9324B5DA78797DB91D59E486F5D365CE0BDB1E4((NativeArray_1_t587B0E555A435D1A1EACD16A8F3C3EBCF3497F5E *)(&V_0), L_20, /*hidden argument*/NativeArray_1_Dispose_mD9324B5DA78797DB91D59E486F5D365CE0BDB1E4_RuntimeMethod_var);SystemBase_set_Dependency_m46343983A977DE641677E0C7032FE7ACCE4169D6(__this, L_21, /*hidden argument*/NULL);// EntityManager.DestroyEntity(entity);EntityManager_t375E301E0D409D57A32EB6EEFEE4DCFA936B3FD0  L_22 = ComponentSystemBase_get_EntityManager_mEA56D9178F087FFF35990C12D2195FF634413AA5(__this, /*hidden argument*/NULL);V_3 = L_22;Entity_tA8DE691EC83EB40E80A611C2E6D8C90C3C97AAF4  L_23 = ___entity0;EntityManager_DestroyEntity_m435E2D8727951379B9F0F9EA9A582E08FD2915A7((EntityManager_t375E301E0D409D57A32EB6EEFEE4DCFA936B3FD0 *)(&V_3), L_23, /*hidden argument*/NULL);// }).Run();return;}
}

可以发现这就是真正lamda的内容.

SetBoidLocalToWorld

这个类就稍微说一下,这是生成每条鱼重要的函数,BoidSchoolSpawnSystem使用它生成每条鱼的Entity,多线程设置每条鱼的初始位置.

重要语法糖

     protected internal override void OnCreateForCompiler(){base.OnCreateForCompiler();this.<>OnUpdate_LambdaJob0_entityQuery = BoidSchoolSpawnSystem.<>GetEntityQuery_ForOnUpdate_LambdaJob0_From(this);this.<>OnUpdate_LambdaJob0_profilerMarker = new ProfilerMarker("OnUpdate_LambdaJob0");}// Token: 0x06000012 RID: 18 RVA: 0x000024BC File Offset: 0x000006BCpublic static EntityQuery <>GetEntityQuery_ForOnUpdate_LambdaJob0_From(ComponentSystemBase componentSystem){EntityQueryDesc[] array = new EntityQueryDesc[1];EntityQueryDesc entityQueryDesc = new EntityQueryDesc();array[0] = entityQueryDesc;entityQueryDesc.All = new ComponentType[]{ComponentType.ReadOnly<BoidSchool>(),ComponentType.ReadOnly<LocalToWorld>()};return componentSystem.GetEntityQuery(array);}

Unity会自动生成<>OnUpdate_LambdaJob0_entityQuery,它式收集BoidSchool类型的集合.被隐式的构造出来,再使用的时候要注意了.

BoidSchool和LocalToWorld他们都是由lamda表达式中的参数被感知到的.

总结

虽然源码不到百行,但最后展开的IL代码却有几百行.

Unity ECS在帮助我们减少代码量的同时,也掩盖了很多实现细节.对于熟悉的人工作效率提高,多于新接触的可能比较难以理解.
下次还要分享代码量更多的BoidSystem.

Unity ECS Sample解析(1)相关推荐

  1. Unity的Json解析二–写Json文件

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/50378805 作者:car ...

  2. unity ECS简介

    什么是Unity ECS Unity ECS是Unity引擎中的一种高性能游戏开发架构,它采用了基于数据的设计思路,与传统的面向对象编程不同.它的目标是提高游戏的性能和可伸缩性. Unity ECS通 ...

  3. [Unity ECS] 游戏对象转换和子场景 [1]

      游戏只是关于玩家输入改变数据,然后看到不同呈现的事物,因此玩得开心.这些数据是使用 Unity 的 WYSIWYG 工具在scene设计的.但是那些基于 GameObject 的数据与 ECS 不 ...

  4. ECS 无法解析域名问题场景分析

    问题现象 ECS 上无法解析域名:xx.xxxx.com 本地非云上网络使用223.5.5.5以及第三方 dns IP 是可以获取解析的 1.本地解析  xx.xxxx.com  正常 nslooku ...

  5. Unity ECS小知识1 - PhysicsTrigger Event

    Unity ECS 小知识1 - PhysicsTrigger Event ECS套件学习过程中会遇到各种问题,专门开辟一个专题"ECS小知识"来记录这些点滴.每个小知识文章是没有 ...

  6. Unity Ecs源码分析

    C# Job System 什么是Job System? Job System通过创建Job而不是线程来管理多线程代码. Job System跨多个核心管理一组工作线程.它通常每个逻辑CPU核心有一个 ...

  7. Unity ECS实例:制作俯视角射击游戏!

    目录 创建主角 3:主角移动和摄像机跟随 4:实现敌人角色 5:子弹,死亡,机器人 6:粒子与音效 这次我们来使用Unity ECS系统制作一个俯视角度的射击游戏.虽然现在网上有不少ECS的资料和项目 ...

  8. Unity ECS 视频笔记

    视频摘要 本文视频资料:使用Entity Component System开发<快乐的Minecraft>游戏 使用Unity2018及以上版本才有ECS功能. 本文是看视频的一些摘要. ...

  9. unity现代人物含代码动画_深入了解 Unity DOTS Sample (一): 代码框架 amp; 工具 amp; 开发模式

    << 返回目录 代码框架 & 工具 相比于 FPSSample, DOTS Sample 进行了更加 package 化的更动, 无关乎游戏本体的代码放在了 Unity.Sampl ...

  10. OpenStack RPM Sample 解析

    目录 文章目录 目录 前言 RPM 打包环境安装 RPM 打包流程 OpenStack RPM SPEC Sample RPM 升级/回退 前言 软件功能升级,尤其是 Python 这类解析型语言的软 ...

最新文章

  1. vb.net调用oracle存储过程,今天搞好了VB.NET调用Oracle存储过程返回游标的问题
  2. .Android开发在Eclipse环境中无法显示提示信息This element neither has attached
  3. php scrscriptipt,xss跨站脚本攻击 (初级-中级-高级)
  4. c++ python 计算100以内的素数
  5. Android心电数据分析,基于Android系统的心电信号采集与分析系统设计
  6. caffe教程 (2)
  7. 高级电工技术实训考核装置
  8. COMSOL:案列应用实操教学---光电
  9. 数字万用表常用软件分享:数字万用表自动计量软件数字万用表上位机软件
  10. C# pdf转png图片
  11. Windows系统封装步骤
  12. Infor CRM咨询服务市场市场报告-Infor CRM咨询服务销售额及预测
  13. xdocreport根据模板生成合同(docx/pdf)神器:(三)如何制作报告模板并根据它生成docx或者ppt
  14. 163邮箱登录跳转php源码,网易等邮箱网页登陆源代码.doc
  15. 你一年就工作一天还想请假......
  16. 假如生活欺骗了你,js for in 遍历对象的Key
  17. 【生物信息】ESTIMATE 分析免疫评分和肿瘤纯度
  18. 【LeNet5】简单车牌识别
  19. Oracle ORA-01033: ORACLE initialization or shutdown in progress 错误解决办法Windows版(手贱强制重启电脑的后果)
  20. VS插件VA小番茄下载破解安装

热门文章

  1. linux卸载内核网卡驱动,Linux下网卡驱动的安装
  2. 信息组织 | 数字图书馆信息组织
  3. python导入自定义模块_python引入不同文件夹下的自定义模块方法
  4. 简单分析2022智能家居现状的优缺点
  5. 医院计算机管理工资,医院绩效管理平台:绩效工资管理系统
  6. PS曲线-进阶教程(深入理解PS曲线)
  7. 外卖行业现状分析_简要分析外卖运营行业的发展现状
  8. 逆流而上:计算机专业图书破圈营销,这个直播间做到了
  9. 关于Oppen Live Writer中插入可折叠着色代码的插件
  10. 涨握在线|欧或重启QE;英市港市合并!