Wednesday, April 04, 2018

Tutoriel libgeds - day 4

Bon, il est temps de vous montrer ce que libgeds peut faire pour ceux qui n'ont pas le C++ dans le sang. Charger des fichiers, définir des animations, positionner les ennemis dans le niveau, tout ça peut être fait à partir de commandes dans des scripts texte lus et transformés en objets C++ par la bibliothèque.

Je vais commencer par un sous-script qui décrit le comportement d'un personnage. On va commencer très simple, avec une seule animation, et toujours le même comportement: ne pas bouger. Voici donc "xdad.cmd"

Code:
# this is xdad.cmd behaviour description
anim1 0 {
  spr0 4
  delay 3
  spr0 5
  delay 3
  spr0 6
  delay 3
  spr0 7
  delay 3
  spr0 8
  delay 3
  spr0 9
  delay 3
  spr0 a
  delay 3
  spr0 b
  delay 3
  loop
}

state0 :anim1

end

Le bloc 'anim<numéro-d-animation>' donne utilise une page du SpriteSet et construit une animation en indiquant les images à utiliser (dans cette page) et combien de temps attendre entre chaque deux images. On peut ensuite l'attacher à un état, c'est à dire une unité élémentaire de comportement . Bon, évidemment, pour l'instant, avec un seul état, il ne se passera pas grand-chose. C'est un peu notre 'hello world'.

Un fichier comme xdad.cmd, on en créera un par type de personnage (imaginez "goomba.cmd", "koopa.cmd", etc.) Maintenant, il va nous falloir un script qui décrit un niveau. Ce sera demo.cmd, pour nous.
Code:
#demo.cmd, resource management
print "loading tileset"
bg0.load "../bg.spr"
print "loading sprites"
spr.load "../hero.spr":1
On y retrouve des commandes gérant le chargement des fichiers de données qui remplace les SpriteSet::Load().

Code:
#demo.cmd, use 'character' description
input "xdad.cmd"
import state 0
On y retrouve aussi évidemment des commandes pour réutiliser les fichiers comme xdad.cmd, évidemment. la commande 'import state 0' mérite quelques mots d'explication supplémentaires. Pour un vrai personnage de jeu vidéo, il y aura bien sûr de nombreux états... On peut en compter au moins 21 par direction dans Super Mario world, par exemple.

Pourtant, seuls un ou deux de ces états sont nécessaires pour décrire le niveau (commencer tourné vers la droite ou vers la gauche, par exemple, ou éventuellement par une glissade). Geds propose donc un jeu d'identifiants pour l'ensemble des états d'un personnage (tous les états d'un goomba, par exemple) qui sera utilisé dans xdad.cmd, et l'ensemble des états utilisables pour créer des nouveaux objets (un goomba, mario, un koopa rouge ou un koopa vert), qui sera utilisé dans demo.cmd.
Une fois le traitement xdad.cmd terminé, la commande 'import state 0' indique de prendre le premier état de l'ensemble de xdad et d'en faire l'état numéro 0 pour demo.cmd.

Code:
# creating gobs
gob0 :state0 (128, 100)
end
Enfin, on peut constuire un nouveau personnage (le Game object) avec cet état, en donnant les coordonnée du personnage à l'écran.

Comme on le voit sur github, on laisse tomber la classe Hero: il s'agit maintenant d'un GameObject construit et contrôlé directement par la bibliothèque suite au commandes du script.

La classe 'MetaWindow', point de départ de notre démo, a pas mal changé aussi.
Code:
#include <GameWindow.hpp>
class MetaWindow : public DownWindow {
  NOCOPY(MetaWindow);
  Window *active;
  InputReader* reader;
  LoadingWindow loadwin;
  GameWindow gamewin;
public:
  MetaWindow(): active(0),
   reader(0),
   loadwin(&reader),    gamewin(this, &reader, &loadwin)  {
     ntxm9 = new NTXM9(); // for the sound, remember ?
     active = &gamewin;
   }
C'est la classe GameWindow de libgeds qui va créer, charger et traiter les scripts, et assurer la gestion de tous les objets qui en découlent, les animations, les personnages, etc. Sa compagne, LoadingWindow sert lors des changement de niveaux (on y reviendra). Pas grand chose à dire sur le constructeur puisqu'à ce moment-là, les fichiers intégrés à la ROM ne sont pas encore disponibles. L'initialisation, la vraie, se passera dans 'setactive()'.

Code:
   void setactive() {
     FileDataReader fd("efs:/sndtrk.xm");
     reader = new FileReader("efs:/demo.cmd");
     ntxm9->stop();
     u16 err = ntxm9->load(&fd);
     ge.setWindow(active);
     restore(); // just to have the tileset shown again.
     if (err!=0) iprintf("ntxm says %x\n",err);
   }
Par le simple fait de demander au moteur de jeu de passer le contrôle à GameWindow, le chargement commence automatiquement à travers le 'FileReader' (lecteur de fichiers, donc) qu'on vient de construire.
Et c'est tout. A la prochaine fois pour rendre ses déplacement à notre petit père Noël.

No comments: