Unity ECS Sample解析(1)

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: 0x000006BC
		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);
		}

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

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

总结

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

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值