La interfaz está localizada; las descripciones y documentos de las Skills se traducen automáticamente con IA a su idioma. El código, los comandos, rutas y términos técnicos se mantienen en el original, y prevalece el documento del autor.
Explorar Skills
Desarrollo · SKILL.md

unity-csharp

unity-csharp

Unity C# scripting and DOTS/ECS mechanics - component systems, Jobs, Burst, archetypes/chunks, async patterns, and C# performance in game code.

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentación de la Skill

GitHub

name: unity-csharp description: Unity C# scripting and DOTS/ECS mechanics - component systems, Jobs, Burst, archetypes/chunks, async patterns, and C# performance in game code.

Unity Data-Oriented Technology Stack (DOTS) & C# Mechanics

This skill covers Unity's data-oriented stack (ECS, Job System, Burst) and the C# practices that make Unity code fast and correct.

1. Why DOTS: The OOP-Based Entry Points

Unity's classic MonoBehaviour model is object-oriented: each Behaviour instance owns its fields, script lifecycle callbacks run per frame, and objects reference each other. For 10k+ entities, per-object Update() incurs:

  • A virtual-call-like dispatch per object per frame.
  • Arbitrary memory layout → cache misses.
  • Heap fragmentation from per-frame allocation.

DOTS replaces this with contiguous data and systems-in-a-loop.

2. ECS Model in Unity

2.1 Entities, Components, Systems

// Component: struct, blittable, data-only
public struct Velocity : IComponentData {
    public float3 Linear;
    public float Angular;
}

// System: logic over queries
[BurstCompile]
public partial struct MoveSystem : ISystem {
    [BurstCompile]
    public void OnUpdate(ref SystemState state) {
        var dt = SystemAPI.Time.DeltaTime;
        foreach (var (tf, v) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<Velocity>>()) {
            tf.ValueRW.Position += v.ValueRO.Linear * dt;
        }
    }
}

2.2 Archetypes & Chunks (Storage)

  • Archetype: unique set of component types. An entity's archetype determines its storage.
  • Chunk: a 16 KB block of memory holding entities of one archetype in SoA form.
Chunk 0 [Archetype: LocalTransform+Velocity ]
  Transform array: | t0 | t1 | t2 | ... | (contiguous)
  Velocity  array: | v0 | v1 | v2 | ... | (contiguous)
  • Iteration of a query walks matching chunks, so the CPU streams compact arrays into L1/L2.
  • ChangeVersion per-chunk tracks modification for change-detect systems.

2.3 Structural Changes (Command Buffers)

Adding/removing components moves the entity to another archetype (memcpy of affected fields). Doing this mid-iteration invalidates chunk iteration → use EntityCommandBuffer:

EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.Temp);
// queue AddComponent / SetComponent / DestroyEntity
ecb.Playback(state.EntityManager);

Rules: never call EntityManager.AddComponent inside ScheduleParallel jobs; always buffer.

3. The C# Job System

3.1 IJobEntity / IJobChunk

[BurstCompile]
public partial struct DamageJob : IJobEntity {
    public float Damage;
    void Execute(ref Health health) { health.Value -= Damage; }
}

var handle = new DamageJob { Damage = 5f }.Schedule(state.Dependency);
state.Dependency = handle;   // chain dependencies
  • Jobs run on worker threads; dependencies serialize through JobHandle.
  • [ReadOnly] / [WriteOnly] / [DisableContainerSafetyRestriction] on component access let Burst AND the safety system reason about aliasing.

3.2 ParallelFor

[DisableParallelForRestriction]
job.ScheduleParallel()   // splits entities across threads
  • Race hazards: only write disjoint slices (NativeArray<T> per-chunk).
  • Use NativeParallelHashMap/NativeAtomic for cross-thread aggregation.

4. Burst Compiler

  • Converts IL → native via LLVM. Uses SIMD automatically from SoA iteration.
  • Requires [BurstCompile] + job code to be Burst-compatible:
    • No managed references, no allocations, no strings in hot jobs.
    • Use float3, FixedString, NativeArray (not List<T>).
  • Burst.CompileSynchronously for predictable startup; assert no managed exceptions.

4.1 Burst-Compatible Data Types

