Unity ECS 实战指南:基于 agents24 仓库 unity-ecs-patterns 技能的 DOTS、Jobs 与 Burst 高性能游戏开发模式
Unity ECS 实战指南基于 agents24 仓库 unity-ecs-patterns 技能的 DOTS、Jobs 与 Burst 高性能游戏开发模式【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents本篇技术指南以 agents24 仓库中 plugins/game-development/skills/unity-ecs-patterns/SKILL.md 及其 references/details.md 为主体系统讲解 Unity 面向数据技术栈DOTS中 ECS、Job System 与 Burst Compiler 的生产级实践模式。读完本文你将掌握从 ECS 组件设计、ISystem 系统编写、实体查询、命令缓冲、Aspect 分组、单例组件、GameObject 烘焙到 Native 集合并行 Job 的完整落地方案可直接用于大规模实体数量场景的 CPU 性能优化与 OOP 代码到 ECS 的迁移。技能背景插件市场中的渐进式披露设计unity-ecs-patterns是 agents24 仓库「多工具链 Agent 插件市场」中 game-development 插件 下的一枚技能包与 unity-developer.mdUnity 开发者 Agent和godot-gdscript-patterns技能同属游戏开发领域。该仓库面向 Claude Code、Codex、Cursor、OpenCode、GitHub Copilot 与 Google Antigravity 等多种工具链分发 Agent 技能在 docs/agent-skills.md 的 Game Development 分类中登记为「为高性能游戏系统实现 Unity ECS」。该技能采用了文档体系中推荐的**渐进式披露progressive disclosure**结构见 docs/authoring.mdSKILL.md作为导航层与快速上手入口控制体积Codex 会硬截断超过 8 KB 的技能正文而完整的模式与可运行示例下沉到references/details.md由 Agent 按需加载。因此本指南在讲解时导航层的核心概念ECS vs OOP、DOTS 组件与深度层的 8 个实战模式会一并展开保证信息密度不低于原文。何时使用本技能构建需要高帧率与大批量实体管理的高性能 Unity 游戏管理成千上万个实体敌人、子弹、粒子等并保持线性扩展采用数据导向架构设计游戏系统摆脱面向对象的内存碎片优化 CPU 密集型的游戏逻辑碰撞、空间哈希、寻路、战斗结算将传统 OOP 游戏代码迁移到 ECS 架构使用 Job System 与 Burst Compiler 实现多核并行化。核心概念一ECS 与 OOP 的本质差异SKILL.md用一张对比表直接点明两种范式的关键差异这也是理解整个技能体系的出发点AspectTraditional OOPECS/DOTSData layoutObject-orientedData-orientedMemoryScatteredContiguousProcessingPer-objectBatchedScalingPoor with countLinear scalingBest forComplex behaviorsMass simulation传统 OOP 将数据与行为封装在对象中对象在堆上散布缓存不友好实体数量增长后性能急剧下降ECS 将数据按组件类型连续排列在 Chunk 内存块中系统以批处理方式遍历同构数据配合多线程与 Burst 编译可达到随实体数量线性扩展的性能。因此 ECS 的最优适用场景是「大规模模拟」而复杂对象行为交互仍可保留 OOP 的组织方式。核心概念二DOTS 五大构件SKILL.md用一段简洁的代码块概括了 DOTS 的核心抽象逐条拆解如下Entity: Lightweight ID (no data) // 实体仅是一个轻量 ID本身不携带数据 Component: Pure data (no behavior) // 组件纯数据不含行为 System: Logic that processes components // 系统处理组件的逻辑 World: Container for entities // 世界实体的容器 Archetype: Unique combination of components // 原型组件的唯一组合 Chunk: Memory block for same-archetype entities // Chunk同原型实体的连续内存块Entity只是指向原型与 Chunk 内部索引的轻量标识创建和销毁的成本极低Component是结构体struct形式的纯数据这是 Burst 能否优化的关键前提System负责以查询Query方式批量处理组件数据不直接持有实体引用World在 DOTS 1.0 中通常是默认的单例世界通过state.WorldUnmanaged访问Archetype决定实体在哪个 Chunk 中存储相同组件组合的实体共享同一 ArchetypeChunk是固定容量的内存块同 Archetype 的实体数据在其中连续排列实现缓存友好的顺序遍历。这也是后续「chunk 利用率」最佳实践的底层依据。实战模式一基础 ECS 设置组件族谱来自 references/details.md 的 Pattern 1 展示了 ECS 中全部四种核心组件类型的定义方式这是所有后续模式的地基using Unity.Entities; using Unity.Mathematics; using Unity.Transforms; using Unity.Burst; using Unity.Collections; // Component: Pure data, no methods public struct Speed : IComponentData { public float Value; } public struct Health : IComponentData { public float Current; public float Max; } public struct Target : IComponentData { public Entity Value; } // Tag component (zero-size marker) public struct EnemyTag : IComponentData { } public struct PlayerTag : IComponentData { } // Buffer component (variable-size array) [InternalBufferCapacity(8)] public struct InventoryItem : IBufferElementData { public int ItemId; public int Quantity; } // Shared component (grouped entities) public struct TeamId : ISharedComponentData { public int Value; }要点解读IComponentData是 ECS 的基本组件必须是struct值类型Value字段直接以原始值存储Burst 可完全内联优化Tag 组件EnemyTag、PlayerTag是零大小的标记组件专用于查询筛选如WithAllEnemyTag()不占用额外内存Buffer 组件IBufferElementData表示变长数组[InternalBufferCapacity(8)]指定内联缓冲区容量——前 8 个元素直接存储在 Chunk 内超出部分才走外部堆分配可显著减少小数组的内存分配开销Shared 组件ISharedComponentData使拥有相同值的实体在 Chunk 中彼此相邻存放适合按队伍TeamId、LOD 层级、动画状态等分组批量处理的场景。注意 Shared 组件的值是引用类型语义Equals/GetHashCode实现会影响分组粒度。实战模式二用 ISystem 编写系统官方推荐Pattern 2 给出了两种系统写法。第一种是ISystemSystemAPI.Query的 foreach 简化写法编译器自动为循环生成 Job第二种是显式声明IJobEntityJob 以获得更细粒度的控制using Unity.Entities; using Unity.Transforms; using Unity.Mathematics; using Unity.Burst; // ISystem: Unmanaged, Burst-compatible, highest performance [BurstCompile] public partial struct MovementSystem : ISystem { [BurstCompile] public void OnCreate(ref SystemState state) { // Require components before system runs state.RequireForUpdateSpeed(); } [BurstCompile] public void OnUpdate(ref SystemState state) { float deltaTime SystemAPI.Time.DeltaTime; // Simple foreach - auto-generates job foreach (var (transform, speed) in SystemAPI.QueryRefRWLocalTransform, RefROSpeed()) { transform.ValueRW.Position new float3(0, 0, speed.ValueRO.Value * deltaTime); } } [BurstCompile] public void OnDestroy(ref SystemState state) { } } // With explicit job for more control [BurstCompile] public partial struct MovementJobSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { var job new MoveJob { DeltaTime SystemAPI.Time.DeltaTime }; state.Dependency job.ScheduleParallel(state.Dependency); } } [BurstCompile] public partial struct MoveJob : IJobEntity { public float DeltaTime; void Execute(ref LocalTransform transform, in Speed speed) { transform.Position new float3(0, 0, speed.Value * DeltaTime); } }关键设计决策ISystem 优于 SystemBaseISystem是struct类型的非托管系统生命周期由 World 管理天然支持 Burst 编译且无托管对象开销性能显著高于基于类的SystemBaseRefRWT/RefROT语义明确标注「读写」与「只读」让 Job Scheduler 能安全地进行读写依赖分析与并行调度——只读组件之间可以完全并行state.RequireForUpdateSpeed()在没有匹配实体时跳过整个系统更新避免空循环开销ScheduleParallel与state.DependencyJob 链通过JobHandle传递依赖保证跨系统的数据安全同时最大化多核利用率。实战模式三实体查询Entity QueryPattern 3 展示了查询的两种用法——声明式的EntityQueryBuilder与简洁的SystemAPI.Query[BurstCompile] public partial struct QueryExamplesSystem : ISystem { private EntityQuery _enemyQuery; public void OnCreate(ref SystemState state) { // Build query manually for complex cases _enemyQuery new EntityQueryBuilder(Allocator.Temp) .WithAllEnemyTag, Health, LocalTransform() .WithNoneDead() .WithOptions(EntityQueryOptions.FilterWriteGroup) .Build(ref state); } [BurstCompile] public void OnUpdate(ref SystemState state) { // SystemAPI.Query - simplest approach foreach (var (health, entity) in SystemAPI.QueryRefRWHealth() .WithAllEnemyTag() .WithEntityAccess()) { if (health.ValueRO.Current 0) { // Mark for destruction SystemAPI.GetSingletonEndSimulationEntityCommandBufferSystem.Singleton() .CreateCommandBuffer(state.WorldUnmanaged) .DestroyEntity(entity); } } // Get count int enemyCount _enemyQuery.CalculateEntityCount(); // Get all entities var enemies _enemyQuery.ToEntityArray(Allocator.Temp); // Get component arrays var healths _enemyQuery.ToComponentDataArrayHealth(Allocator.Temp); } }要点WithAll/WithNone分别表示「必须包含」与「必须不包含」的组件集合组合使用可以精确圈定查询范围EntityQueryOptions.FilterWriteGroup启用 WriteGroup 过滤用于解决多个系统写同一组件时的语义冲突如位置被移动系统与物理系统共同修改时显式声明所有权WithEntityAccess()在迭代时同时拿到Entity句柄便于将实体交给 ECB 延迟销毁临时数组的 AllocatorAllocator.Temp是栈上/每帧临时分配帧末自动回收适合每帧查询跨帧持久的数组应改用Allocator.Persistent并手动Dispose。实战模式四Entity Command Buffers结构变更Pattern 4 是全套模式中最重要的并发安全知识点。创建/销毁实体、增删组件属于结构性变更structural change会触发同步点sync point绝不允许在 Job 内直接执行——必须通过实体命令缓冲ECB延迟到帧末统一应用// Structural changes (create/destroy/add/remove) require command buffers [BurstCompile] [UpdateInGroup(typeof(SimulationSystemGroup))] public partial struct SpawnSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { var ecbSingleton SystemAPI.GetSingletonBeginSimulationEntityCommandBufferSystem.Singleton(); var ecb ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged); foreach (var (spawner, transform) in SystemAPI.QueryRefRWSpawner, RefROLocalTransform()) { spawner.ValueRW.Timer - SystemAPI.Time.DeltaTime; if (spawner.ValueRO.Timer 0) { spawner.ValueRW.Timer spawner.ValueRO.Interval; // Create entity (deferred until sync point) Entity newEntity ecb.Instantiate(spawner.ValueRO.Prefab); // Set component values ecb.SetComponent(newEntity, new LocalTransform { Position transform.ValueRO.Position, Rotation quaternion.identity, Scale 1f }); // Add component ecb.AddComponent(newEntity, new Speed { Value 5f }); } } } } // Parallel ECB usage [BurstCompile] public partial struct ParallelSpawnJob : IJobEntity { public EntityCommandBuffer.ParallelWriter ECB; void Execute([EntityIndexInQuery] int index, in Spawner spawner) { Entity e ECB.Instantiate(index, spawner.Prefab); ECB.AddComponent(index, e, new Speed { Value 5f }); } }要点ECB 的获取方式通过SystemAPI.GetSingletonBeginSimulationEntityCommandBufferSystem.Singleton()帧开始或EndSimulationEntityCommandBufferSystem.Singleton帧结束Pattern 3 的销毁逻辑即使用它在系统更新循环外获取循环内复用同一个 ECBEntityCommandBuffer.ParallelWriter并行 Job 中必须使用ParallelWriter并把 Job 内的实体索引index作为第一个参数传入所有 ECB 方法保证多线程写入 ECB 内部缓冲的顺序安全延迟语义Instantiate/AddComponent/DestroyEntity只是记录命令真正执行发生在同步点因此循环内反复生成实体不会破坏当前查询的 Chunk 迭代。实战模式五Aspect组件分组与领域接口Pattern 5 用IAspect把相关联的组件封装为面向领域语义的只读视图是「Clean component grouping」最佳实践的落地形态using Unity.Entities; using Unity.Transforms; using Unity.Mathematics; // Aspect: Groups related components for cleaner code public readonly partial struct CharacterAspect : IAspect { public readonly Entity Entity; private readonly RefRWLocalTransform _transform; private readonly RefROSpeed _speed; private readonly RefRWHealth _health; // Optional component [Optional] private readonly RefROShield _shield; // Buffer private readonly DynamicBufferInventoryItem _inventory; public float3 Position { get _transform.ValueRO.Position; set _transform.ValueRW.Position value; } public float CurrentHealth _health.ValueRO.Current; public float MaxHealth _health.ValueRO.Max; public float MoveSpeed _speed.ValueRO.Value; public bool HasShield _shield.IsValid; public float ShieldAmount HasShield ? _shield.ValueRO.Amount : 0f; public void TakeDamage(float amount) { float remaining amount; if (HasShield _shield.ValueRO.Amount 0) { // Shield absorbs damage first remaining math.max(0, amount - _shield.ValueRO.Amount); } _health.ValueRW.Current math.max(0, _health.ValueRO.Current - remaining); } public void Move(float3 direction, float deltaTime) { _transform.ValueRW.Position direction * _speed.ValueRO.Value * deltaTime; } public void AddItem(int itemId, int quantity) { _inventory.Add(new InventoryItem { ItemId itemId, Quantity quantity }); } } // Using aspect in system [BurstCompile] public partial struct CharacterSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { float dt SystemAPI.Time.DeltaTime; foreach (var character in SystemAPI.QueryCharacterAspect()) { character.Move(new float3(1, 0, 0), dt); if (character.CurrentHealth character.MaxHealth * 0.5f) { // Low health logic } } } }设计价值readonly partial structAspect 必须是只读结构体其字段为RefRW/RefRO/DynamicBuffer包装编译器据此生成查询与访问代码[Optional]组件用特性标记的组件在实体缺失时IsValid为 false调用方可用HasShield安全降级避免为「可有可无」的数据强行拆分系统领域方法收敛TakeDamage、Move、AddItem把组件读写封装成语义操作系统内迭代代码变得极简如character.Move(...)同时仍完全保留 Burst 内联优化能力——Aspect 是纯编译期抽象零运行时开销。实战模式六Singleton 组件全局配置与状态Pattern 6 解决「全局唯一的游戏配置/状态」问题。任何IComponentData都可以通过确保全 World 只有一个实体携带它来充当单例// Singleton: Exactly one entity with this component public struct GameConfig : IComponentData { public float DifficultyMultiplier; public int MaxEnemies; public float SpawnRate; } public struct GameState : IComponentData { public int Score; public int Wave; public float TimeRemaining; } // Create singleton on world creation public partial struct GameInitSystem : ISystem { public void OnCreate(ref SystemState state) { var entity state.EntityManager.CreateEntity(); state.EntityManager.AddComponentData(entity, new GameConfig { DifficultyMultiplier 1.0f, MaxEnemies 100, SpawnRate 2.0f }); state.EntityManager.AddComponentData(entity, new GameState { Score 0, Wave 1, TimeRemaining 120f }); } } // Access singleton in system [BurstCompile] public partial struct ScoreSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { // Read singleton var config SystemAPI.GetSingletonGameConfig(); // Write singleton ref var gameState ref SystemAPI.GetSingletonRWGameState().ValueRW; gameState.TimeRemaining - SystemAPI.Time.DeltaTime; // Check exists if (SystemAPI.HasSingletonGameConfig()) { // ... } } }要点GetSingletonT()读取、GetSingletonRWT()写写访问返回ref引用注意GetSingletonRW会引入与其他系统的写冲突依赖频繁写入的单例应尽量拆分到独立系统处理HasSingletonT()用于在单例可能尚未创建例如系统更新顺序早于初始化系统时做防御性判断初始化时机GameInitSystem.OnCreate在世界创建阶段调用EntityManager直接创建实体并添加组件后续所有系统即可安全GetSingleton。实战模式七BakingGameObject 到 ECS 的转换Pattern 7 覆盖了 DOTS 1.0 的子场景SubScene工作流美术/策划在场景中用 MonoBehaviour 配置数据编译期由 Baker 转换为 ECS 组件。EnemyAuthoring是编辑器侧的 Authoring 组件内嵌BakerEnemyAuthoring定义转换逻辑using Unity.Entities; using UnityEngine; // Authoring component (MonoBehaviour in Editor) public class EnemyAuthoring : MonoBehaviour { public float Speed 5f; public float Health 100f; public GameObject ProjectilePrefab; class Baker : BakerEnemyAuthoring { public override void Bake(EnemyAuthoring authoring) { var entity GetEntity(TransformUsageFlags.Dynamic); AddComponent(entity, new Speed { Value authoring.Speed }); AddComponent(entity, new Health { Current authoring.Health, Max authoring.Health }); AddComponent(entity, new EnemyTag()); if (authoring.ProjectilePrefab ! null) { AddComponent(entity, new ProjectilePrefab { Value GetEntity(authoring.ProjectilePrefab, TransformUsageFlags.Dynamic) }); } } } } // Complex baking with dependencies public class SpawnerAuthoring : MonoBehaviour { public GameObject[] Prefabs; public float Interval 1f; class Baker : BakerSpawnerAuthoring { public override void Bake(SpawnerAuthoring authoring) { var entity GetEntity(TransformUsageFlags.Dynamic); AddComponent(entity, new Spawner { Interval authoring.Interval, Timer 0f }); // Bake buffer of prefabs var buffer AddBufferSpawnPrefabElement(entity); foreach (var prefab in authoring.Prefabs) { buffer.Add(new SpawnPrefabElement { Prefab GetEntity(prefab, TransformUsageFlags.Dynamic) }); } // Declare dependencies DependsOn(authoring.Prefabs); } } }要点TransformUsageFlags.Dynamic声明实体的 Transform 是动态变换的Baker 据此决定是否附加LocalTransform等内置组件GetEntity(引用)把场景/预制体引用转换为实体引用多个 Authoring 通过它建立实体间关联AddBufferT(entity)烘焙缓冲组件把数组字段烘焙为IBufferElementData缓冲与运行时 Pattern 1 的InventoryItem用法对应DependsOn声明依赖当 Baker 读取了其他 GameObject 时必须调用DependsOn否则变更这些对象不会触发正确重烘焙。实战模式八Jobs 与 Native 集合空间哈希实战Pattern 8 是一个完整的「空间哈希」多线程并行化示例将前面的知识点串联成一个可落地的性能优化场景——例如用于万级单位的邻近查询或碰撞粗筛using Unity.Jobs; using Unity.Collections; using Unity.Burst; using Unity.Mathematics; [BurstCompile] public struct SpatialHashJob : IJobParallelFor { [ReadOnly] public NativeArrayfloat3 Positions; // Thread-safe write to hash map public NativeParallelMultiHashMapint, int.ParallelWriter HashMap; public float CellSize; public void Execute(int index) { float3 pos Positions[index]; int hash GetHash(pos); HashMap.Add(hash, index); } int GetHash(float3 pos) { int x (int)math.floor(pos.x / CellSize); int y (int)math.floor(pos.y / CellSize); int z (int)math.floor(pos.z / CellSize); return x * 73856093 ^ y * 19349663 ^ z * 83492791; } } [BurstCompile] public partial struct SpatialHashSystem : ISystem { private NativeParallelMultiHashMapint, int _hashMap; public void OnCreate(ref SystemState state) { _hashMap new NativeParallelMultiHashMapint, int(10000, Allocator.Persistent); } public void OnDestroy(ref SystemState state) { _hashMap.Dispose(); } [BurstCompile] public void OnUpdate(ref SystemState state) { var query SystemAPI.QueryBuilder() .WithAllLocalTransform() .Build(); int count query.CalculateEntityCount(); // Resize if needed if (_hashMap.Capacity count) { _hashMap.Capacity count * 2; } _hashMap.Clear(); // Get positions var positions query.ToComponentDataArrayLocalTransform(Allocator.TempJob); var posFloat3 new NativeArrayfloat3(count, Allocator.TempJob); for (int i 0; i count; i) { posFloat3[i] positions[i].Position; } // Build hash map var hashJob new SpatialHashJob { Positions posFloat3, HashMap _hashMap.AsParallelWriter(), CellSize 10f }; state.Dependency hashJob.Schedule(count, 64, state.Dependency); // Cleanup positions.Dispose(state.Dependency); posFloat3.Dispose(state.Dependency); } }工程要点NativeParallelMultiHashMapint,int一对多的并行安全哈希表ParallelWriter让多个工作线程并发写入同一哈希桶[ReadOnly]标记声明Positions只读使 Job Scheduler 允许该 Job 与其他只读 Job 并行执行[EntityIndexInQuery]/IJobParallelFor索引Execute(int index)由调度器以批次batchSchedule(count, 64, ...)中 64 为每批元素数分发到线程生命周期纪律Allocator.Persistent的字段在OnCreate分配、OnDestroy释放每帧的临时数组在Schedule后通过Dispose(state.Dependency)挂到 Job 依赖链上确保 Job 完成后才回收——这正是SKILL.md「Dont forget disposal」规则的直接体现容量动态调整实体数量超过当前容量时先扩容count * 2再Clear()复用避免每帧重新分配。性能优化要点与最佳实践details.md末尾的性能建议与SKILL.md的 Dos/Donts 互为表里归纳为以下可执行清单// 1. Use Burst everywhere [BurstCompile] public partial struct MySystem : ISystem { } // 2. Prefer IJobEntity over manual iteration [BurstCompile] partial struct OptimizedJob : IJobEntity { void Execute(ref LocalTransform transform) { } } // 3. Schedule parallel when possible state.Dependency job.ScheduleParallel(state.Dependency); // 4. Use ScheduleParallel with chunk iteration [BurstCompile] partial struct ChunkJob : IJobChunk { public ComponentTypeHandleHealth HealthHandle; public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask) { var healths chunk.GetNativeArray(ref HealthHandle); for (int i 0; i chunk.Count; i) { // Process } } } // 5. Avoid structural changes in hot paths // Use enableable components instead of add/remove public struct Disabled : IComponentData, IEnableableComponent { }Dos应当遵循ISystem 优先于 SystemBase前者是非托管结构体系统天然支持 Burst性能更好全量 Burst 编译为系统与 Job 标注[BurstCompile]可获得数量级的指令优化SIMD、去托管检查批量结构变更创建/销毁实体一律走 ECB减少同步点次数用 Profiler 定位瓶颈结合 Unity Profiler 与 Burst Inspector 确认热点确实在 ECS 代码中用 Aspect 做组件分组让系统代码保持领域语义清晰同时零运行时开销。Donts必须避免不使用托管类型class、string、ListT等托管引用会破坏 Burst 编译迫使数据落入托管堆拖垮缓存性能不在 Job 内做结构变更同步点会序列化整个 Job 链抵消并行收益必须改用 ECB不过度架构先以简单 foreach 起步确认瓶颈后再引入手动 Job 与 Chunk 级优化不忽略 Chunk 利用率Chunk 容量固定约 128 个实体应避免大量「半空 Chunk」——把共享同质组件如 Shared 组件、Enableable 标记的实体聚合减少碎片与遍历损耗不忘记释放 Native 集合NativeArray、NativeParallelMultiHashMap等若在OnDestroy或 Job 依赖链上漏掉Dispose会造成无法回收的原生内存泄漏。热点路径的结构变更替代方案当需要在运行时大量「禁用/启用」实体时与其反复AddComponent/RemoveComponent每次都是结构变更不如使用可启用组件IEnableableComponent实体保留组件但被查询默认排除切换成本远低于结构变更且不会打断 Chunk 遍历。上述代码中的Disabled : IComponentData, IEnableableComponent正是这一模式的标注示例。如何在多工具链环境中使用该技能在 agents24 仓库中技能可通过多种方式引入你的开发环境直接阅读导航层见 SKILL.md完整模式与可运行代码见 references/details.md配合 Agent 使用由 unity-developer.md 定义的 Unity 开发者 Agent 会主动运用本技能覆盖 Unity 6 LTS、URP/HDRP 渲染管线、Job System/Burst、跨平台优化等场景安装与分发该技能遵循 Agent Skills 规范frontmatter 含name与description的 Use when 激活条件可经gh skill install/npx skills add按路径安装并会由仓库的适配器转换为 Codex、OpenCode、Copilot、Antigravity 等工具链所需的技能格式细节见 docs/harnesses.md 与 docs/authoring.md。结语从组件类型选择、ISystem 编写、查询过滤、ECB 并发安全到 Aspect 抽象、单例管理、GameObject 烘焙与 Native 集合并行 Jobunity-ecs-patterns提供了一条从 OOP 思维过渡到数据导向架构的完整路径。落地时始终牢记三条主线数据要连续Archetype/Chunk、逻辑要并行Job/Burst、变更要延迟ECB。将导航层的设计原则与 references 层的 8 个模式配合使用即可在数千实体规模下获得线性扩展的高性能游戏逻辑同时保持代码的可读性与可维护性。【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考