Saturday, September 19, 2026

Croc's World - il est où le fun ?

Des blocs à casser avec des power-ups dedans, un thème pyramide ... vous pensez bien que j'ai cliqué sur "télécharger" en Juillet 2020 quand je suis tombé sur une démo de "Croc's World", pensant tomber sur quelque chose du calibre d'un Super Mario Bros revisité ... ah ouaih. Cruelle déception

Mettons de côté les graphismes qui ont réussi à paraître travaillés-mais-cheap, avec son animation génération-flash où on s'est contenté de faire pivoter sur leur axe quelques décalcomanies, et l'insupportable boucle musicale de 8 seconde qui va continuer tout le jeu et concentrons-nous sur le gameplay.

Croc avance lentement, et toujours à la même vitesse. Croc s'arrête instantanément si je lâche le stick, même s'il est en l'air. Croc saute en boucle si vous gardez le bouton de saut enfoncé.

Bref, loin de l'athlétisme de Super Mario, on a ici l'impression d'un personnage ... mou. Ça aurait pu passer pour du character design sans le ton guilleret de la musique et le repompage de la grammaire de jeu de Mario avec les blocs-briques et les blocs-étoiles-pas-question pour les power-up. Ce sentiment de mollesse est à son comble dès que vous essayer de cogner quelque-chose avec votre tête. Tapez dans un bloc dans Mario, il bouge un peu et en même temps vous fait rebondir vers le bas. Rien de ce genre ici: le bloc de Croc reste immobile. Aucun son ou effet visuel ne vous confirme que vous auriez pu le briser. En plus, Croc se contente de s'arrêter en l'air et commencer à retomber. Ça peut passer pour une guimauve comme Kirby qui s'applatit contre le plafond, mais Croc ne fait pas ça non plus. Et ça devient ridicule quand Croc devient équipé d'un casque et peut enfin briser les blocs.

Et là encore, c'est mou. Le power up monte lentement hors du bloc (par devant ?_?), avance lentement, se met à tomber sans transition quand vous cassez un bloc sous lui ... bof, quoi. D'autant que les blocs-étoile ne contiennent *que* des power-ups. Il n'y a aucun suspense du type "est-ce que ça va être une pièce ou un champi". Si c'est une pièce, c'est hors des blocs, si c'est un "champi", c'est dans le bloc. Et ne comptez pas sur la présence de pièces/power-ups/vies dans les blocs de briques, hein. On est sur du sans surprise. 

Il y a un moment, le développeur de Super Sunny World nous confiait

Did you ever notice: In Mario 3, if you hit a block that bounces up, it pushes Mario downward faster than if he hits a solid block? There's so many subtle details in SMB3 that make it play great! Super Sunny World (my new NES game) will also do this!

Et on aurait pu se dire "il en fait un peu trop, là. On a pas besoin de cloner Super MArio à ce niveau de détail-là pour faire un jeu!". Sauf qu'en fait, sans ce niveau de détail, on fait un Croc's World. Et ça se sent manette en main.

Idem quand Kirby Kid nous expliquait la "functional blind box" des tirs de Super Mario:

To balance out the effectiveness of fireballs and the deconstructive effect it can have on the core gameplay (making things less interesting JUMP wise for the player), the developers of Super Mario Brothers implemented some genius design features.

On peut aussi se demander s'il n'en fait pas des tonnes. Mario aurait pu tirer en ligne droite. Est-ce que ça aurait changé à ce point la donne ? ... Bin essayez donc de vous amuser en lançant les caillous de Croc, tiens. On en reparle après.

Alors pourquoi Croc est il si mou ? Sans doute parce qu'à l'origine ce n'est pas juste un jeu pour les gamins: c'est un jeu mobile pour les gamins. Donc contrôles imprécis, lisibilité discutable et compagnie. Toucher un ennemi en tirant depuis un saut pour compenser l'angle ? Hah! Aucune chance.

Friday, September 18, 2026

--dump=D

Okay, I need to remember this once for all. I'm frequently using gcc [OPTIONS] someFile.c -E to understand some of the error messages from the compiler, but too often, I have to ask a crawling duck what preprocessor option would let me see the values of the #define statements, not just the lines of code with all substitutions applied. So it's time I post something to remember me it's -dD

...

Or maybe I could just add some line in my cpp-output-colorizer that would remind me of it ?

Thursday, September 17, 2026

Retrobar pour Windaube 11

Avec les écrans toujours plus larges et les fenêtre toujours plus hautes, vous ne croyez pas qu'on va finir par avoir des ennuis ? A priori, chez M$, ça ne les choque pas. La barre des tâches de W11 est une horreur à utiliser même après avoir défait tous les pré-réglages foireux, mais ça non plus, ça ne les gêne pas. C'est que pour W10, j'avais pris l'habitude de la mettre en mode vertical, moi. Bon, ok, même ça, c'était mal codé, mais au moins c'était là.

Heureusement, il y a l'open source et pour le coup, il y a retrobar. Alors oui, ça pique peut-être un peu aux yeux, en particulier avec le thème "Windows 98 / Windows NT" que j'ai fini par choisir, mais le mode vertical marche comme une fleur et j'ai pu trouver le coin du code où on définit la largeur minimale et forcer quelque-chose de plus proche de ce que j'utilisais habituellement.

Au moins, j'ai l'heure en permanence dans le coin inférieur droit sans devoir gérer une barre qui apparaît et disparaît à tout bout de champ.

Les fenêtres que j'avais "épinglées sur la barre des tâche" dans W10 se retrouvent dans M:\AppData\Roaming\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar, prêtes à être customisées si je veux. 

(ah oui, je me suis fait un subst pour que mon répertoire utilisateur apparaisse comme M: ... il faut juste se souvenir que les autres utilisateurs ne voient pas ce disque virtuel, y compris le compte admin)

Et oui, j'aurais pu/du vous en parler depuis Mai 2025. Scsi.
 

 

edit: passer 1 jour à relancer des recherches Internet sur "comment faire pour qu'il n'y ait pas de boîte `cmd.exe` qui traine pour mon raccourci", tomber sur start /MIN ma_commande qui ne marche pas parce que la boîte de dialogue du raccourci ne connaît pas l'emplacement de "start" ... et finalement remarquer le Run: Normal Window [v] juste sous "Shortcut key:" .. qu'il suffisait de passer sur "Minimized" T_T

Tuesday, September 08, 2026

Terra Ninfa

Prenez le coeur historique de votre ville, tournez-lui le dos pour vous diriger vers le coeur folklorique. Là, au bout du boulevard, à côté des ruines classées du vieil hôpital se tient le nouveau centre multi-culturel combinant bibliothèque, fab lab, salle de spectacle et "classes" de conférences ... et à l'étage, dans "l'espace des possibles" se tient en plus de l'apéro jeu-videos la soirée du "gaming club" où on retrouve des consoles rétros, des tables de jeu de rôle et de jeu de société.

Et une tablette où les développeurs peuvent mettre leur prototype à l'épreuve du playtest. Parmi eux, en juin, il y avait l'ami Tog qui présentait le prototype de jeu Godot qu'il a développé avec sa dame. Le jeu a un petit côté "monument valley" et fait la part belle à la manipulation de l'eau.

Tog n'était pas présent en ce début de Septembre, mais quelques-uns de ses colocataires-de-tablette avaient insisté pour que je revienne avec ma DS même si Dreamland n'est pas encore un jeu. Je suis repassé, donc et récolté quelques "tu me ramènes à mes 8 ans" ou "Franchement, chapeau! On ne dirait pas un jeu fait en solo!", voire même "J'adore les cahiers! Il faut que tu fasses un livre pour nous raconter le dev!"
 

 

Thursday, September 03, 2026

Inspector Widget Improved

Inspector Widget ... le mode pause du moteur de jeu de GEDS qui permet de voir à travers la Matrice. Repérer les zones de collision, mais aussi visualiser le terrain autour des personnages tel que les contrôleur le perçoivent. Sauf que le code qui faisait l'affichage du terrain date de l'époque Apple Assault  et qu'il est plus ou moins inutile avec le nouveau système de map physique.

During AppleAssault and SchoolRush development, the "playfield" feature of InspectorWidget has proven an extremely valuable feature of the GEDS engine. I could get an overview of what the engine sees of the level without having to manually decode contents of the physics map. But with the evolution towards a new, richer encoding, the information it was showing became mostly useless. But hopefully, during the "Blador-vs-Spike" episode, I located where the responsible code was and could start fixing it. Initially, it was looking like the listing below.

Le code qu'il aurait fallu que je retrouve il y a un moment était caché dans InspectorWidget::clearmain(). 

