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 :-/

edit: le jeu avait été conçu par une équipe de 16 personnes, dont 4 programmeurs, 4 background artists, 2 consultants, 3 planificateurs

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.