Build scalable Unity games with Entity Component System (ECS): systems, queries, jobs, burst compilation, and DOTS patterns. Use for high-performance Unity.
Pro scans all 2 files and shows the line behind each finding
Scanned 10/1/2026
npx -y skills add ssrjkk/agent-skills --skill unity-ecs --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Unity Ecs?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ssrjkk-unity-ecs)More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.
---
name: unity-ecs
description: "Build scalable Unity games with Entity Component System (ECS): systems, queries, jobs, burst compilation, and DOTS patterns. Use for high-performance Unity."
category: gamedev
tags: [unity, ecs, dots, jobs, burst, game-dev, performance, csharp]
models: [sonnet, opus, gpt-6, gemini-3, glm-5]
version: 1.0.0
created: 2026-09-29
updated: 2026-09-29
author: ssrjkk
---
# Unity ECS
> Building high-performance Unity games with Entity Component System and DOTS.
## Quick Start
```csharp
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
// Define a component
public struct Health : IComponentData
{
public float Current;
public float Max;
}
// Define a system
public partial class DamageSystem : SystemBase
{
protected override void OnUpdate()
{
float dt = SystemAPI.Time.DeltaTime;
foreach (var (health, transform) in
SystemAPI.Query<RefRW<Health>, RefRO<LocalTransform>>())
{
if (health.ValueRO.Current <= 0)
continue;
// Example: regenerate health over time
health.ValueRW.Current = math.min(
health.ValueRO.Current + dt * 5f,
health.ValueRO.Max
);
}
}
}
```
## When to Use
- Building games with thousands of similar entities (bullets, particles, NPCs)
- When MonoBehaviour performance is not enough
- Need for data-oriented design and cache-friendly code
- Large-scale simulations or strategy games
## Step-by-Step
### 1. Design Components (Data)
Keep components small and focused:
```csharp
public struct MovementSpeed : IComponentData { public float Value; }
public struct TargetPosition : IComponentData { public float3 Value; }
public struct DamageOnContact : IComponentData { public float Amount; }
```
### 2. Create Systems (Logic)
Systems operate on entities with specific component combinations:
```csharp
public partial class MovementSystem : SystemBase
{
protected override void OnUpdate()
{
float dt = SystemAPI.Time.DeltaTime;
foreach (var (transform, speed) in
SystemAPI.Query<RefRW<LocalTransform>, RefRO<MovementSpeed>>())
{
var pos = transform.ValueRO.Position;
pos.z += speed.ValueRO.Value * dt;
transform.ValueRW.Position = pos;
}
}
}
```
### 3. Use Jobs for Parallelism
```csharp
[BurstCompile]
public partial struct CalculateDamageJob : IJobEntity
{
public float DeltaTime;
void Execute(ref Health health, in DamageOverTime dot)
{
health.Current -= dot.DamagePerSecond * DeltaTime;
health.Current = math.max(0, health.Current);
}
}
public partial class DamageOverTimeSystem : SystemBase
{
protected override void OnUpdate()
{
var job = new CalculateDamageJob
{
DeltaTime = SystemAPI.Time.DeltaTime
};
job.ScheduleParallel();
}
}
```
### 4. Entity Queries
```csharp
partial class TargetingSystem : SystemBase
{
private EntityQuery _enemyQuery;
protected override void OnCreate()
{
_enemyQuery = new EntityQueryBuilder(Allocator.Temp)
.WithAll<Health, EnemyTag>()
.WithNone<DeadTag>()
.Build(this);
}
protected override void OnUpdate()
{
var enemies = _enemyQuery.ToEntityArray(Allocator.Temp);
// Process enemies...
}
}
```
### 5. Shared Components (Rendering)
```csharp
public struct SpriteRenderer : ISharedComponentData
{
public Texture2D Texture;
public Material Material;
}
// Entities with same shared component are grouped together
```
## Best Practices
- **Keep components small** — single responsibility
- **Avoid managed references** in components (use Entity references)
- **Use Burst** for math-heavy jobs
- **Batch entities** by shared components for rendering
- **Profile with Unity Profiler** — measure before optimizing
## Common Pitfalls
- Forgetting to mark jobs with `[BurstCompile]`
- Using `foreach` instead of `IJobEntity` for large datasets
- Creating too many systems — group related logic
- Not disposing NativeArrays and other native containers
## Examples
### Spawning Entities
```csharp
public partial class SpawnerSystem : SystemBase
{
protected override void OnUpdate()
{
var ecb = new EntityCommandBuffer(Allocator.TempJob);
foreach (var (spawner, transform) in
SystemAPI.Query<RefRO<Spawner>, RefRO<LocalTransform>>())
{
if (spawner.ValueRO.CanSpawn)
{
var entity = ecb.Instantiate(spawner.ValueRO.Prefab);
ecb.SetComponent(entity, new LocalTransform
{
Position = transform.ValueRO.Position
});
}
}
ecb.Playback(SystemAPI.GetSingleton<EntityManager>());
ecb.Dispose();
}
}
```
### Health and Death
```csharp
public partial class DeathSystem : SystemBase
{
protected override void OnUpdate()
{
var ecb = new EntityCommandBuffer(Allocator.TempJob);
foreach (var (health, entity) in
SystemAPI.Query<RefRO<Health>>().WithEntityAccess())
{
if (health.ValueRO.Current <= 0)
{
ecb.AddComponent<DeadTag>(entity);
ecb.RemoveComponent<Health>(entity);
}
}
ecb.Playback(SystemAPI.GetSingleton<EntityManager>());
ecb.Dispose();
}
}
```
## Validation
```csharp
[Test]
public void MovementSystem_UpdatesPosition()
{
using var world = new World("Test");
var system = world.GetOrCreateSystemManaged<MovementSystem>();
var entity = world.EntityManager.CreateEntity();
world.EntityManager.AddComponentData(entity, new LocalTransform
{
Position = new float3(0, 0, 0)
});
world.EntityManager.AddComponentData(entity, new MovementSpeed { Value = 10f });
system.Update();
var transform = world.EntityManager.GetComponentData<LocalTransform>(entity);
Assert.Greater(transform.Position.z, 0);
}
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!