Sunday, December 17, 2023

tapis roulant!

Nous y voilà enfin! Après l'eau-qui-pousse, je peux vous présenter le sol-qui-pousse. Le point délicat, vous vous en doutez, ça aura été de mélanger ça avec des sols pentus. Ce à quoi je ne m'attendais pas franchement, par contre, c'est que être poussé pendant qu'on est immobile sur le sol se révèle plus compliqué à gérer qu'être poussé pendant qu'on avance.

The natural step after water-that-push-Bilou was ground-that-push-Bilou. It started quite nicely and it is finally working, but to reach that nice behaviour, there has been significant ups and downs, and especially to get it working on sloped ground. But hey, sloped conveyor ground was my trick to have one-way halls without getting too mechanical.

C'est que pendant qu'on avance, on appelle régulièrement la fonction do_slopes, voyez-vous. Et même si le sol annonce "je te pousse de deux pixels sur la gauche" alors qu'on est sur une pente, on finira bien 2 pixel à gauche et 1 pixel plus bas si nécessaire. Mais rien de ce genre dans l'état "immobile sur le sol". Et notre fonction do_slopes est prévue pour aller directement corriger la vitesse et les déplacement retardés du personnage, or l'idée du "sol qui pousse", c'est justement de manipuler la position dans un premier temps et de laisser le code qui traite la vitesse tranquille. Sans ça, sur un tapis roulant trop rapide, vous verrez Bilou se retourner pour marcher tout seul vers la gauche plutôt que de le voir s'échiner à avancer vers la droite tout en reculant malgré tout vers la gauche. Pas terrible.

Dans Rayman, j'avais pu voir qu'on avait deux types de pentes: des normales et des glissantes. Chaque angle et chaque offset est dédoublé avec un second type pour gérer les deux types de physiques. J'avoue que je souhaite plus de souplesse pour Bilou. Pas tant que j'ambitionne de faire un jeu plus complexe que Michel Ancel, mais surtout parce que je n'ai pas l'occasion de planifier l'ensemble du jeu. Je suis incapable actuellement de garantir qu'il n'y aura jamais plus de 2 types de sol dans un niveau ni 2 types de pentes. Le projet était donc d'utiliser des emplacements séparés pour encoder la pente et les propriétés du sol. Et quand je me suis mis à coder, c'était encore plus simple que prévu: quelque soit la position de Bilou sur une pente, il est toujours à l'intérieur du tile "pentu". Et donc pour trouver le tile avec le type du sol, il suffit toujours de regarder 8 pixels plus bas. Enfin ... presque toujours.

And that was the final test for my "neat idea" to "simplify" the level editor: use separate tiles to indicate the slope (if any) and the ground properties. Ground properties are always on the 'plain' part of the ground and the slope types sit on top of it. A new getGroundType function can probe through that slope layer to find the actual ground and return its numerical type. Then, each controller use that to index to retrieve relevant parameters, such as push vector, friction, or whatever needed. It mostly worked except on one spot: the precise location where Bilou's hotspot has just been shifted out of the lowest 'sloped' tile of a slopes stripe. It is now mid-air, with one 'slope' tile below it and the ground properties one more below. Then Bilou stops because it is no longer pushed but doesn't fall either. And if I try to hack that around, I end up with Bilou moved horizontally instead of following the slope because there's no slope to follow.

Comme toujours avec les pentes, les problèmes commencent quand le sol n'est plus dans le prolongement horizontal de celui utilisé une frame plus tôt. On se retrouve dans ce cas-là soit avec Bilou qui s'arrête au milieu de la pente, soit continuant à se faire pousser, mais à l'horizontale

Yet, when you walked on the sloped ground rather than letting yourself pushed by flowing sands, you wouldn't get any issues. The trick is that walking state already has a call to the do_slope function that keeps Bilou in contact with sloped ground despites of motion. The extra shift happened prior that call, so it would still re-align when Bilou's own velocity is applied. But there was no such call in "idle, standing" state so far. And the do_slopes function wasn't meant to affect anything but character's speed, while it should now sometimes affect temporary variables used to immediately apply a coordinates update.

And just in case that seemed too easy, a typo in the first coding sprint made me change accumulated step instead of actual speed, ruining the whole thing with Bilou digging into the ground. Then a bug introduced in the level editor broke some part of the level without me realizing it and I started suspecting wrong properties for the ground here or there.

But there we are. It's working, even though it cost me hopping back in time with Mercurial and re-doing the sprint one dash at a time, checking, committing, re-importing maps and the like. And about one week later, I finally shot a decent .gif of the behaviour so I could post it and write this stuff. It's been planned for so long. It has been through so many preliminary work and so that I'm gonna call it a milestone.

Bref, inspector widget, ddd, j'ai pu sortir toute la panoplie. Presque (pas les unit-tests, cette fois). Mais l'éditeur de niveau m'aura bien cassé le rythme.

(wow. Le soir est tombé, j'ai encore une machine à faire tourner et je n'aurai pas fait plus de homebrew de cet aprèm' libre que de vous raconter tout ça :-P)


No comments: