Unity ECS

🔊 S'abonner au flux RSS

________________________________________________________

Je vais ici parler dans un contexte Game Dev, mais fondamentalement, c’est un sujet qui est transverse au mĂ©taverse (ouai j’ose le mot 😏) du dĂ©veloppement : l’orientĂ© Object VS l’orientĂ© Data.

________________________________________________________

Aux origines de la galĂšre : le OOP !

Le OOP (Object Oriented Programming) dispose de cette incroyable force qu’il Ă©pouse Ă  merveille les prĂ©dispositions de nos cerveaux mollassons :

  • on dĂ©coupe nos concepts mĂ©tier en objets
  • ils portent Ă  la fois des propriĂ©tĂ©s et des mĂ©thodes/fonctions
  • chaque objet a droit Ă  son instance distincte et il pourra donc ĂȘtre autonome dans son coin
  • et on pourra ensuite lentement tomber dans l’enfer des hĂ©ritages et des dĂ©pendances en cascade
 mais c’est un autre sujet. 😌

Dans le cadre du jeu vidĂ©o, cette approche est trÚÚÚÚÚÚs attrayante. Parce que non seulement ça colle d’un point de vue dĂ©coupage fonctionnel (un objet par joueur / ennemi / dĂ©cors / UI
), mais ça colle aussi vachement bien d’un point de vue gameplay :

je veux crĂ©er plusieurs ennemis distincts qui attaquent mon joueur ? Hop, une instance d’objet par ennemi, chacun avec ses propres points de vie, son propre attack pattern, sa propre reconnaissance du terrain
 et potentiellement, rĂ©sultante de tout ça : un comportement unique par ennemi !

Tous les gros moteurs de jeux ont donc adopté cette approche dans leur design de base et dans le choix du langage adossé :

  • Unreal Engine avec le C++
  • Unity avec le C#
  • Godot avec le C# et son langage dĂ©diĂ© le GDScript (qui est une variante intĂ©ressante, plus modulaire autour d’un concept de composition/noeud).

Mais tout aussi flexible et adaptĂ© qu’est le POO pour le game design, il a un problĂšme majeur : il scale trĂšs mal. A vouloir regrouper au sein d’un mĂȘme objet Ă  la fois les donnĂ©es et ses traitements, par design les objets deviennent des Ă©lĂ©ments extrĂȘmement volatiles dont on ne sait Ă  l’avance, ni ce qu’ils vont faire, ni la taille mĂ©moire qu’ils vont occuper.

-- La flexibilité est un compromis de performance -- Comparaison mémoire GameObject vs Entity Source de l'image

Cette nature indĂ©finie de l’objet oblige une architecture qui permet de manager n’importe quel Ă©lĂ©ment qui lui serait attachĂ©. Ne pouvant anticiper la structure de l’objet, sa crĂ©ation se fait Ă  la volĂ©e avec un rangement mĂ©moire parcĂ©laire (ou en moins poĂ©tique : yolo, je te range oĂč je trouve de la place libre).

Travailler sur un objet nĂ©cessite alors de le reconstituer façon fil d’Ariane, en remontant Ă  chaque section de mĂ©moire oĂč une partie de ses donnĂ©es est stockĂ©e.

Or les accĂšs mĂ©moires, c’est le coeur de la performance et ce scan incessant pour reconstituer les objets est un couperet brutal.

________________________________________________________

Le saint sauveur : le DOD !

L’ECS (Entity Component System) est une architecture qui rentre dans le paradigme du DOD (Data Oriented Design). Dans le cadre de Unity, c’est mĂȘme trĂšs clair, on parle de DOTS (Data Oriented Technology Stack). Promis je m’arrĂȘte lĂ  avec les acronymes des enfers infernaux. 😚

L’ECS en soi n’est pas un concept nouveau. Si j’en crois WikipĂ©dia, la 1Ăšre version d’une architecture similaire Ă  l’ECS dans un jeu commercial remonte Ă  Thief : The Dark Project en 1998.

