Thursday, January 11, 2018

Engine Refactory

The Big Refactory has started (I could pretend it is a new-year resolution). And it even went pretty far, like abstracting away the animated objects list so that only the code for animated objects need to know details of the animation scheduler.

I was about to try changing the VRAM allocation system so that only classes deriving from using Resources could request items, and I got stuck in the animation editor.

Unlike SEDs and -to some extent- LEDs, AniMEDs still use a lot of global variables. Things like the sprite set or the animation being editted are used almost directly in many places, instead of being captured as "structural singletons". And at some places, it also means that we were calling Ressource Manager directly at top-level code, and that contradicts what a common base class can do.

There is one other peculiar thing about the animation editor: the set of pixels used in the game isn't uploaded to the video memory. Instead, we keep it in main memory, and only some bits of it go tothe VRAM through a Sprite sheet that map some sprite memory.  These sprite sheets are linked to a specific widget, such as the timeline or the frame preview. I must not try to make them part of a "model": they truly belong to the implementation of the widgets.

And yeah, although I have a digital sketchpad and an e-boox, I still enjoy some good paper and fine (erasable) pens for such things.

Thursday, January 04, 2018

Presenting monsters

This is something I really loved in DKC closing cutscene and which I'll now seriously start working on for School Rush: seeing the nicknames of all the baddies in the game with the baddies themselves. Later on, when I wanted to bring Badman II to an end, I tried to do something similar: which apparently worked quite well it was acclaimed by Aderack in his wiki and essays.

And as if I'd need one more proof, my brother just convinced Lazycow that such a show was all he needed to make the. end-of-game cut scene of Power Glove feel satisfying for the players reaching that point.

J'étais complètement fan de la séquence de fin de Donkey Kong Country, avec sa présentation des ennemis un peu humoriste qui dévoile leurs noms et permet de se souvenir de tout ce qu'on a traversé. J'avais fait quelque-chose d'un peu similaire pour la fin de Badman II, ce qui a plu, visiblement (au moins à Aderack ;)

Et comme s'il en fallait plus pour m'encourager à remettre le couvert dans School Rush, voilà que mon frère me raconte que LazyCowse demandait que faire pour le final de son PowerGlove et mon frère de lui dire que "bin si, les joueurs aiment bien qu'on leur remontre la galerie des monstres/boss avec les noms de tout le monde (surtout quand les noms sont un peu rigolos). Et sisi, y'a pas forcément besoin de beaucoup plus.

Donc ne vous inquiétez pas, je vais quand-même garder un petit quelque-chose d'original : le croquis ci-dessus est une ancienne idée. Mais j'ai encore quelques petits détails à régler pour que ce soit réussi. 

Of course, these are just some preliminary sketches, and there has been some evolutions. But I know you'll allow me to keep those details a secret, and not spoiling your future satisfaction myself.

Wednesday, January 03, 2018

A dos de blador.

Mes taille-crayons, une fois en mouvement, font d'assez mauvaises plates-formes, en vérité. Celà vient de leur animation. D'abord (comme la plupart des animations de marche), elle va retarder certains mouvements pour consommer d'un coup 2 pixels de déplacement après être restée immobile pendant 4 images si la vitesse de consigne est d'1/2 pixel-par-60eme de seconde. Ensuite, parce que contrairement à Bilou, le déplacement de dumblador s'interrompt pour une courte pause avant de reprendre: non seulement ce taille est trop "dumb" pour mettre un pied devant l'autre, mais en plus, il lui faut un moment pour se souvenir de ce qu'il convient de faire pour finir le mouvement qu'il a entammé. Autant dire qu'il vaudrait sans doute mieux pour une "pile de dumbladors" de tomber d'un étage quand un des tailles-crayon se remet en mouvement plutôt que de jouer à rajouter des "selles invisibles" pour offrir quelque-chose de plus souple.

Non. Je préfère tenter maintenant de faire tenir Bilou sur un taille-crayon à l'arrêt. Et là aussi, j'ai du travail: il faudra veiller à

  • forcer une mise à l'arrêt complet au contact, puisque le contrôleur "stopper" sera court-circuité,
  • "détacher" Bilou de son support lorsqu'il saute,
  • compléter le contrôleur "onpath" pour qu'il provoque le détachement lorsque Bilou n'est plus par-dessus le chemin.
This has been a "known issue" since April 2014, and it still wouldn't be easy to fix it today: you can walk on a Dumblador (after stunning it) as if it was a platform, but as it wakes up, weird things occur that make Bilou slightly slip forward and eventually fall of the blador. Initially, it was also affecting stacked dumbladors, so I added a rule to "break" the stack as a blador wakes up.

