Wednesday, April 01, 2020

The Dreamland Map

I'm reaching the last pages of my plan-your-things notebook. It helped a lot completing both real-world and hobby projects. I've got more books available to take over, but I also need to make sure I won't miss contents of the 2019 book when I'll be hanging around with the 2020 book. That's why the 'todo maps' are on flying sheets rather than on proper pages.

Maybe there are things I should blog for remembering. Clearly there are things I should doxygen...

There are things I still need to blog in there. Notes I've taken about SNES hardware, for instance, and similar hardware features from the NDS which I haven't used yet.

And then, there are game analysis things, which are totally unrelated to tools & engine development, but which I'd like to bring into the 'design class'. Those, hopefully, will not be missing if I don't have them around in the new book.

You see, having the dsgametools code around in a e-boox is nice, but I need some additional place to "think out loud", and with my eyes not liking using screen more than 10 hours/day, it cannot only be this blog anymore. That's what the notebooks are for ;)


Friday, March 27, 2020

covid

Hello there. If you're not an alien archeologist hunting for what happened to humanity over what they called the 21st century, chances are that this post can be skipped. If you are, and if all but the archive of this blog has been damaged beyond recognition, here is what you need to know.

We used to be fighting against microscopic entities we call 'virus' that lack the proper material to 'live', but can self-replicate if they break through the defense of larger CHON entities like use, humans. Most of those virus either don't understand how to break through our defense (or use our biological factories) or are well-known adversaries against which our bodies and medical staff have well-established weaponry. But from time to time, one such virus usually targetting another mammal species encounters a random mutation that suddenly makes us a potential target. It had happened over the '80s with AIDS, and it happened again this year with COVID19.

I've spent much more time than usual checking the broadcast news for updates: this virus can propagate from human to human through dropplets we expel while breathing, but it may also survive for up to one work period (well call that 8 hours) on solid surfaces like those we use to manipulate daily objects. We have no cure for it so far (almost 3 months elapsed since it shown up) but we have supplies that may sustain live to give our immunity system time to find a cure of its own and get rid of the virus before we die, exhausted. But we have limited supply for them.

Of course, you could believe that we had reached a level of civilization where we could easily focus our efforts on making more of such devices .. enough to reduce the losses to a marginal amount. I truly hope you'll be right in a few weeks. But so far, this crisis is shedding raw light on all the flaws and failures of our civilisation. All those stupid tussles to remain in position of economical supremacy. All those fake news and who-gets-most-buzz. Some have concentrated industrial facilities in a fairly small area of the planet to maximize their profits, taking advantage of weaker social rules they have there, and we have failed to force to keep significant industrial activity near us.

Meanwhile, our best hope is to slow down the exponential progression of the virus by avoiding to meet too many other humans. We call that a quarantine when it applies to a ship that must wait before releasing passengers, except this time, we're all aboard the ship and we must stay confined within our houses. Some manage to work for their employer under those conditions (including me), others can't. In some country, this puts them in serious trouble. In others (including mine), they can get money from collaborative efforts managed by the government.

We used to take care of our kids for about 1/3rd of a daily light/shadow cycle of our planet (we call "day"), let them sleep for another 3rd and have them taught shared knowledge by professionals in so-called "schools" for the 3rd third. We know have them 24/7. It has been said they wouldn't receive more knowledge to learn meanwhile, but it isn't quite true. We need to supervise that in addition to our daily work. And for most of us, we haven't got robotic assistance to house management. At best some of the tasks are mechanized. It's manageable, but sufficienly disturbing so that I have only made a single ammendment to my hobby-project over the last month.

I know I used to make a special release on March 24th for my birthday. I'm afraid I couldn't arrange such a thing this time.

I believe we can sort it out, I don't know whether we'll collectively be smart enough to make it be the very last time we're shocked by such a little thing.

Friday, March 20, 2020

Coder pour Onyx Boox

Bon, j'avoue que autant installer un devkit android sur mon NUC était un objectif quasi-prioritaire en 2019, autant il ne s'est quasiment rien passé de ce côté-là, en fin de compte. Au mieux j'ai refait le week-end dernier un tour des repositories open-source et Androïd-Demo ... et je trouve assez curieux que l'un des deux soit entièrement avec du code C++ pour Qt. Mais tournerait-il vraiment sur le boox ? Les derniers commits sont de Nokia et on plusieurs années (je dirais qu'ils datent de 2012 ou 2013...) est-ce du code qui était prévu pour un ancien modèle (pré-android) ? Fort possible puisque les boox Androïd arrivent fin 2013.

Moi j'ai un modèle N96, qui est une évolution du M96. Le package "booxsdk" propose des versions de gcc pour les modèles M90, M91 et M92, qui sont tous pré-androïd selon wikipédia.

On ne peut pas vraiment dire qu'Internet croule sous les projets et pourtant, il y aurait moyen de faire tellement mieux qu'un browser classique ou qu'une adaptation poussive de Tomboy ou de l'application Wordpress ... Je devrais peut-être essayer de commencer par termux ? Mais moi, ce que j'aimerais c'est plutôt un stylux :-/

C'est là que j'aurais bien aimé avoir sous la main un pote qui fait de temps en temps du développement Androïd pour me guider un peu dans ce nouveau monde.

Friday, March 13, 2020

Dans le code de Celeste ...

Je m'étais fait une conversion epub du code de Celeste, peu après avoir reçu mon boox, pour étudier un peu tout ça pendant que *deline était à son cours de sport. Il faut bien dire que ce n'était pas simple à suivre, entre les hyper-jump et compagnie. Mais ici, un des développeurs vient de tweeter une série de mini-vidéos pour montrer toutes les ruses de gameplay qui ont été mises en place pour que le gameplay soit satisfaisant.

Oh, j'ai une partie en cours sur Switch, aussi ... mais M. Oshiro en furie me mène la vie dure.

  • De 1 à 4: on a des techniques équivalentes dans Bilou
  • 5 - contourner les coins au lieu de se cogner la tête dessus. Pas encore.
  • 6 - s'aligner sur une plate-forme à sens unique quand on passe à travers
  • De 7 à 10: différentes manières d'étendre les zones de collisions avec les murs / plate-formes pour compenser des pressions de touches un peu tardives de la part du joueur (un peu comme le vile-coyote-time, mais dans d'autres circonstances - notamment pendant un wall-jump).
edit: ça y est! j'ai passé M. Oshiro!

Tiens, pour la comparaison, on atteint quand-même les 5000 lignes de code pour Player.cs (qui pourrait contenir plus que le code de Madeline, hein)

En stand-by ?

L'élocution de *deline sur Hergé m'aura déjà bien occupé sur ce début de mois de mars. Ce coup-ci, s'il n'y a pas grand-chose de bloggé, c'est parce que j'étais plongé dans tout autre chose la plupart du temps.

Et avec la quarantaine nationale qui vient d'être décrétée, ça ne risque pas de changer beaucoup dans les prochains jours >_<

Oh, au fait, vous saviez que les albums pré-casterman avaient été imprimés avec un procédé cliché/stéréotype qui ressemble étrangement au système utilisé pour la gravure des piste de cuivre sur un PCB ?

Friday, March 06, 2020

Détection automatique des pentes ?

Bon, j'ai réglé les problèmes de corruption de niveau dans la nouvelle mouture de l'éditeur (grâce à FakeMetaWindow) et on va pouvoir passer à la suite. Par exemple commencer à ajuster les "méta-boutons" pour qu'ils permettent d'utiliser directement les nouveaux types de tiles.

Parmi tous ceux-là, il y aura les nouveaux types de pentes, et si on doit commencer à jongler avec 64 types à la main, on ne risque pas de tenter beaucoup de fantaisie là-dedans. Du coup, je me disais: comme j'envisage déjà de juste copier-coller des tiles dans une 'sprite page' spéciale pour définir les types de pentes, est-ce qu'on essaierait pas de faire un système qui reconnaisse automatiquement la pente la plus proche quand on passe le stylet sur un tile ?

Une répétition pour le scribble widget, en somme.

edit: si l'idée est sympa pour un peu cogiter le soir, en revanche il est clair qu'un système de ce type ne pourra pas atteindre 100% d'exactitude, et qu'il me faudra de toutes façon un widget pour corriger les p'tits défauts de l'auto-slopeur... donc l'approche pragmatique sera de commencer par ce widget et d'ajouter l'auto-slopeur uniquement par après.

Sunday, March 01, 2020

Top 100 Video Game Music

Last December, my brother finally released his top-100 chart of video game music. It took me a few days to understand his process: although he names one track per game he lists, we shouldn't consider it is a video game tracks chart. He's really trying to compare full OSTs to one another.

That was a lot of things to check at once, especially since there are games in this chart I had never played, and was aware of their music only through overclocked remixes. So I started a twitter thread, commenting one track a day, bottom up. And there are many points where we apparently disagree. (of course, the fact that we start with the soundtrack for Fury of the Furries out of the top 100 didn't help).


En décembre dernier, mon frangin nous a sorti son top-100 des musiques de jeu vidéo. Projet ambitieux et longtemps maturé puisqu'il ne s'agit d'un classement piste-par-piste, mais bien jeu par jeu. Comprenez par là que quand il met "Introduction de Dune" en 30ème position, c'est tout l'OST de Dune qui est repris: Chani's Eyes, Morning, etc. mais qu'on nous propose un 'aperçu' de l'OST à travers la musique d'introduction. Et moi, pour me rendre compte si j'étais ou non d'accord avec son tri, j'ai repris une musique par jour sur twitter. Du bas vers le sommet. Demain, on attaque le top 10.

Mais plus j'avançais, plus je me rendais compte que j'avais un problème avec la façon de faire "intuitive" de mon frère. D'une certaine façon, un top-100, c'est pour moi le résultat d'un tri à l'aide d'une fonction d'évaluation entre les objets. Si Super Mario World se retrouve devant new Super Mario Bros, il doit y avoir moyen de dire pourquoi. Un certain nombre de "qualités" de la musique doivent pouvoir être dégagées (qualité des instruments utilisés, richesse des accompagnements, "personnalité"  de la mélodie) et une musique ne pourra être proclamée meilleure qu'une autre que si elle se montre meilleure sur un nombre suffisant de ces qualités. Ensuite, un jeu ne pourra être proclamé meilleur qu'un autre que si un nombre suffisant de ses musiques sont jugée meilleures que les musiques de l'autre.

Au final, ça nous permettrait de test un challenger (disons Céleste ?) par rapport à la collection actuelle avec un nombre raisonnable de "matchs" entre les jeux.

As I progressed towards #50, one thing turned obvious: my brother and I do not approach making charts the same way. Not to say that his way is bad. And neither of us do that through statistics. I figured out I see charts as the result of a sorting process. Being a "computer scientist", I know that sorting implies we have a comparison function that is capable of telling which of two items is the greatest. If items have multiple dimensions, it relies on simpler functions applied to their constitutents (e.g. comparing their catchiness and the quality of their instruments separatedly), then combining those things together - either through priorities or through weights - to get a final comparison result.

I also know that if I have a pre-sorted list and a new challenger, I should be able to find its rank with a fairly small amount of comparisons (log2 N, to be precise) to existing items (that number would be about 7 per challenger in a top-100). That in turn implies that such comparison should work for items we pretend to be sorted.


Les jeux retenus par mon frère sont assez variés, aussi bien en styles (RPG, shoot'em'up, sandbox, plate-forme, horror shooter, point-n-click) qu'en plate-formes (on va du C64 à la Switch). Le premier problème du coup, c'est qu'au fil des années, la taille des OSTs n'a cessé de croître. Comment comparer Warhawk et son excellent thème (mais unique piste) avec les 10 pistes de Lotus II ou les 52 pistes de Skyrim ? C'est d'autant plus délicat que dans les jeux modernes, on a souvent beaucoup de remplissage dans la bande son. Des pistes avec un solo instrumental pour présenter un NPC ou une ambiance de fond pour les landes perdues qui auraient vite fait de 'plomber' le jeu.

Pour pouvoir faire un match entre 2 jeux sur la durée d'une pause café au plus, je pense que chaque jeu devrait être représenté par un petit nombre de "championnes" disons 3 pistes (5 au grand maximum et on évitera les nombres pairs). L'idée est que si un jeu A parvient à avoir une meilleure piste pour chacune des championnes du jeu B, alors le jeu A est déclaré vaincqueur, et on accepte par principe le fait qu'aucune autre piste du jeu B n'aurait pu le sauver -- sinon, elle aurait dû faire partie des championnes. On peut très bien imaginer qu'une des championnes de A explose toutes les championnes de B ou que chacune des championnes de B a trouvé une championne de A qui la déclasse spécifiquement.

Se ramener à une poignée de musiques plutôt qu'à une seule évite d'avoir ratatiné tous les shoot-em-up avec un titre péchu (la jungle de DK) pour se faire étaler par le premier JRPG venu et son thème-requiem-du-NPC-perdu si poignant. Un jeu à la BO variée (à mon avis c'est un plus) pourrait donc avoir plus de chance de grimper vers les sommets qu'un titre très mono-thématique.

The first thing that doesn't quite work with my brother's top-100 is that we do not know what to compare. He names only one track per game, but considers many other should be taken into account. He has games with only one track (let's say warhawk), some with a few dozen (say a regular SNES platformer), and some with so many hours of soundtrack that you cannot decently hear them all (yes, you JRPG). Moreover, the longest the soundtrack, the more likely you are to see it filled with uninteresting 'NPC solo themes' or ambiant tracks of 10 minutes that hardly feature 30 seconds of true "music" (yes, you, Rayman II).

I would suggest instead that for every game, we pick at most 3 tunes that will be the 'champion' for that game. If none of those tunes manage to beat the tunes of a challenger game, we could pretty much assume that none of the OST would be on par. The selection should be made carefully, but I believe it can accomodate for more sophisticated stories with different kind of emotions, where we need a beautiful-and-quite tune to face JRPGs, a dynamic tune to face Megaman and an epic tune to face hack-and-slash, if any. In Link to the past, that trio would likely be (Overworld, Darkworld, fairy fountain). When comparing two games, we would make at most 3 matches, track-vs-track. The game that won most matches is claimed better than the game who lost them.


La deuxième règle serait de se limiter aux musiques de jeu vidéo, pas à l'OST tout entière. On ne prendrait donc pas en compte les effets sonores ou le doublage des personnages quand on compare deux titres. Je pense aussi qu'on devrait mettre de côté les ambiances sonores non-musicales. Il nous faut quelque-chose à base de notes qui peuvent être jouées sur des instruments. Sans aller jusqu'à dire qu'on devrait faire comme si les sons de vents et de gouttes qui tombent dans les grottes doivent être filtrées avant le match, mais quelque chose qui est constitué presqu'exclusivement de sifflement de vent, de craquements, de chuchotements avec à l'occasion quelques notes de violon dissonnantes qui durent si longtemps qu'on arriverait pas à les chanter ... bin, laissons ça de côté. Que le jeu se choisisse des championnes qui sont de vraies musiques, et s'il en est incapable, qu'il reste en-dehors du concours.

Troisièment, la musique doit faire partie du jeu. Peu importe qu'elle soit sur l'écran titre, dans un niveau, un menu ou les crédits de fin, mais elle ne peut pas être sur un CD vendu à côté du jeu avec des versions remasterisées ou une vidéo de bande-annonce. S'il y a eu plusieurs éditions du jeu, on devrait choisir une seule édition qui semble la meilleure pour y pêcher les championnes, et toutes les autres éditions sont hors-concours.

Je pense aussi qu'on devrait déclarer hors-concours toutes les musiques qui ont été reprises dans un jeu mais qui viennent en réalité d'ailleurs. Que ce soit un titre de JMJ dans loco 64, un groupe pop dans Xenon Megablast, JS Bach revisité dans Gyruss ou la bande son du film Star Wars: tout ça n'a rien à faire dans le top 100 des musiques de jeu: ils ont déjà leur propre championnat. Que les jeux concernés se choisissent d'autres championnes ou qu'ils se taisent à jamais.

Second thing, I'd like it to be a video game music chart, not a sound track chart. That means the quality of the sound effects, the voice acting is not taken into account when comparing two games. That also means that ambient moods in the OST are automatically dismissed. It has to be music, that is, instruments playing notes. Some ambiant, non-instrument sounds are accepted, but they cannot be the main part of the track. That mean it would be very tricky to find three "tracks" for games such as HoB, despite it has a very long soundtrack. It means if you want to convey fear of anxiety, you have to do it through notes, not through whispers, cracks and windblows with occasional dissonant violin notes that last for so long that you couldn't even sing a note that long.

Third thing, although it's the most obvious, tunes that are considered must be part of the game. They may be title songs, in-game music, staff roll, soundtracks for cinematics, but they cannot be tracks on a promotional audio CD, remasters or clips from video teasers. At least, my brother and I seem to agree on that. If there have been re-editions of the game (or multiple editions with different soundtracks), we are free to pick either edition we believe the best (is it SMB or SMB-as-in-all-stars, or SMB-tune-as-in-melee), but it can only enter once. And we should use the same edition for all the matches the game does. It should be original composition, too. Covers of Jean-Michel Jarre in Loco 64, of Sky playing J.S. Bach in Gyruss and the pop band sampled for Xenon Megablast are ruled out. If a game features a mix of original composition and imports from non-video-games (e.g. a Star Wars game), only original compositions may be champions for the game.


Enfin, je crois que l'on doit faire abstraction de tout ce qui n'est pas musique et expérience d'entendre la musique pendant le jeu. Que le jeu ait un gameplay pourri et qu'on ne l'ait utilisé que comme un juke box ? pas d'importance. Qui a contribué à la musique ? pas d'importance. Il a fait un bide au niveau des ventes pour Dieu-sait-quelles-raisons? aucune espèce d'importance. Il n'a jamais été disponible qu'en téléchargment gratuit et jamais dans un catalogue commercial ? pas d'importance. Par contre, le jeu doit être un vrai jeu. Pas de démo jouable qui n'a pas d'objectif. Pas de vaporware dont la bande son existe mais le jeu n'a jamais été disponible.

Finally, we should abstract from everything that is not the music, and the experience of enjoying the music while playing the game. A game with terrible gameplay but great music should be able to enter the top 100, even if we say "yeah, I never played further than level 1 in XXX, but I loved to launch the game, just to listen to musics in the secret juke box screen". Who did them ? Was the game a commercial success or an obscure title released while official support for the console had been dropped ? Was it a free-to-download game that never received a commercial release ? That doesn't matter. That must not matter. But it may not be a cancelled game that nobody could complete because it isn't finished. It may not be a demo. (Sorry, basket island: that means you cannot enter).

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

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.

    Friday, January 31, 2020

    looser throw specifier

    J'utilisais assez volontiers les descriptions de "quelles exceptions peuvent être produites par cette fonction" en Java. Nettement moins en C++. J'ai en tête que le compilateur n'était pas si fiable que ça sur ce point et que le jeu n'en vaut donc pas la chandelle. Au point qu'avec les derniers GCC, j'ai peut-être bien dû supprimer des throw(iScriptException) pour que le code de libgeds continue de fonctionner.

    Mais il y a au moins un cas pour lequel ça semble fonctionner et qui mérite qu'on y réfléchisse: les destructeurs (et plus particulièrement les destructeurs d'exception).

    
    class InvalidArgs : public LibraryException {
    public:
        InvalidArgs(const std::string &detail) : 
            LibraryException(INVALID_ARG_SUBCODE, INVALID_ARG_NONSENSE, detail)
        {}
        virtual ~InvalidArgs() throw() {}
       // LibraryException has defined its own destructor unable to throw any exception.
       // we can only make this stricter when sub-classing it.
    }; 
    
    
    Update: Il y a une FAQ sur la norme ISO C++, qui traite justement de la question des exceptions dans les constructeurs et les destructeurs. On y explique que tout les mécanismes de la bibliothèque standard partent du principe qu'un destructeur ne peut pas lancer d'exception. Entre autres parce qu'en réaction à une exception, votre libc++ va identifier les destructeurs de tous les objets alloués sur la pile jusqu'au code du catch et les invoquer, mais libc++ ne sait généralement pas faire remonter deux exceptions à la fois.

    Donc il ne faut pas laisser une exception sortir d'un destructeur, et ajouter un throw() à la déclaration de son destructeur est un bon moyen que le compilateur nous y force. En particulier si on définit ça au sommet d'une hiérarchie de classes, auquel cas le compilo va aussi nous avertir si on essaye d'assouplir le contrat pour faire passer plus d'exception hors d'une méthode-fille que ne le permettait la méthode-parent.

    (merci à hg grep pour avoir retrouvé les anciennes lignes où j'avais des throw(xxx). C'est un bon complément mercurial à hg annotate quand on cherche quelque-chose qui a disparu plutôt que le moment où quelque-chose a été introduit.)

    Thursday, January 30, 2020

    Yodlei

    eh, on pourrait facilement faire en sorte que les rocher ressemblent à un empilement de becs et de serres ^_^ (bon pas forcément tous les rochers)
    C'est le deuxième jeu présenté pour cette édition de l'Ultime Décathlon: Mickey Magical Quest premier du nom. Un jeu pour lequel j'ai un coup de coeur depuis qu'il est sorti, même si j'avoue avoir gardé un souvenir mitigé de ma partie sur Game Boy Advance il y a quelques années.

    Mais oui, si je n'envisage pas un Bilou's Adventure sans un grappin, c'est entre-autres à cause de ce jeu et de son niveau montagnard. Et comme justement je suis occupé à cogiter à un environnement de la montagne pour le projet "Bilou's Dreamland", je me refais deux ou trois fois le niveau dans Youtube, histoire de regarder un peu si on peu trouver des idées ré-exploitables. (Sinon, on ira piocher dans Celeste et dans le Temple Suspendu Dans les Airs des Voyages d'Endymion ;)

    Mickey Magical Quest comes back: it will be featured at the Ultimate Decathlon, a French speedrunning event I'm following with my kids. MMQ is one of my significant games, although I have fantasied playing it much more than I've actually played it, and its mountain level is one of the core reasons I'd like to have a hook-thing in Bilou's adventure too (other reasons being Fury of the Furries and WORMS's ninja rope).

    Since I'm also considering using 'mountain peaks' as the final level for "Bilou's Dreamland", I've checking the speedruns and longplays for re-usable design elements, but there was actually little to pick apart for "mountains are birds' realm. We'll need some bird-like creatures, not just palette-swapped berrybats".


    Joli aussi, les pics qui dépassent de la mer de nuages.
    • "Pour la montagne, penser à avoir des ponts (genre Sonic Bridge Zone sur SMS), des cavernes avec des structures métalliques (morceaux du vaisseau échoué) dedans. Si les structures métalliques sont mauves, c'est très bien aussi."
    • "Les ponts sont là à cause d'autochtones qui essaient d'utiliser le vaisseau échoué comme source de matières premières, évidemment."
    • "On pourrait imaginer une évolution des berrybats qui se sont adaptées à la montagne. Et si les 'chavrous' peuvent utiliser leur cornes pour se déplacer rapidement le long des cordes / ponts, c'est tout bon.
    • 'faudra trouver quelque-chose qui fasse piaf. Les gros piafs, c'est parfaitement à sa place dans la montagne, et ça remplit bien l'espace de jeu dégagé." Si on ne veut pas que les piafs fassent trop "bah, c'est des oiseaux", on peut leur donner un look de ptérodactyle en costume de Batman.
    • Et ce serait marrant que les 'tentacules' de la pyramide soient en fait les marmotes de la montagne qui ont perdu leur fourrure en s'adaptant au désert.
    Mouais. Pas grand-chose en fait. Entre les 'petits-oeufs-qui-vous-attaquent' et les guèpes, l'ennemi le plus original au final, c'est un courant d'air :-/

      There's no places.sqlite home...

      Evidemment, qui dit nouvelle machine dit "ach bin non, on va fous faire une noufelle profil pour fotre firefox!" (prononcez 'fawerfogz'). J'avais repompé le répertoire 'profiles' pour le mettre sur un linux bidon histoire d'aller à la pêche aux mots de passe sauvegardés, mais on va pas pousser si loin pour retrouver les fichiers dans l'historique des téléchargements histoire de donner des infos pertinentes pour 388156*.mpeg, si ?

      Eh bien, ça se passe dans places.sqlite. Avec deux ou trois autres choses, d'ailleurs.

      Tuesday, January 28, 2020

      Meka-Bilou au rapport ...

      J.L.N s'est beaucoup intéressé à ce que je faisais, ce.tte.s dernière.s semaine.s sur mon ordinateur. Il y avait régulièrement une espèce de mini-niveau (en ASCII art) dans un coin de mon écran qui accompagne les rapports d'erreur du système de test des terrains pentus. Je suppose que ça attirait son attention.

      Difficile d'expliquer le principe du unit-testing à un louloup de 7 ans, mais il y avait aussi mon carnet avec le même "niveau" et un bilou-mécanique prêt à le traverser. "Oh oui, c'est le tic-tac-Bilou de parrain! Tu mettras aussi celui avec un réacteur?"

      Il ne croyait pas si bien dire. Après avoir reporté des paquets de coordonnées sur un schéma du 'niveau' et analysé dans ddd à quel étapes de la fonction "doslopes()" elles correspondaient, j'ai déjà pu mettre en évidence (et corriger) quelques couacs. Le fait par exemple que doslopes n'indiquaient "on est sur une pente" que si le dernier tile visité est pentu. Malheureusement, ça signifiait un glitch vertical au moment de passer sur le 'sol plat' à la fin d'une pente à plus grande vitesse parce que le code du GobController qui fait appel à doslopes pensait devoir "éviter un sursaut brusque"...

      Mais le plus curieux m'attendait encore. Lancé à presque 8 pixels / frame voilà Meka-Bilou arrivé en haut de la pente, et par un malencontreux concours de circonstance (plus un p'tit bug), il ne détecte pas qu'il devrait redescendre. Le code du GobController, lui, constate bien qu'il n'y a plus moyen de se déplacer normalement sur le sol et génère un FAIL (qui doit normalement provoquer un changement d'état dans le comportement du personnage). Sauf que, désolé, les amis: meka-Bilou n'a pas de machine d'état, et le contrôleur n'a pas annulé le mouvement (il était possible: on ne rentrait pas dans un mur). Du coup, rien n'empêche le même mouvement d'avoir lieu au(x) cycle(s) suivant(s). Faisant fi de ses "roulettes", Meka-Bilou s'est mis à traverser le ciel à toute allure jusqu'à ce qu'il soit stoppé net par un 't'as rien à faire là' qui met fin au test.

      Un peu de code en plus, et je peux à présent capturer les transitions 'on fail' dans mes cas de tests et tout arrêter quand ça se produit. Et ça me fait penser que, quand j'aurai réussi à importer le comportement des applemen et autre dumbladors dans mon environnement de tests, ça pourrait être intéressant de marquer certaines portions de tests plus sophistiqués comme "interdiction de tomber ici", "interdiction d'atterrir là" ...

      Monday, January 20, 2020

      test de pente en cours

      Voilà, j'ai mis en route quelques modifications pour appliquer les idées du nouveau système de description du niveau avec comme point de départ un p'tit morceau de code qui crèe un 'niveau de référence' et place un personnage simple dessus qui devra avancer d'un bout à l'autre sans ce faire stopper.

      Tout ça se passe dans l'environnement 'unit-testing' plutôt que sur la console elle-même et donc est testé contre les fuites de mémoire. Mais au moment d'essayer de comprendre pourquoi il y a une fuite, je me rends compte que scan-mem.pl (qui traduit les adresses stockées dans un fichier trace%d.log en nom de fichier/fonction/numéro de ligne) ne marche plus.

      La faute au "nouveau" système de brouillage d'espace mémoire qui ne charge plus les fichiers .elf des programmes Linux à des adresses fixes (définies dans le programme) mais qui va utiliser la faculté des fichiers ELF à se reloger en mémoire pour que chaque exécution du programme utilise des adresses légèrement différentes. L'idée est de faire en sorte qu'un hacker qui parviendrait à provoquer un crash dans votre machine avec des données à lui (au hasard, une police .ttf véreuse ;) ne puisse pas pour autant appeler la fonction popen() ou system() avec des données à lui ... parce qu'il faudrait d'abord qu'il devine où elle se trouve dans ce processus-ci.

      Ça ne fait pas mes affaires, mais c'est assez simple à régler: une 'simple' ligne supplémentaire dans le fichier log pour indiquer l'emplacement actuel d'une fonction précise et un appel à nm fichier_elf | grep nom_de_fonction dans le script de décodage, et je peux recalculer le décalage utilisé, le soustraire aux valeurs trouvées dans le fichier log et conquérir le monde (mouah hah hah ...)

      Euh. Enfin. On va déjà essayer de conquérir le "leakage: 0%", ce sera pas si mal.

      Où était le memory leak, alors?

      Le bloc incriminé, c'est une palette d'actions spéciales qui est allouée dans le parseur de scripts. Je n'utilise encore rien de ce genre pour mes petits tests, mais ils sont alloués automatiquement quand on crée le parseur. Normalement, ils devraient ensuite être délégués à GameScript quand le parseur est détruit (et qu'on est prêt à jouer au niveau) .. sauf que dans ce cas-ci c'est le destructeur de GameScript qui détruit le ScriptParser, mais il le fait après avoir regardé aux palettes d'actions ... et donc cette délégation tombe trop tard. Facile à corriger.

      Sunday, January 12, 2020

      un p'tit pas de plus pour LEDS

       Bien. J'ai donc un éditeur de niveau capable de faire l'affichage des niveaux même quand j'utilise le "nouveau" format. Y compris pour les blocs spéciaux. J'ai encore un peu de travail à faire dessus (notamment faire en sorte que les boutons à droite de l'éditeur ne s'incrustent pas dans le niveau chaque fois qu'on les invoque), mais c'est plutôt bien parti.

      Avec tout ça, et l'introduction de nouveaux types de pente, je me dis qu'il deviendra bien utile de pouvoir faire des cas de tests sur des micros-niveaux, avec un système capable de détecter qu'on arrive bien à passer les "obstacles" quelques soient les variations de conditions initiales (légèrement plus à l'ouest, vitesse qui n'est pas un multiple entier de pixels, etc.) sans pour autant entrer en contact avec les blocs supposés en dehors du trajet.

      If I want to be effective with introducing more complexity in the sloped-ground engine code, I think I'll have to add some more unit-testing. I've learnt the hard way that sub-pixel initial position, interaction with step-motion and animation quirks can lead to broken slopes code, and that debugging that takes lots of time because it needs parts in-engine breakpoints and parts in-debugger breakpoints.

      A micro-level with a few simple slope scenarios, easy control on the initial state that can be automated should help a lot. And help is welcome. Plus, it makes support for those slopes independent from Level editor updates, which is welcome as well.


      Si ça peut sembler une perte de temps, vu que je n'ai encore aucun moyen d'ajouter des nouveaux types de pentes dans LEDS, ça ne serait peut-être pas si mal. En plus, dans un niveau comme celui de *deline, il est assez inconfortable de vouloir vérifier si la logique du code de gestion des pentes fonctionne bien comme prévu, parce qu'on est en permanence interrompu par ce que les autres "personnages" du jeu font.

      Ça pourrait aussi être l'occasion d'introduire un truc qui me titille depuis un moment: une série alternatives de constructeurs pour les objets principaux du moteur de jeux (déclarateurs de blocs spéciaux, états du comportement des personnages, zones de collisions, etc) qui ne passent pas forcément par une analyse de bloc de texte ... et seraient donc un premier pas vers la possibilité de "compiler" du gobscript en code C++ (ou assembleur 68000 ?)

      tempting to use that as an excuse to introduce an alternate set of constructors that could build objects without necessarily having to rely on text parsing. Like state.Using<GobWalkerController>("") rather than relying on "using walker;" processed by GobState::parse(). That would be handy for GBA or 16-bits ports of the engine, but it isn't easy to achieve with the current codebase, unfortunately. The core reason being that classes for the controllers are encap~insulated into a separate .o that was meant for 'dynamic linking' with the engine 'happily ignoring they even exist', except through a std::map of factories that can be invoked by controller names.