-Digression- Jeu extraordinaire au passage, auquel j’ai eu la chance de pouvoir jouer dans mon enfance (attention vos rĂ©tines : trailers d’époque).

Il disposait d’une quantitĂ© impressionnante d’objets interagissables et dotĂ©s de physique, qu’on pouvait lancer pour faire du bruit, faire bouger d’autres objets, assommer des gardes etc etc
 en vue de commettre le vol parfait sans aucun mort. Une rĂ©fĂ©rence en terme d’infiltration. -Fin de digression-

Thief: The Dark Project - Trailer

L’essence de l’ECS : ne plus organiser le code autour d’une logique fonctionnelle, mais d’une logique qui vise Ă  optimiser l’agencement de la donnĂ©e, aussi sommairement nommĂ© le principe de localitĂ©.

Son design en soi est relativement simple :

  • on remplace le concept d’objet par celui d’entity, qui n’est qu’un identifiant unique.
  • Ă  cette entitĂ©, on va lier des components, qui ne sont que des conteneurs de donnĂ©es (des structs)
  • on regroupe les entitĂ©s qui disposent des mĂȘmes composants dans des archetypes : toutes les entitĂ©s appartenant Ă  un mĂȘme archĂ©type sont rangĂ©es de maniĂšre contiguĂ« en mĂ©moire
  • on peut alors query des groupes d’entitĂ©s en filtrant par composant (comme on requĂȘterait une base de donnĂ©es)
  • au travers de systems centralisĂ©s, on traitera la donnĂ©e requĂȘtĂ©e en masse via un dĂ©coupage en chunks et une rĂ©partition sur du multi-threading

Concept ECS Unity

Implémentation OOP vs ECS
En OOP, on aurait ici eu un personnage qui porterait une position, une direction et une vitesse ainsi qu'une méthode Move() qui s'exécuterait à chaque frame.

En ECS, on crĂ©e 3 composants de donnĂ©es, liĂ©s entre eux par l’ID unique d’une entitĂ©. Ensuite un systĂšme isolĂ© va requĂȘter toutes les entitĂ©s qui disposent de la combinaison de ces 3 composants (qu’ils appartiennent ou non au mĂȘme archĂ©type, seule la combinaison de composants importe) et va traiter le calcul du mouvement en parallĂšle.

Cette approche permet d’augmenter d’au moins un facteur (x10) les performances. Des exemples seront plus parlant :

Pas d'ECS, 1k unités sans VAT*, sans simulation, sans décors
ECS, 100k unités avec VAT*, simulation simple, sans décors
ECS, 50k unités avec VAT*, simulation avancée, 180k décors
VAT (Vertex Animated Texture)

C'est une technique d'animation qui stocke les mouvements des modÚles dans une texture lue directement par le GPU. AllÚge fortement la charge CPU, au détriment d'un coût en RAM et d'une perte de flexibilité dans le process d'implémentation des animations. Lien vers un article (anglais) si vous voulez plus de détails.

- Les 3 vidĂ©os tournent autour de 40-60 FPS. L’approche OOP me permet d’animer 1 000 unitĂ©s (disclaimer : en y ajoutant le VAT, entre 5k et 10k serait une cible envisageable). Avec l’approche ECS, je peux monter Ă  100 000 unitĂ©s, avec par dessus une simulation qui leur permet de s’esquiver et d’avoir un vrai pathfinding via un champs de vecteurs. L’écart de performance entre les 2 implĂ©mentations est abyssal pour ce genre de cas d’usage. -

C’est donc une architecture extrĂȘmement puissante, qui a trouvĂ© moult cas d’usage dans des simulations de :

  • foules
  • trafic
  • villes / Ă©cosystĂšmes
  • projectiles / particules
  • sandbox / MMO

qui manipulent tous de grandes quantitĂ©s d’objets non-statiques et pour lesquels le DOD fait des merveilles.

