Friday, October 25, 2024

Hanging around in the ICE ...

Good thing with the German express trains is that they provide unlimited power and some WiFi. Your trip might not go as you expected, but at least you've got time to sit, think and check your code base to plan what you'll do in your homebrew project afterwards.

Among those "what's next", some are already done now, like "converting furblock to treebump"... which it did not need after all.

For some time, I have this little note in my notebook... Because many of the levels in the design book expect that we could hook and hang to some objects. I'd like it to be stylish, with swinging animation and all. But for the purpose of testing the levels and trying the game, just snapping to the hook and waiting for the player to press JUMP or leave would do the trick.

The train-idea here is for the step just after that bare proof-of-concept: I already have a "radius" controller that keep a character within a given range of a "pin point". Being hung could use that controller rather than being snapped to a static position. 

To do so, we can shoot a new game object, Bilou's hand(s), that will snap to the hook and use that as a pin point for the swing. That means we'll have to hide bilou's hands on the existing hero game object (like we do when he's carrying something) ... or just don't draw the hand at all, and reuse its OAM slot to draw Bilou's eyes separately from his body, meaning we'd gain one extra freedom degree for the animation, and wouldn't have to draw a dedicated body-and-eye sprite for every angle.

Then I started brainstorming about the croc-platform: I'm not satisfied with its current look. I dug some real egypt crocodile pictures (and real statues pictures). I toyed with the idea of having the crocodile head showing sideways rather than front view -- that would have meant it wouldn't stop sands when flapped anymore ... The blue book said it wouldn't harm that much.

But I couldn't convince myself it would work either. When the crocform#1 flaps down, it completely cease to interact with characters. A sideways crocodile head flapping down by 90° wouldn't "disappear" that way. It would still be in Bilou's way, mostly as a small wall, but it should still be possible to stand on the rear of its neck ...

A few spots in the ongoing level design would work fine with crocform#2 repurposed, but in other spot, it would mean throwing the player into spikes, rather than just let them fall down...

And then I thought about a type of object in New Super Mario Bros that would behave quite like what I need for my collapsing platform, and it meant I wouldn't even need to drop the "shut the sand door" idea:




Monday, October 21, 2024

bug on blador

J'ai tout les morceaux pour qu'on puisse à nouveau utiliser la map "anniversaire" de la school zone dans l'exécutable de "Three Rooms Demo" ... mais quand je veux le faire tourner, on ne peut pas vraiment dire que les choses se passent merveilleusement bien. J'ai cru au départ que c'était des choses que j'avais "cassées" en développant le "soft landing" des furblocks (la motivation n° 1 à faire revenir ce niveau *maintenant*, c'était précisément de vérifier l'absence de régressions). Et des choses qui vont de travers, il y en a quelques unes ^^°.

I wasn't 100% confident with the changes I made to special flags used to implement the furblock... So as I'm entering one week off, it seemed appropriate to ensure I have all the required material to revive a School Zone level where all the "monsters" are featured and ensure there aren't regression. So here's the "anniversary" level again.

Mais pour certains bugs, un petit voyage dans le temps avec Mercurial ne laisse aucun doute: ils étaient déjà là avant. C'est notamment le cas avec dumblador, et Bilou qui tout d'un coup se retrouve bloqué et immobile s'il lui atterrit dessus au moment où il devrait pouvoir servir de plate-forme...

Cette fois encore, c'est dans ddd que la réponse est apparue. Si le n° d'état renseigné par InspectorWidget (bi28) est pour "RIDLE", l'affichage de Bilou en train de tomber n'est pas un glitch: on a jamais su rester sur le taille-crayon parce que le contrôleur "onpath" estime qu'il n'y a plus de plate-forme... la faute à une modification pour crocform qui ne s'est pas re-propagée jusqu'à dumblador: le choix du bit d'état qui indique si on est bien sur une plate-forme ou non ...

And well, we do have some regressions, and some of them are quite older than the furblock modification. Today I repaired the ability to stand on a stunned blador, which should have been updated after I implemented the pyramid "collapsing" platform: it reuses bit-testing that allowed stacking dumbladors, but for obscure internal reasons, it did not use the same bit to declare that the platform is indeed valid. Tricky to find, but easy to fix.

Saturday, October 19, 2024

On y est !

Enfin ! Un peu de bidouille, un sprite qui doit encore être invisibilisé, mais j'ai enfin les physique voulue pour cette branche rebondissante! Dites-moi ce que vous en pensez, mais moi, je suis plus que satisfait par son mouvement ^_^

Euh ... non, je n'ai pas grand-chose de plus à en dire, en fait... mais bon, ça traine depuis tellement longtemps que je voulais marquer le coup avec un p'tit post qui reprenne l'image. 

Je ne suis pas sûr que ça mérite de ré-uploader un .nds ... je vais plutôt me faire un jus et me mettre au lit. Ciao tutti ;)

Finally ... Finally, I've got my bouncing branch working with the intended "furblock" physics. Almost everything else is said in the previous post, and you also have a download link there to try the physics on the original furblock ... But this has taken so long, I wanted it to have its own post.

Newer collision flags

It wasn't as easy as I wanted to make the "soft land" mechanism work, and knowing that Bilou will have to attach to an invisible block for it to work with the "bumping branch" rather than to the branch itself will make it even a bit harder. The issue is to allocate new "kinds of collisions" in an already crowded 16-bit space.

That issue is not new: it already appeared when I wanted to add pick-and-throw mechanism together with get-your-feet-back while I was just done with direction tiles for inkjet. Each of these would require about 4 different type of "messages" exchanged between game object and I had barely more than 8 flags left... And the solution had been to use some combination of bits for the different things. So you'd still have 0010 saying "up" and 0020 saying "down", but that would only be valid in connection with 0100 that says "direction tile" and not with 0400 that says "interplay" or with 0800 that has been used to collect feet and animate ink level in pipes.

I've got notes already about addressing that, but they mostly question the fact that there are only two "casts" (read game object lists) in the engine: heroes and foes. And that actually address a different issue (collision performance) although they somehow partition "messages" as well: almost only Bilou can receive a "HURT" collision (well, blador receives it too from spiky pencils tiles so it can align with them and this is likely BadDesign ^^")

And well, introducing bridges and things like that could easily use more casts to keep good performances: both heroes and baddies will collide with bridges, but that doesn't requires baddies to test each others to work. And likely only part of the bridge internal.

