Thursday, February 27, 2020

fgets

J'ai apparemment laissé dans un commentaire de revue "fgets doesn't guarantee you have a terminating \0 on oversized lines". Il faut bien reconnaître que c'est le genre de farce auxquelles il faut s'attendre de la part de la bibliothèque C standard. Mais là, à y regarder une 2eme fois, j'avais tout faux.

fgets(ptr, size, stream)  reads in at most one less than size characters from stream and stores them into the buffer pointed to by ptr.  Reading stops after an EOF or a newline.  If a newline is read, it is stored into the buffer. A terminating null byte ('\0') is stored after the last character in the buffer.
C'est presque le mieux qu'on puisse espérer, non ? on lui passe un buffer alloué avec data[N] comme (data, N) et il se garde un dernier p'tit caractère pour la route le \0 de fin-de-chaîne. Que demander de mieux ? Non, en vérité, c'est de strncpy qu'il faut se méfier.

Mais de ma phase de déni/doute, je me suis quand-même refait un p'tit programme pour tirer ça au clair. Bin rien à redire. On a bien un \0 de terminaison à chaque coup (le programme ne lit que 16 caractères à la fois). Soit juste après le retour à la ligne (\n), soit en dernière position.

Seul cas où il peut être manquant: si il n'y avait rien à lire du tout. (auquel cas fgets nous renvoie un pointeur nul plutôt qu'un pointeur vers notre buffer, ce bon vieux data). Même une fin de flux sans fin de ligne ne le met pas en défaut.


Brave petit.

Toujours à vous demander ce que c'est que cette histoire de \0 ? vous pensiez qu'un ordinateur auquel on répond "Piet Burner" quand il vous demande "Entrez votre nom >" savait où se trouvait le début et la fin du nom en mémoire ? Bin pas franchement. Dans la majorité des cas, il a besoin d'un caractère spécial, en fin de chaîne, pour savoir qu'il a tout lu / copié / analysé / imprimé ... C'est le caractère de valeur 0 (pas le caractère ASCII en forme de 0 que vous rajoutez à la fin de votre fiche de paie) qui s'y colle. Enfin. Presque toujours. Il existe un obscur système d'exploitation dans lequel ce rôle était dédié au caractère '$'. Si, si...

Faites en sorte que le \0 soit manquant (en mangeant trop de pommes, en écrabouillant la tête de Yoshi ou en tapant le Konami Code pendant le chargement du jeu), et le CPU continuera "sagement" à manipuler "des choses" comme si c'était votre nom ... avec potentiellement la possibilité d'aller écraser l'emplacement de votre personnage sur la map, des bouts d'inventaires au le nom du prochain pokemon que vous allez rencontrer :P

Oh, et tant qu'on y est, j'utilise aussi régulièrement snprintf, bien que codant en C++. Elle a le bon goût de ne pas écrire plus de size caractères, terminateur \0 compris et renvoie la longueur de chaîne qui aurait été écrite si on avait eu la place. Longueur qui s'entend au sens strlen (sans compter le terminateur) et donc si on me répond que 16 quand j'ai passé un tableau de 16 bytes pour stocker le résultat, c'est déjà un sacrifice de données (bien vu, jigé ;)

Tuesday, February 25, 2020

fakeMetaWindows

Bon, après un week-end assez "rock and roll", j'ai fini par pouvoir essayer un peu mon nouvel atout: un exécutable NDS alternatif pour la mise au point de l'interface graphique de LEDS. Parce que débugger SEDS c'est déjà pas rigolo mais il n'y a que "START + L + A" à taper pour charger un fichier. Dans LEDS, ça se fait avec les p'tits widgets d'exploration de répertoires. On clique par-ci, puis par-là, puis enfin l'émulateur charge le script principal, les spritesheets, le niveau. Et là tu peux faire A, réactiver tes breakpoints et commencer à débugger.

https://twitter.com/pypebros/status/1230601848022847494
Mais ce sera bientôt du passé. J'ai pu extraire en tous cas les dépendances de la "MapeditWindow", la "fenêtre" principale à travers laquelle on voit et modifie le niveau dans une structure qui lui prépare un niveau rien que pour le test qu'on pourra faire défiler, modifier et pour lequel on pourra aller regarder le contenu de la VRAM pour s'assurer qu'on a bien affiché ce qu'il fallait à chaque étape.

