怎么找人做淘宝网站吗淘宝做推广网站
2026/1/16 10:11:59 网站建设 项目流程
怎么找人做淘宝网站吗,淘宝做推广网站,seo的培训班,高端礼品定制网站前言 还是因为期末考试导致ECS系统的学习推迟了很久#xff0c;再加上ECS的内容比较抽象#xff0c;这里只是简单讲讲进阶内容 原型和chunk 在笔记一中我们介绍了chunk#xff0c;我们知道IJobEntity是它的语法糖#xff0c;现在#xff0c;让我们正式和它见一面吧。 简单…前言还是因为期末考试导致ECS系统的学习推迟了很久再加上ECS的内容比较抽象这里只是简单讲讲进阶内容原型和chunk在笔记一中我们介绍了chunk我们知道IJobEntity是它的语法糖现在让我们正式和它见一面吧。简单来说chunk就是连续内存块每一个的大小一般是16kb。它的里面装满原型相同的实体这也是为什么ECS的速度非常快的原因之一。上面这段话很难理解所以我们逐一为您解释原型是什么原型就是所有的组件相同共享组件(SharedComponent)的值相同的实体我们称其为一个原型Unity把对应的原型分成多个chunk,便于查找。了解了原型我们还要知道它在代码中出现的情况。通常情况下只要你给实体添加组件就会有对应的原型唯一用到的地方是你要创建大量的新实体,并且实体上要添加较多组件请不要给每一个实体AddComponent一遍而是创建出对应的原型再统一创建EntityArchetype _bulletArchetype; public void OnCreate(ref SystemState state) { _bulletArchetype state.EntityManager.CreateArchetype( typeof(BulletComponent), typeof(LocalTransform), typeof(LocalToWorld), ); EntityManager.CreateEntity(_bulletArchetype, count, Allocator.Temp); }改变原型既然原型由实体挂载的组件决定那它的原型会不会改变呢答案是肯定的这种情况专业术语称为结构性变化。它会导致chunk中的分布发生变化每一次结构性变化后Unity都会帮你把新原型放到对应的chunk中。这样会很耗性能下面几种情况会导致结构性变化:删除增加实体为实体删除增加组件sharedComponent中的值发生变化低频少量的改变对性能的影响极小可以放心使用如果是高频大量的改变可以考虑以下的方案使用ecb(EntityCommandBuffer),请注意这个是在系统的主线程中使用,它并不会让增删的性能变化只是打上标记在当前帧的帧末调用playback方法统一增删。只是提供安全性并不能提供性能。playback是否手动调用取决于ecb是通过CommandBufferSystem的CreateCommandBuffer方法还是你new出来的。使用ecb的AsParallelWriter()方法它可以为你提供一支多线程安全的笔让你在JobEntity或JobChunk中想用ecb相同的安全性真正能够提供性能的是IEnableComponent它类似IComponentData只是多了一个打开关闭的属性类似Mono中的enable属性我们可以在查找时选择性忽略某个组件被关闭的实体而且它的打开与关闭并不影响实体SharedComponent组件请不要感觉神秘它也类似IComponentData,只不过主要用来充当不常改变的原型相同的公共值取值起来比一般组件更快更省内存你可以把它当成普通组件只要牢记一改变它的值就会发生结构性变化即可ECS中的事件系统回想c#中的事件系统为我们带来了很多便利然而ECS世界中并没有这种便利为了实现这样的效果我们需要自己创建类似的机制原理使用类似监听与命令的方式将事件作为一种组件每当事件发生就挂载到对应的实体上再由监听系统统一处理逻辑。我知道上面这段话很难理解所以接下来为您举一个例子例子首先定义一个事件参数的组件public struct HitEventData:IComponentData { public int Damage; //伤害事件 }接下来的逻辑是满足特定情况时就给实体添加上面的事件常见的比如碰撞这里为了演示方便直接让有Player标签的一直受到Hitpublic particla struct OnHitSystem:System { public void OnUpdate(ref SystemState state) { var playerSystemAPI.GetSingletonEntityPlayer(); AddComponent(player,new HitEventData() { Damage100; });//这里本来是要用ecb,我是为了演示方便 } }最后只需要一个监听系统看看谁身上有HitEventData组件并执行相关逻辑就好了。可以是减少Health组件的值等等这里就交由读者自行完成。最后提一嘴大量添加组件会导致结构性变化…………ECS中的碰撞系统首先想要碰撞请自行导入Unity.Physics包之后可以为SubScene中的对象添加刚体和碰撞体等Mono组件ECS在渲染时会自行为您生成对应的组件。ICollisionEventJob与ITriggerEventJob我们真正需要关心的是碰撞事件的产生好在Unity为我们提供了两个接口用来替代Mono中的OnTriggerEnter等事件。首先我们需要对应的Job事件继承自标题的两种之一[BurstCompile] partial struct CollisionEventJob : ICollisionEventsJob { public ComponentLookupHealth HealthLookup; // Lookup类似Dictionary,以实体为键 [ReadOnly] public ComponentLookupEnemy EnemyLookup; public void Execute(CollisionEvent collisionEvent) { Entity a collisionEvent.EntityA;//发生碰撞的实体A Entity b collisionEvent.EntityB;//发生碰撞的实体B // 根据组件判断谁是敌人谁是子弹 Entity enemy EnemyLookup.HasComponent(a) ? a : b; Entity bullet enemy a ? b : a; if (EnemyLookup.HasComponent(enemy) HealthLookup.HasComponent(enemy)) { Health hp HealthLookup[enemy];//获取敌人的生命组件 hp.Value - 10; // 扣血 HealthLookup[enemy] hp; // 子弹回收 最好用ecb这里演示直接删 // EntityManager.DestroyEntity(bullet); } } }有了Job还不够还需要一个系统[UpdateInGroup(typeof(PhysicsSimulationGroup))] // 必须在这个组里 [UpdateAfter(typeof(PhysicsSimulationGroup))] // 等物理跑完再处理 public partial struct CollisionEventSystem : ISystem { [BurstCompile] public void OnCreate(ref SystemState state) { state.RequireForUpdateSimulationSingleton(); } [BurstCompile] public void OnUpdate(ref SystemState state) { var job new CollisionEventJob { HealthLookup SystemAPI.GetComponentLookupHealth(false), EnemyLookup SystemAPI.GetComponentLookupEnemy(true) }; state.Dependency job.Schedule(SystemAPI.GetSingletonSimulationSingleton(), state.Dependency); } }[UpdateInGroup(typeof(PhysicsSimulationGroup))]这个我忘了有没有在第一节提过了这里提一嘴UpdateInGroup可以决定系统的运行时机这里是在物理组中也可以在初始化组和一般组还有FixedUpdate组等等UpdateAfter/Before可以决定系统的执行顺序这里也包含你自己的系统一搬用到的情况就是读数据在写数据之后。ECS中的对象池系统对象池的核心在于为池中的对象添加Disabled组件Unity已经内置并在需要时直接找寻对应实体并移除Disabled组件这里简单给一个例子为对象池初始化的可以设置预制体和初始大小public class BulletPoolAuthoring : MonoBehaviour { public GameObject prefab; public int size; private class Baker : BakerBulletPoolAuthoring { public override void Bake(BulletPoolAuthoring authoring) { Entity entityGetEntity(TransformUsageFlags.None); AddComponent(entity,new BulletPool() { Prefab GetEntity(authoring.prefab,TransformUsageFlags.Dynamic), PoolSize authoring.size, }); } } }初始化对象池系统,填充对象池只执行一次[WorldSystemFilter(WorldSystemFilterFlags.Default)] partial struct InitBulletPoolSystem : ISystem { private EntityQuery _poolQuery; [BurstCompile] public void OnCreate(ref SystemState state) { _poolQuery state.GetEntityQuery(ComponentType.ReadOnlyBulletPool()); state.RequireForUpdateBulletPool(); } [BurstCompile] public void OnUpdate(ref SystemState state) { state.Enabled false; var ecb new EntityCommandBuffer(Allocator.Temp); var pools_poolQuery.ToComponentDataArrayBulletPool(Allocator.Temp); foreach (var pool in pools) { for (int i 0; i pool.PoolSize; i) { var bullet ecb.Instantiate(pool.Prefab); ecb.AddComponentDisabled(bullet); } } ecb.Playback(state.EntityManager); ecb.Dispose(); }后续想要子弹只要查找有BulletComponent和Disabled组件的实体并删除Disabled组件即可想丢弃子弹就加上Disabled就好了配置表Blob想要实现Unity中的SO最简单又实用的方法就是用一个IComponentData作为配置表当然这里有一个更麻烦的方法但是既然它有就必然有其存在价值这里简单略过首先搞一个SO资产[CreateAssetMenu(fileName PlayerConfig, menuName SO/Config/PlayerConfig)] public class PlayerConfig : ScriptableObject { [Header(基础属性)] public float baseHealth; public float baseMaxHealth; public float baseSpeed; public int baseLevel; public int baseNeedExperience; [Header(视角输入)] public float viewSensitivityX 200f; public float viewSensitivityY 200f; [Header(开火设置)] public float fireRate; public float bulletSpeed; public float bulletDamage; }再用一个结构体接受SO资产public struct PlayerConfigBlob { public float BaseHealth; public float BaseMaxHealth; public float BaseSpeed; public int BaseLevel; public int BaseNeedExperience; public float ViewSensitivityX ; public float ViewSensitivityY; public float FireRate; public float BulletSpeed; public float BulletDamage; }还有一个组件数据来接收public struct PlayerConfigComponent : IComponentData { public BlobAssetReferencePlayerConfigBlob ConfigBlob;//一个引用 }再来一个辅助方法实现从SO到Blob的转化public static BlobAssetReferencePlayerConfigBlob ConvertPlayerConfigBlob(PlayerConfig so) { if (so null) { Debug.LogError(没有玩家配置表); return default; } using var builder new BlobBuilder(Allocator.Temp); ref var blobData ref builder.ConstructRootPlayerConfigBlob(); //要求获得一片内存区域的引用 blobData.BaseHealth so.baseHealth; blobData.BaseLevel so.baseLevel; blobData.BaseMaxHealth so.baseMaxHealth; blobData.BaseNeedExperience so.baseNeedExperience; blobData.BaseSpeed so.baseSpeed; blobData.BulletDamage so.bulletDamage; blobData.BulletSpeed so.bulletSpeed; blobData.FireRate so.fireRate; blobData.ViewSensitivityX so.viewSensitivityX; blobData.ViewSensitivityY so.viewSensitivityY; //冻结成只读资产并返回一个只读引用 var blobRef builder.CreateBlobAssetReferencePlayerConfigBlob(Allocator.Persistent); return blobRef; }最后烘培即可[SerializeField] private PlayerConfig config; public PlayerConfig Config config; private class Baker : BakerPlayerAuthoring { public override void Bake(PlayerAuthoring authoring) { if (authoring.Config null) { Debug.LogError(${nameof(authoring.Config)} is null); return; } Entity entityGetEntity(TransformUsageFlags.Dynamic); var blobConfigBlobConverter.ConvertPlayerConfigBlob(authoring.Config); if (!blob.IsCreated) { Debug.LogError(${nameof(authoring.Config)} is not created); return; } //用引用计数防止假死 AddBlobAsset(ref blob, out var hash); //清除警告 _ hash; //这个组件留着当备胎以后需要了才用 AddComponent(entity,new PlayerConfigComponent() { ConfigBlobblob, }); } }绕了这么大一圈其实真不如一个IComponentData来的快吧结语ECS后面应该就是学一些场景方面的内容了看看寒假之前会不会有第三节吧

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询