Showing posts with label tutogit. Show all posts
Showing posts with label tutogit. Show all posts

Sunday, November 16, 2025

Signets et attach

J'ai pour la SchoolZone l'intention d'introduire des signets/marque-pages qui pendouillent... on pourrait s'y accrocher (indispensable), grimper, descendre (sympa) et ils réagiraient comme des cordes plutôt que comme des barres.

J'ai appris dernièrement qu'il fallait que je prototype ce genre de choses dans l'environnement des "three rooms" sous peine d'être démoralisé par le côté "nu et inintéressant" d'un niveau à peine commencé. Et coup de bol, il y a un coin de la salle "école" qui conviendrait bien : le haut. On pourrait atteindre les signets en utilisant la gomme et s'en servir pour rejoindre l'éponge, un peu compliquée à utiliser pour l'instant.

Hanging to a rope-like bookmark, using it to swing around and hop to the next ... that's clearly something I'd like to bring into the school zone and I may have just found the right way to introduce it first in the "three rooms" demo. Yes, I could use one of the levels in which they are featured, but recent development on the green zone shown that a rushed large level doesn't motivate me as much as a small polished screen can. They would be there, in the top corner and providing an alternate way to reach the swinging Spongebop.

Avant de permettre de s'y accrocher et de se balancer, je voulais voir comment m'y prendre pour une interaction plus simple: juste laisser Bilou bousculer le signet et qu'il ondule un peu en reprenant sa place. J'ai le comportement "circular" qui pourrait être pas mal pour ça.

Before I'll let Bilou grab them and swing, I'll have to start with something easier, like just having Bilou disturb them and make them swing stronger when passing nearby. It should be a mere matter of attaching segments to one another with the "circular" controller... except that once Bilou pushes the bottom part of the "rope", segments now need to lookup two objects instead of just one. And that's a bit more tricky to handle for my engine that only allow one object pointer per object.  

