Voir sur Github

Quel passionné de jeu vidéo n’a jamais voulu créer son propre jeu vidéo de manière intuitive et ludique ?
De nos jours il est possible de répondre à cette problématique et au besoin utilisateur en créant son jeu vidéo avec un éditeur / moteur de jeux vidéo tel que Unity ou Unreal Engine.
Ces éditeurs sont très développés et très complets.

Un éditeur de jeux vidéo

L’idée ici est de proposer un éditeur de jeux vidéo multi-plateforme (Windows, Linux et Mac OS) tout en restant ludique et intuitif.
Note: Dans un premier temps, cet éditeur sera assez limité en fonctionnalités car il est en développement. Avec les technologies et outils dont nous disposons aujourd’hui, il est possible de réaliser un tel éditeur avec les fonctionnalités principales suivantes :

  • Concept de preview incorporée à la game scene
  • La phase de compilation utilise un outil pour gérer la compilation et ses options (e.g. CMake)
  • Interfaces simplifiées et intuitives, avec des technologies portables
On propose DreamInEngine, un éditeur de jeu qui utilise un moteur 2D/3D d’architecture ECS.
A l’heure actuelle ce moteur est en développement.

Utilisation d’OpenGL avec GLFW pour le rendu et les fenêtres

Développer un éditeur nécessite tout d’abord de créer une fenêtre et d’être en mesure de dessiner à l’intérieur.
On peut créer une fenêtre simplement avec une librairie graphique telle que GLFW. Cette librairie a l’avantage d’être cross-plateforme, légère et simple d’utilisation.
Pour que la création fonctionne et que l’on puisse afficher quelque chose dans cette fenêtre, il faut créer ce que l’on appelle un contexte graphique.
Pour ce faire, on a choisi la librairie OpenGL pour son caractère cross-platform et ses fonctionnalités en termes de programmation graphique.
Cependant, la création d’interface n’étant pas directement la responsabilité d’OpenGL, on a pris une librairie cross-platform pour créer des interfaces utilisateurs.

ImGUI et les interfaces utilisateurs

Plusieurs questions se posent lorsque l’on parle de conception et d’implémentation d’interfaces graphiques. Comment améliorer l’expérience utilisateur ? Quelles technologies utiliser ? Une librairie graphique peut-elle aider dans ce cas, mais laquelle ? DreamIn Engine utilise ImGUI, une librairie qui a l’avantage d’être « cross-platform » (Windows, Linux et MacOS) tout en étant facile d’utilisation, flexible et légère.
Par conséquent, les interfaces de l’éditeur sont totalement customizables et flexibles.
Créer des interfaces n’a jamais été aussi simple ! ImGUI peut s’inscrire dans différents contextes (SDL, OpenGL3 et GLFW). Ici, on l’inscrit dans un contexte OpenGL3 et GLFW pour des soucis d’optimisation et de portabilité. DreamIn Engine propose donc une interface découpée en plusieurs parties qui ont des responsabilités propres.

Cas d'utilisation de l'éditeur DreamIn Engine

Comment utiliser cet éditeur ? Cette section détaille les étapes et les fonctionnalités de l’application.
Note : certaines des fonctionnalités présentées dans cet article sont en développement.

Créer et supprimer des entités

La fenêtre “Window Scene” montre les entités présentes dans une scène. On rappelle qu’une scène correspond à l’environnement (2D ou 3D) dans lequel sont rendus les objets qui composent notre jeu en développement.
Comment les entités sont gérées par le moteur de l’éditeur DreamIn Engine ?
Dans cette fenêtre, les entités sont affichées les unes à la suite des autres par rapport à leur identifiant.
Pour créer une entité « OneMoreEntity », il suffit de cliquer sur le bouton « ADD ENTITY » et un menu s’ouvre. Dans ce menu, on identifie :

  • Le nom
  • La position sur l'axe X
  • La position sur l'axe Y
Note: La version 3D est toujours en et seules deux dimensions sont présentées dans cet article. Enfin, on clique sur le bouton « ADD » pour ajouter une entité « OneMoreEntity » aux coordonnées [250 ;250] dans la scène. On aperçoit un deuxième container sur la droite de l’image qui montre l’entité nouvellement créée sur l’image ci-dessous:

