Monday, December 06, 2021

greent.map

Se pourrait-il que j'arrive malgré tout à avoir une démo "3 rooms" pour la fin de l'année. Enfin un premier jet. Le hic n° 1, jusque là, c'était la quasi-impossibilité de faire une nouvelle map propre. Depuis l'introduction de la branche newmap, l'éditeur de niveau ne savait plus le faire, mais j'ai fini par trouver ce qui n'allait pas

Maybe I'll have a 3-rooms demo by the end of the year ? Not with all the features working, of course. Expect static waterfalls and incomplete water physics, but at least a .nds where you could travel freely between the 3 environments I have so far. Until yesterday, that was hindered by a bug in the level editor that prevented me from creating new maps: I could only update existing ones. But that bug is now solved, so I started tiling 'greent.map' and 'schoolt.map' as I intended them to look like in my notepad.

Du coup j'en ai profité pour redessiner en 512x256 les niveaux-démos prévus, rajouter les palettes de couleurs que j'avais essayées pour les cascades. Il n'y a pas encore d'animations ni de physique de l'eau ... ce qui donne un résultat un peu perturbant (mais pratique pour aller voir ce qu'il y a d'autre sur le 2eme écran). Ouaip. c'est l'avantage de la Saint-Nicolas en quarantaine quand les enfants ont assez grandi. J'ai eu l'occasion de m'asseoir avec ma DS à côté d'un Gimp.

Then I went ahead, taking advantage of the 'woot-we-have-new-toys' while we're all locked-home by quarantine to open my earlier waterfall mock up and redraw that into SEDS.

I hope I'll be able to do the same with pyrat.map soon.

Thursday, December 02, 2021

The true Mario Jump

J'ai un vieux post, le premier qui raconte comment on peut faire sauter un personnage dans un jeu vidéo. Dedans, il y a une image où j'explique que la physique de SMB3 est un peu 'truquée' du côté des sauts. Mais bon, j'avais fait ça à la grosse loupe sur une vidéo youtube, alors que l'ami Upsilandre, lui, a du lourd sur le sujet: il a analysé en détail les mouvements de Mario et ceux de TinyToons Adventure pour voir s'il y avait eu des fuites de code source entre les deux jeux.

When I was writing one of my first post about having a character jump in a tile-based game, I had the surprise to see that Super Mario bros. 3 doesn't seem to use Newtonian gravity. Instead of having a smooth parabolic curve, there seems to be linear rise, parabolic climax and linear fall in a Mario jump. But I did that just by checking a let-s-play video on youtube. On his French blog, Upsilandre did a detailed comparison of SMB3 and Tiny Toons Adventure where he gathered all the impulse and gravity constants, so why not pay him a visit ?

Il pointe notamment une correspondance exacte pour les impulsions de saut. au centième de pixel par frame près. Troublant ? Eh bin, rappelons-nous: quelques paragraphes plus haut, il relevait aussi que les deux jeux utilisent le même format de nombre pour les vitesses: 4,4 bit

La vitesse dans Tiny Toon est encodée exactement dans le même format à virgule fixe 4b.4b que je n'ai vu que dans SMB3 (même pas dans SMB1), en général c’est plutôt du 8b.8b (voir du 3b.5b). [...] La même force de gravité faible de 0.06 tant qu’on maintient le bouton saut (comme si on était sur la Lune) et une force de gravité forte de 0.31 (retour sur Terre) quand on lâche le bouton ou que la vitesse verticale passe en dessous des 2 pixels par frame (donc quand on approche du sommet du saut). [...] [on va retrouver] strictement les mêmes 5 valeurs d’impulsion à la décimal prêt (respectivement 3.44, 3.56, 3.69, 3.94 et 4.00 ppf). La seule chose qui diffère c’est la valeur qui sert à caper la vitesse max de chute qui, comme pour la glissade en pente, est plus basse dans TTA.

Petite précision: cette histiore de 4,4 (ou 4b.4b selon la formulation d'Upsilandre) signifie que toute vitesse est exprimée en un nombre entier de 16 de pixel/frame. et on peut aller de -16 à +16 pixels par frame (mais personne n'ira jusque là). Du coup, 0.44 c'est 7/16, 0.56=9/16, 0.69=11/16 et 0.94=15/16. Déjà beaucoup moins surprenant. Notons au passage que la gravité lunaire de 0.06 pixels/frame² correspond à une simple décrémentation de la vitesse en 4,4bit. C'est 1/16eme. Tout simplement. Sur un processeur tel que le 6502, si on peut décrémenter plutôt que de soustraire 2, c'est toujours ça de pris.

The most interesting part is that the game uses two different gravity values. the 'ramp up' part of the jump uses the lowest possible gravity the game can deal with, of 1/16th pixel per frame². The switch to another gravity happens when we reach a vertical speed of 2 pixels/frame (or if the button is released), and we then go for 5ppf².

The impulse value may seem surprising, especially when expressed as decimal values like 3.69ppf. In fact, they integrate to nicely integer jump height expressed in Super Mario Blocks. What it means is that any game that wants to use the same gravity as SMB3 and a map made of 16-pixels blocks is likely to need the same impulse values as well.

Mais pourquoi ces valeurs-là ?
C'est le moment de ressortir un autre vieux post où on reverse-designait Super Mario World. Le game design forum y pointait que tout se mesure en bloc, dans le monde de Mario. Y compris la hauteur et la longueur des sauts. je ne serais pas surpris de découvrir que les impulsions correspondent aux vitesses qui permettent de franchir un obstacle de 3, 4, 5 ou 6 blocs le plus justement possible. Mais on a les valeurs, donc vérifions!

Voilà donc: selon l'impulsion initiale (v0), la hauteur atteinte (y2) au moment où la vitesse vaut 2 (et où on applique une gravité "normale" proche de 5/16 ou 6/16 ppf²). Avec en prime le temps mis pour y parvenir. Les valeurs 'magiques' correspondent à un obstacle de 4, 4.5, 5 et 6 blocs respectivement.

During the fall down, the game physics makes the terminal velocity kicks in very soon. As soon as 2 blocks high, actually. It may be an important part of consistent air control, giving you equal chance to hit RIGHT and reach a platform regardless of how long you've been falling down. The quasi-linear ramp up with super-small gravity does its best to mimic that for gameplay symmetry and ensures that we don't need speeds near 1 tile/frame if we want to jump up to 6 blocks high, as 1 tile/frame is almost warp speed for a 8-bit game engine.

ça, c'est pour la montée en gravité lunaire. Avec une gravité de 5/16, il faudra 22 frames pour tomber de 65 pixels de haut, mais 2 frames plus tard, on aurait déjà franchi 80 pixels. Enfin, ce serait en supposant que les programmeurs de SMB3 n'aient pas mis une 'terminal velocity' pour la chute libre en-dessous de 6ppf². En réalité, comme le fait remarquer Upsilandre, la vitesse de chute est limitée à 4+5/16 ppf par la "friction dans l'air". La mini-gravité en début de saut est essentiellement là parce que le gameplay veut une hauteur qui ne devrait pouvoir être atteinte qu'avec une vitesse de chute supérieure à cette vitesse terminale. Sans ça, il faudrait une impulsion de plus de 7+8/16 ppf pour dépasser 6 blocs de hauteur. On s'approche dangereusement de la limite de 1 tile / frame à partir duquel le code de détection de collision avec le niveau doit être radicalement modifié.

Au final, 

  • la descente de Mario est principalement linéaire. Il n'y a accélération que pendant les 2 premiers blocs (1 mario) de hauteur.
  • la montée de Mario n'est pas strictement linéaire, mais la gravité est si faible que la différence est à peine perceptible. Elle va surtout agir comme un compteur intégré de frames de montée forte avant de passer à la phase 'sommet du saut'
  • le changement de gravité au moment de relâcher le bouton offre une alternative sympa à ma solution de "forcer la vitesse de saut à -2 si on relâche le bouton [et que...]" 

edit: j'en profite pour sortir d'un vieux draft un autre schéma 8-bit d'upsilandre: la comparaison des courbes d'accélération de différents personnages.

edit+: en comparaison, Gomez ne sait sauter que par-dessus un obstacle de 2 blocs de haut mais peut s'accrocher à un rebord à 3 blocs de hauteur. Plus approprié pour un jeu de puzzle comme FEZ.

Tuesday, November 30, 2021

bg0.more vs. spr.more

 Bin ç'a été un drôle de week-end. Avec la p'tite famille en attente de résultats des tests covid et moi qui savais déjà que j'étais négatif ... enfin, le point positif dans tout ça, c'est que j'ai pu (dû?) me poser et clarifier sur papier ce qui n'allait pas avec ma gestion des 'overlays de spriteset' (si, vous savez bien: la superposition de deux fichier dans la mémoire vidéo de la console).


Reprenons. J'avais remarqué que mes écrans bleus étaient liés à des pages incohérentes, et ça m'avait conduit à constater que ni l'indexage page-dans-le-fichier ni bloc-dans-une-page ne contrôlait que je restais dans des objets définis. En clair, si je prends la 12eme page sur un fichier qui en fait 10, bin il y a des chances que ça se termine mal.

J'ai donc rajouté du code pour détecter et rapporter les erreurs (ces petits yeux gluants sur mon dessin de l'autre jour) si bien que le niveau de l'école ne chargeait plus. En cause, l'animation de ce smiley bleu qui sert de renfort d'énergie à Bilou et qui est un peu un extraterrestre dans le jeu. Tout comme les livres, les fardes et les lettres-bonus, il s'agit d'un élément de la map du niveau. Un simple bloc animé. En revanche, son animation fait partie du fichier bilou.spr, histoire que je puisse le réutiliser dans les autres zones à l'identique.

Sauf que jusque là, si je chargeais bien un 2eme fichier .spr par-dessus bilou.spr dans la mémoire des sprites (malgré les complications pour l'animation), du côté des blocs, c'était school.spr et rien que school.spr. Et le code qui demandait de créer un BlockAnim à partir de la page spr:6 ne pouvait pas fonctionner, vu que quand on charge un .spr en tant que "sprites", tous les autres types de pages (blocs et anims) sont ignorés. Une ruse pour éviter de charger deux fois les animations en mémoire.

Bien. On va charger les blocs de bilou.spr dans la mémoire des blocs. Mais on les mets où ? Si je les rajoute par-derrière school.spr (ou green.spr, ou desert.spr), les nouvelles pages d'animations auront un numéro différent dans chaque zone (galère pour écrire les scripts). Si je les mets par-devant, toutes mes maps sont bonnes à jeter. Et si je les corrige, je pourrai recommencer chaque fois que j'ajouterai ou retirerai un bloc de bilou.spr >_<

Alors me voici occupé à ajouter le support pour bg0:-1 qu'il faudra comprendre comme 'la dernière page du SpriteSet des blocs'.


Friday, November 26, 2021

Three tunes

Having three different visual environment for Bilou's Dreamland's first demo is one thing. I'd like to given them distinct musical background, too. That was last week-end's target, but unfortunately, it hasn't been very satisfying.

Sure, I could get 'school rush' theme played while being in the school room, and 'Apple Assault' theme while being in the green room (sic), but the loading time between them became quite excessive. Even if I expect this to happen only at 3 different time in the game, being completely silent and blank then is a no-go.

The second issue is with sound effects. Apple Assault used simple samples to play sound effects for e.g. jumps, stuns and the like. School Rush instead had mini-patterns with 3-4 tracks to produce the desired arpeggios and effects from ultra-basic sound palette. Of course the green zone tune did not featured any of this.


 The third and final(?) issue is an endless loop within the memory manager. Most likely, something's wrong within libNTXM memory management (or in my messed' up clone of it) which never showed up since I was playing the same module over the whole game's lifetime in previous installments.

Eh bin ... ça en a fait, des choses à fixer pour pouvoir passer d'une musique à l'autre au sein d'un même programme basé sur GEDS. Entre les makefiles, la bibliothèque NTXM elle-même, les p'tits soucis de parser et les modifications à apporter aux scripts, heureusement que TortoiseHg était là pour déméler tout ça au moment de faire enfin des commits.

C'est encore hautement perfectible, notamment au niveau des temps de chargements, mais si je veux avoir une première version jouable de Dreamland d'ici la fin des primaires de J.L.N., il va falloir que je me concentre d'abord sur le reste.

So I've been trying to see where I could have poorly managed memory ... something that would explain how the loop appeared, but given how shielded the memory management code already was in libntxm, I started doubting of my own deductions.

Then the emulator suddenly decided to give me addresses and register dumps! Huzzah!... but they were all for the ARM7 core.

It turned out that, no matter whether you invoked NTXM9->stop(), the timer interrupt keeps running and it keeps checking for the NTXM7->song pointer and dereference it. Simply, all channels are turned to mute, or something alike when you've stopped the playback on the ARM7. Note that background color for the top screen turns to weird orange when this occurs.

And of course, the ARM9 code would delete() that song before it sends the 'set song' command to the ARM7, meaning that the ARM7 core would start using recycled content to guide how it should work (including objects and VPTRs!) ... Pretty weird to see shared virtual tables between the two co-processor of a console, btw. Don't try to do that with the M68000/Z80 duo of Megadrive development.

  • step one: fix the .cmd so they use SFX that suit with the loaded level
  • step two: find a way to share revamped SFX through levels
  • step three: find a way to hide music loading latencies.

Don't start addressing step three before you get the 'three rooms' demo running and you're ready to encode levels.

Tuesday, November 23, 2021

Super Bilou 2

 Supposons qu'il soit possible de changer la manière dont SchoolRush affiche son encre qui monte,
histoire de laisser les 3 plans de background disponibles sur Super NES tranquilles.
On pourrait alors s'en sortir avec moins de 1024 tiles pour la constructions du niveau, et un moteur de scrolling plus classique.

Supposons encore qu'il soit possible de convertir le décor-hibou en 4-couleurs-par-tile sans arriver à une qualité décevante. Il resterait alors entre 12 et 20K de 'sprite tiles' 16 couleurs pour se faire un 'Super School Rush'. ça demanderait clairement une gestion dynamique d'une partie de la VRAM pour les sprites, mais ça semble déjà beaucoup plus cool. On pourrait par exemple garder les sprites 8x8 statiques (pieds, mains, gouttes, etc.) et se contenter d'un tableau de bytes pour encoder l'utilisation dynamique des sprites 16x16. ça reste un gros morceau, mais c'est déjà nettement plus 'viable' que demander du streaming de bouts de niveau.

I had a dream of porting Bilou School Rush to the Queen Console: the Super NES. Last study of how that could be done concluded to a bitter 'not a chance unless you've got a team of SNES geniuses along'. The issue is that I can't draw a full line of sprites on the SNES as if it was an additional plane and still hope to see more sprites through. And the inkline in School Rush DS is all made of sprites.

But the idea came back a few days ago with a striking simple observation: what if instead of changing everything to free up a layer for the ink I change the ink itself ?Like replacing the repeated wave spikes with mostly-flat ink and a crossing bigger wave every now and then ?

J'ai deux options pour ça. La première, c'est de trouver une illustration sympa de vague déferlante. Je garde de l'encre principalement plate et statique (construite par du masquage) et je fais passer de temps en temps une déferlante composée d'un gros sprite (32x32) et qui fait le lien avec un niveau d'encre plus haut par-derrière.

La deuxième option, ce serait de modifier la position verticale des sprites utilisés pour la bande d'encre (graphismes gardés à l'identique) de façon à construire un motif en créneau. Après tout, dès que l'encre couvre de toutes façon tout l'écran, peu importe que la limite de 272 pixels/ligne empêche les pieds des bladors d'être dessinés: ils sont cachés dans l'encre, de toutes façons. Il devrait y avoir entre 8 et 9 "créneaux rouges" visibles à l'écran, soit 128 à 144 pixels consommés sur le budget de 272. En fait, pour que ça coince dans ces conditions, il faudrait que les personnages à l'écran couvrent la moitié de la largeur de l'écran (quand on les dé-superpose, évidemment). Je ne pense pas que ça puisse se produire avant le niveau 4.

Eventuellement, on pourrait même imaginer forcer l'encre à rester plus plate autour des personnages qui pataugent dedans histoire de diminuer temporairement le budget-sprites qu'elle nécessite... éventuellement.

Another thing I realized is that only one part of the ink stripe consumes near 100% of the sprite-pixels-per-line budget. On the most interesting part (the spikes), we have nice 16-pixels blank space between two 16-pixels spikes. The NDS graphics absolutely don't take advantage of this, but an SNES port perfectly could. The top-part of the ink (red) then consume about 50% of the sprite-line budget and what happens as soon as the blue part kicks in doesn't matter because there, the ink is obscuring everything anyway. That will make the ink more tricky to animate, with sprites coordinates changing much more often, but that should remain manageable.

Now the next step is to ensure the background owl can still be nice to look at when using only 4 colours per tile.

Sunday, November 21, 2021

direct framebuffer

Parmi les projets tombés en désuétude, il y eu mon dernier GUI en date pour plate-forme PC. Mais pour des raisons techniques, celle-ci devait se faire avec la même technologie que celle choisie pour faire de la vidéo de fou: directfb. Rien à voir avec directX (enfin, presque rien): c'est une bibliothèque permettant de manipuler le plus directement possible l'abstraction de mémoire vidéo (fbdev) sous Linux.

J'avais déjà fait quelques petits programmes de test avec mais ici je me suis retrouvé évidemment à vouloir tester l'application qui était derrière, de manière systématique, chose qui était impossible à travers HDMI/USB ... (enfin, disons peu pratique plutôt qu'impossible).

dfb->WaitForSync(dfb) (☑) et DSCAPS_PRIMARY sans DSCAPS_FLIPPING avec un dfb->SetCooperativeLevel (dfb, DFSCL_EXCLUSIVE). Tout venait de là. En monitorant un peu les timestamps obtenus au moment du retour de WaitForSync, il devenait possible de se la jouer "Future Crew" et prédire dans combien de temps le retour d'écran allait avoir lieu. Mieux: je pouvais même prédire quelle portion de la VRAM était succeptible d'être utilisée par l'écran, et donc quelle portion de cette même VRAM pouvait être modifiée sans produire d'artefacts visibles.

Le site que j'utilisais jusque là n'est plus trop en vie... mais le code devrait toujours être présent sur github ... encore que les dates des dernières mises à jour semblent crier "do not use for new designs". Dommage.

Et sur devterm ? est-ce que ça fonctionnerait ? le package est disponible, son package 'bin' aussi ... par contre, j'ai systématiquement un 'segmentation fault' quand j'essaie d'utiliser les outils comme dfbshow ou dfbplay (juste après l'initialisation du joystick). Même dfbinfo n'y échappe pas. Il y a un /dev/fb0 sur l'appareil, fonctionnant en 480x1280 selon /proc/fb...

Voilà, c'est ce qu'il y avait à en dire en 2021, mais je note ce matin que quelqu'un s'est lancé dans directFB2 ... il faudra que je regarde ça de plus près ;)

Saturday, November 20, 2021

Smashing pixels

I did a few tries to render the heavy punch smashers for the pyramid in SEDS, and most of them were deceiving. My best render So far was crafted with the Gimp using the style and palette of an inspiring Sonie-like indie game dubbed "Kyle and Lucy".
Since I had a day off yesterday, I brought them back on top of my Pyramid level mockup. After all, the pixels for the Smashers were all mine. They just needed to be moved out that Kyle-and-lucy environment.

I also took the opportunity to try another approach: some structures in the School Zone are made of wooden, gianthands. What if I turn then upside down? Can I get something Convincing by Shading them with blues and pretend they're now metallic?
 

Bon, ceux-ci ne sont pas les premiers gros-poing-écrabouilleurs que je tente, mais les précédents ne ce sont pas vraiment révélés concluant (#euphémisme. Voir ci-dessous). Mais là, je retombais sur un screenshot de Kyle & Lucy sur lequel j'avais profité de la palette pour redessiner un gros poing d'un autre genre alors que j'avais toujours mon mockup "desertcolor.xcf" ouvert. J'ai fait un test. 

Et tant qu'à faire, j'ai essayé un autre truc que j'avais en tête: retourner le poing-pillier de la SchoolZone et lui donner une teinte blue-métallique, histoire que ça ne fasse pas trop bois. Les avis sur twitter sont assez unanimes: c'est le gros poing du bas qui gagne. Par contre, un truc de cette taille en métal, ça ne fait pas fort égyptien. L'histoire a beau ne pas se dérouler sur Terre, je prends note: je m'en tiendrai à un gros-poing en pierre.

I haven't been running any twitter poll this time, but I still managed to gather interesting comments. Generally, the bottom puncher are perceived superior to the recycled school-zone structures flipped and recolorized. Of course, I should have X-flipped them for coherent lightning with the rest of the scene.
Among others, Joke@bilouCorp pointed out that Egyptians did not have the technology to produce large metallic structures. That's both quite irrelevant (since Bilou's pyramid is nowhere near the Nile and not even on our planet) and super-important, because I want people to feel like if they were in an Egyptian pyramid while at the same time feel like it is something else. If I come up with hammers looking like they're from the Misty Mountains or from Vinea, they won't "buy" it. Similarly, although I won't use the Egyptian hieroglyphs, I'll use glyph-like writings anyway and not neon ads.

Et je ne résiste pas à l'envie d'en profiter pour vous présenter le projet Kyle & Lucy de Cellar Chateau. Un jeu bien dans la veine de Sonic 2, avec ses sols qui font des crolles, ses boucles et ses tremplins. Je trouve très bien trouvé l'introduction des rollers aux pieds des héros félins (déclenchés dès que la vitesse est suffisante), ce qui permet de garder une animation lisible tout en ayant une vitesse de déplacement digne de Sonic.
On est ici dans une "zone de la musique" qui n'a pas à rougir devant celle de Rayman ou de Zool. Chapeau. Il faut dire que le talentueux Lapper (qui nous présente les avancées de son projet "Sonic Studio" sur sa chaîne Youtube) prête main forte au niveau du graphisme.

Maybe you had never heard of Kyle and Lucy before. It's another game project I'm following on twitter, with Sonic-inspired gameplay and surrealistic aesthetics. The music zone is clearly one of my favourite. Everything looks so readable there. Note how the designer has given Kyle retractable rollerblades so he could zoom through the level without having to move his legs at ludicrous speed!