Sauf que on tombe dans le cas de figure compliqué où les mouvements d'un segment dépendent à la fois de la position du segment au-dessus et en-dessous de lui, ce qui pose trois questions:

  • Est-ce qu'il faut que j'ajoute une zone "solide" à Bilou ?
  • Quels flags (pour les collisions) sont disponibles pour ajuster les comportements (j'ai oublié ^^") ?
  • de quelles infos est-ce que je dispose après une collision entre deux segments ? Est-ce suffisant ? 

J'avais pensé relire le tag "attach" pour me rafraîchir la mémoire, et j'ai eu la désagréable surprise de le trouver confus, avec quelque malheureuses infos pratiques perdues au milieu du "gamedev story". Il est devenu mon "tag de la semaine", mais j'ai dû reconnaître que ça ne suffisait pas. Je me suis retrouvé à essayer de l'extraire avec les outils "blogpress" et lui appliquer une feuille de style avant de l'utiliser pour tester les "pages web codeberg".

So, that was the idea back on 11/11 when I sat down with my notebook and collected the questions that needed answers before I could get to the coding stage. I thought unrolling the "attach" tag of the thread would give me answers, but it turned out the useful information was somehow lost into trivias, screenshots and other progress reports. And the code documentation wasn't much better, so I ended up restoring a setup for blogpress and tutogit at the same time, uploading them all on codeberg and see whether I could apply simple.css etc.

ça m'a donné le déclic pour reprendre le travail sur le repository "tutogit", en plan depuis 7 ans, vu que maintenant le nouveau système de gestion des propriétés du niveau est arrivé à maturité. Je pense que ce serait là le bon emplacement pour des pages thématiques présentant chaque élément du moteur de jeu ... qui puisse au final s'intégrer à la documentation doxygen. Voilà déjà celle pour attach.

Sunday, November 15, 2020

DS Day Off

 Il me restait quelques jours de congé à prendre. Et la Wallonie avait prolongé les congés de Toussaint de 7 jours ... du coup de mercredi à dimanche, j'ai pu prendre à peu près 2 heures par jour pour faire un peu de développement DS. L'objectif: pouvoir faire une démo des "blocs interactifs de taille variable". La stratégie: remplacer les fichiers de la "démo git père Noël" par les fichiers de Crazy Brix.

J'ai fini par y arriver, mais avec 3 jours de bidouille pour parvenir à utiliser des fichiers pré-existants, on ne peut pas dire que dsgametools soit prêt pour une game jam.

Mon éditeur de sprite ne m'a pas aidé à manipuler ce 'brix.spr', importé par WiFi, si bien que j'ai finalement ajouté un widget pour pouvoir ouvrir n'importe quel fichier (et pas juste les quatre "projets en cours").

Je devrai rajouter une p'tite couche de ce côté-là: une tentative pour sauvegarder les modifications, et vlan, c'est le répertoire tout entier qui s'est retrouvé renommé 'movibak'. Et aussi bien runMe que mon éditeur de niveau se sont retrouvés incapables de poursuivre le travail parce qu'ils n'avaient plus leur répertoire temporaire.

Le code de base du moteur de jeu m'a mis les bâtons dans les roues, lui aussi. Pour pouvoir changer la couleur des briques, j'ai utilisé les changements de palettes. Si, vous savez: ce mécanisme qui permettait à Super Mario Bros 1 de gratter quelques blocs mémoire en recolorant les nuages pour en faire des buissons. Ouais. Bin la DS sait faire ça aussi mais avec 16 variantes de couleurs pour 256 couleurs. Quelque part cet été, j'avais ajouté la possibilité de repeindre les morceaux du niveau (pas juste les éléments de décor, comme dans School Rush, mais aussi les éléments principaux). Mais j'avais oublié que le moteur de jeu, lui, n'était toujours pas prêt pour cette rajoute ^^". Et desmume n'est pas aussi sexy de ce point de vue-là que les émulateurs des devkits SNES ou NES: je ne me suis rendu compte de rien jusqu'à ce que je fasse un dump des registres graphiques dans DDD...

Voilà. Ajoutez un premier jour bien cahotique où le code importé du repository git ne voulait pas compiler, ou ne trouvait plus ses fichiers intégrés, ou "oubliait" de reprendre les couleurs des personnages parce que, dans sa branche, il n'y a même pas encore de support multi-palette pour les sprites (mais si, enfin. Ces p'tits blocs mobiles qui se déplacent librement sur l'écran, en plus des grilles qui servent pour les décors)... Vous comprendrez pourquoi ce genre de chose ne s'était pas mis en place depuis un bon moment.

Friday, May 18, 2018

Tuto branch update.

A few weeks ago, I found myself pressing the direction pad of my DS to keep
that little character onscreen. It had the most basic behaviour could think of because its sole purpose was to demonstrate how we control things in my game engine. Somehow, it felt a bit like an empty level in Space Taxi.
today, that same character moves around a place that comes from the level editor, with blocking tiles effectively blocking you. What it misses is a target. Snake-like pellets, if you want.

That requires me to revise:
- collisions between Gobs
- counters
- in-game level changes.

Sunday, April 22, 2018

to $(AR) or not to $(AR)

During the preparation of the "controllers" tutorial, I faced a weird linking problem. I wanted to split the huge "controllers.cxx" file so that every controller would be in a sub-file that could be compiled separately and no longer depend on the code from other controllers unless there is a good reason for that. And all of suddens, I had no more factories registered.

Just before that, I had reviewed the factory registering system so that it was enough to just write MomentumFactory mf("momentum"); as a top-level declaration to get everything up and running. But that meant there was no more reference from the main .o files of the game/demo that would require .o files with the factory code (and instance declaration), so they wouldn't be packed in, and certainly wouldn't be initialized either.

So I started thinking about weird mechanisms invoking bool pointers to dummy variables, or no-code functions, and even why not UsingPlatformer empty class that would extend UsingMomentum, UsingDpad and others... Then I realized that all this happened because the .o files (compilation output, that is. Equivalent of your *.OBJ if you're on MS-DOS) are packed into a static library and only pulled to populate the .NDS file on-demand at link-time. If instead I explicitly say "link Demo/*.o Controllers/*.o", they are put into the binary and no trick is needed anymore.

Monday, April 09, 2018

Tutorial revision goes on.

I reached the point where you can write very simple scripts and have them processed on the "tutorial" branch. Of course there isn't much follow-up at the moment despite the 3 forums on which I comment stuff. That doesn't really matter, although I'd love to get feedback on whether it reads well.

What is really interesting here is that it forces me to get rid of many odd things. Hopefully, that will lead to a code base that will be easier to extend. Things like "rules.gam", for instance.

Being busy reviewing the expressions system, for instance, make it obvious that some static array could be gone now that I have the gob collision structure. the "game counter al so cry for a refactoring out of the GameScript class. And making the 'guns/controllers' system easier to understand (esp. by automating the registration system) made it obvious that I need to re-think the way classes access the Camera object.

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.

Tutoriel libgeds - jour 5



Redonner du mouvement au personnage dans geds, ça correspond à spécifier une série de contrôleurs pour l'état choisi. Chaque contrôleur a une mission bien précise, p.ex. ici

Code:
state0 :anim1 {
   using dpad
   using momentum(x to 512)
   using momentum(y to 512)
}
dpad va lire les registres de la console et sauver les directions
momentum va utiliser les directions sauvées pour augmenter ou diminuer la vitesse horizontale ou verticale (selon qu'on a utilisé "x" ou "y")

On peut aussi passer des paramètres aux contrôleurs: c'est le cas ici du "512" qu'il faut interpréter comme un nombre de 256emes de pixels par frame (1/60eme de seconde) et qui représente la vitesse maximale autorisée sur un axe.

Le ScriptParser cherchera les classes C++ correspondantes et fait le nécessaire pour que le code qu'elles contiennent soient appelées à chaque image générée par le jeu.

Trois lignes de plus dans le script donc (et quelques modifications dans les Makefiles). C'est tout.

Saturday, March 24, 2018

Tutoriel Libgeds - Jour 1

Salut à tous. Vous le savez déjà, je fais des programmes et des jeux sur Nintendo DS. L'idée, c'est que tout ce que j'ai fait devrait permettre à d'autres d'en faire autant. J'ai commencé une repasse sur mon code pour montrer petit à petit comment se servir de mes outils et de mon moteur de jeu.

Pour ça, il vous faudra d'abord le kit de développement non-officiel pour NDS et GBA. Ils ont fait du bon travail et il y a un installeur automatique pour ceux qui travaillent sous Windows.

De mon côté, j'ai préparé une structure d'accueil pour les programmes. Règles de génération des ROMs nds à partir des sources et des données du jeu, les petites bibliothèques supplémentaires pour faire de la musique, etc. Et un un premier programme à faire tourner sur DS. Evidemment, on est sur une machine "bare metal", sans système d'exploitation, donc il y a un peu plus de code d'initialisation qu'à l'habitude, mais le fait de créer un objet "Engine" fait déjà une grande part du travail.

Code:
void setactive() {
    FileDataReader fd("efs:/sndtrk.xm");
    ntxm9->stop();
    u16 err = ntxm9->load(&fd);
    ge.setWindow(active);
    if (err!=0) iprintf("ntxm says %x\n",err);
}
Un premier morceau, qui charge un morceau de musique (on en trouve d'autres du genre sur modarchive.org). Il sera joué sur le processeur secondaire de la console, l'ARM7. L'objet ntxm9 nous permettra de transmettre des commandes du genre "passe moi la fanfare de fin de niveau" ou "joue un bruit d'explosion" au fil du jeu.

Je propose deux manière d'interagir avec les boutons et l'écran tactile de la console: l'un pour la partie "action" du jeu (pas encore dans le tuto), et l'autre qui me sert pour les éditeurs: ge.setWindow() a défini notre objet window comme étant l'activité actuelle, donc le moteur appellera la fonction ci-dessous chaque fois qu'on pousse sur un des boutons.
Code:
bool handle(uint& keys, Event evt) {
    if (keys & KEY_A) {
      ntxm9->play();
    }
    if (keys & KEY_Y) {
      ntxm9->stop();
    }
    return true;
}
Allez, la prochaine fois je vous raconterai comment mettre des images à l'écran

Tutoriel libgeds - jour 2

Bon, avant de voir comment le moteur 'GEDS' peut charger des images dans la mémoire vidéo de la Nintendo DS, il faut que je vous explique un peu comment son processeur graphique construit les images que l'on voit à l'écran. J'utilise le mode "texte", ici, où les images sont composées d'élément de 8x8 pixels appelés "tiles" (prononcez 'taïlesz') que l'on dispose sur une grille.

Vous avez tous déjà utilisé un éditeur de donjons RPG où l'on travaille carré par carré (je crois qu'on dis volontiers des 'chips' ?) plutôt que de mettre un arbre ou une maison d'un coup. Le mode texte de la DS va un cran plus loin: la mémoire de la machine elle-même est découpée en une région pour retenir des pavés de 8x8 (le 'tileset') et une région pour indiquer quel pavé montrer à quel endroit (la 'map' de l'écran, couvrant généralement 256x256 pixels pour la DS). Parfois, on mettra le même tile à plusieurs endroit de l'écran (en inscrivant juste son numéro dans plusieurs cases de la map), et parfois un tile ne sera pas repris (pour l'instant). C'est une technique a peu près aussi vieille que les machines 8-bit et qui a perduré pendant toute la période 16-bit (mais ça, c'est une autre histoire). Ce qui a changé au fil du temps, c'est le nombre de couleurs autorisées par tile (de 3 pour la NES à 255 pour la NDS) et le nombre de calques que l'on peut superposer pour obtenir l'image souhaitée (jusqu'à 4 sur la NDS).