Et ce sera bien utile, parce que là, tout de suite, je me suis attaqué à "permettre de masquer/afficher les boutons qui définissent les propriétés des tiles sans corrompre le niveau, mais du coup, je casse le niveau dès le départ >_< Vous le voyez, ce gros pavé jaune dans la zone "radar"? et toutes ces petites flèches noires sur l'écran du bas (par-dessous le texte de debug blanc, c'est difficile, je vous le concède) ? Bin c't'un bug.

Tuesday, February 18, 2020

Don't send namespace do an inline job

Okay, granted, I'm not a namespace master. I know they exist, I know they are helpful, but I'm not using them a lot myself, and I'm never too sure how I should write things like namespace cp = Clicker::process;. I'm not completely sure whether going for using namespace ietf::http within HttpServer class is smart or silly.

Anyway. I had code in a .cpp I wanted to extract into a .h, for it contained assert helpers that should now be used in more than one test program. Unfortunately, when I started using it in my new program, I got the linker complaining that some assert_bool() function was defined in multiple .o files. That was the only one that was no template, unlike assert_equals() and its children. I then foolishly wrapped the whole thing into a namespace /* anonymous */{, so that things couldn't be reused in multiple areas.

But one instance of gcc got it wrong. You see, I'm not using that assert_bool() in all my .o, and that version of gcc, with its parano flags settings, thought it shouldn't keep going with dead code: assert_bool() wasn't used internally in that translation unit, and it couldn't be used from outside, as it was anonymous for the rest of the world.

What I should actually have done was to define the function "inline". Simply.

Monday, February 17, 2020

Thème Mobile ?

Tout ça parce que j'avais décidé de ne pas prendre de carnet-geek pour la patrouille de St-Valentin, mais que ma fée avait besoin que je l'attende (sans avoir besoin de son smartphone). Du coup j'ai découvert que '?m=1' passait sur le "thème mobile" de blogger. Un thème à l'ergonomie acceptable, mais perfectible (en ce qui concerne les tags, notamment).

Par contre, pour ce qui est du look ... euh ... y'aura un peu de travail, là. 

If you want to customize your Mobile template styles, you need to set the Mobile Template to Custom.

By then any additions to your Theme "Edit HTML CSS" section will be rendered.

Using Blogger built in functionality use the .mobile classname to target the styles for mobile views. Example


.mobile .post-title {
  font-size: 21px;
}


Will change the post title size to 21px on mobile device but does not effect the post title web view style.

Et moi, il faut que je m'adapte à un truc comme
<div class="mobile-date-outer date-outer"> <div class="date-header"> <span>Monday, February 17, 2020</span> </div> <div class="mobile-post-outer"> <a href="http://sylvainhb.blogspot.com/2020/02/theme-mobile.html?m=1"> <h3 class="mobile-index-title entry-title" itemprop="name"> Thème Mobile ? </h3> <div class="mobile-index-arrow">›</div> <div class="mobile-index-contents"> <div class="mobile-index-thumbnail"> <div class="Image"> <img src="https://1.bp.blogspot.com/-7w5i6XE-rQg/Xkp_FEWuuCI/AAAAAAAAI_E/b4RuPqzNa2U8w-glm-OsOIgAwT3b7XaowCLcBGAsYHQ/s72-c/Screenshot_2020-02-17%2BBlogger%2BBilou%2BHomeBrew%2527s%2BBlog%2B-%2BTheme.png"> </div> </div> <div class="post-body"> Tout ça parce que j'avais décidé de ne pas prendre de carnet-geek pour la patrouille de St-Valentin, mais que ma fée avait besoin que je... </div> </div> <div style="clear: both;"></div> </a> <div class="mobile-index-comment"> </div> </div> </div>
  • la partie "bannière" est bien trop haute. Il faudra changer la valeur height dans #header-wrapper (80px) et ajuster le padding du #header (top: 10px)
  • le titre du blog doit arrêter de se faire compresser sauvagement (padding droit de #header).
  • la petite "flèche" à droite de chaque entrée n'est plus à droite. Il faut lui rendre son thème.
  • la ligne d'aide à la navigation doit se faire une place plus normale. (disons avec position: absolute, top: 100px, right:20px)
  • il faut remettre une ligne entre les items
  • il faut que les thumbs soient flottants (float et padding sur #mobile-index-thumbnail)
  • il ajuster les pixels de bordure sur la gauche.
  • il faut réparer la largeur de la page (widthde #content-wrapper, #header-wrapper)
Bon, ce qui tient lieu d'éditeur de thème pour blogger est assez peu ergonomique, et la technique du  .mobile ne marche pas pour tout. Donc, pardon mais il est possible que le look du site soit tout cassé pendant quelques jours parce que je ne vais quand-même pas prendre congé pour ça :-P

    Sunday, February 16, 2020

    Plate-formes volantes ?

    Si je veux faire quelque-chose de plus "aérien" pour la dernière zone, il va me falloir des plate-formes volantes. Mais voilà, je n'ai pas envie de leur coller des petites hélices (qui aurait fabriqué ça) ou d'invoquer du gravitium (pas partout, en tout cas). Pas envie de resservir le cliché du "bloc de pierre collé à un autre bloc de pierre qui vole grâce à des petites ailes de Parakoopa" ...

    Pas convaincu non plus par des piafs qui auraient justement une forme de plate-forme. Il y a quelque-chose d'un peu ce genre-là dans DKC:TF, mais il s'agit de plus de bumpers volants -- rôle que les parakoopas avaient employé déjà bien avant. Ici, je veux bien parler de quelque-chose de suffisamment large pour qu'on puisse marcher dessus et de suffisamment coopératif pour qu'on puisse traverser un écran avant qu'il ne s'en aille.

    You know, I'm trying to make Bilou's Adventure a somewhat consistent world. I won't say "believable" or anything like that, because we play as a ball with hands/feet floating around him anyway, but I'd like to avoid introducing too many alien elements like gravity-defying blocks or cartoon pockets or even human characters. If something exists in the game's world, at least Bilou and Bouli must find it believable. And that makes designing a mountain level with floating platforms ... a bit more challenging. I'd like to avoid the generic, Zool-like "floating rectangle -- just don't ask", and its Mario-like "floating rectangle with not-so-little wings".

    Je m'oriente vers un croisement entre les zeppelins et les piafs. Les saucisses/zeppelins, c'est sympa. J'ai bien aimé l'idée dans Endymion, dans Titan et dans "L'incident Jésus". Dans Kirby, aussi ^_^. Avec un bec et des zyeux, on peut leur donner plus d'expressivité et les écarter d'une trop grande ressemblance avec Kirby, justement.

    ils sont suffisamment dépendant des caprices du vent pour ne pas vraiment pouvoir éviter que Bilou ne les emprunte, pas vraiment mis en danger par ses atterrissages non plus.

    I've postponed this post for a while as I was considering and then discarding ideas. I finally converged towards zeppelin-birdos. I loved zeppelin-like sentient creatures in Endymion, Titan and Frank Herbert science fiction books. They're close enough from a regular platform shape so that we can land and walk on them, not just bump on them. But in Bilou's world, it would be best if they had eyes and stuff that can suggest they feel something. And giving them little wings will make them more interesting to look at when you're not on them. But they're wings are too small to be able to do anything but follow the winds. And their body is soft enough to avoid taking damage from Bilou's lands.

    Sure, I'm not the first one to try using second-class creatures as platforms. One of the most prominent example I can think of are the owls in Tropical Freeze. You'll note that these are more floating bumpers than floating platform, though: you cannot move freely just like on a parakoopa. And it make sense: if you had intruders landing on your head, chances are you wouldn't just wait for them to leave. Even the Parabeetles don't just keep moving unchanged if you land on them. Maybe SML2 owls ?

    J'ai écarté juste avant ça des tapis volants (pourtant, des écharpes rouges volantes, ça aurait été un clin d'oeil sympa) et des plate-formes pendues à des poulies. Des cordes et des ponts suspendus, il y en aura sans aucun doute, mais je n'ai aucune raison pour justifier que Bilou ne puisse pas s'accrocher au "câble porteur", et donc c'est très différent d'une plate-forme volante.

    A final word about dismissed designed. No flying carpet (flying scarf could have been fun). No walkable cloud. Since I plan to have ropes between peaks here and there, I must admit I've been tempted to go for platforms-on-pulleys. But no matter how I approached it, I couldn't explain why Bilou wouldn't just grab the carrying rope in case of emergency. Knowing my kids, they'd feel it unfair if they went for the rope and just fell through what is just decoration element.

    Saturday, February 15, 2020

    Soldier Blade: can you be Mr. Perfect ?

    Quelque part entre 2000 et 2001, mon frère me ramène un émulateur PC-Engine et une quantité impressionnante de ROM pour aller avec. N'étant pas un fan de Bonks, je lève un sourcil circonspect. Une machine de 1989 ? T'es sérieux, là ? Mais deux semaines plus tard, j'arrive au bout de Tyrian, donc je jette quand-même un coup d'oeil à ce que son CD a dans le ventre ...

    Et je tombe sur Soldier Blade. J'ai toujours eu un faible pour les shoot-em-up (un reste de ma phase 'quand je serai grand, je serai astronaute' d'avoir lu les Yoko Tsuno, j'imagine), mais à part Warhawk sur C64, je dois bien reconnaître que j'ai finalement assez peu joué aux titres de shoot, largement dominés à l'époque par le style 'R-Type' où le vaisseau explose au moindre pet de moustique.

    Tyrian était plus dans la veine de Warhawk, avec une barre de bouclier qui compense la majeure partie des tirs encaissés. Mourir, dans l'un comme dans l'autre, c'était recommencer le niveau du début, parfois en aillant perdu une partie de ses power-ups dont je dépends tant. D'où mon attachement à Tyrian où au moins on fait l'acquisition de certaines armes de manière définitive.

    Soldier Blade avait un comportement différent et assez unique pour moi: on peut stocker des power-ups, les consommer comme super-bombes (généralement contre les boss), les combiner pour monter en puissance (si je ramasse 3 power-ups "laser" à la suite, sans ramasser de 'plasma' ou de tirs rouges, je passe au laser-niveau-3 en trident. Cerise sur le gateau, si j'ai le laser-3 et que je ramasse un 'plasma', je passe directement à plasma-3 (note bien ça, Space Invaders Extreme).

    Si je me fais latter, mon vaisseau explose, éparpillant mes power-up autour de moi. Un autre vaisseau arrive alors assez rapidement à la rescousse pour reprendre le combat. Suffisamment rapidement pour que je puisse récupérer au moins 2/3 des power-ups perdus. La pénalité est beaucoup moins rude que dans un R-Type où on redémarrerait avec un vaisseau "tout nu".

    Avec une bande-son tout en synthé qui donne la super-pèche, des graphismes certes aux coloris limités mais réalisés avec un brio, le jeu a beau tourner sur un processeur 8-bit, je suis scotché. Mais voilà: le jeu ne propose aucune sauvegardes et cet émulateur-ci, contrairement à z-snes et nesticle (que j'ai beaucoup utilisés sur mon AMD K6-II à l'époque) n'offre pas de save-states. Du coup, le seul moyen d'aller plus loin dans le jeu en cas de game over, c'est de recommencer et de s'améliorer. Recommencer de la mission 1.

    Bref, après quelques semaines d'entrainement intensif (l'avantage d'avoir réussi en 1ere session à l'unif, c'est qu'on a deux mois de vacances ;-) arriver à la mission 6 était devenu une sorte de formalité. Un peu comme faire ses gammes. Y arriver avec suffisamment de vies pour pouvoir atteindre ce que je croyais être le boss final, c'était une autre histoire: on parle quand-même d'un niveau 2 fois plus long que les autres, avec des espèces de boss rush. Battre le boss final, je n'y suis jamais parvenu. Il aurait presque fallu faire un sans-faute jusqu'au boss pour pouvoir tenter le coup.

    Si le jeu n'est pas à proprement parler un 'bullet hell', il y a quand-même énormément de projectiles à éviter, chacun susceptible de détruire notre vaisseau. Si bien que j'ai fini par prendre conscience que je jouais mieux quand je n'essayais plus de regarder en détail les différents objets du jeu. Je fixais mes yeux au centre de l'écran (non plus sur mon vaisseau) et je concentrais mon attention sur ma vision périphérique. Je pouvais alors bien mieux détecter les différent mouvements et guider mon vaisseau vers les zones dégagées.

    Je ne suis pas devenu "Mr. Perfect". Je n'ai pas fini le jeu. Peut-être si j'avais pu me rendre compte que le vaisseau-compagnon peut faire office de bouclier contre à peu près tous les projectiles ?

    Wednesday, February 12, 2020

    Thèmes Elementaux

    Faute d'un meilleur terme. Mais je suis retombé sur une cogitation de fin 2019 quand est apparu l'idée de faire un 'Bilou's Dream Land', mais avant que la décision ne tombe de prendre la montagne (Peaks Zone) comme 4eme et dernier niveau.

    You know those many games where the levels are designed around "elemental" themes. Like fire - ice - forest - water - air - metal. It's almost everywhere. And it's not the most novel idea you can think of. But it brings in something interesting, as all the challenges / monsters can be designed around a unifying concept. And generic ideas can be declined according to levels, like fire-bats in the fire zone, freezing-bats in the ice zone, and so on.

    I'd like to have diversity in 'Bilou Dream Lands', but not that kind of diversity. What I'd like to have is gameplay diversity. I've ruled out having keen-like keys and doors in the School Zone because it would make little sense, but I'd like to have them in a Bilou game anyway. At least in the pyramids. For the lack of a better term, I'll think of those as "elefundamental gameplay themes".


    pour l'inspiration. Hoshi wo ou kodomo via Tohad
    Quel environnement utiliser pour la 4eme zone de ce nouveau jeu? La logique voudrait que je réponde "le chateau" pour m'intégrer au mieux dans le design existant (monstre, tilesets, etc.) Mais ça nous donnerait avec la School Zone et la Pyramide un 3eme environnement "artificiel" qui risquerait d'être redondant.

    Je suis très tenté de répondre "le temple englouti", mais je préfère le garder pour un jeu plus complet du point de vue scénario. Il faudrait que je trouve 4 "thèmes éléfondamentaux" au niveau du gameplay. La pyramide apporte le thème "labyrinthique". l'école quelque-chose de plus "militaire" avec des ennemis organisés et sous les ordres de Square Root.

    La logique voudrait aussi que le 4eme monde soit le plus exigeant au niveau du "platforming". Potentiellement plus vertical et/ou avec plus de trous/lave/... (partant du principe que je ne recyclerai pas le niveau vertical de fin de School Rush pour ce jeu).

    Tohad. Toujours pour l'inspiration et la palette.
    So, what are the 'gameplay themes' for the already-designed zones ? and what should the 4th zone offer to complete the experience in an interesting way ? Pyramid level at least is clear to me: it brings in the 'maze-like' theme. The School zone brings in the 'invasion army' theme with pendats following SquareRoot orders.

    There wasn't much 'theme' for the green zone, but it could turn to cooperation with NPCs like the rabit and the frog. Now, what should be in the 4th zone. What is missing ? Possibly some tricky-platforming elements, with moving platforms and so. Think about mushroom levels in NSMB, if you want to picture what I'm talking about. The extra bonus with 'platforming' as the fundamental theme for level 4 is that it stems for open-space areas rather than enclosed areas and will better balance the game than, say, a "castle zone" or "lost temple" would do.

    Je n'ai pas de meilleur nom pour ça, mais si vous voyez les niveaux-champignons de SMB et NSMB, vous avez une idée de ce que la 'peaks zone' pourrait apporter comme thème élémental. Bon, bin j'ai plus qu'à trouver quelque-chose qui convienne pour les plate-formes volantes, du coup...

    Pourquoi ce trip "thème élémental" ? Disons qu'il est classique dans les jeux de baser les différents mondes autour d'un thème basé sur un élément (eau, feu, roche, air ...). Chacun de ces thèmes inspire à son tour des idées d'obstacles, de monstres, de boss... Mais si on prenait le contre-pied. Si on cherchait à avoir des thèmes de gameplay pour définir chaque "monde".

    A compléter avec la Méthode Hascoet (Rapidité - Astuce - Synchronisation - Précision) ?

    Nouveau Gimp

    Je n'ai malheureusement pas réussi à ce que Gimp conserve ses anciens paramètres lors de l'installation de mon nouveau PC de bureau. J'ai même été franchement contrarié de les voir passer à une interface "tout intégrée en une seule fenêtre" comme le "nouveau" lecteur PDF d'adobe (eh non, plus moyen de continuer à utiliser Acrobat XI un peu plus longtemps). Mais au moins, chez gimp, on a une cochette [x] Single Window Mode pour si on veut utiliser une image de référence sur un écran pendant qu'on bidouille ses pixels-à-soi sur l'écran d'à côté.

    Restons confiant, donc. Après tout, j'ai aussi pu remettre mon 'F12 = snapshot" en cherchant 'screen' dans Edit > Keyboard Shortcuts. (enfin, il fallait quand-même d'abord activer [x] Use dynamic keyboard shortcuts dans Edit > Preferences).

    Je n'étais pas franchement convaincu par l'interface revisitée pour changer la taille du pinceau/crayon. 'faut dire que je suis plus souvent entre 1 et 4 pixels qu'entre 20 et 800, personnellement. La 'nouvelle' interface sépare chaque barre en deux zones, une qui permet un règlage absolu (sur le dessus de la barre. Le curseur souris devient une flèche verticale) ou relatif (sur le dessous de la barre. Le curseur ressemble à "changer la taille des colonne"). Mais ni l'un ni l'autre n'offre la vitesse de réaction que j'attends de mon outil.

    Je sais que j'ai déjà changé ça: j'avais remappé CTRL+SHIFT+roulette, qui par défaut change la 'forme' du pinceau (ovale vertical -> cercle -> ovale horizontal). J'ai juste oublié comment j'avais fait.

    5-10 minutes d'exploration des préférences. Toujours rien. Je cale. Je finis par refaire une recherche et tomber sur la vidéo-tuto où j'avais probablement trouvé le truc la première fois. Je n'étais pas loin: il faut bien aller dans 'input controllers' (logique), mais ce n'est pas un clic droit qui me proposera de configurer les choses. Un bon vieux double-clic-qu'on-avait-oublié-depuis-l'ipad.

    J'ai pris tool-increase-size-relative, mais je ne suis pas 100% convaincu. J'aurais aimé pouvoir passer de 1x1-2x2-3x3-4x4-5x5 à 6x6, au lieu de quoi j'ai le choix entre 1x1-2x2-4x4-8x8-... et 1x1-3x3-3x3-3x3-5x5-5x5-5x5-7x7-...
    Bah. ça fera l'affaire au bureau, j'imagine.

    Tuesday, February 11, 2020

    Au tour de meka-blador ...

    Même si, j'avoue, mon analyse de "et qu'est-ce qu'on fait maintenant" m'avait conduit à définir MetaEdit dans l'éditeur de niveau comme la priorité suivante ... Mais la tentation a été trop grande: comment se comporterait un vrai personnage dans les tests automatiques de pentes que je viens de faire fonctionner avec un 'tic-tac-Bilou' complètement abstrait.

    Je n'en suis pas au stade du Test.Read("blador.cmd"), mais j'ai au moins pu charger un vrai .spr et en extraire les animations (Merci, MedsAnim) puis constuire un nouveau cas de test basé sur un bout de texte extrait directement de blador.cmd.

    Pour les bonnes nouvelles on s'arrête bientôt. Le meka-blador obtenu comme ça ne passe pas les tests. C'est qu'il est basé sur la vieille technique des testpoints qui sondent l'environnement autour de lui, et l'arrêtent avant qu'il n'approche trop du bord d'une plate-forme (là où le comportement de Bilou le laisserait avancer au-delà du bord). Mais blador ne saute pas.

    Bref, mes collègues m'ont lancé dans la lecture de "Working Effectively with Legacy Code" où il est notamment question de "comment va-t-on s'y prendre pour que notre code écrit avant l'introduction des tests unitaires puisse subir des tests unitaires sans endommager sa fonctionalité". Je fais donc des p'tits exercices pratiques avec un iStateInspector que l'on peut définir au niveau de la classe GameObject et qui sera passé aux appels à GobState(::do_checks(), notamment) à la place de l'ancien flag "verbose_prints". Les vieux printf avec des coordonnées et des CON_GOTO peuvent donc quitter le code de GameObject.o: ils seront remplacé par des appels au StateInspector (s'il existe) qui peut être défini au niveau de MapTests.

    Monday, February 10, 2020

    GameEngine design: script-to-code

    Somewhere in 2009, I added support for actions triggered by the script-part of my game engine but implemented in C++. This is the cornerstone of "GEDS" game engine. This is how run-time monsters spawning and sound effects work. This is also how level load request are processed.

    The design survived the years, so let's see how responsibilities are split.

    • Anything that will start invoking code upon game event (collision, new input, animation completion, etc.) is captured in a *Gun instance. The instance carries all the parameter needed for firing a specific kind of code. E.g. An instance of the LevelGun capture the specific level script to load. An instance of GobGun captures which type of monster to spawn, etc.
    • Configuring the *Gun instance happens at script parsing time. In other terms, most of the *Guns could actually be constant objects.
    • The c++ code instanciating an *Gun must be located from the name of the action on the script (with a using [action-name] ([arguments]) as [holster-slot-number] statement). That requires every type of "gun" to have its associated "factory" class, so that an instance of each "factory" can be registered into an std::map to be the link between actionname and the *Gun constructor.
    • Amount of support code for a new *Gun or a new *GunFactory is minimal. Each class have only one (virtual) method, either create() or shoot().
    • *Gun instance typically forget about what they 'shot' as soon as shooting is done. Often, the created object is registered as an animated item at the game engine, which will take care of running its code periodically. This may lead to the need for an additional "progress" object when there isn't any yet, like with the "TrackSequence" following the instructions (e.g. shooting more guns) as a sound track unrolls in the music player.
    • when processing script expressions, a palette of "guns" (the multi-slot holster, if you want) is received in addition to the set of variables accessible to the script. However, the transitions between states are the one capturing those palettes.
    • The GameScript is responsible for recording every *Gun instance created, so that they can all be reclaimed when the level is destroyed and we switch to something new.
    • There is one guns palette per "state machine file", with the constraint that all the states used by a single "character" in the game have to be described within the same file, this means that a "character" can only use up to 16 different sounds+special effects.
    • The GameScript has the ownership of all these palettes. Reusing guns from parent's palette is explicitly requested. The GameScript knows when to stop using a given palette for new transition and switch to a new/old one because it has seen input/end statements. There is room for improvement here.
    Lots of guns. But anyone in GEDS can at most carry 16 of them at a time.
    Clearly, the major limit comes from fixed-size palettes of gun, which itself comes from the byte-code nature of the (parsed) script expression where only 4 bits are dedicated to the storage of which-gun-to-use. This is perfectly ok for a Mario-like game, where the distinct number of actions per character remains low. I would definitely need to extend this (and other parts of the game engine like sprite memory management) if I was to create a run-and-gun game where you can pick up lots of different weapons, each requiring a different kind of amno sprite and sound effect.

    Sunday, February 09, 2020

    Thank you, Fabien

    It's a true pleasure to keep reading the reports of Fabien Sanglard about the "polygons of Another World", one system after another. He went for people who did the ports, like a great investigator from Pix'n'Love would and mix those live coding moments with technical details about the various 16-bit architectures that make it quite exciting and pleasant to discover.

    Of course, there's already a significant amount of things I have learnt about the bowels of Another World: because Eric Chahi himself documented them on his website. Like the language used for game logic, the development of the polygon modelisation tool and so on. That makes it (imho) perfectly for Fabien to focus on getting high-performance drawing primitives. But if you really want to, he covered the virtual machine source code back in 2011. 

    For instance the episode about the homebrew GBA port finally allowed me to understand why the heck there were thumb-vs-ARM modes and IWRAM-vs-EWRAM and things alike in gba coding. With a simple diagram of how chips and busses were connected. That could definitely help if I was to port some Bilou games to the GBA later on (likely I'll take closer attention to make that possible with "Bilou Dream Land"). But I enjoyed the description of how the Amiga used its blitter to fill polygons quickly, too. and how the SNES version could have been running at 60 fps if the manager had said yes to a SuperFX chip on the cartridge.


    Thursday, February 06, 2020

    Attempting to reference a deleted function

    Now, all of sudden, the C++ compiler decides to make copies of my exception class before throwing it. Well, apparently, it is allowed to do so. But for some other reason, that very same C++ compiler (wasn't gcc this time) decided that my classes shouldn't receive a default copy constructor, and complains that "my" code is "attemtpy to reference a deleted function" when throwing the exception.

    Oh well.

    Most of the code isn't new, and it has compiled with this very compiler with these very flags just an hour ago. But while working on it, I suddenly changed at least one thing: I made it so that all the arguments of the constructor for the base class (the one complaining) are now constants. I suspect that Mr-Smart-C++ decided that my code would be happy to have one CustomException in .rodata with the corresponding fields compile-time-ready and that it would then copy that into the area allocated for ExtendedException (child class) instead of "constructing" a new one from scratch.

    Now, why wouldn't it create a default copy constructor ? Well, I introduced something new in the class, that is a std::stringstream. And it turns out this one has a 'deleted' copy constructor... this apparently propagates and makes the containing class considering it should flag the copy constructor as deleted as well.

    Just when you thought you had mastered the language. Welcome to Wonderland ...

    Sunday, February 02, 2020

    Bilou Dream Land (codename)

    Bon, j'ai plus ou moins déjà présenté l'idée, mais comme c'est un peu perdu au milieu d'autre chose je remets le couvert. J'ai décidé de mon prochain projet de jeu. Il s'agit toujours d'un jeu de plate-forme, et toujours aussi dans l'univers de Bilou. Mais ce ne sera pas "infinite Pyramid". Pas encore.

    My 'todo map' for 2019 was trying to review all the things that could possibly use a bit of work, but had no clear direction of where to go.  For 2020, I finally have a direction to follow: a new game code-named "Bilou Dream Land" so far.
    • Ce sera une version "courte" de Bilou's Adventure avec un début et une fin. Plus de gameplay en boucle cette fois-ci.
    • On y parcourra la Green Zone, la School Zone, la Desert Zone et probablement la Peaks Zone.
    • Les zones seront plus courtes que prévues pour Bilou's Adventure: plutôt la taille d'un niveau de Kirby's DreamLand (d'où le nom de code) que celle d'un monde de SMB. (ça fait quand même l'équivalent 2 à 3 niveaux de la version BASIC de Bilou's Adventure).
    • Dans la mesure du possible, je reprendrai les level design d'origine, avec des adaptations pour corriger les 'injustices', mais je m'autorise à avoir des portes-magiques sans devoir les justifier.
    • J'essaierai d'y introduire des boss.
    • Pas de pouvoirs 'définitifs' à la Rayman, mais des power-ups comme ceux qu'on a pu voir dans School Rush, probablement avec un nouveau-venu qui fait grappin
    • Les PNJs de la BD pourraient bien servir de "pouvoirs spéciaux" liés à une zone. Napin qui creuse, Froggy qui nage... vous voyez l'idée.
    The idea is to pick four environments from Bilou's Adventure and use them to create a platformer that has the length, the rhythm and the depth of the seminal Kirby's Dreamland. I'd reuse existing level design as much as possible, like the 'anniversary School Zone' map and the sketched maps for Green Zone.

    If we think of Bilou's Adventure as a Cave Story-like adventure with multiple endings based on player's in-game choices and actions, then Bilou Dream Land would be the set of levels you'd play if you'd go for an any-%, going for the quickest-to-reach ending where Bilou and Bouli barely managed to escape the planet, not trying to investigate anything about why they crashed and whether that world needs to be saved.

    There'd be some fixing on the old maps, possibly some keys or switches by NPCs, but that shouldn't be as ambitious as The Big Green Zone Relooking I've been talking about 3 years ago. The aim would rather to make the game more fun to play, and clearly not to get rid of any magic door.

    Saturday, February 01, 2020

    DoSlopes

    Ok. Ajouter des pentes dans un jeu de plate-forme, ça devrait ne pas être compliqué, mais dès qu'on modélise son niveau à l'aide de dalles pré-définies (toujours les bons vieux tiles), ça cesse d'être simple. J'en ai déjà beaucoup parlé (cf. le tag) mais sans jamais vraiment (reality check: si) présenter la solution que j'utilise depuis Apple Assault: la fonction doslopes.

    L'algorithme derrière doslopes travaille uniquement avec le 'hotspot' des sprites, et veille à garder ce point en contact avec le sol tout en appliquant un déplacement horizontal donné (qui peut s'étendre sur plusieurs tiles). Il utilise aussi une fonction annexe -- groundheight(x,y) -- qui donne la hauteur du sol pour un tile du niveau à partir de la base de ce tile. On y reviendra.

    L'algorithme est constitué d'une boucle optionnelle (en jaune) pour atteindre le tile de destination puis une phase d'affinage (en vert) qui calcule la position du sol pour la position horizontale voulue.
    En sortie, on obtiendra un  déplacement vertical correspondant au déplacement horizontal donné. A chaque déplacement intermédiaire, doslopes s'assure que l'on est pas en train de s'envoyer dans un mur à l'aide de la fonction cando -- la base de la gestion des interactions sprites/niveau.


    Le principe de base, c'est de regarder la hauteur du dernier pixel d'un tile pentu juste avant de le quitter. Il peut avoir une 'hauteur = -8' ce qui fait positionne le joueur juste au-dessus du tile (comme on le fait normalement pour du sol) et permet du coup de regarder le bon tile pour la suite de la pente au tour suivant.