plan-4ging

2026/03/14

ECS(Entity Component System)とは

Unity の DOTS(Data-Oriented Technology Stack) の中核をなすアーキテクチャ
従来の MonoBehaviour ベースのオブジェクト指向とは根本的に異なるデータ指向設計でゲームオブジェクトを管理する

【MonoBehaviour Architecture】
GameObject
 └ MonoBehaviour(データ + ロジックが混在)
 → 扱いやすいが大量処理に弱い

【ECS Architecture】
Entity(識別子のみ)
 └ Component(データのみ)
System(ロジックのみ)
→ 大量処理に強い

4つの概念

Entity

ゲームオブジェクトに相当する識別子(ID)
データもロジックも持たない

Entity は単なる整数のID
Entity 0 → Position, Velocity, Health コンポーネントを持つ
Entity 1 → Position, MeshRenderer コンポーネントを持つ

Component

データのみを持つ構造体
ロジックは一切書かない

using Unity.Entities;
using Unity.Mathematics;

// IComponentData を実装した struct がコンポーネント
public struct Position : IComponentData
{
    public float3 Value;
}

public struct Velocity : IComponentData
{
    public float3 Value;
}

public struct Health : IComponentData
{
    public float Current;
    public float Max;
}

System

ロジックのみを持つクラス
特定のコンポーネントを持つ Entity を検索して処理する

using Unity.Entities;
using Unity.Burst;
using Unity.Mathematics;

// SystemBase を継承して System を定義する
public partial class MovementSystem : SystemBase
{
    protected override void OnUpdate()
    {
        float deltaTime = SystemAPI.Time.DeltaTime;

        // Position と Velocity を持つ全 Entity に対して処理
        Entities
            .ForEach((ref Position position, in Velocity velocity) =>
            {
                position.Value += velocity.Value * deltaTime;
            })
            .ScheduleParallel(); // 並列実行(Job System)
    }
}

World

Entity, Component, System をまとめた単位

実装例

Entity の生成とコンポーネントの付与

using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;

public class ECSSpawner : MonoBehaviour
{
    void Start()
    {
        // EntityManager:Entity の生成・管理を行うクラス
        EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;

        // Entity を生成
        Entity entity = entityManager.CreateEntity();

        // コンポーネントを付与
        entityManager.AddComponentData(entity, new Position
        {
            Value = new float3(0, 0, 0)
        });
        entityManager.AddComponentData(entity, new Velocity
        {
            Value = new float3(1, 0, 0)
        });
    }
}

Archetype を使った大量 Entity の生成

同じコンポーネント構成を持つ Entity を大量生成する場合は Archetype を使うと高速

void SpawnEnemies(int count)
{
    EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;

    // Archetype:コンポーネントの組み合わせを定義したテンプレート
    EntityArchetype archetype = entityManager.CreateArchetype(
        typeof(Position),
        typeof(Velocity),
        typeof(Health)
    );

    // NativeArray で一括生成(個別生成より高速)
    using var entities = new NativeArray<Entity>(count, Allocator.Temp);
    entityManager.CreateEntity(archetype, entities);

    // 各 Entity に初期値を設定
    for (int i = 0; i < count; i++)
    {
        entityManager.SetComponentData(entities[i], new Position
        {
            Value = new float3(i, 0, 0)
        });
        entityManager.SetComponentData(entities[i], new Velocity
        {
            Value = new float3(0, 0, 1)
        });
        entityManager.SetComponentData(entities[i], new Health
        {
            Current = 100f,
            Max     = 100f
        });
    }
}

Burst + Job System と連携

using Unity.Entities;
using Unity.Burst;
using Unity.Mathematics;
using Unity.Jobs;

[BurstCompile] // System 全体に Burst を適用
public partial struct MovementSystemBurst : ISystem
{
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        float deltaTime = SystemAPI.Time.DeltaTime;

        // 並列実行で大量 Entity を高速処理
        new MoveJob { DeltaTime = deltaTime }
            .ScheduleParallel();
    }

    [BurstCompile]
    partial struct MoveJob : IJobEntity
    {
        public float DeltaTime;

        void Execute(ref Position position, in Velocity velocity)
        {
            position.Value += velocity.Value * DeltaTime;
        }
    }
}

MonoBehaviourとECSの違い

設計思想の違い

MonoBehaviourECS
設計思想オブジェクト指向(OOP)データ指向(DOD)
データとロジック同じクラスに混在完全に分離
メモリレイアウトオブジェクトごとにバラバラコンポーネントが連続したメモリに配置(キャッシュ効率が高い)
大量オブジェクト苦手得意

メモリレイアウトの違い

【MonoBehaviour のメモリレイアウト】
GameObject A → [Position][Velocity][Health][その他データ...]
GameObject B → [Position][Velocity][Health][その他データ...]
 → オブジェクトごとにメモリが離散している
 → CPU キャッシュミスが発生しやすい

【ECS のメモリレイアウト(Chunk)】
Position: [A.pos][B.pos][C.pos][D.pos]... → 連続したメモリ
Velocity: [A.vel][B.vel][C.vel][D.vel]... → 連続したメモリ
 → 同じコンポーネントが連続して並ぶ(Chunk と呼ばれる)
 → SIMD・CPU キャッシュが効きやすく高速

注意点・実務での使い所

向いている場面

  • 大量の敵・弾・群衆シミュレーション
  • パーティクルの物理シミュレーション
  • 広大なオープンワールドのオブジェクト管理
  • リアルタイムストラテジー(RTS)のユニット処理
  • 地形・ボクセルの動的生成

向いていない場面

  • 少数オブジェクトの処理
  • UI・演出・カメラなどエディタとの連携が重要な処理
  • 短期間のプロトタイプ開発

参考