Les fichiers .spr créés par le SpriteEditor pour DS sont principalement une sauvegarde du contenu de la mémoire vidéo tel qu'on voudrait l'avoir pendant le jeu. Du coup, il n'y a vraiment pas grand-chose à faire pour pouvoir les importer dans son programme.

Code:
  SpriteRam myRam(WIDGETS_CHARSET(512));
  SpriteSet mySet(&myRam, BG_PALETTE);

  mySet.Load("efs:/bg.spr");
Et voilà. quelques précisions pour dire au moteur de jeu où mettre les graphismes (ici, sur l'écran "du haut", en laissant 512 emplacement pour une police de caractère et pour les 'maps' des différents calques) et où mettre la palette de couleur présente dans le fichier .spr (également dans la mémoire de palette de l'écran supérieur). La classe SpriteSet du moteur de jeu s'occupe de manipuler le fichier et d'en reconnaître le format. On pourrait aussi prendre le contrôle de toute la mémoire vidéo en utilisant directement myRam(BG_GFX), mais c'est un peu moins confortable pour la suite.

Bon, malheureusement, avoir des graphismes en mémoire ne suffit pas pour les avoir à l'écran. La démo n°2 doit aussi configurer la puce graphique pour qu'elle utilise nos données et remplir la grille/map d'un des calques.