for (int ty=sy; ty<=ey; ty++)
  for (int tx=sx; tx<=ex; tx++) {
    unsigned f=gob[0]->world->getflags(tx,ty);
    unsigned c=BCHECK; // pattern for the "outer ring" of the zoomed tile
    if (f&F_BLOCKING) c=BON; // plain light ring = solid block
    if (f&F_PLAYERTHRU) c=BOFF; // dark ring = air / water / etc.
    if (f&0x10000) c=BCHECK; // checkered ring = special block
    if (f&F_SLOPE) c=97; // striked through = slopes
    char sq[16];
    memset(sq,c,16);
    if ((f&(F_FLOOR|F_SLOPE))==F_FLOOR) memset(sq,BON,4);

    sq[5]=80+((f>>12)&0xf); // 4-digits code in the inner area
    sq[6]=80+((f>>8)&0xf); // encodes the F_* flags for cando() calls.
    sq[9]=80+((f>>4)&0xf);
    sq[10]=80+(f&0xf);
    u16* v = vram+MAP+(ty-sy)*128+(tx-sx)*4;
    for (int i=0;i<16;i++) {
      *v++=sq[i];
      if ((i&3)==3) v+=28;
    }
  }

Pour ceux qui ne parlent pas le C couramment, le listing ci-dessus raconte que chaque pavé de la map va être représenté par un code à 4 caractères entouré d'une bordure dont le pattern est variable. 

  • bordure solide pour ce qui ne laisse pas passer le personnage
  • bordure en damier pour les blocs spéciaux
  • bordure en hachure pour les pentes.

Le code au centre du carré, ce sont les propriétés utilisée par la fameuse fonction cando(). Et il faut bien admettre que maintenant qu'il y a plusieurs types de pentes différents, plus de blocs spéciaux et des blocs aux propriétés particulières, juste les flags pour cando(), c'est devenu à la limite de l'inutile. Parce que la plupart des blocs spéciaux ont les mêmes propriétés et que celles des pentes sont prédéfinies.

Mais heureusemement, j'ai trouvé l'occasion d'améliorer ça.

  • un code à 2 chiffres, c'est un tile à encodage direct. on voit littéralement le byte de la map physique et chacun de ses bits nous renseigne pour une propriété. 44, c'est de l'air.
  • un code à 2 chiffres sous une petite ligne à damier, c'est un bloc spécial. Ici aussi, la valeur et celles du byte de la map. Les valeurs ff, fe et fd servent pour les fameuses "flèches jaunes" de l'éditeur.
  • les pentes sont toujours identifiées par leur contour hachuré. Le code à 4 chiffres donne les hauteurs des pixels au centre du tile. 3456 ou 6543 pour des pentes à 45°. 2233 et 6677 pour des pentes plus faibles en "montée" de droite à gauche, etc.
  • Enfin, pour les autres blocs, on reste sur un code à 4 chiffres qui contient les flags. à l'ancienne. 

The new code varies the shapes a bit more. Some tiles will only have a 2-digit code (the byte straight out of the map), sometimes with a checkered line on top of them for special blocks. Slope tiles still have a 4-digit code, but it now shows how heights ramp up or down along the tile. And the so-called "indirect" tiles, those which can be assigned physical properties such as friction and flow, keep showing the 16-bit cando() flags as before ... at least so far.   

 

 

Tuesday, September 01, 2026

CompoundGob::RefreshPage

I guess you can hardly tell what's going on on the picture below, and I can't blame you for that. It's supposed to be a stomped scorpeye shell, but since I've added crawling animation for the scorpeye, we see that glitchy mess of sprite parts instead.


Ah oui, je m'étais fait un joli scorpion qui marche, mais si vous parvenez à l'assommer, tout à coup, il ne ressemble plus qu'à un tas de pixels complètement glitché. Comme j'envisage de passer refaire un coucou au "gaming club" de vendredi, ça ne serait pas mal de corriger un peu ça.

La cause du problème, je la connais: l'animation de la marche est construite avec 5 sprites hardware: un "large" pour la carapace du scorpeye et un carré pour chaque "patte". En revanche, les animations "carapace seule" et "carapace qui tourne parce qu'on l'a lancée" sont toujours inchangées et n'utilisent que 3 sprites hardware. Et le couac, c'est qu'en plus, le sprite large n'est pas sur le même d'une animation à l'autre. Il était donc temps que je me gratte un peu la tête et que je retrouve les fonctions-clé pour gérer ça, en particulier loadAnim() dans CompoundGob et setupOAM() qui peut redéfinir les tailles et aspects des sprites.