I had collected a set of questions on my new notes, and one of the first one got its answer: despite we have only 16 bits communicated to the script about what truly happened in a collision, a full 32-bit number is stored internally. Some of the high bits are already use for special purpose such as "keep checking collision even after a first item was found" or "only consider objects attached to me", but plenty others could be used to restrict the scope, e.g. creating a private "namespace" between blador and blador feet so that the feet cannot accidentally attach to an inkjet (although maybe that's redundant with "must be attached to me"). It makes little sense to keep the upper 16-bits as "flags" and process them the same way the lower 16-bits are processed (a single matching bit and bingo, we have a collision) because we would be unable to identify which flag had a match. Did we caught fire ? or get smashed ? or got an electric shock ? no way to find out.

So the plan would be the following:

  • 8 "casts" (lists) seems a good number. Each test area indicates exactly which cast it tests. If we have casts Evil and Bridge and need to test both for STOMP, then 2 test areas are needed.
  • two "control" bits: ALL and ATTACH
  • 16 "flags" bit: a collision occur as soon as two masks have at least one in common
  • 8 "namespace" bit: a collision occur only if the two area exactly use the same namespace
  • any other are reserved for future extensions.

Saturday, October 12, 2024

Un furblock qui a du ressort

ah. Voilà qui est mieux... Le saut est amorti, puis le bloc re-propulse Bilou en l'air une fois dans la phase à gravité positive. J'ai encore un glitch temporaire à régler, mais au moins Bilou ne se met plus à rebondir dans le vide une fois sur deux. Alors je suis sûr que vous avez d'essayer ça, donc.

And give it a try yourself. I finally have a bouncy block that is bouncy the way I want, dampening your fall, kicking you up when it is back.

Not only that, it also allows buffering of your JUMP commands so that you get a high-jump if you press and hold the JUMP button anytime while the furblock is dampening. JLN managed to get a high jump on any of his attemps. (of course, he is disappointed that it isn't possible to use the glitch to charge even more jump power and make a super-jump taking you out of the map into a super-secret area :P)

Et si on appuie sur le bouton de saut au bon moment (c'est à dire n'importe quand pendant qu'on est sur le bloc), on part en super-saut. Hahaa... On est prêt pour ramener ça sur la branche aussi...


$BACK->$IDLE on event2 [v1 256 <] ($VTHROWN(0) 0 :1 0:6); // 1 
$BACK->$IDLE on event2 [v6 0 <=] ($VTHROWN(0) 0 :1);      // 2
$BUMP->$BACKLAST on event2 [v6 1 =] (v1 2 / :1 v6 1 - :6 $DIR(D_DOWN));
$BUMP->$BACK_ on event2 (v1 2 / :1 v6 1 - :6 $DIR(D_DOWN));  // 4

$BACK->$BUMP on event2 (v1 2 / :1 $DIR(D_UP) $VTHROWN(VTHROWN 3 * 2 /);

$IDLE->$BUMP on hit0 [w1 0 >] ($VTHROWN(200) w1 512 m :1 $DIR(D_UP) 3:6);
$BACKLAST->$BACK_ on hit0 [w1 0 >] ($VTHROWN(200) w1 512 m 2 * :1 3:6);

The little glitch we still observe is linked to the BACKLAST state. Normal cycle alternates between BUMP where Bilou can stay landing on the block (think as "compressed" state) and BACK where Bilou would be ejected ("expanded" state). There may be up to 4 such oscillations before the block comes to a halt. A former glitch happened when Bilou would fall back while we're in BACK state and react as if it hit an eraser although it isn't close enough.

BACKLAST was intended to fix this: it let the block oscillate one last time, but it doesn't feature the hitbox that would propel Bilou up. Of course, that does not work alone, so I also added a transition that restart a cycle if Bilou still shows up, exactly as if we were idle. But we cannot simply do BACKLAST->BUMP, else we will screw up how the "on grid" controller decide where we should transition.

My last glitch came from the speed division on line #3, that makes each oscillation smaller than the previous one: if we keep the last line's expression identical to that of $IDLE->BUMP, the speed will almost immediately be very low, and we might not hit and propel as intended, hence the additional 2 * to compensate the division that is about to occur as soon as we've reached the "default" position of the block. (still, I'll have to cross-check the collision coordinates: it doesn't feel right that it need that much fine-tuning...)

update: okay, works for the branch as well. Just took 1 or 2 hour of tuning...

Friday, October 04, 2024

furblock de montée

La dernière tentative d'améliorer la branche s'est plus ou moins soldée par un échec constructif. Puisque le week-end de montée m'offre un peu de répit, je vais partir sur une idée qui m'est venue en passant en revue les autres jeux avec des éléments de gameplay similaire: commencer par me faire un "bloc-note" à la SMB3, qui se concentre sur le mécanisme, pas sur l'animation. Et une fois que le mécanisme sera validé, je fait la même chose avec un objet invisible.

So trying to combine physical motion and animation for the bouncy branch proved to be a bad idea. Rolling back. I'll keep my satisfying animation and combine it with an invisible block behaving like the "note block" of Super Mario Bros 3 instead. And I'll prepare that with non-invisible block in an easier-to-test environment, that is the pyramid room.

  • premier fix: je dois retirer les zik.import de mon script pyrat.cmd: ces commandes sont propres à la "trhee rooms demo" qui pré-charge un module de base (bilou.xm) et runMe ne connaît pas (encore) l'équivalent, même après recompilation du dernier modèle
  • deuxième fix: runMe a besoin d'un "../spriteB.spr" explicite pour aller chercher le nouveau fichier (et pas un vieux fichier de SchoolRush dans efs:/moving/spriteB.spr ^^")
  • 3eme fix: ma petite anim' faite à la main doit utiliser la SpritePage 8+2 (parce que le fichier bilou.spr préchargé contient 8 pages)

Bon on y est. J'ai un "furblock" dans le niveau-test de la pyramide. Je saute dessus et il s'enfonce bien puis ... il décole vers l'infini et au-delà (ç.à.d  -2147483648). Ah oui, et il n'a encore un tête de fury que sur DS, pas sur l'émulateur. 

J'ai utilisé pour le réaliser un nouveau contrôleur "grille" qui indique si on est repassé au "bloc" suivant, histoire de passer d'un état "repoussé vers le haut" à un état "repoussé vers le bas", et que le bloc finisse par se stabiliser à sa position d'origine. Mais manifestement, ça ne marche pas encore.

There have been a few "setup" issues, leading to a few TODO items to be processed later (this season?) in my notebook, like runMe not supporting the multi-music commands and the lack of "translate to that sprite page" macro for multi-spriteset that leads to annoying magic numbers. But I have to admit that even with that done, the behaviour was fairly surprising. Well, on the DS, the "furblock" did a downwards bump and then skyrocketed to negative numbers: I needed something to fire an event when the original position has been reached. And that thing could be the "grid" controller that was part of my "how to code bosses" arsenal.

But even with that, the resulting behaviour is emerging and perplexing. I guess I haven't found the proper set of rules yet.

Et nous voilà le week-end d'après encore plus au calme, ce qui m'a permis de décortiquer avec InspectorWidget le comportement émergeant (mauve) et de trouver les corrections (bleues) nécessaires pour que ça marche pour de vrai ;)

Sunday, September 29, 2024

Herby: the map

And then the idea popped in. Has anybody ever done a speedrun of the C64 game Herby ? And while I'm watching what is supposed to be one, I wonder "doesn't he have any map to do it ? He seems lost all the time. And checking ... I couldn't find any. But I did find a website that offers online play of the game !

Le JDG avait Fantasia et Super Copter pour se prendre la tête quand il était jeune. Moi qui était encore plus jeune, je n'avais même pas ça. Mais j'avais Radar Rat Race, Slamball et ... HERBY. Et il vous faut bien toute la passion d'un fan de labyrinthes pour jouer à un jeu pareil.

  • Les murs vous tuent au moindre contact
  • à chaque salle, il faudra aligner un personnage de 18x20 pixels sur un couloir de 24x24 pixels. Ceux qui disent "oh ça va! c'est large" n'ont jamais joué avec l'image bombée de la télé du salon située aux 1m50 règlementaire avec un joystick d'époque
  • Le premier truc qui ressemble à un trésor plonge la salle dans le noir total
  • Régulièrement on se retrouve dans une salle vide où il suffit d'aller droit devant soi
  • Et pour les autres "trésors", de toute évidence ils ne font absolument rien
  • On ramasse des clés mais on ne voit jamais la moindre porte!

So let's try to get past the unbearable sounds, avoid getting trapped by sliding blocks after 11 rooms (about 2minutes play) and draw a map of where I go. There are "room numbers" in the stats, and yes, that is how you know your position over the 12x10 cells of the maze. And well, collectibles actually *have* an effect, but that will only be shown when the score panel is repainted together with the room when you'll switch to the next room. Needless to say that this kind of detail aged poorly.

I was a bit puzzled that finding keys actually makes the number of keys *decrease* on the score panel. I haven't met any door, but some room actually change shape when you have collected a given key, opening access to more rooms in the maze.

Mais bon, on est là pour tracer une carte, alors allons-y en prenant son temps (au clavier PC, et avec le zoom de l'émulateur, 2 pixels de marge, ça devient correct) et traçons. En partant du principe que faire la course avec un bloc écrabouilleur est une mauvaise stratégie et que puisqu'on a commencé en haut à gauche, la sortie est probablement en bas à droite, donc privilégeons ça tant que possible.

Je n'avais pas un niveau extraordinaire à l'époque, mais je suis sûr que si on avait pris le temps de faire la carte, on aurait fini par comprendre à quoi les clés servaient, qu'elles ouvraient les "portes" à distance, mais juste de mémoire, ce n'est pas le genre de choses qu'on peut remarquer. Et comme on avait droit à 30 minutes de jeu, que mon frère n'aimait pas celui-là, il était rare que j'ai l'occasion d'essayer de trouver la sortie.

So with no clue on where are the doors, which key opens what, random rewards that show up delayed, all this game is lacking to become iconic was a hidden pixel you'd have to hit with 42% to get the true ending. Because spoiler alert: there is no exit to the maze. You complete the game by fulfilling a winning condition. And I'm not event sure it can happen in any room, although it could. And there are bugs that make some room exit towards the surrounding wall of the neighbouring room and so on. I guess only disassembling the program would give us the actual rule. Anyway, my map isn't complete because at some point I managed to pick up a 6th key and end up with 255 more to collect. Please ping me if you decide to complete it.

Et j'y aurais même mis le temps au point de faire la carte de l'entièreté du labyrinthe, je n'aurais toujours pas trouvé. On est ici dans quelque-chose digne d'Aventure(s?) sur Atari ou du jeu mystère de "Video Games" (le roman). Le labyrinthe est sans issue. Pour obtenir un "game over" sans perdre de vie, il faut atteindre les 100%. Enfin, je crois. Et tout ça dans l'équivalent numérique du jeu du fil d'Arianne...