Seules, les entités créées n’ont pas beaucoup de valeur. Ajoutons-leurs des composants !

Attacher des composants aux entités

Comment attacher des composants aux entités ?
Pour attacher des composants aux entités, on utilise la fenêtre sur le côté droit de l’éditeur.

Cette fenêtre montre tout d’abord les caractéristiques de l’entité sélectionnée (e.g. « OneMoreEntity (id : 3, mask : 5)).
On peut voir que cette entité possède déjà des composants de base :

  • SpriteComponent. Ce composant permet à l’entité d’être rendue avec un Sprite (un Sprite est un composant qui possède une image ainsi qu’une position dans un espace 2D)
  • InputComponent. Ce composant permet de commander une entité avec le clavier de l’ordinateur lorsqu’une simulation est en cours
Grâce à ces deux composants, on peut contrôler l’entité avec le clavier de l’ordinateur et suivre le rendu à l’écran. Pour ce faire, il faut être en « mode simulation »

Démarrer/Arrêter une simulation

En haut à gauche de l’éditeur, on aperçoit une barre d’action, comme ceci:

Elle regroupe l’ensemble des actions qui peuvent modifier l’état d’une scène :

  • Run simulation correspond au premier bouton d’action et lance une simulation
  • Stop simulation correspond au deuxième bouton d’action et stoppe une simulation en cours
On note que les boutons sont grisés lorsqu’ils ont été cliqués :
  • Lorsqu’une simulation est en marche, le bouton de démarrage de la simulation est grisé
  • Quand aucune simulation n’est en marche, le bouton d’arrêt de simulation ne peut pas être cliqué
Que se passe-t-il si l’on souhaite modifier les informations d’un composants telles que sa position, sa taille, sa couleur ? A-t-on besoin d’arrêter la simulation pour effectuer ces modifications ?
Non, il est tout à fait possible de modifier les paramètres des composants au « runtime », c’est-à-dire lorsqu’une simulation est en marche.

Visualiser et modifier les informations des composants

Peu importe si une simulation de jeu est en marche ou à l’arrêt, il est toujours possible de visualiser et de modifier les informations relatives aux composants dans la fenêtre « COMPONENTS DETAILS » située en bas à droite de l’éditeur.
Pour cet exemple, on a sélectionné le composant « Sprite » qui contient les informations suivantes :

  • Position
  • Taille
  • Rotation
  • Couleur
  • Texture

Note : une variable de texture est présente et il est donc possible de modifier la texture d’un composant associé à une entité.

Gérer les textures

DreamIn Engine possède son propre gestionnaire de textures et les textures utilisables pour le projet sont affichées dans l’explorateur de ressources (e.g. « Resource Explorer »):

Prenons la scène de l’éditeur dans son ensemble:

Il est possible de modifier la texture d’une entité sélectionnée, simplement en cliquant sur la texture à utiliser depuis l’explorateur de ressources. Dans l’exemple ci-dessous, nous avons remplacé la texture du « container » par la texture « button_open » depuis l’explorateur de ressources.
Note : une fonction de Drag’N’Drop est présente et permet de glisser une texture depuis l’explorateur de ressources vers la texture présente dans les informations du composant Sprite.
Lorsque des changements ont été apportées à un projet, on souhaite éventuellement sauvegarder les modifications.

Sauvegarder un projet

Une barre tout en haut de la fenêtre compile l’ensemble des raccourcis possibles que propose l’éditeur et les regroupe sous forme d’onglets cliquables en liste déroulante :

L’onglet « Project » concerne les fonctionnalités relatives au(x) projet(x) ouvert(s). Il possède plusieurs fonctionnalités :

  • « New project » créé un nouveau projet
  • « Open project » ouvre une fenêtre qui permet de charger un projet existant
  • « Save » sauvegarde un projet et sauvegarde-sous si le projet est nouveau
  • « Save as » sauvegarde le projet sous quoiqu’il arrive
  • « Quit », ou le raccourci « Alt+F4 » ferment l’application
Cette barre d’action permet la gestion d’un projet telle que dans l’exemple montré ci-dessous où on tente de sauvegarder un projet.

Note: cette application est en développement et a besoin d’être enrichie pour le moment.

Visualiser l’architecture du projet et le contenu des fichiers