The core of the problem comes from the fact that a carried GOB will adapt to the "moving platform"'s speed in order to give the illusion of friction, but when it comes to dumbladors, the speed and the effective motion quite disagree. First because - as with any WALKing GOB - the horizontal speed isn't constant, and second because I introduced a small pause between two steps for the blador, to reinforce the feeling of "dumbness". As a reminder, the GPath abstraction is as follow:

  • GameObjects have an 'onpath' pointer, which complements the 'attach' pointer (to a gob).
  • GobArea now implements the (horizontal) GPath API, returning always the same y coordinate, and checking that you're in the desired xrange.
  • 'Ap' in a gobexpression will attach the object to a "path" rather than to an object, the area that triggered the collision will be used to define the new path.
I gave path-capable engine a try back in february 2013, but that was nothing I could test. The idea was to support both NSMB-like angled mushrooms and (softly) swinging ropes. The current code with dynamic GPath comes from June 2013 and has still to be complemented with a controller that uses it.

It's all described and motivated in

Saturday, December 30, 2017

SchoolRush NY2018

Happy New Year Everyone. I've got a new build of SchoolRush uploaded. Hope you'll enjoy it. For those of you who mastered the game, you'll discover the credits level and the hint towards the secret, vertical level that I've been working on half this year.

Prêts pour la nouvelle année ? Voici une version de Bilou: School Rush avec un niveau secret terminé, des images de chargement qui racontent l'histoire du jeu, la séquence de crédits ... Et pour ceux qui n'arriveraient pas encore jusque là, deux modifications qui rendent le jeu moins impitoyables: on peut "nager" hors de l'encre (encore faut-il pouvoir trouver une plate-forme où atterrir) et on grimpe automatiquement dans les encriers quand on tombe dessus, même si on tenait un taille-crayon entre les mains.

For everyone, you'll enjoy the "swim up for your live" mechanics that will let you go forward even if you missed a jump and fell into the ink. Well, you cannot recover *every* missed jump that way, but it's already much more forgiving than it used to be.

You'll also enjoy how jumping into an Inkjet now automatically let you in, dropping the Dumb Blador you're carrying, if any.


You're controlling Bilou, a blue, ball-shaped explorer. You make him JUMP with the (A) button and grab things (or throw them) with (B). Your goal is to reach the right of each level before you're caught by the ever-raising ink.
You'll need to be quick, too. Use (R) or double-tap in left/right directions as if you were a pink, living vacuum cleaner.

You can stomp some monsters, you can throw sharpeners at others. Remember: the pencil soldats are the only real threat here, and they must be stopped from pouring even more ink for their autoritarist plans. Everything else that looks dangerous is mostly acting on fear and may prove very useful if you keep your head cold. Think about how useful a bobbing sponge could be if you could ride it (B). or how high an inkwell could shoot you ...

There are rumours of magical artifacts that could help you. The Fist of Justice, that noone can stand against (double-B) and the Floating Twister (hold A), that let you reach far away places. It's unlikely the pendats will let you recover them without a fight, though.


At the far east of this school-like country, there is a gauge that will stop the ink. Rush for it! The books city is close to be destroyed once for all, and the elders' knowledge will be lost. This must be another plot from Square Root, who decided that mathematics are the only thing worth of being written down.
Everyone here seems to believe that Bilou is a sort of legendary hero...

How to play

Get the NDS image and play it on your homebrew-ready console or in an emulator, such as DeSmuME. See this page if you need extra explanation/instructions for running homebrews.

Wednesday, December 27, 2017

[done] fargrounds

Eh bien, ça en aura fait des rebondissements pour débloquer le "super décor du dernier niveau"! Mais on y est. Du coup, les derniers éléments sur la "todo list" de School Rush, je vais les rassembler ici façon "bullet journal"

  • la séquence de fin pour de vrai
  • le niveau bonus
  • le mécanisme pour se rendre dans le niveau bonus
  • une éponge qui monte-et-descend à la surface de l'encre, svp ?
  • un affichage du nombre de vie (intégré aux images de chargement ?) 
