Skip to content
On this page

Étude comparative : ECS vs OOP dans la conception d’un moteur de jeu 2D en C++

1. Introduction

Dans la conception de notre moteur de jeu 2D en C++, nous avons fait le choix d’adopter une architecture ECS (Entity Component System) plutôt qu’une approche purement orientée objet (OOP).
Ce document présente une étude comparative entre ces deux paradigmes, en mettant en avant les raisons techniques et structurelles de ce choix.


2. Rappel des deux paradigmes

2.1 Programmation Orientée Objet (OOP)

L’OOP repose sur la modélisation du monde sous forme d’objets.
Chaque objet combine données (attributs) et comportements (méthodes).
On utilise des classes, héritages et polymorphisme pour structurer le code.

Exemple :

cpp
class Player : public Entity {
public:
    void move();
    void render();
private:
    Vector2 position;
    Sprite sprite;
};
class Player : public Entity {
public:
    void move();
    void render();
private:
    Vector2 position;
    Sprite sprite;
};
1
2
3
4
5
6
7
8

Avantages :

Structure intuitive (proche du monde réel).

Encapsulation : chaque entité gère son propre état. Héritage et polymorphisme facilitent la réutilisation du code.

Inconvénients :

L’héritage multiple peut rendre la hiérarchie rigide et difficile à maintenir. Difficile d’ajouter de nouveaux comportements sans casser la hiérarchie. Couplage fort entre données et logique (faible flexibilité).

2.2 Entity Component System (ECS)

L’ECS découple complètement les données (components) de la logique (systems). Une Entity n’est qu’un identifiant. Les Components stockent les données. Les Systems appliquent la logique sur les entités possédant certains composants.

Exemple :

cpp
struct Position { float x, y; };
struct Velocity { float dx, dy; };

class MovementSystem {
public:
    void update(Registry& registry) {
        for (auto entity : registry.view<Position, Velocity>()) {
            auto& pos = registry.get<Position>(entity);
            auto& vel = registry.get<Velocity>(entity);
            pos.x += vel.dx;
            pos.y += vel.dy;
        }
    }
};
struct Position { float x, y; };
struct Velocity { float dx, dy; };

class MovementSystem {
public:
    void update(Registry& registry) {
        for (auto entity : registry.view<Position, Velocity>()) {
            auto& pos = registry.get<Position>(entity);
            auto& vel = registry.get<Velocity>(entity);
            pos.x += vel.dx;
            pos.y += vel.dy;
        }
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Avantages :

  • Architecture flexible : les entités sont dynamiques et modulaires.
  • Découplage fort : la logique et les données sont indépendantes.
  • Favorise la parallélisation (chaque système peut être exécuté sur un thread).
  • Idéal pour gérer des milliers d’entités dans un moteur de jeu.

Inconvénients :

  • Moins intuitif pour les débutants (abstraction plus conceptuelle).
  • Peut nécessiter une gestion mémoire plus fine.
  • La débogue et la traçabilité des entités sont parfois plus complexes.

3. Comparaison directe

3. Comparaison directe

CritèreOOP (Programmation Orientée Objet)ECS (Entity Component System)
StructureHiérarchie de classesDonnées + systèmes séparés
FlexibilitéLimitée par l’héritageTrès élevée (composition dynamique)
PerformanceSouvent limitée par le polymorphismeOptimisée (cache-friendly, data-oriented)
Réutilisation du codePar héritagePar composition
MaintenanceHiérarchie rigideCode plus modulaire et isolé
ExtensibilitéDifficile sans refactorisationSimple : ajouter un nouveau système ou composant
Adaptation au multithreadingComplexeNaturellement compatible
Lisibilité pour petits projetsPlus simplePlus complexe
Évolutivité pour gros projetsMoins adaptéeTrès adaptée

4. Justification de notre choix (ECS)

Nous avons choisi ECS pour notre moteur 2D car il répond mieux à nos objectifs de performance, de modularité et d’évolutivité : Performance : la séparation des données permet un accès séquentiel en mémoire (data-oriented design), idéal pour les mises à jour massives d’entités (ex. : projectiles, ennemis, particules).

  • Modularité : chaque système (Input, Render, Physics, Collision, etc.) peut être développé indépendamment.
  • Flexibilité : ajout ou suppression de composants à une entité à l’exécution sans refactoriser les classes.
  • Évolutivité : facile d’intégrer de nouveaux systèmes sans impacter la structure existante.
  • Parallélisation : permet de tirer parti des architectures multi-threadées modernes.

5. Conclusion

L’ECS représente une évolution naturelle de la conception orientée objet pour les moteurs de jeux. Alors que l’OOP met l’accent sur la hiérarchie et l’encapsulation, l’ECS privilégie la composition et la performance.

Notre choix d’utiliser ECS s’explique donc par :

  • la recherche d’un moteur modulaire, évolutif et performant,
  • une meilleure gestion des entités dynamiques et une architecture claire pour séparer la logique du contenu.