Code:
REG_DISPCNT|=DISPLAY_BG2_ACTIVE;
REG_BG2CNT=BG_MAP_BASE(GEBGROUND)|BG_TILE_BASE(0)|BG_COLOR_256;
La configuration, on va régler ça en programmant directement les registres de la puce graphique. C'est tellement facile sur DS . J'active le bit correspondant au calque n° 2 (j'l'aime bien, celui-là) dans le contrôle principal de l'écran (REGister_DISPlayCoNTrol), puis je donne les paramètres de ce calque dans son registre à lui: les données des tiles seront interprétées comme ayant 256 couleurs, quelle grille utiliser comme map, et si je veux ajouter automatiquement un décalage à tous les numéros de tiles de la map (BG_TILE_BASE) par rapport à la position dans la mémoire du tileset (ce que je ne fais pas ici).

La bibliothèque 'libgeds' donne des paires de noms à différentes grilles: un nom pour la configuration de BG_MAP_BASE, et un nom pour le tableau correspondant dans la mémoire vidéo (WIDGETS_BACKGROUND). Du coup avec la configuration qu'on vient de faire, on peut changer le pavé en haut à gauche de l'écran en écrivant dans WIDGETS_BACKGROUND[0]. Dans celui en haut à droite avec WIDGETS_BACKGROUND[31] (parce qu'il y a 32x8 dans 256 ) et WIDGETS_BACKGROUND[32] sera le pavé juste en-dessous de WIDGETS_BACKGROUND[0]. Et ainsi, ligne après ligne. Bref, avec un peu de sucre et une feuille de papier, vous arriverez rapidement à voir que WIDGETS_BACKGROUND[32*ligne+colonne] vous permet de modifier n'importe quel emplacement de l'écran.

Code:
for (int l=0; l<32; l+=2) {
  for (int b=0; b<8; b+=2) {
    WIDGETS_BACKGROUND[b+l*32]=tile++;
    WIDGETS_BACKGROUND[b+l*32 +1 ]=tile++;
    WIDGETS_BACKGROUND[b+l*32 +32]=tile++;
    WIDGETS_BACKGROUND[b+l*32 +33]=tile++;
  }
}
Moi, j'avais envie de montrer l'ensemble des graphismes de mon fichier .spr, tels qu'on les voit dans l'éditeur. Et dans le quart le plus à gauche de l'écran (une zone de 64x192 pixels). Il reste un petit truc à régler: l'éditeur travaille par blocs de 16x16 pixels, pour le confort du graphiste. En interne, un bloc est composé de 4 tiles de 8x8 pixels, agencés eux aussi suivant le mode "une ligne, puis l'autre". Si je veux que les blocs ne se retrouvent pas coupés en 2, je dois respecter cet agencement au moment de remplir la grille:
Code:
/* 0 1
 * 2 3
 */
D'où les boucles qui passent une ligne sur deux et les quatres écritures à WIDGETS_BACKGROUND par itération.

Voilà. Le code est sur github, donc. Avec le fichier .spr (creative common)


N'hésitez pas à me ralentir avec quelques questions si ça va trop vite pour vous.

Tutoriel libgeds - jour 3

Un des éléments les plus importants dans un jeu vidéo (2D), ce sont sans doute les sprites. Rien à voir avec une boisson pétillante, il s'agit du terme consacré pour les objets graphiques librement déplaçable à l'écran, y compris le personnage principal, les adversaires, mais aussi certains power-ups ou des effets spéciaux.

Les sprites ont besoin de données graphiques (des valeurs de couleurs) tout comme les décors, et ces données sont de nouveau constituées de "tiles". On va utiliser surtout des blocs de 16x16 pixels ici (et donc constitués de 2x2 tiles) mais la DS peut en réalité utiliser des sprites de 8x8 à 64x64 pisxels (avec quelques restrictions quand-même).

Mettre à jour la mémoire vidéo pour que les sprites s'affichent à l'écran (quels graphismes, quels réglages, etc) est délégué à la classe SpritePage dans la libgeds, et la fonction "sync()" de GuiEngine fera le nécessaire pour mettre à jour les coordonnées en respectant les timings de la puce vidéo (et faire en sorte que ça ne clignote pas, par exemple).

The English version of these tutorials sit at https://gbatemp.net/threads/tutorials-for-my-game-engine.497728/, where they are hopefully more likely to connect to potentially interested users. I once had the French version hosted on a forum too, but that forum is now defunct, so I'd rather bring them back home before the forum goes broken.

Les SpritePages ajoute un niveau de correspondance entre les identifiants logiques des graphismes (ceux que le développeur utilise, "c'est sur la page 3, deuxième ligne, première colonne) et les emplacement "physiques" dans la mémoire vidéo (42eme bloc sur 256 en mémoire). Bref, le contenu de la SpriteRam est généralement un joyeux chaos résultant des créations et supressions de blocs alors que chaque SpritePage est organisée exactement comme l'utilisateur le décide.

le brol de la SpriteRam la SpritePage, aussi organisé que vous

Code:
class Hero : private UsingSprites {
  NOCOPY(Hero);
  const SpritePage *page;
  unsigned x, y;
  oamno_t oam;
public:
  Hero(const SpritePage *pg) : page(pg), x(128), y(96),
         oam((oamno_t) gResources->allocate(RES_OAM))
  {
    page->setOAM((blockno_t)2, sprites);

  }

  void move(int dx, int dy) {
    x += dx; y += dy;
    iprintf("(%u,%u)", x, y);
    page->changeOAM(sprites + oam, x, y, (blockno_t) 4);
  }
};
Notre petite classe 'Hero' montre tout ce qu'il faut pour avoir un objet mobile:
- se souvenir des coordonnées (le bon mot pour parler de la position à l'écran) actuelles;
- une SpritePage qui sait comment mettre à jour les entrées de la "MAO" (ou Mémoire des Attributs d'Objets -- Object Attribute Memory -- le terme de Nintendo pour parler des blocs de contrôle des sprites);
- avoir réservé une entrée de MAO et en retenir le numéro.

En disant que notre classe dérive de "UsingSprites", on obtient l'accès au tableau des MAOs (le tableau 'sprites[]') que le moteur de jeu va utiliser pendant la fonction sync(), mais aussi au gestionnaire de ressources (`gResources`) qui nous donne notre numéro de MAO. Du coup, la SpritePage a tout ce qu'il lui faut pour faire son travail.

Code:
void setactive() {
   SpriteRam myRam(WIDGETS_CHARSET(512));
   SpriteSet mySet(&myRam, BG_PALETTE);

   mySet.Load("efs:/bg.spr");
/*+*/ sprSet.Load("efs:/hero.spr");

  // rest of MetaWindow::setActive() as defined in previous tutorial
/*+*/ hero = new Hero(sprSet.getpage(PAGE0));
}
Charger les graphismes des sprites en mémoire vidéo ressemble très fort à ce qu'on a déjà fait pour les décors dans le tutoriel précédent. Sauf que cette fois, il faut s'assurer que les objets "SpriteSet" et "SpriteRam" resteront 'en vie' au moins aussi longtemps que notre Hero (qui les utilisera à travers la SpritePage). Du coup, on en fait des membres de la MetaWindow, plutôt que des variables temporaires. Ça signifie aussi qu'il nous faut attendre que les données soient chargées avant de pouvoir créer notre Héro.

Puis il n'y a plus qu'à tester l'état de la croix directionnelle (et les transmettre par des appels à la fonction 'move()') pour pouvoir déplacer le personnage en réaction aux mouvements imprimés par le joueur. Bon, ne vous attendez pas à quelque-chose de fluide ici: j'utilise toujours l'interface utilisateur prévue pour les éditeurs du projet "GEDS" qui ne produit un 'évèment DPAD' que lorsqu'on appuie sur une nouvelle direction. On arrangera ça la semaine prochaine avec les Animators.

Code:
if (keys & KEY_UP) {
  hero->move(0, -4);
}
if (keys & KEY_DOWN) {
  hero->move(0, 4);
}
if (keys & KEY_LEFT) {
  hero->move(-4, 0);
}
if (keys & KEY_RIGHT) {
  hero->move(4, 0);
}
Les détails sont sur github, comme toujours.

Monday, March 19, 2018

Biggest Refactory Ever

For me, at least. I wanted to make the scripts occur as soon as possible in my tutorial series, since the GEDS engine is meant to allow game-making even for those who don't know about C++ programming. But I also want to be able to introduce a behaviour editor, which suggests that the same script-parsing logic should be able to drive either the game engine or the state machine model in the editor.

So this last week, I've been busy splitting the big singleton "GameScript" that had both the parsing logic and the engine intimacy into two classes, the ScriptParser that knows the language rules and the Game* objects well enough to create them but has no knowledge about the Nintendo DS resources or the game engine per se, and the GameScript, that knows about the engine's runtime, last as long as the level does, hold resources and the like.


ça bosse ferme ... restructuration du lecteur de scripts pour pouvoir introduire un éditeur de machines d'état ...

I've finally reached a point where all my automated tests work again. Of course, School Rush isn't running fine in this branch ... yet.

edit: Okay, SchoolRush runs fine again in the emulator. Just some un-initialized arrays. -Weffc++ should have caught that, though.

Wednesday, March 07, 2018

libgeds tutorial

I have just started a github with one branch of the dsgametools project: the 'tutorials' branch, where I'm reconstructing and detailing step by step the components of the (refactored) game engine... together with Creative-Commons pictures and sounds to make demos on a regular basis.

Additional chatting and promotion of the tutorials happen in gbatemp and e-magination forums.


Cette fois-ci ça y est. J'ai transféré la branche "un tutoriel après l'autre" sur github. Pour que chacun puisse facilement suivre ma tentative de réécrire le moteur des jeux Bilou. Histoire que les différentes fonctions disponibles soient capturées clairement, et non pas éparpillées sur une demi-douzaine de patches.

On verra bien si ça intéresse du monde...

the mercurial-to-git conversion is performed by the fast-export tool from Frej. The process looks as follows:

cd hg2git/
cd dsgametools-hg/
# hg incoming -r $(hg id -b)
hg pull -r $(hg id -b)
cd ../tutorials-git/
../fast-export/hg-fast-export.sh -r ../dsgametools-hg
# git log
# git push --dry-run git@github.com:PypeBros/libgeds-tutorials.git
git push git@github.com:PypeBros/libgeds-tutorials.git
cd ..

Friday, February 16, 2018

typedef u16 pageno_t

J'avoue que quand j'ai fait ma transition de l'assembleur vers le C, je faisais une mimique assez cocasse à la vue de uint32_t et size_t. Quoi, c'est un 'dword' (double-mot, jargon intel dans les assembleurs). Pourquoi aller lui donner un nom à coucher dehors pareil ? Bref, j'étais pas un fan de typedef, à part pour éviter de devoir écrire "struct" devant le nom de mes structures. Alors rajouter un #include<stddef.h> ...

Mais sur l'année écoulée, j'ai eu droit à plusieurs situations du genre int bitrate. Ah oui? en quelle unité, s'il vous plait, le bitrate ? bit/seconde ? kilobit/seconde ? megabit/seconde ? Et dans le code de mon moteur de jeu, int x ou int width est à peu près pareil. Est-ce que x est une coordonnée absolue (dans le niveau) ou relative (à l'écran) ? est-ce qu'elle est exprimée en pixels ? en tiles (si, si, souvenez vous, les petits pavés élémentaires de graphisme) ? en 256eme de pixel pour les calculs de déplacement avant affichage ?

Alors bien sûr, on peut tenter int kbps, int x_in_tiles, etc. Mais pourquoi. Pourquoi faire rentrer dans le nom de la variable une information (l'unité de mesure) qui dénote plutôt de son type (on peut additionner deux valeurs en kbps entre elles, mais pas des Mbps et des kbps sans faire une conversion au préalable). Bref, j'ai pris l'habitude de construire des types qui expriment des unités de mesure. Beaucoup. Au point que je me méfie presque maintenant du code qui annonce juste un "int" parce que dès qu'on va commencer à intégrer des morceaux de code qui viennent d'horizon différents, on aura aucun moyen de se souvenir si le * 1000 qui est là dans l'appel de fonction est justifié ou non.

Et comme je viens d'atteindre le point ou la branche "revisite pour cause de tutoriel" de mon moteur de jeu est prête à recevoir le code servant à charger des fichiers .spr, ce serait peut-être le bon moment pour y introduire des types comme "numéro de page, numéro de bloc, numéro de tile", etc.

Tuesday, December 12, 2017

branches, reviews and cannelloni

The idea is hanging around. It has been for some times, now. Possibly since I re-started exporting code to e-book readers through Doxygen, or since I tried to use apple assault as a tutorial to libgeds. I'd like to go for some in-depth review of my engine code. I'd like to use powers of code versioning system to slice code into readable, purpose-supported chunks, which would help the reader which components bring what feature and how they interact together.


Plus les choses avancent, et plus j'ai envie de pouvoir proposer quelque-chose de plus didactique pour encourager d'autres amateurs de développement de jeu à s'essayer à la plate-forme NintendoDS. Pour ça, il me faudrait pas mal de réorganisation du code, et (idéalement) une branche mercurial qui approcherait les techniques nécessaires une par une, mieux documentées et testables. Et là, maintenant, c'est parti.

But now, I started it. I've got a "bare minimum" DS application with corresponding library code (mine or 3rd-party), and its build system.
[done] found the source of Noda's EFs tool again.
[done] have it built as part of the dsgametools host-tools binaries, buildroot-style.

Tuesday, November 14, 2017

Qui est volontaire ?

Je voudrais pouvoir faire une série "tutorielle" pour introduire progressivement les concepts de mon moteur de jeu et fournir une base de travail à d'éventuels game-makers amateurs qui voudraient s'essayer sur DS. Je voudrais aussi qu'ils puissent avoir quelques graphismes de référence, y compris les personnages.

ç'aurait pu être la bestiole de Pipemare (RSD), mais j'ai du mal à me l'approprier. ça ne peut pas être Jack Boost, Badman, Spector, parce qu'ils ne m'appartiennent pas en tant que personnage. Je n'ai pas envie que ce soit Bouli ou Biokid parce que j'y suis trop attaché, alors qui ?

For ten years now, I've been developing a game engine for the Nintendo DS. It isn't perfect but it already allows to do interesting things. And while most of the homebrew we've seen in the golden era of NDS development were using static screen, with GEDS, we have the full power of large maps and parallax scrolling.

Yet so far, I have failed to offer a workable starter kit for the libgeds and dsgametools. Apple Assault source code is mostly obsolete. Discovery packs for LEDS and AnimEDS weren't really helping to kick into game development. And my tilesets are too complicated for a 8-years-old to start sketching levels.

I'd like to take some time to craft something better. A small tileset inspired by Kenneth Fejer mockups. A generic-enough-but-yet-inspiring character that could be sent onto a Commander Keen / Nicky Boom-like adventure.


J'ai envisagé de commencer par un exemple basé sur Out'm'Up, SeaFox ou Crazy Brix, mais aucun n'est vraiment pratique pour montrer ce dont le moteur GEDS est capable (scrolling multi-niveaux, animation modulaire, etc). Non, il me faut une aventure à la Nicky Boom ou Commander Keen.

Reste les personnages secondaires que j'ai développés. Nono le gamin malchanceux (une version anonymisée de Badman, en sorte), Mo le sorcier maladroit, Mol la taupe punk ou Mike Boost, le talentueux mais ténébreux. Ou alors affubler spector d'une tête de souris ?

Rien de complètement convaincant. Reste la possibilité de faire des pixels sur mesure. Voici donc "power kid", qui a l'avantage d'être un perso rigolo.

Of course, given the amount of games I have contributed to together with other PPP Team members, it may sound weird that I'm on a quest for a character to drop to the public domain. The thing is, most of them were designed by other members (Badman, Jack Boost, Biokid) or collectively... or were pastiche of copyrighted characters (Calimero, Xeen, Frogger). My best candidate would be the punk mole I inserted in Badman II and who was playable in my brother's "4 to save Toon Land", althoug -- as you can see from the sketches -- it is definitely not the only option.

Saturday, December 31, 2005

tutogit [t.a.g]

Well, if you're an English reader, chances are this category wasn't convincing for you. There's a good reason for that: the set of presentation posts that was used to promote the libgeds tutorial branch on github was initially posted on gbatemp forums. There was a french translation too, but on deserted boards that are likely to turn 404 fairly soon. 

But don't worry: the whole story in English is now available as a pdf.