brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
unity-csharpUnity 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
This skill covers Unity's data-oriented stack (ECS, Job System, Burst) and the C# practices that make Unity code fast and correct.
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:
DOTS replaces this with contiguous data and systems-in-a-loop.
// 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;
}
}
}
Chunk 0 [Archetype: LocalTransform+Velocity ]
Transform array: | t0 | t1 | t2 | ... | (contiguous)
Velocity array: | v0 | v1 | v2 | ... | (contiguous)
ChangeVersion per-chunk tracks modification for change-detect systems.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.
[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
JobHandle.[ReadOnly] / [WriteOnly] / [DisableContainerSafetyRestriction] on component access let Burst AND the safety system reason about aliasing.[DisableParallelForRestriction]
job.ScheduleParallel() // splits entities across threads
NativeArray<T> per-chunk).NativeParallelHashMap/NativeAtomic for cross-thread aggregation.[BurstCompile] + job code to be Burst-compatible:
float3, FixedString, NativeArray (not List<T>).Burst.CompileSynchronously for predictable startup; assert no managed exceptions.| Use | Avoid |
|---|---|
float3/float4x4/quaternion (Unity.Mathematics) | Vector3/Matrix4x4 (managed overhead) |
NativeArray<T>, NativeList<T>, NativeHashMap | List<T>, Dictionary<K,V> |
int4/uint4 | System.Numerics types |
Burst.CompileSynchronously() | exceptions/casting in hot path |
Unity's managed GC pauses frames. Hot-path rules:
StringBuilder pooled, or FixedString128Bytes).object params, IEnumerable foreach on List/Dictionary where possible (or cache enumerator).T[] buffers as static/class fields; ArrayPool<T> for bigger needs.LINQ in Update (allocates enumerators): Where/Select/OrderBy — replace with loops.public struct PlayerState { public int Id; public float Hp; public float2 Pos; public int TeamId; }
NativeArray<PlayerState> when used with jobs; in plain arrays for serialization.// 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.MainThread dispatcher.Addressables.LoadAssetAsync + .Completed to keep loads off the frame.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; }
}
[SerializeField] fields for inspector persistence.ISerializationCallbackReceiver for custom (de)serialization hooks.JsonUtility / Newtonsoft) on managed side, or custom bin with Buffer.BinaryWriter for versioned saves..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.[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).| Rule | Why |
|---|---|
Prefer TryGetComponent over GetComponent | avoids exception/lookup cost |
Cache Camera.main | camera lookup is static-per-frame expensive |
| Begin/End sample with profiler markers | measure before optimizing |
Use Mathf.Approximately sparingly | branchy; use tolerance math |
| Pre-allocate everything once | cache and pool |
Avoid FindObjectOfType | scans scene; expensive |
| Prefer fixed-point for sync systems | determinism across devices |
| Criterion | DOTS/ECS+Jobs | MonoBehaviour |
|---|---|---|
| 100k entities / massive crowds | Strong | Poor |
| Rapid UI/prototype | Poor | Excellent |
| Deep gameplay narrative logic | More setup | Natural |
| Physics via Individual Bodies | Has DOTS Physics | PhysX direct |
| Shader/instancing synergy | GPU-instancing friendly | Manual |
Rule: mix intelligently — DOTS for the simulation hot-path, MonoBehaviours for the editors/design-facing layers.
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 usageskills/game/unity/SKILL.md — full Unity engine guide