What happens is that you have dedicated bits in the hardware sprite entries to indicate whether you want a square, tall or wide sprite and of what size. So far, in my engine, those properties are defined once when you allocate hardware sprites for an object and then preserved as we just update coordinates, VRAM location and optionally palette slot of each sprite as we animate them. But by mixing the new crawl and the old spinning animations, I'm breaking an old habit of sharing the same structure for all animations of a given game object. So I need to extend the game engine with the following function:

  void refreshPages(const GobAnim *ani) {
    unsigned nlimbs = ani->getnlimbs();
    unsigned i;
    pages = ani->getpages();
    for (i = 0; i < nlimbs; i++) {
      if (oam[i]==NO_OAM) continue;
      pages[i]->setupOAM(sprites + oam[i], 0 /*?*/);
    }
    for (; i < nboam; i++) {
      if (oam[i]==NO_OAM) continue;
      sprites[oam[i]].attribute[0] = ATTR0_DISABLED;
    }
    nboam = nlimbs;
  } 

Je dois dire qu'au départ, je m'attendais à plus compliqué, mais la petite fonction ci-dessus et une brave ligne de plus, les animations se sont réparées presque d'elles-même. à utiliser avec prudence tout de même: le système ne se déclenche que si les deux animations ont un nombre différent de sprites.

To be honest, I was expecting it to be harder to code. It was a bit tedious to locate where to act in the code (state transition? animation loading ?) and I spent a significant part of a holiday afternoon in ddd setting conditional breakpoints to figure it out. Then I got puzzled by the update/setup/allocate functions manipulating hardware sprites through the "SpritePage" class: the one that is used at every frame to update what we see on screen keeps aspect ratio and size of the sprite unchanged... but after all, it was just a matter of a small function called when we detect that the current number of OAMs (aka hardware sprites) is different from the number of limbs the animation uses. Pretty and straightforward.

Monday, August 24, 2026

Crawling Scorpeye

Sur bsky, MagicalScope nous poste d'impressionnants designs d'objets magiques qui sont ensuite vendus à des internautes. Parmi eux, je suis tombé sur une potion-qui-marche particulièrement inspirante. J'ai d'abord eu le réflexe de voir comment je pourrais l'intégrer comme nouveau perso dans la pyramide jusqu' ce que je réalise que mon brave scorpeye pourrait simplement profiter du type de déplacement que suggère cette potion tout en restant lui-même. 

Après des mois où on voyait un scorpeye tout immobile dans un coin de la salle pyramidique, voici enfin une petite animation (encore un brin brouillonne) du scorpeye patrouillant autour de son trésor. J'aurai probablement un peu de travail à faire sur le moteur de jeu: l'animation de la carapace lancée supposait 3 sprites hardware alors que la marche en crabe en utilise 5 ... le résultat est assez bizarre à voir quand on assomme et ramasse notre scorpeye.

At last! After months (years ?!) of design blockage on how-the-heck-am-I-going-to-make-scorpeye-walk, I can propose you a prototype animation for the crawling scorpeye ! Maybe not as "crawling" as I had imagined after seeing MagicalScope's mimmic potion, but that shall be a start.

Key idea for the redesign is to embrace the "limbless" nature of Bilou's world and grant the scorpeyes 4 versatile spike sattelites. It can use them to crawl, pinch or sting depending on the situation's need. It will make it clear whether it's currently safe to stomp on its shell to stun it.

"Mais où sont passées ses pinces ?" me demanderez-vous ? Eh bien c'est justement là tout le sel du redesign: les même membre lui serviront soit de pattes, soit de pinces, soit de morceau de queue de scorpion. Je décide que ce sera plus fun et plus lisible qu'un vrai arachnide avec tous ses chéli-chose (J.L.N ? c'est quoi le bon nom, encore ?) 

As a bonus, an intermediate step where I was studying the design of the magic potion and considering "well, why not. It would be an extended version of Inkjet that can move along... quite fits the universe. You lose some part of the crab-like suggestion by not having limbs between the pinching part and the body, but that's how I came up with the idea of keeping scorpeye and having it walk on its pincher, so I'm okay with it.