Mais vous remarquerez que cette liste est plutît restreinte et qu’on n’utilise pas cette architecture partout
 👀

________________________________________________________

Un grand pouvoir implique


Il est un piĂšge dans lequel il ne faut pas tomber : la performance pour la performance, ce bon vieux over-engineering ! (et bon sang que c’est dur de ne pas tomber dans ce piĂšge quand on fait de l’ingĂ©nierie
).

S’il est vrai que — La flexibilitĂ© est un compromis de performance —, l’inverse est tout aussi vrai — La performance est un compromis de flexibilitĂ© —. Or la flexibilitĂ© est l’un des coeurs de la productivitĂ©.

La performance n’est que rarement un objectif en soi (Ă  part si vous vous appelez Google/Amazon et que vous devez rĂ©pondre Ă  des milliards de requĂȘtes utilisateurs Ă  la seconde). Non elle est surtout un prĂ©-requis minimal d’acceptation de l’utilisateur :

  • si la performance est trop dĂ©gradĂ©e, l’expĂ©rience utilisateur le sera aussi et il partira
  • mais ĂȘtre trop performant n’amĂ©liorera pas l’expĂ©rience perçue cĂŽtĂ© utilisateur et vous aurez dĂ©pensĂ© temps/argent en pure perte

La performance est donc une affaire d’équilibre : une limite basse stricte Ă  ne jamais franchir et une limite haute diffuse Ă  tempĂ©rer, afin de maximiser la productivitĂ© de features, qui est le but premier.

L’ECS Ă©tant une rĂ©ponse de performance, il est par nature plus complexe et peu flexible au changement. Il est beaucoup plus long Ă  mettre en place, demande de nombreux composants distincts, impose des restrictions sur le type de donnĂ©es et globalement, rallonge drastiquement les temps de dĂ©veloppement, mĂȘme pour des features simples.

L’industrie a choisi comme toujours l’approche la plus pragmatique : l’hybride. Savoir choisir ce qui mĂ©rite une approche ECS pour la performance VS choisir l’approche OOP quand le fonctionnel et l’itĂ©ration priment. L’approche ECS est par exemple inutile dans la plupart des jeux avec des scĂšnes restreintes, qui compose l’immense majoritĂ© de nos catalogues. Au contraire, la moindre simulation de masse gagnera massivement Ă  l’implementer.

Mais si l’industrie a longtemps dĂ» traiter l’ECS et l’OOP comme deux mondes sĂ©parĂ©s, une nouvelle voie s’ouvre peut-ĂȘtre. A la GDC de mars 2026, Unity a dĂ©cidĂ© de taper fort : pourquoi ne pas fusionner les 2 approches ?

GDC Unity 2026

L’ECS deviendrait un package core du moteur (et non plus un add-on Ă  installer), Ă  la maniĂšre d’un Bevy (un moteur de jeu en Rust nativement ECS). Les entitĂ©s deviendront alors le backend de tout le moteur, mais pour autant les GameObjects ne disparaissent pas : ils deviennent une couche de confort par dessus les entitĂ©s, le moteur prenant la main pour faire la conversion. La force du design OOP par dessus, la puissance de l’ECS en dessous. — L’ECS ne sera plus un choix, mais le socle. Le GameObject ne sera plus une alternative, mais une interface. —

En d’autres termes, l’approche hybride dont je parlais plus haut ne sera plus un compromis d’architecture, mais le mode de fonctionnement par dĂ©faut du moteur. Vous voulez du prototypage rapide ? Vous restez au niveau GameObject. Vous voulez de la performance brute ? Le moteur vous permettra de basculer votre architecture en GameObjects vers de l’ECS et ainsi profiter de ses options. MĂȘme donnĂ©es, mĂȘme moteur, mais deux mondes en un.

Et je vous avoue que je suis trĂšs curieux de voir le rĂ©sultat. 👀