> For the complete documentation index, see [llms.txt](https://azuriohs-organization.gitbook.io/r-type/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://azuriohs-organization.gitbook.io/r-type/ecs-system/how-work-our-ecs.md).

# How work our ECS

Our ECS (Entity Component System) is a **data-oriented architecture** implemented in C++. It is designed to be **modular, cache-friendly, and easy to extend**, while avoiding the pitfalls of heavy inheritance or complex object hierarchies.

This section explains how our ECS is structured and how its core components — the **ComponentPool**, **Entity**, and **GameEngine** — work together.

***

## 🧩 Architecture Overview

Our ECS is composed of three main layers:

| Layer             | Responsibility                                                                   | Key Class                  |
| ----------------- | -------------------------------------------------------------------------------- | -------------------------- |
| **ComponentPool** | Stores and manages instances of each component type efficiently                  | `Engine::ComponentPool<T>` |
| **Entity**        | Represents a unique object in the world and provides an API to attach components | `Engine::Entity`           |
| **GameEngine**    | Manages all entities, provides creation, deletion, and lookup                    | `Engine::GameEngine`       |

Each layer is isolated and uses the **Singleton** design pattern to ensure global access without static order issues.

***

## 🧱 ComponentPool

The `ComponentPool` template is responsible for **storing components of a given type**. Each component type (`Position`, `Velocity`, `Sprite`, etc.) has its own independent pool instance.

### ✳️ Sparse–Dense Storage

To efficiently store and access components, we use a **sparse–dense array pattern**. This pattern allows us to perform operations in constant time while keeping memory usage compact and contiguous.

#### 🎯 Goals

* **Fast lookups:** `O(1)` access to any component by entity ID
* **Memory efficiency:** Components of the same type are stored contiguously
* **Cache locality:** Improves CPU cache performance during system iteration

### 🧩 How It Works

Our pool maintains two structures:

```cpp
std::vector<std::vector<std::optional<std::size_t>>> _sparseArray;
std::vector<std::shared_ptr<ComponentType>> _denseArray;
```

| Structure     | Type                                | Purpose                                                                                                |
| ------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------ |
| \_sparseArray | `vector<vector<optional<size_t>>>`  | Maps entity IDs to indices in \_denseArray. It’s paginated to handle very large ID spaces efficiently. |
| \_denseArray  | `vector<shared_ptr<ComponentType>>` | Stores the actual component instances, tightly packed for iteration.                                   |

### 🔢 Example Mapping

Let’s say we have three entities (E1, E2, E3) that each have a Position component.

| Entity | Sparse | Index | Dense Index Component Data |
| ------ | ------ | ----- | -------------------------- |
| E1     | 0 → 0  | 0     | Position(0, 0)             |
| E2     | 1 → 1  | 1     | Position(1, 0)             |
| E3     | 2 → 2  | 2     | Position(5, 3)             |

Visually:

```
Sparse Array (entity IDs → dense indices)
[ 0, 1, 2, ∅, ∅, … ]

Dense Array (components in memory order)
[ Position(0,0), Position(1,0), Position(5,3) ]
```

* The sparse array acts like an address book: “Entity #2’s component is at dense index 1.”
* The dense array contains the actual component data packed together for fast iteration by systems.

### 📄 Pagination

To handle large or non-contiguous entity ID ranges efficiently, the sparse array is divided into pages of size `PAGINATION_SIZE` (typically 1024).

* `PAGINATION_IDX(id)` = which page contains this entity ID
* `IDX_IN_PAGINATION(id)` = position within that page

This prevents allocating millions of entries when you only have entities with IDs like \[5, 1000000].

### 📦 Adding a Component

When calling:

```cpp
ComponentPool<Position>::GetInstance().Add(entityId, component);
```

1. If the entity already has this component:
   * We look up its dense index in \_sparseArray and replace it in \_denseArray.
2. Otherwise:
   * We push\_back() the new component to \_denseArray.
   * We update \_sparseArray to point the entity ID to the new dense index.
   * Pagination ensures that even very large entity IDs are supported without huge allocations.

Result: Lookups and insertions both happen in constant time.

### 🗑️ Deleting a Component

Removing a component is also efficient — no costly memory shifts.

When deleting:

1. The component at the entity’s dense index is swapped with the last element in \_denseArray.
2. The sparse entries of both are updated to reflect their new positions.
3. The last element (now the removed one) is popped off.

This keeps \_denseArray contiguous and prevents fragmentation.

Example before deletion:

```
Sparse: [0, 1, 2]
Dense:  [PosE1, PosE2, PosE3]

Delete E2:

Swap PosE2 ↔ PosE3
Sparse: [0, 2, ∅]
Dense:  [PosE1, PosE3]
```

Result: only one swap and one pop — still O(1).

### 🧼 Clearing the Pool

`Clear()` resets both `_denseArray` and `_sparseArray`, removing all components safely. This is typically used during scene unloading or engine shutdown to prevent static destruction issues.

### 🧠 Singleton Management

Each ComponentPool is a Singleton, instantiated as:

```cpp
class ComponentPool<T> : public Misc::Singleton<ComponentPool<T>>
```

This ensures:

* There is only one pool per component type.
* Global access is easy through ComponentPool::GetInstance().
* Safe cleanup at shutdown.

### ⚙️ Summary

Operation Complexity Description Add O(1) Adds or replaces a component and updates sparse–dense mapping Get O(1) Retrieves the component pointer by entity ID Delete O(1) Swaps and removes component while maintaining dense contiguity Clear O(n) Clears all component data

This sparse–dense strategy allows our ECS to scale to thousands of entities while maintaining predictable performance and excellent memory locality.

***

## 🧍 Entity

An Entity is a lightweight handle that represents an object in the game world. It stores: - A unique ID - A name

### 🔧 Entity Responsibilities

Entities themselves hold no data or logic — they act as keys to access their components in ComponentPool.

### 💡 Example Usage

```cpp
Engine::Entity player("Player1");

player.Add<Position>(0, 0);
player.Add<Velocity>(1, 0);

if (player.Is<Position>()) {
    auto& pos = player.Get<Position>();
    pos.x += 1;
}
```

### Key Methods

| Method                        | Description                          |
| ----------------------------- | ------------------------------------ |
| `Add<ComponentType>(args...)` | Adds a new component to the entity   |
| `Get<ComponentType>()`        | Retrieves a reference to a component |
| `Is<ComponentType>()`         | Checks if the entity has a component |
| `Remove<ComponentType>()`     | Removes a component from the entity  |

🚨 If you try to Get a component that doesn’t exist, a ComponentNotSetup exception is thrown.

***

## 🕹️ GameEngine

The GameEngine acts as the manager of all entities and provides lifecycle control.

It is also a Singleton, ensuring only one instance manages the world state.

### 🔧 Responsibilities

| Responsibility           | Method                                                                |
| ------------------------ | --------------------------------------------------------------------- |
| Create an entity         | `Entity& CreateEntity(const std::string& name)`                       |
| Retrieve by ID or name   | `Entity& GetEntity(size_t id)` / `GetEntity(const std::string& name)` |
| List all entities        | `std::vector<Entity>& ListEntities()`                                 |
| Delete entities          | `DeleteEntity()`, `DeleteAllEntities()`, etc.                         |
| Delete by component type | `DeleteKindOfEntities<ComponentType>()`                               |

### 🧠 Example Workflow

```cpp
auto& engine = Engine::GameEngine::GetInstance();

// Create entities
auto& player = engine.CreateEntity("Player");
auto& enemy  = engine.CreateEntity("Enemy");

// Add components
player.Add<Position>(0, 0);
enemy.Add<Position>(5, 0);

// Access components
auto& pos = player.Get<Position>();
pos.x += 2;

// Delete all entities with a specific component
engine.DeleteKindOfEntities<Position>();
```

***

## 🧩 How It All Connects

Here’s how everything ties together:

```
+-----------------------+
|     GameEngine        |
|  - List of Entities   |
+----------+------------+
           |
           v
+-----------------------+
|       Entity          |
|  - ID, Name           |
|  - Add / Get / Remove |
+----------+------------+
           |
           v
+-----------------------+
|   ComponentPool<T>    |
|  - Sparse / Dense     |
|  - Add / Get / Delete |
+-----------------------+
```

Each Entity uses its ID to access components inside a type-specific ComponentPool. The GameEngine manages the overall collection of entities and serves as the entry point for game logic.

***

## 🚀 Advantages of This Implementation

| Advantage         | Explanation                                                                         |
| ----------------- | ----------------------------------------------------------------------------------- |
| Type Safety       | Template-based pools ensure compile-time safety per component type.                 |
| Performance       | Sparse-dense arrays enable cache-friendly iteration and fast lookups.               |
| Flexibility       | Components can be added, replaced, or removed at runtime.                           |
| Simplicity        | Clear separation of responsibilities between Entity, ComponentPool, and GameEngine. |
| Singleton Control | Prevents issues with global state destruction order.                                |

***

## ✅ Summary

Our ECS is:

* Entity-centric — Entities are just identifiers.
* Component-driven — All data lives in type-safe component pools.
* System-ready — Systems can iterate efficiently over relevant entities.
* Efficient and modular — Designed for scalable, high-performance games.

🧭 The ECS core focuses on data organization, letting systems handle the logic — ensuring clean, maintainable, and fast gameplay code.