At last, I have proper background graphics for my final secret level. The time is right to review the to do items, close some and bring here what will have to be done to get the game completed, bullet-journal style (as I don't have phabricator-for-sourceforge).
None of the things that are still on the todo list for School Rush could really be completed by the end of the year. But none is blocking a release either. I think we can call the vertical level .done. That took almost half the year, but I think it worked. Enjoy your season holidays.

Rien de tout ça ne semble faisable en quelques jours de super-papa-bros, donc on va emballer ce que j'ai pour boucler 2017 et prendre le temps de faire le reste correctement en 2018. Bonnes vacances.

Ce niveau vertical aura occupé une grosse partie de l'année donc, du mois d'Avril à la fin décembre, mais au moins il est testé et validé. Il reste sans doute un peu mystérieux à la lecture de ces lignes ... forcément, c'est quand-même un niveau secret ;-)

    Thursday, December 21, 2017

    Refactored, but freezing

    ok donc, j'ai eu du code qui compilait en un rien de temps, malgré un refactoring plutôt osé. Par contre, plus moyen d'atteindre la fin du premier niveau: le jeu freeze, à peu près tout le temps au même endroit, juste avant de m'afficher les premiers "inkjet" mobiles.

    Good joke! How useful is it to get refactored code compiling if you cannot reach the exit of level 1 anymore? The game now freezes every time roughly at the same spot, just before the first moving inkjets. I will need my mercurial time machine...

    Je prends donc ma machine à remonter le temps (comprenez mercurial) ... le bug semble aussi se produire avant la refactorisation ... j'évite donc de passer pour un clown qui fait des effets d'annonce sur son flux twitter, mais je n'ai quand même pas du code qui marche. J'ai noté que A. avait réussi à rejouer aux premiers niveaux après avoir fini le niveau vertical, donc il existe un point pas trop éloigné dans l'espace-temps où j'ai du code qui n'a pas ce problème.

    "Good" news is that the bug wasn't introduced by the refactory -- at least, my twitter-honor is safe. But honor does not make code run. I know that A/S-team could beat levels 1 and 2 during the last playtesting session, so the bug must have been introduced fairly recently. If I could find the last working commit, that would help understanding what went wrong and how to fix it.

    Reste à le trouver pour comprendre ce qui cloche. Pour ça, j'ai maintenant mon programme automatique de "unit-testing" qui simule un va-et-vient dans les niveaux.
    Et le programme de test en question crashe, lui. Un beau gros "segmentation fault", dû à un débordement de pile. Et la fonction "backtrace" capable de m'indiquer où s'est planté le programme et comment on en est arrivé là prend un plombe à s'exécuter (en fait, j'ai intérêt à l'interrompre):
    • CompoundGob::collide(#288)
    • BlockArea::collision(#1934)
    • InfiniMap::getflags(#350)
    • GameObject::cando(#1786)
    • CompoundGob::loadAnim(#178)
    • CompoundGob::setstate(#52)
    • CompoundGob::collide(#288)
    • BlockArea::collision(#1934)

    Hopefully, I now have an automated test that moves back and forth through the levels. And that test program crashes (big segmentation fault) when running one failing build. The backtrace function of my debugger takes ages to point out where the crash occurs (and how the program reached that state). When I interrupt it, I see no memory reference on the "call" instruction. All registers have valid values, no invalid opcode to be spotted around. The only suspicious thing is the fact that there seems to be a repetitive pattern in the function calls.
    Then I checked the value of the stack pointer and Captain Obvious knocked on my head.

    Oui, vous avez bien vu: on tourne en rond. Et le code fautif serait apparu pendant que j'essayais de corriger le problème des personnages qui jouent à Philadelphia Expérimental avec le plafond.

    Mais comme j'ai une release à assurer demain au boulot, je vais pas la faire trop longue. On sait où chercher. On cherchera pendant les congés entre les paquets de Noël et les cotillons ;-)

    This is a stack Overflow, caused by something in the new code that enforces alignments when resizing bounding boxes. It is obvious because the stack pointer has the lowest allowed value, given the area allocated as stack according to /proc/self/maps. It is too late to start searching what and why, but at least I know what to look for and roughly where.

    edit: trouvé en 20 minutes de "cybook" pendant que *deline travaillait sa danse. Corrigé en à peine davantage. On va pouvoir reprendre le travail sur les plans de scrolling ;-)

    got it located while *deline was having her dancing lessons, fixed in about half an hour. I thought it would take me at least a week-end. Good. I'll be able to go on with the rest (todo: figure out what still has to be done)

    Tuesday, December 19, 2017

    Refactoring de dingue!

    J'hallucine. J'ai pris une de mes plus vieille classes -- InfiniMap, responsable à la fois du scrolling et des collisions sprites/map. J'ai renommé ça en "CommonMap", appliqué les changements partout sauf aux sites de construction. J'ai ensuite déplacé le code utile dans un nouvel InfiniMap, déclaré l'une ou l'autre méthode comme purement virtuelle dans CommonMap ... et recompilé.

    I can hardly believe it. I picked of my oldest classes -- InfiniMap, that controls  scrolling and  -sprite-vs-world collisions -- and renamed it common map, everywhere but on lines of code building some instances. I then moved the "real" code into a new InfiniMap, mentioned a few ."pure virtual" markers in common Map, and rebuilt...

    Et ça marche ! C'est du délire à l'état pur. Ok, j'avais une classe iWorld mais je ne m'attendais pas à ce que le truc ne réclamme aucune autre intervention. Nada.
    Allez, demain, je déplace le maximum de variables membre.

    And it works! I can't beleive it! (dott). I knew I had some interface class already, but I wasn't expecting it to work that easily, not requiring any fix or whatever !