Je ne savais pas trop où poster ça. Vu que c'est un projet sur lequel je bosse et qu'il est
presque terminé (les 3/4 du code sont bouclés et ça devrait être fini d'ici un mois), j'ai opté pour la section "projets terminés". Je m'excuse d'avance pour la publicité mensongère.
Voici donc mon projet: AGE. AGE, pour
Adaptable Game Engine.
Introduction AGE est une bibliothèque DLL écrite en
C# permettant la création de toutes formes de jeux/applications multimédia. Elle utilise
IrrlichtNETCP pour la vidéo,
Bass.NET (pas
IrrKlang, qui n'offre pas assez de possibilités) pour le son et
ODE.NET pour la physique.
L'utilisation du moteur est simple : il suffit de créer une instance de la classe
AGEEngine (imaginez-la comme une sorte de
IrrlichtDevice, la mère de tout le reste). Ensuite, cette classe a pour principale fonction de créer des entités via les diverses méthodes
AddEntity().
1- Le concept d'entité C'est quoi donc, une entité? En fait, tout élément du monde de AGE dérive de la classe abstraite
AGEEntity. L'idée est de faire en sorte que cet objet soit la SEULE chose dont vous ayez besoin pour ajouter un élément à votre jeu. Vous voulez lui faire émettre un son? Pas de problème, le moteur gérera la stéréo et le volume automatiquement en fonction de sa position relative à la caméra. Vous préférez qu'il émettre un vrombissement permanent ? Très bien, AGE s'occupe de tout: quand l'entité passera à côté de vous, le volume et la stéréo évolueront automatiquement. Oui, l'
effet Doppler est géré. De la même façon, plus besoin de se prendre la tête à "lier" l'objet du moteur physique à l'objet du moteur vidéo. Une entité a un modèle 3D (ou autre chose d'ailleurs, ça peut être un
skydome, une fontaine de particules, un
billboard, etc...), c'est un fait, mais elle a aussi une masse, une vitesse, etc... En gros c'est un « objet » complet, comme dans le monde réel. Quand je me casse la gueule de ma chaise, il n'y a pas mon modèle 3D d'un côté, ma physique de l'autre et un informaticien derrière qui se bagarre pour lier les deux : pourquoi cela devrait-il être différent dans un moteur de jeu ?
Mais le concept d'entité va plus loin : au delà du moteur de jeu, l'entité est donc supposée être un "objet" du monde. Pourquoi alors faudrait-il stocker ailleurs les éléments qui ne relèvent pas du moteur mais du gameplay ? La classe
AGEEntity contient donc une sorte de
hashtable (pour ceux qui ne connaissent pas, c'est un tableau qui lie une clé -ici une
string- à une valeur) baptisée
Properties. Vous voulez que votre entité ait des points de vie? Ajoutez une valeur
health de type integer à ses propriétés. Pour y accéder, vous n'aurez qu'à faire
MyAGEEntity.Property[health]. Une propriété peut être de n'importe quel type (même une autre entité ou une autre table de propriétés, mais là bon courage), et peut aussi être un tableau.
Maintenant, si vous voulez que votre entité reste tranquille à regarder les étoiles scintiller dans la
skybox au dessus de sa tête, vous pouvez le faire. Mais si vous voulez qu'elle ait un comportement un peu plus dynamique, rien de plus simple. Tout se fait via des
events et des
delegates. Par exemple, l'évènement
OnEachFrame est appelé 10 fois par seconde. Ecrivez une petite méthode d'intelligence artificielle, et hop, en une ligne de code (
MyAGEEntity.OnEachFrame += MyAIRoutine()) vous pouvez l'assigner à toutes les entités qui doivent l'utiliser. D'autres évènements seront prévus pour tout ce qui peut se produire (clic sur l'entité, collisions, proximité, etc...)
En résumé : avant, un personnage c'était un node Irrlicht + un Geom ODE + tout un machin truc pour le son + une classe en plus qui gérait son comportement. Maintenant, c'est une entité AGE.
2- Autres fonctionnalitésEn plus de cela, AGE contient (pour l'instant, ça va s'alourdir avec le temps) :
AGEInputHandler qui permet de gérer (via des événements) à peu près tous les « inputs » dont on peut avoir besoin dans une application multimédia. Cela va des classiques
OnMouseMove(),
OnMouseWheel() et
OnKeyUp() à d'autres plus exotiques comme
OnJoystickMove(), par exemple.
AGEAudioPlayer qui permet de jouer un son/une musique (wav, ogg, mp3 ou midi) et d'altérer sa position dans l'espace mais aussi sa fréquence (par exemple pour simuler le moteur d'une voiture qui accélère). Une variation aléatoire de la fréquence peut aussi être spécifiée (pour que le son d'un flingue sonne un peu plus grave ou plus aigu d'une détonation à l'autre, par exemple).
- Un nouveau type de caméra en plus de la caméra FPS et de la caméra "targeted" : la caméra "rotating". Sa rotation est passée via un
Vector3D comme pour un node "normal", y compris sur l'axe Z (axe "roll"). Ceux qui se sont cassés les dents à essayer de simuler un cockpit d'avion sous Irrlicht savent de quoi je parle.
- AGE étend également les possibilités de Irrlicht en ce qui concerne les jeux 2D. Certes, Irrlicht a toujours permis de créer des jeux en 2D, mais bon, c'était pas pratique: il fallait, à chaque boucle "
BeginScene()EndScene()", redessiner tout le bordel, calculer la position modifiée par rapport à la "caméra". Il n'y avait pas d'équivalent 2D du
SceneManager. Maintenant, c'est fini : une entité peut être 2D. C'est à dire qu'elle aura une taille, une texture et une position (comme un Node 3D de Irrlicht). Quand à la classe
Camera2D, elle a une position et un "field of view" comme sa contrepartie 3D que vous connaissez déjà. Du coup, plus à se fatiguer à calculer les coordonées-écran de vos petits personnages de votre jeu de rôles 2D à l'ancienne, AGE le fait pour vous.
3- L'espace AGE.LibraryAGE contient également, dans le namespace
AGE.Library, toute une batterie de classes "gadgets" qui peuvent servir pour divers types de jeux, entre autre (il y en a beaucoup) :
AGERandom a un constructeur qui admet en paramètre une chaîne pouvant contenir toutes sorte de plages de valeurs aléatoires : rentrez "1-8" et un chiffre entre un et huit sera généré lors du tirage. Entrez "3d6+4" et la classe simulera le jet de 3 dés à 6 faces auquel 4 sera ajouté (ce qui permet, entre autre, de distribuer les résultats de façon non linéaire – selon une
distribution de Gauss, pour être plus précis). Il est également possible de spécifier des valeurs "plancher" et "plafond" pour que, par exemple, le résultat de votre tirage de "2d8-4" ne soit jamais inférieur à 1.
NameGenerator permet de générer aléatoirement des noms en combinant création aléatoire de syllabes et parties "fixées". Par exemple, spécifier un prénom dans une liste de prénoms existants (fournis via un tableau de strings) et laisser le nom de famille être généré totalement aléatoirement. Ou seulement la deuxième partie du nom de famille pour un écossais dont le nom commencera forcément par "Mac". Enfin c'est juste un exemple.
Ici un programme en ligne qui fait grosso modo la même chose, pour vous donner une idée.LevelGenerator crée, d'après certains paramètres, un niveau de "donjon" (utile pour un jeu de rôle, ou pour le mode "skirmish" d'un FPS par exemple) ou une carte géographique (avec la distribution des différentes "tiles" : eau, montagnes, rochers, neige... Par exemple pour un wargame, ou les niveaux en extérieur d'un jeu de rôle).
Ici un programme en ligne qui fait grosso modo la même chose, pour vous donner une idée.AGEXMLFile permet de gérer facilement des fichiers XML pour enregistrer/lire les paramètres de jeu, ou pour permettre de créer des jeux "moddables" (si chaque unité d'un wargame est un fichier XML dans le répertoire "units", et bien le jeu gagne beaucoup en durée de vie par rapport à une version où elles seraient "hardcoddées" dans le code source, non?)
AGEEncryptedXMLFile fait la même chose, sauf que le fichier XML enregistré est crypté via un algorithme RC2. Utile pour les sauvegardes de jeu, histoire que le petit Kévin, 11 ans, ne s'amuse pas à se rajouter quelques vies vite fait. On pourrait faire la même chose en utilisant un fichier binaire pour les sauvegardes, me dites-vous? Ouais, mais là vous conservez la souplesse d'utilisation du XML.
4- Et maintenant ? Et bien voilà... J'attends vos suggestions, vos conseils, vos critiques... Pensez-vous que tout ce projet est une bonne idée ou pas ? Qu'aimeriez vous y voir de plus ?
Tenez-moi informé, j'en ferai de même d'ici un mois environ, quand la version 0.1 de AGE sera mise en ligne. Je rechercherai alors des gens pour m'aider à écrire une API, tester tout ça à fond et m'aider à réaliser le plus vite possible une version totalement crossplatform (certains morceaux du code de la version actuelle, comme ceux utilisés pour le moment pour le son et le joystick sont windows only).
Voilà voilà. Merci d'avoir lu jusqu'ici !