UseAvoid
float3/float4x4/quaternion (Unity.Mathematics)Vector3/Matrix4x4 (managed overhead)
NativeArray<T>, NativeList<T>, NativeHashMapList<T>, Dictionary<K,V>
int4/uint4System.Numerics types
Burst.CompileSynchronously()exceptions/casting in hot path

5. C# Patterns for Game Code (Non-DOTS)

5.1 Avoiding Allocation Churn (GC Spikes)

Unity's managed GC pauses frames. Hot-path rules:

  • No string concatenation per frame (use StringBuilder pooled, or FixedString128Bytes).
  • No boxing: avoid object params, IEnumerable foreach on List/Dictionary where possible (or cache enumerator).
  • Reuse arrays: cache T[] buffers as static/class fields; ArrayPool<T> for bigger needs.
  • Avoid LINQ in Update (allocates enumerators): Where/Select/OrderBy — replace with loops.

5.2 Value Types for Gameplay State

public struct PlayerState { public int Id; public float Hp; public float2 Pos; public int TeamId; }
  • Structs avoid heap alloc per instance; but watch copying large structs.
  • Store state in NativeArray<PlayerState> when used with jobs; in plain arrays for serialization.

5.3 Async / Await Patterns

// UnityWebRequest + async
async void LoadLevelAsync() {
    var req = UnityWebRequest.Get(url);
    var op = await req.SendWebRequest();
    // post-process on main thread
}
  • async void only for event handlers; prefer async Task.
  • Never touch the scene graph from a background thread; marshal via MainThread dispatcher.
  • Use Addressables.LoadAssetAsync + .Completed to keep loads off the frame.

5.4 Singletons & Service Locators

public sealed class GameManager : MonoBehaviour {
    public static GameManager I { get; private set; }
    void Awake() { I = this; }          // Set only if null at scene start
    void OnDestroy() { if (I == this) I = null; }
}

6. Serialization & Persistence

  • [SerializeField] fields for inspector persistence.
  • ISerializationCallbackReceiver for custom (de)serialization hooks.
  • For save data: JSON (JsonUtility / Newtonsoft) on managed side, or custom bin with Buffer.BinaryWriter for versioned saves.
  • Never serialize large live ECS state; snapshot to stable DTOs on save.

7. Compilation & asmdef

  • .asmdef per system group → parallel module compile, controlled references.
  • unsafe blocks (rarely needed) need Allow 'unsafe' Code project setting.
  • PlayerPrefs deprecated in favor of Application.persistentDataPath + files, or Unity Cloud Save for live ops.

8. Profiling C#

  • Unity Profiler "C#" module: allocations, GC mark/sweep, script cost.
  • [BurstCompile] + Burst Inspector to verify SIMD usage (Show dot-product).
  • try/catch in Update: avoid exceptions per frame; let one crash surface early.
  • Debug.Log in hot loops: disable in production (#if UNITY_EDITOR || DEVELOPMENT_BUILD).

9. C# Best-Practice Cheat Sheet

RuleWhy
Prefer TryGetComponent over GetComponentavoids exception/lookup cost
Cache Camera.maincamera lookup is static-per-frame expensive
Begin/End sample with profiler markersmeasure before optimizing
Use Mathf.Approximately sparinglybranchy; use tolerance math
Pre-allocate everything oncecache and pool
Avoid FindObjectOfTypescans scene; expensive
Prefer fixed-point for sync systemsdeterminism across devices

10. Decision: DOTS vs MonoBehaviour

CriterionDOTS/ECS+JobsMonoBehaviour
100k entities / massive crowdsStrongPoor
Rapid UI/prototypePoorExcellent
Deep gameplay narrative logicMore setupNatural
Physics via Individual BodiesHas DOTS PhysicsPhysX direct
Shader/instancing synergyGPU-instancing friendlyManual

Rule: mix intelligently — DOTS for the simulation hot-path, MonoBehaviours for the editors/design-facing layers.

11. References

  • skills/game/game-engine/ecs-pattern/SKILL.md — ECS deep internals (archetype storage, scheduling)
  • skills/game/game-engine/ecs-pattern/references/unity-dots-in-practice.md — real project DOTS usage
  • skills/game/unity/SKILL.md — full Unity engine guide
  • Unity Learn: "ECS for game craft" and Burst docs
Skills guardadas