A tout moment, on peut prendre du recul et visualiser l’architecture du projet en cours. Il est possible de la voir facilement grâce à l’explorateur de projet (e.g. fenêtre avec l’onglet « Project Explorer »).
Ce menu parcourt les fichiers du projet et les affiche. En cliquant sur un dossier, le menu déroule et affiche ce qu’il contient.
En cliquant sur un fichier, il est possible de voir sont contenu depuis l’onglet explorateur de fichiers (e.g. fenêtre avec l’onglet « File Explorer ») en bas à gauche de l’application.

Le concept d'ECS

Beaucoup de jeux vidéo ont été réalisés avec la programmation orientée objet (POO). Ils fonctionnent correctement mais cette approche peut engendrer une baisse rapide des performances.
En effet, dans un jeu en programmation orientée objet, nous entendons souvent le concept de GameObject, qui représente une entité indépendante dans une scène. Les GameObjects possèdent des composants qui contiennent les données et parfois de la logique. Dans les jeux traditionnels, chaque GameObject possède une méthode Update. Si l’on veut mettre ces GameObjects en mouvement, il va falloir appeler cette méthode Update. Si des centaines de GameObjects sont présents dans une scène, cela signifie que l’on va devoir appeler la méthode Update plusieurs centaines de fois. Cette opération prend du temps !

Cependant, l’idée d’un ECS est de combiner ces GameObjects et de gérer leur logique (ou comportement) en un seul appel de fonction dans un système unique.
Portons un peu plus attention à ce que ce pattern architectural:

Entité

Les entités sont les « nouveaux GameObjects ».
Elles sont souvent représentées sous la forme d’un simple identifiant (ID) et ont pour rôle l’association de données.
En pratique, les entités sont très légères dans une scène contrairement aux GameObjects qui possèdent beaucoup d’informations. De plus, les entités ne sont pas « physiquement » présentes dans une scène du fait de leur caractère de simple identifiant.

Composant

Les composants contiennent absolument toutes les données (e.g. un composant « Transform » pourrait contenir des données de position, de rotation et d’échelle d’une entité).
Les composants ne contiennent pas de logique.

Système

Les systèmes gèrent toute la logique en une seule fois pour toutes les entités qui leurs sont associées.

Finalement, qu’est-ce qui rend l’ECS meilleur ?

  • Le concept d’entité permet d’économiser de la mémoire. On a plus de contrôle sur la nature et on sait comment les composants sont stockés et gérés en mémoire
  • Ce modèle évite les créations coûteuses des GameObjects (plus de données et logique) au profit d’une création de Composants (moins de données et pas de logique)
  • La parallélisation du code devient plus facile à réaliser. La séparation de la logique et de la donnée dans un ECS permet de paralléliser l’exécution de systèmes et au sein d’un système
  • Le code peut être facilement optimisé pour être « cache-friendly ». Comme les composants ne contiennent que de la donnée, on peut les parcourir de manière contigüe en mémoire

Quelles sont les limites de l’ECS ?

  • Il est difficile de débugger des entités
  • Il est parfois nécessaire d’écrire plus de code pour une même fonctionnalité
  • Il n’est pas vraiment enseigné aux programmeurs de jeux vidéo
  • ECS est basé sur un Design Orienté Données (DOD) dont le concept peut être difficile à assimiler

Utilisation du Design Orienté Données (DOD)

Nous avons vu les principes, avantages et limites d’un ECS, mais à quoi le concept de DoD fait référence dans un pattern architectural ?
Contrairement à la POO où tout se résout autour des objets, le DoD concerne exactement toutes les données. Au lieu de structurer le code tel qu’on l’imagine, il est préférable de le structurer en prenant en compte le flux de données que l’on doit manipuler.

Intégration d’un Entity Component System dans l’éditeur DreamIn Engine.

DreamIn Engine intègre un moteur ECS pour Entity Component System pour accélérer le traitement des données (entités, composants et systèmes) et prône le concept de DoD pour son ECS.
Ce choix architectural permet d’améliorer :

  • Les performances
  • La maintenance
  • La gestion des données et de la logique

Pistes d'améliroation

Pour le moment, DreamIn Engine intègre un moteur Entity Component System réalisé sur mon temps personnel, mais dans le futur il est prévu d'utiliser un ECS existant et probablement plus performant tel que EnTT.

DreamIn Engine