Showing posts with label state machine. Show all posts
Showing posts with label state machine. Show all posts

Sunday, August 02, 2026

Un dernier ver ?

Si vous avez un peu essayé n'importe laquelle de mes démos "green zone" ces 20 dernières années, ça n'a pas pu vous échapper: le petit ver jaune - ce croisement entre un combattant dans Worms Armageddon et un poison slug de Commander Keen - est pénible.


Jusque là, je ne lui avais jamais fait d'animation "éliminé, le petit ver". On l'assomme, il attend, il repart. Il n'avait qu'un rôle minime dans Apple Assault... et le fait qu'on puisse le réassommer à volonté y permettait de reprendre des points. On le supportait.

I've had to apologize about that point to about any beta-tester who tried the Green Zone: the woodworm feel unfair and annoying. You could stomp it, but after a mere second, it would wake up and resume worming. Unlike the Appleman or the the Dumblador, there's no visual clue that the worm is about to wake up, so you're likely to take a hit from something that seemed defeated just a couple of seconds earlier.

Enfin, on le supportait mais de loin, parce que sa manie de repartir à l'attaque sans avertissement, c'est certainement ce qui vous a pompé le plus. Alors le week-end dernier, après avoir déposé les gamins en camp, j'ai allumé la DS et refait 3 petits dessins de ce ver tournoyant dans les airs pour qu'au moins, quand on lui roule dessus avec une pomme, on en soit quitte. ça ajoute de l'interaction et en théorie, ça devrait être rigolo à voir.

The core reason for this are a) the lack of a proper "defeated for real good" animation and b) the fact that worm.cmd was intended to be a tutorial for "the most simple ennemy you could think of". I could justify it for Apple Assault, where the fact it was never really defeated implied you'd always have a way to build up your punch meter. But for Dreamland, it no longer makes sense. Especially when you can throw an apple rolling over them! So I picked up my NDS last week-end and drew a few frames that make it look like it's spinning mad in the air. Yes, exactly as if you had used the bat of Worms Armageddon (or PWorms demo ;).

Il m'a fallu un peu de chipotage pour que le sens de rotation soit cohérent avec celui de la pomme, et j'en ai profité pour lui rajouté un état "détection" qui le remballe directement dans l'état "assommé" s'il sent Bilou à proximité. J'aimerais aussi rajouter une autre fioriture, un état "se fait rouler dessus" qui le maintiendrait au sol jusqu'à ce que la pomme soit passée, et ça, ça va sans doute demander un petit contrôleur supplémentaire...

I'm not quite done with it. Not yet. I feel like the worm starts spinning a bit too early, and I don't really want to fix that with a hard-coded delay but rather by saying "when the apple is done rolling, the worm get caught by the "leftover motion" and *then* starts spinning and falling. Maybe it could be settled with additional hitboxes, and maybe not. If not, I sketched a state machine fix that would help, with a "rolled_over" state, a way to attach the worm to the apple when entering that state and a controller that triggers an event when we're the attached item is far enough... or maybe the regular "track another gob" controller would do the trick if I make the "dead zone" (where it doesn't pull your controlled gob to the left or right) configurable in size (spoiler: it isn'tnow it is). That would give


$STUNNED->$ROLLEDOVER on hit0 [w0 0 >] (128 :0 A);
$STUNNED->$ROLLEDOVER on hit1 [w0 0 <] (128 ~ :0 A);
$ROLLEDOVER->$LKICKED on event0 [v0 0 <] (400 ~:1);
$ROLLEDOVER->$RKICKED on event0 [v0 0 >] (400 ~:1);
$ROLLEDOVER->$RECOVER on done (0 :1)
with
$ROLLEDOVER :anim7 {
    using tracking(@ over 12);
}

And then I'll have something else to fix regarding whether a monster that get hit by a flying-apple-weapon is strong enough to turn back the apple (funky funghi, appleman, caterpillar) or let it fly through (worm, berrybat).  

Un dernier détail qu'il faudra régler: de base, si on touchait le ver avec la pomme avant que la pomme ne se soit mise à rouler, la pomme rebondissait dans la direction opposée. Un reste de quand elle était un taille-crayon, j'imagine. Mais maintenant que j'ai modifié le script de la pomme pour qu'elle passe à travers le ver, elle peut aussi passer à travers les autres pommes ... pas terrible. Il faudrait bien que je me donne une variante de F_WEAPON qui indique "ennemi léger" et une autre "ennemi lourd", ou encoder ça dans encore-une-autre-variable-propre des gobs, ce qui serait sûrement plus facile, mais moins cohérent avec le type de programmation proposée ... un peu comme ajouter un "if" bash dans un Makefile, quoi :P

L'occasion de passer au nouveau système de flags de collisions ?

Saturday, April 11, 2026

Better THROWN->ROLL transitions

 Since the introduction of the appleman ROLL mechanics, there was something I couldn't completely fix: if you managed to throw the appleman straight into a "jump thru" platform, it would stop as if it was a wall, while you'd expect it to roll over the platform or fall through it instead.

I envisioned a number of solution to this problem until I realised there was one quite obvious one: just bounce the appleman upwards a little bit when that happens. It will then be able to advance sufficiently into the platform so that it is then in the normal "thrownroll" transition. If instead it was thrown into a solid wall, the bounce will be visible, but have no lasting effect

Au début, ça ressemblait à un petit détail: au moment de se mettre à rouler, un appleman pouvait se retrouver bloqué bêtement par un sol qui trainerait en l'air. Mais si, vous savez: ces plates-formes qu'on ne peut franchir que de bas en haut, mais qui vous retiennent quand vous allez de haut en bas.

Eh bien pour vous retenir, il faut qu'elle soient solides au moins pendant que vous tombez. Et à ce moment-là, elles ne font pas dans la dentelle: pas question de venir avec un "oui, mais non, mais regarde: en vrai je ne peut pas atterir, là: c'est juste le côté de mon haut qui passe de quelques pixels dans le bord de ton bas ... j'fais qu'passer, quoi!". Nada. Je me retrouve avec une pomme qui était lancée à vive allure et qui s'arrête nette sur un plan d'herbe à travers lequel elle passait sans problème quand vous la portiez sur la tê♪te, la pomme ♫ i' faut pas'l'nier.

And let's be honest: it would have been a nightmare to debug without the recently introduced GobExpression debugger. You can quite easily end up in a situation where you expect some speeds to have been non-null in some condition and realise that, well, no they're null here.

The alternatives I had envisioned were globally more complicated, like holding the speed for some time and then restoring it. More complicated in the sense that they required introducing new states in the behaviour or even new controllers. Here, it's just one extra transition that says "stay in THROWN state if {conditions}, but update velocities as follows"
 

C'était devenu un sujet de cogitation dans mon carnet, et un assez bon exemple de ce qu'on pourrait vouloir faire avec un contrôleur "around" pour contourner les obstacles. Au final, ça se passe de ce genre de complication: il suffit de redonner une petite impulsion verticale, juste assez pour que la pomme monte d'un demi-bloc et puisse atterir sur la plate-forme plutôt que de passer à travers.

Tout ça grâce au nouveau débuggueur d'expressions que vous voyez dans le bas de l'animation, qui représente chaque opcode par un caractère qu'on fait avancer petit-à-petit avec la touche L et qui complémente agréablement ce bon vieil Inspector Widget :P 

Wednesday, April 23, 2025

appleman 2.0.1

A little bit of work on the Appleman last week-end (at last, you could add and I wouldn't blame you). I've got the "shocked" animation revised, added "carried" animations and gathered infos about where these are in green.spr.

I'll still need to see why there is no "bounce" when it is shocked (reason: it's just using stopper and the animation is supposed to do the job) and patch the greent.cmd level script on the SD card of DarkneSs, because it still show the appleman with big purple punches instead of feet. (appleman.cmd must be correct, since level 2 doesn't seem to have any similar issue).

Voilà donc enfin le moment que je prends pour compléter les animations et le comportement de l'Appleman pour le projet Dreamland. J'ai corrigé l'animation "étonné", j'ai ajouté les animations "transporté", tout ça attend dans un petit fichier green.spr le prochain passage du WiFi. Je note au passage que le fichier "greent.cmd" qui décrit le premier niveau des "3 salles" a besoin d'un petit rectificatif pour ne plus me montrer un appleman aux poings mauves ^^".

La prochaine étape sera d'ajouter les animations des "pieds perdus". J'ai aussi retiré la commande de boucle pour l'animation "assommé", mais j'arrive trop tard: c'était bon pour compléter le comportement "Apple Assault" où les applemen se réveillent seuls, mais c'est inutile pour le comportement construit à partir du fichier "blador.cmd". Car oui, le nouvel appleman est plus ou moins la fusion des deux.

So let's add tonight "undead feet" animations, check a "do not loop stunned animation" that must be over 1 year old in my notebook. I've got another notebook where I've written down blador's behaviour ... let's merge that into appleman's script and we'll cleanup the resulting code mess once the home mess is tidied up.

edit: adding the wandering feet turned out extremely annoying. They're one-sprite objects, unlike most of the things I animate with AnimEDS, and it seems the software still handle that in a very different manner: touching an sprite in the side panel adds a frame with that item, rather than changing the current frame. It also breaks relationship between timeline, frame editor and buttons in general. I'll have to get that fixed: it really breaks the user experience...

edit': pick up works, stun works, wandering feet work. Apple/water interaction is a catastrophy, throwing only work from times to times, and there's something odd when you stomp on a stunned apple (blador acted as a platform there, appleman won't). That feels like it should roll instead ... A good thing animation 2.0 freed some frames ;)
 

Saturday, October 12, 2024

Un furblock qui a du ressort

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

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

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

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


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

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

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

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

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

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

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

Monday, May 27, 2024

Compile-Time Regular Expressions

Well, guess what: there's a C++ header/library out there that allows regular expressions compiled at build-time. And I've got state machine parsing code that could use a little performance boost, especially if I envision GBA support rather than NDS for some future release.

#include <ctre.hpp>
#include <optional>

std::optional<std::pair<std::string_view, std::string_view>> 
match(std::string_view sv) noexcept {
    if (auto re = ctre::match<"state([0-9]++) *-> *state([0-9]++) *on (hit|found|event|fail)">(sv)) {
        return std::pair{
            std::string_view(re.get<1>()),
            std::string_view(re.get<2>())
        };
    }
    return std::nullopt;
}

Is what the siscanf(ln, "state%d -> state%d on %[hitfoundeventfail]%n") test for state transitions would look like, for instance. Some things will be cheaper, like testing explicitly for one of the 4 transition types rather than getting any garbage word you could craft with their letters and testing if (strcmp(reason, "event")) afterwards. 

Other things will require more code, like converting re.get<1>() into a digit as a post-processing step, since regexp do solely text matching and extraction, no text-to-number conversions. 

The code generated was quite convincing on x86_64, I'm a bit more suspicious about its ability to improve performance on 32-bit ARM processor, given how it requires 9 instructions to match every single character of the "state" constant string, for instance. If it helps for speed, it might have a significant impact on code size...

It seems to build even for GCC 10.2.0, the latest I installed from devkitpro, but not for the one used to build SchoolRush ...

Thursday, May 25, 2023

Battle Plan : Big Caterpillar

Maybe these should stay secret. Maybe I should make sure my blog doesn't spoil the game by having too much "strategy guide" items in it. Who knows ... Anyway, here's a few ideas on how being able to throw things or having the Big Punch power-up would affect the fight.

It keeps the 'crawl' and the 'tail attack' of the BASIC version. It keeps the 'changing target' where there's one segment to hit, and that's the one where the magic stone currently is. It simplifies the fight by assuming we're good hitting *the segment with the stone* rather than the one next to it "so that it pushes the stone in the right direction".

J'avoue, ça fait un moment que j'hésite à les poster, celles-là. Ce serait moins drôle que mon blog se transforme en soluce du jeu avant même qu'on ne puisse l'essayer, non ? Mais bon, en même temps, j'ai besoin de pouvoir me confronter à mes idées, les trier, les rassembler... et les cahiers à points ne sont pas forcément l'idéal pour ça.

Voilà donc mes notes pour le face-à-face Bilou/Big Caterpillar. Le seul boss qui ait jamais été codé dans la version BASIC. Je conserve la manière dont il avance en rampant sur le sol et son attaque "coup de queue". Comme je l'avais déjà dit, le fait que Bilou puisse depuis SchoolRush lancer des objets change la donne. Plus question de demander de frapper toujours la tête ou la queue. Mais si on doit viser un segment en particulier, il faut que ce soit évident pour le joueur. J'avais déjà envisagé d'utiliser la gemme magique comme illustration pour ça, mais avec un système tordu où il aurait fallu frapper le segment *suivant* la gemme pour la forcer à avancer, frapper le segment précédent l'ayant au contraire fait reculer. Plus rien de ce genre: frapper la gemme la fera avancer, frapper ailleurs sera sans effet.

Then I started trying to bring all that into one single state machine. The goal was to ensure actions taken by the boss would make sense and not lead to tricky corner cases. For instance, the 'tail attack' should only be performed if there's enough room in front of the boss so that it does not attack through the edge of the arena. (as a bonus, that also means that it won't do that attack in a case where that would 'trap' Bilou in a situation where taking damage is inevitable). But then there's a new 'coil' attack that is completely horizontal.

Mais à côté des "idées de gameplay", j'ai voulu regarder si je parvenais à rassembler tout ça en un comportement cohérent. A quel moment faire quelle attaque pour éviter que la moitié du boss ne se retrouve dans un arbre ou qu'une des attaques devienne complètement imparable parce que le joueur n'a pas la marge de manoeuvre nécessaire. C'est comme ça qu'on se retrouve avec une attaque supplémentaire, horizontale et dans laquelle le boss s'assomme lui-même (ou écrase Bilou) quand il arrive trop près des murs.

Sunday, November 06, 2022

Scorpeye... Enfin!

 Oui, je l'avoue, j'ai été lent. J'ai été distrait (au sens attention détournée). J'ai été démoralisé par cette "carapace" qui ne voulait pas faire demi-tour à chaque fois ou qui faisait des demi-tours intempestifs. J'ai douté, de cet empilement de couches qui devait me permettre de laisser des personnes non éduquées au C++ de bricoler aussi leur propres personnages. Sauf que tout ça, c'est bien joli mais que quand vous avez un dysfonctionnement quelque-part, le débugger vous balance des instructions machines alors que le problème est dans le bytecode qu'elles interprètent. Et mon "inspector widget" (pas encore fonctionnel dans le projet 3 rooms) est loin de valoir ddd.

It's been a long time, I have to admit. I've been slow to get things running; I've had lost the hope that I could get that scorpio-shell turning back when it hits a wall... and only when it hits a wall. It felt like I had built a Jenga stack of complexity in order to have a 'simple' interpreter for state machines. But a language is never less complex than the tools you provide to debug it. And Inspector Widget fell short when trying to explain the issue (partly because it is surprisingly not yet working on Dreams.nds)

Une intuition pendant mes vacances ... j'ai retracé la machine d'état de mon scorpion-cyclope. J'ai bien identifié deux ou trois incohérences, mais rien qui ne conduise au bon comportement une fois corrigé.

Oui, je sais aussi, par rapport à ce que je bricolais sur le côté pendant mes semaines de vacances, c'est maigre. C'était des vacances un peu ... particulières.

Puis hier, j'ai repris la machine d'état de pendat. Lui aussi, il réagit quand il fait demi-tour en se prenant un mur. Et il n'est peut-être pas parfait, mais il marche en général bien mieux que cette satanée carapace.

Alors que scorpeye tentait de reconnaître l'absence de sol à l'aide d'un testpoint, pendat se contentait de "dire" "ah bin si la vitesse horizontale est tombée à zéro, c'est qu'on s'est pris un mur. Sinon, c'est qu'on a plus de sol. C'est forcé."

I found only a small evening of ndsdev during my summer holiday this year, and I used it to map the state machine of Scorpeye. It helped me finding a few weird stuff, but it would not make things run properly enough, unfortunately. Then I realised past Inktober that I already had a 'working' monster that bounced off walls. That was the running pendat. And I started mapping its state machine too (granted, after all these years of dsgametools, I should have given myself a tool to make that automatically). To my surprise, it almost never used the same tricks to perform the same task.

For instance, I used a TestPoint below scorpeye to tell me whether there was ground underneath when it claims it failed to slide on the ground. But this is unreliable because it checks only one point to decide for ground while the WalkController checks the whole surface. Instead, the pendat would test whether it came to a halt horizontally. If it did, that means there has been a wall. Otherwise, it bets there's no ground left.

Same with fall/slide transition: the scorpeye tried to use a testpoint to know whether it FAILed because of a ground. Pendat code author (past self) knew the only thing that can make GobGravityController FAIL was a ground. Being stopped by a wall triggers an event. That means no testpoint validation is required.

Finally, I gave myself an extra variable (there are still plenty available for scorpeye) to remember the sliding speed so that we can bounce walls without having to rely on an ImpactController to save the last speed, because so far I don't think GobWalkerController is an ImpactController. It requires to double some states (like left-thrown vs. right-thrown), but that should not be a big deal.

Still, there's one thing that I'll need to fix with unit testing: from times to times, being stopped by a wall while 'walking' doesn't make the move FAIL, but it does clears the speed. Pendat doesn't suffer for that because it has an "increase horizontal speed" statement in its running states that prevents the speed to stay null. I had to add the same statement to the shell, but it shouldn't be required. that's a todo item for XMAS, I guess.

Il me fallait un double-état pour la carapace lancée, une variable supplémentaire pour retenir la vitesse à la place de la 'variable d'impact'... ce genre de choses. Mais il y a un élément suspect. Pour qu'il n'y ait aucun soucis, je suis obligé de mettre une instruction forçant la carapace à accélérer. Sans ça, il reste des situations dans lesquelles je retrouve ma carapace toujours dans l'état "on glisse vers la droite" mais avec une vitesse nulle est un mur juste à ça droite.

Comme si GobWalkerController avait un bug qui l'empèchait parfois de signaler l'échec (FAIL) même si la vitesse tombe à zéro. ça, ce sera une tâche pour un test unitaire.


Monday, April 25, 2022

Behaviour edition on DS. ?


I'd like to be able to edit state machines (for Bilou and monsters) on the Nintendo DS itself. That'd be the pinnacle of on-the-road game making. There's a significant drawback to address before I can do that, though: usable state machine scripts currently heavily rely on GCC pre-processor to turn into engine-compatible text. Most of it is just providing nicknames for things that the engine solely knows as numerical identifiers.

So I'd need at least a sort of token-parser that can handle some of the substitutions on the DS itself. Both for potential Behavour Editor on DS and for runMe. Only the compiled .nds that embed the game would still use PC-pre-processed scripts (and see only numbers).

I've been toying with that idea summers ago, digitized and kept-as-draft the best part of it for seasons. It's not yet time I start implementing it (I don't think so, at least. It's irrelevant to the 'dreamland' effort), but it may be time I stop being silent about it...

Tuesday, April 05, 2022

Codons du scorpion

J'ai fini par avoir un petit temps creux avec le cube allumé. J'en ai profité pour faire deux animations-bidon du scorpion dans AnimEDS et les transférer par wifi hors de la Nintendo DS. Du coup, en reprenant le comportement de base de dumblador (seul autre ennemi que l'on puisse ramasser pour le moment), je peux *enfin* voir ce que donne le fait de ramasser une carapace de scorpeye pour se promener avec.

Eh oui, vous aviez reconnu les pieds de bladors qui s'échappent, hein. On ne vous la fait pas. A terme, ils seront remplacés par les pinces du scorpion, évidemment. Avec à la clé une question de game design: est-ce qu'elles devront pincer Bilou ou non?

I've been creating dummy animations for the Scorpeye with existing pixels and beamed them out of my DS so I could start toying with the ennemy in the playground level. The dumblador state machine provided a neat template to start with, and despite there are still many rough edges, I could get a proof-of-concept within a couple of hours.

Mais bon, un dumblador, ça s'arrête net quand ça arrive sur le sol. Moi, je veux un comportement de carapace de koopa. quelques petites modifications dans le script permettront ça en moins d'une heure: deux nouveaux états $LSLIDE et $RSLIDE au lieu de $STUNSTAND

Les transitions du style 

$STUNFALL->$STUNSTAND on fail [t] ($8000 F $vPlatform(1));

sont maintenant remplacées par une paire de transitions

$THROWN->$LSLIDE on fail [v2 1 & v0 0 <= &] ($8000 F $vPlatform(1));
$THROWN->$RSLIDE on fail [v2 1 & v0 0 > &] ($8000 F $vPlatform(1));

Un petit rappel de la syntaxe ? l'expression entre crochets [] est la condition à vérifier pour que la transition puisse avoir lieu et l'expression entre parenthèses, l'effet de bord à appliquer en plus de la transition. (ici, j'ai du nettoyage à faire, puisqu'une carapace ne devient pas une plate-forme quand elle touche le sol. $vPlatform() ne sert donc à rien)

Les expressions utilise la notation polonaise inverse, donc soit vous ajoutez des valeurs sur une pile (v2 qui empile le résultat des test-points, v0 qui empile la vitesse horizontale, les nombres qui s'empilent eux-même), soit vous retirez des valeurs pour faire une opération (comparer deux valeurs et les remplacer par vrai/faux avec <= ou >, faire un ET logique avec &).

I'd like to tell you that I've got more animations done on the DS and that they are going to be integrated soon. The reality is somewhat different. I've lost several improvements attempts while animating yesterday and I'm not 100% sure of what got saved and what didn't. Apparently, there are still many combination of altering the 'animation structure' and returning to edition that need to be unit-tested and fixed. But that's not done yet. I'd like to be able to give you a 'meet you on saturday afternoon for a updated demo', but IRL struck again, and fairies only know where I'll be by then.

Saturday, January 29, 2022

Les bonus s'emmèlent...

J'étais tout content de voir que Bilou savait aller dans l'eau, et je ne me suis pas rendu compte qu'il y avait un soucis avec les bonus: on pouvait carrément marcher dessus. Quelque-chose lié à la nouvelle propriété F_START_FALLING, sans doute ... sauf que non. c'est surtout lié aux bytes 'regarde à côté'.

C'est que l'ancien moteur de jeu utilisait le numéro du 'bloc spécial' pour décider s'il devait être solide ou non, et la fonction qui indique la 'hauteur du sol' essayait toujours de faire comme ça. L'ennui, c'est que j'ai utillisé les codes 0xfc à 0xff pour les fameux 'regarde à côté' qui permettent aux blocs spéciaux d'être des blocs, et pas juste des pavés de 8x8.

Jan.24. Managed to have Bilou switch to 'swim' state when it gets in contact with F_WATER tiles. It's as swimple as $LFALL->$INWATER on fail [H WATER ?] ...

Jan.25. It uses the new H GobExpression 'operator' that puts type of the tile under character's hotspot on stack, where it can later be compared with a constant flag (WATER). That operator will expect an elevation value on the stack first. like [2 H WATER ?] to tell "check 2 pixels above the hotspot"

But this is not the point of this post. The point is, looking at the video I captured (bottom left on the toot panel below), I noticed I was walking on disappeared apple before going into the water.

Jan.29. When you pick up a bonus, a MapAnim is spawn, that will edit graphics to get that sprinkling animation. It should clear "properties" as well, as soon as you get in contact with the collectible.

Yet, the change to newmeta changed what 'cleared' means on the map. Now, the clear value 0 means 'lookup World::properties[0] to know what you can do'. Another trap was that, when checking ground height, you might find yourself on one of the new "lookup one tile left" or "lookup one tile up" that are used to make special *blocks* of adjustable size (not just special mini-squares of 8x8 pixels). If that happens, code was still lacking "locate the actual block defining corner" and then use that special blocks's properties set to decide whether it has ground or not.

Pas le choix, donc: ici aussi, il faut retrouver le 'coin actif' du bloc spécial et aller chercher ses propriétés dans le BlockInfo correspondant.

Deuxième farce (voir l'animation): une fois le bonus effacé, il a laissé derrière lui un bloc à travers lequel il est possible de continuer à tomber, mais aussi de continuer à marcher. La faute cette fois au tableau des propriétés pré-encodées pour les blocs à définition indirecte (prévus pour les physiques particulières, essentiellement).

edit: if you don't have a twitter account, here's what the videos looked like:

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.

A few time after I got my first boox, I found the code for the game Celeste by Matt/Maddy Thorson. It seemed appropriate to study it while *deline was having sports in the evening, and it did give me some difficulties with all those hyper-jumps and similar advanced techniques. Especially since I barely started a game of Celeste on my switch and I'm nowhere in mastering those advanced moves. But the developer did tweet a list of 10 tricks they used to make the gameplay more satisfying.

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)

The tricks are the following (if twitter dies, they are hosted on "Celeste & Forgiveness" with their original animated gifs)
1coyotte timeYou can still jump for a short time after leaving a ledge.done
2jump buffering If you press and hold the jump button a short time before landing, you will jump on the exact frame that you land.done
3Halved gravity jump peakIf you hold the jump button, the top of your jump has half gravity applied (gives more time to adjust for landing)done
4Jump corner correctionIf you bonk your head on a corner, the game tries to wiggle you to the side around it.todo
5Dash corner correctionif you dash sideways and clip a corner, it'll pop you up onto the ledge.todo
6Dash corner 2also pop you up if it is a semi-solid platformtodo
7Lift momentum storage.Add momentum of upwards-moving platform to regular jump impulse, but allow to use it even a few frames after platform stopped moving upwards.done
8coyotte wall-jumpyou can wall-jump 0.25*playerwidth away from the actual walld.n.a.
98 for super-wall-jumpd.n.a.
(the 'done/todo' status indicates whether I have a corresponding solution in Bilou's game engine/state machine)

Tuesday, June 26, 2018

Guru Meditation again

Bon, je me suis retrouvé après avoir fait quelques essais du nouveau système de gestion des évènements de mon moteur de jeu avec un bel écran bleu. Sur DS uniquement, évidemment. Après quelques tentatives infructueuses de régler ça en une demie-heure, j'ai fini par profiter du fait que ma fée était en réunion pour me faire une soirée "guru méditation" à l'ancienne.

Papier quadrillé, désassemblage des fonctions impliquées (au moins, la position dans le programme était correcte), déduction de quel registre contient quelle variable (pour pouvoir exploiter le contenu de l'écran bleu) et structure physique des différents objets impliqués à grand coup de ddd en comparant le contenu "brut" de la mémoire et des affichages haut-niveau.

Vu que le crash se produit à cause d'un accès à la mémoire via quelque-chose qui n'a rien à voir avec un pointeur, j'étais prêt à rajouter des "nombres magiques" ça et là pour pouvoir reconnaître une transition, un état, une expression, etc. Mais en réalité, je n'ai besoin de rien de tout cela. Tous mes objets critiques ont au moins une méthode virtuelle, ce qui signifie que je peux utiliser la référence vers la vtable pour déterminer directement si une zone de mémoire donnée contient toujours un objet d'un type donné ou si elle a été écrasée.

A partir de là, c'est de la navigation dans la mémoire de la DS en suivant les pointeurs retrouvés sur l'écran bleu pour reconstruire l'état des objets impliqués dans le crash. Et au terme de tout ce sudoku-géant je finis par trouver deux indices troublant:
- l'adresse d'une des transitions à tester en cas d'évènement est un anagramme de l'adresse qui a causé le crash
- l'adresse de la liste de transitions correspondante n'est pas multiple de 4 alors que toutes les adresses ont une taille de 4 (bytes, mon cher Wattson).

L'émulateur voyant cet accès étrange aura "redresser" l'adresse, ignorant les bits les plus faibles. Parce que, oui, la machine sait que je veux prendre 32 bits quand-même. Le CPU de la DS, lui ... eh bien, il m'a sorti une variante mélangée des 32-bits se trouvant à l'adresse utilisée par l'émulateur. Les 8 bits "les plus à droite" de la valeur en mémoire se sont retrouvés à gauche pendant que tous les autres étaient décalés vers la droite.

Friday, September 15, 2017

Come back from the ink ?

Bon, entre les programmes d'activité des loupiots qui grandissent, les centrales vapeur qui tombent en panne et les interventions de réparation dans la maison, je me prends une petite paire d'heure pour essayer de corriger un couac avec le passage à un niveau vertical dans "School Rush": s'assurer que le jeu relance bien le niveau si l'encre nous rattrape.

Je dois  notamment éviter que Bilou ne puisse rester indéfiniment dans un encrier sous l'encre. Etre invulnérable dans l'encrier, ok, mais pas retomber immédiatement dedans quand il nous projette jusqu'à la fin de la batterie.

It is time to check what the vertical level looks like when we add rising ink in the mix. And the first tests show that there's quite some tuning required. The first mis-steps that my last playtester did led Bilou to be stuck in the ink, invulnerable, but also unable to keep on playing. One of them involved cycling between in-inkjet and hit.

I'm trying to make the state machine detect that we're in the ink and switch to a "swim up" state that would give the player a chance to get out. This is possible because ink has an additional flag that makes it possibly different from a regular hazard. All the engine requires is that the test on "hurts and is ink" precedes the test on just "hurts".


Se faire projeter par l'encrier, c'est "$HJUMP". L'encre, c'est à la fois F_HIT (blesse Bilou) et F_ISINK (fait flotter les éponges). Une réaction "normale" pour le personnage qui tombe dans l'encre serait d'essayer de nager pour en sortir. En particulier s'il atteint quelque-chose qui peut le propulser hors de l'encre. Ce sera "$SWIM", dans lequel on est insensible à l'encre mais qui repasse faire un test périodiquement et continue donc à consommer des points de vie tant qu'on est dans l'encre.

Il faudra aussi que je complète ce "swim" lorsque Bilou arrive hors de l'encre.

Sunday, June 25, 2017

Behaviour Edition ... brainstorm

Prochain outil pour le projet "dsgametoosl" ? Je ne sais pas encore. Mais j'aimerais beaucoup construire quelque-chose qui permette de manipuler les machine d'état définissant le comportement des personnages dans les jeux qui tournent sur mon moteur "geds".

Quelque-chose à moitié graphique (je clique sur un bilou en train de sauter, on me montre tous les états qui sont accessibles depuis celui-là. J'en choisis un, je vois les conditions et les actions annexes pour la transition correspondante si elle existe), et à moitié texte (je peux en éditer une ou en créer une nouvelle, sans s'embêter, rien qu'en écrivant les expressions que je veux).

Quelque-chose de pratique (je clique sur une variable, je vois tous les états où elle est manipulée).

Pour permettre la réalisation de "School Rush", j'ai introduit pas mal de fonctions à coup de macros qui permettaient de "nommer" des tests du genre "est-ce que la direction choisie sur le DPAD va vers la droite ?" Pour que l'éditeur soit pratique, il faudrait qu'il permette de conserver ce genre de simplifications, et ne pas imposer à l'utilisateur de mettre dans chaque test "est-ce que le bit 5 de la variable numéro 3 est à 1?"

Du coup, l'éditeur doit à la fois savoir que l'expression utilise la variable 3 (l'état du dpad) pour qu'elle soit listée dans "toutes les expressions qui dépendent du DPAD), mais aussi qu'elle s'affiche avec un "DRIGHT". et pouvoir indiquer à l'utilisateur ce que fait DRIGHT au cas où ce ne serait pas suffisamment explicite.

ça demande d'une part de faire avec assez de précision le tour de tous les éléments de scripting qui ont besoin de pouvoir servir de "critère de tri", mais aussi de faire en sorte que le logiciel tournant sur DS puisse comprendre la version "évoluée" du script et puisse en tirer la version "interprétable par le moteur de jeu" pour essayer les modifications dans runME.

Un défi qui n'est pas à prendre à la légère, en fait. J'avais envisagé pendant mes congés de l'an dernier de refaire l'équivalent du préprocesseur de gcc, mais je me rends compte aujourd'hui que je suis parfaitement libre d'utiliser autre-chose que des macros C pourvu que je sois en mesure de produire le fichier voulu. Par exemple en produisant un fichier .h à partir de ce que le nouvel éditeur utilise pour connaître les variables, les compteurs, les types de collisions, etc.

Ce sous-projet m'intéresse pas mal, et commence à consommer de plus en plus de feuilles quadrillées dans mes petits carnets, même si je traîne un peu à blogger tout ça ces derniers temps. J'ai ma petite idée sur la saisie de texte (à mi-chemin entre pixel-art et reconnaissance d'écriture manuscripte), par exemple, ou  la possibilité de représenter sous une forme d'arbre les expressions mathématiques du style "v6 := min(v6 - 32 , -400)" qui s'écrit en GobScript "v6 32 - 400 ~ m :6" pour être plus facile à traiter par l'interpréteur.



Sunday, August 07, 2016

LivingStone, I presume

Les ennemis de Rayman, sur PSX étaient assez évolués dans leur comportement. Les "livingstone" par exemple -- existant en deux tailles -- ne se contentent pas de patrouiller sur leur plate-forme: le grand livingstone peut faire des pauses pour ajuster son casque, fuir effrayé ou se faire assommer d'un coup de prune.

Le petit "teigneux" lui, peut se mettre à pourchasser rayman, mains en avant, tenter de l'aggriper à distance et s'abaisser pour se mettre hors de portée de nos coups de poings. Pas encore exactement un personnage de Street Fighter, mais nettement plus sophistiqué qu'un goomba.

Ennemies in Rayman PSX were fairly sophisticated in their behaviour. The Livingstones -- one of the first monster you encouter -- not only patrol on their platform. They pause here and there, they can be frightened or stunned with bouncing fruits. Then you have the smaller living stone, detecting Rayman's presence, chasing him, or attacking with its hands. It is not yet as complex as a Street Fighter encounter, but not quite your average goomba either. 

J'étais donc assez surpris de constater que les "lividstone" de Rayman Origins sont fondamentalement statiques, occupant sans avancer (ni même se retourner ?) une plate-forme unique. Certains ont un bâton en main, d'autre une balle. Mais d'un point de vue "gameplay", ça ne change rien: ils se contentent d'attendre Rayman. Ils sont assez comparable à des blocs à pics sur lesquels ont peut sauter et qu'on peut casser. Enfin presque: une fois touchés, on peut se servir de leur "bulle" pour aller plus haut, encore que je n'ai pas encore vu beaucoup d'endroit dans les niveaux où cet élément est développé.

Comparatively, I was shocked to see Lividstones of Rayman: Origins almost static, standing on their platform wiht no additional move, not trying to hit rayman with their stick when they have one... just waiting to get smacked. They're functionally equivalent to spiky blocks that you could break with a punch. The "why" is pretty clear: make the game easier. What puzzles me is "how does it come it works? Why haven't I got any feeling of core gameplay being lost ?"

Que s'est-il passé, donc ? Pourquoi cette simplification à l'extrême et surtout où est la "compensation" dans le reste du gameplay qui fait que cette simplification n'a pas d'impact négatif sur l'intérêt du jeu ?

Dans "l'histoire de Rayman", on nous présente la méthode Hascoët qui répartit les challenge contenus dans les niveaux en quatre catégories:

  • Rapidité: aller plus vite que la lave, grimper plus vite que l'eau, suivre un scrolling imposé, être parti d'un nuage avant qu'il ne disparaisse ... d'une fleur avant qu'elle ne se fanne... Bref, tout ce qui incite le joueur à rester en mouvement. Dans Rayman Origin, ce rôle est essentiellement joué par le "roi des lums" (score doublé temporairement) et par les bonus-en-bulle dont on ne saura profiter que si on arrive assez vite dessus. Mais il y aura aussi des pans entiers de montagne qui s'abaissent et mettent le joueur trop lambin en danger.
  • Astuce: tout ce qui demande au joueur de réfléchir un peu pour résoudre un problème, comme le coup de la prune sur la tête du livingstone, ou parvenir à lui mettre un coup malgré ses stratégies d'évasion. Dans "Origins", l'astuce est souvent secondaire, mais les développeurs ont prévu de nombreuses situations où les plantes-interrupteur font apparaître ou disparaître des plate-formes ou des yeux-à-pointe. On peut ainsi à distance précipiter les lividstone vers leur défaite, les prenant à leur propre jeu. Bien rigolo à faire, en tout cas. Faute d'une récompense intégrée au jeu, on est récompensé par un sentiment de supériorité sur ces mécréants pathétiques.
  • Précision: sauter/frapper pour atteindre un endroit en hauteur, ce sera l'élément principal dans Rayman PSX. Rayman Origins monte fortement les exigences ici, en particulière avec les défis des "pièces de la mort" qui demande des sauts et des rebonds impeccables. Je suis aussi tenté de penser que les nuances possibles que dans Rayman PSX, ne serait-ce parce qu'il y a plus d'inertie dans la course du personnage. En plus, ça n'aura échappé à personne, Rayman peut maintenant rebondir sur les têtes des ennemis, et on a droit à plusieurs constructions dans les niveaux ou on joue au parakoopa en rebondissant d'ennemi en ennemi pour les éliminer tous.
  • Synchronisation: passer au bon moment ou frapper au bon moment. C'est peut-être un des éléments qui est en retrait, en tout cas dans les premiers mondes, encore qu'il reste quelques plate-formes mobiles pour aller récupérer des pièces de la mort, justement.

Sunday, April 24, 2016

Costumes, folks.

https://www.youtube.com/watch?v=xI3xZAn7r2AJe vais appeler "costume" un ensemble alternatif d'animations pour un personnage qui ne change pas fondamentalement le comportement du personnage. Ce sera le cas par exemple de Mario quand il grandit. Bien sûr, mario-grand est capable de faire des choses que petit-mario ne sait pas faire, mais les animations modifiées vont bien au-delà des nouveaux mouvements. Devenir Mario-tanooki, c'est enfiler un costume. Devenir Mario-feu ou Mario-Marteaux aussi. Devenir Mario-Grenouille (SMB3) change fondamentalement l'ensemble des mouvements du personnage, la physique des déplacements et ne peut clairement pas être assimilé à un costume comme défini plus haut.

Some heroes use costumes. When they have some specific powers, their apparence is changed. Their set of moves doesn't fundamentally change -- it's a costume, not a mutation, but they gained an important additional move that may change strategic choices at some points. Yes, exactly like the fact that Mario is currently able to shoot fireballs, just in case the last platforming section made you forget about it. Grabbing the tanooki suit is a costume. Same for the Hammer Bros. suit. The Frog suit in SMB3, however, is more like a mutation. Many basic moves of Mario like running and jumping are no longer available when you're a frog, and replaced by another set of moves. This is truly a distinct part of Super Mario's state machine, while the Fire Flower merely grant you to access one conditional state (throwing fireballs). I need to find something similar for Bilou's BigPunch power-up.

https://www.youtube.com/watch?v=xI3xZAn7r2ALa question qui se pose pour le développement de Bilou est de choisir le bon moyen de réaliser ce changement d'apparence. Vu la complexité de la machine d'état, plus franchement question de doubler l'entièreté des états pour tenir compte de la disponibilité ou non d'un power-up.

Dans certains cas, un simple changement de contenu de RAM grahique suffit. C'est plus ou moins le cas de SMB3: en utilisant son "mapper" pour remplacer la page de ROM présente, les dessins de Mario petit disparaissent et ceux de Mario grand prennent leur place. A part modifier le visage de Bilou, cette technique ne me permet pas vraiment de changer d'animation parce que moi, je fais de l'animation modulaire: la mémoire vidéo ne contient donc pas d'étapes d'animations mais uniquement des fragments d'image génériques.

I've seen some costume as simple as a palette swap. Megaman uses it quite efficiently. I don't feel to use it for Bilou: its colors are deeply linked to his identity, as far as I'm concerned. I've seen other costumes implemented as a video memory update: some new pictures are loaded and used, while the rest of the code -- including the one that decide which portion of the video memory to use at what time -- remains unchanged. Super Mario Bros 3 obviously works that way, at least for Big / Racoon / Tanooki / Hammer Mario. Same moves at the same place within the different pages. A simple re-mapping of the video ROM and the costumes are swapped.

As much as I like that behaviour, it's useless for me. Bilou's hands and feet cannot be easily replaced because they're shared with bladors and pendats. Only the head could be updated. It wouldn't make the animations -- especially the idle animation -- fundamentally different because I'm doing modular animation: the video memory doesn't contain frames but merely fragments.

A more practical alternative would be to reuse Sonic's shields idea, because those shields are animated and rendered independently from Sonic himself. I don't quite know how I could convey the idea "you have punch power" with such a shield around Bilou, though.


La version plus facile, héritée de la NES et de ses palettes séparées, c'est de changer le jeu de couleurs du personnage (demandez donc à Mega-Man, il en sait quelque-chose). Une approche que je mets de côté pour Bilou: ses couleurs font bien trop partie de son identité.

Autre alternative possible, on se la joue Sonic et son espèce de bouclier transparent. Ici, le sprite de base et toutes ses animations restent inchangées: il suffit de faire suivre Sonic par un sprite supplémentaire suffisamment creux pour qu'on voie encore le personnage par-dessous. Jouable pour Bilou aussi, j'imagine.

Je choisis un système moins rétro mais mieux adapté à mon moteur de jeu: j'introduis des sections conditionnelles dans les animations elles-même. L'idée est d'éviter de devoir modifier les infos liés à l'état -- il continue à ne connaître qu'une seule animation -- mais de profiter du fait que j'ai déjà des instructions type RISC pour les animations (déplacer tel OAM, changer l'image utilisée par tel autre, etc.). Du coup, il est assez facile d'ajouter une "instruction d'animation" qui est en réalité un saut conditionnel dans la séquence, sur base d'un des compteurs de bonus ou d'une des variables internes du personnage. Reste à construire la séquence correctement. Ça, ce sera le rôle du lecteur de scripts. Les animations elles -- et leur éditeur --
restent totalement inchangés. On se contente au moment du parsing de construire quelque-chose de plus complexe comme "if [compteur%] animA else animB".  C'est encore insuffisant pour émuler SMB3 (au niveau script, je veux dire), mais ça devrait faire l'affaire pour Bilou.

So there's one option left if I want to swap animations without modifying the states (and e.g. start having multiple animations per state): the animations themselves. They are build as a sequence of a RISC-styled instructions, each instruction changing one specific parameter of the rendering. My idea is to have one additional instruction that behave as a conditional branch, and allow merging of two animations (or more) in a single one.

It's not quite perfect: it requires the two animations to use the same pages with the same structure because at the moment, only one of the structure will be kept for the merged - conditional - animation. The script-parser that performs the binding is still a bit crude too. Likely too much problem-specific while those instructions could do much more. But it will do the trick for Bilou: School Rush and that's my current interest.

Enfin ... le ROM mapping de SMB3 est peut-être un peu plus compliqué que ça. On voit sur la vidéo de Bisqwit qu'une seule "page" de 256x16 pixels est utilisée à la fois pour Mario, or il y en a 4 différentes par "costume" de Mario. Selon l'action en cours (marcher: +0, courir et tenir une carapace +2, voler +3), la page choisie est différente.

And while we're at it, the costume management for SMB3 could be a bit more sophisticated than I originally thought. Only 1 row is accessible to the NES' GPU at any time, and one "costume" offers at least 3 such rows (dubbed 'pages' on bisqwit's original picture) plus one that is used for star-powered sommersaults. I also spot a "page" that is useful only when Mario is carrying a koopa, or turning back. But excepted for little Mario and Frog Mario, all the rest replicate the same layout for common movements.

Sunday, October 25, 2015

segfault.

J'ai tenté une des deux approches me permettant d'avoir une animation d'attente pendant le chargement des niveaux. Et c'est un échec. L'émulateur se plante sur une instruction non-définie en cours de chargement du niveau 1. Le débuggeur fait crasher complètement l'émulateur avant même d'avoir atteint cette instruction.

Failed attempt to have some background task running while level loading is in progress. Something simple like moving some sprite on the bottom screen, playing samples to count the score, etc. But it changes quite a lot the execution context for the loading, and as of writing, it makes the emulator crash when loading level 1 and the debugger makes it crash even earlier. That's a job for some automated testing and I have plans to bring such techniques to my DS development since I had the opportunity to see it in action at work.

Je pense que ce serait un cas de figure à étudier avec l'approche de tests automatique inspirée de mes travaux au boulot, avec une couche d'abstraction du matériel pour que le test se passe en natif sur le PC. Mais c'est un peu gros à mettre en place: je préfèrerais que ce genre de développement ne mette pas en attente le jeu "school rush". Il me reste une deuxième piste à explorer succeptible de tout simplement raccourcir les temps de chargement: permettre de réinitialiser la map et la position des ennemis sans ré-interpréter l'entièreté des machines d'état.

Yet, I have another approach I could follow, which would make the whole loading process faster. I think I will try this first, and fall back to the auto-testing system if that doesn't work either.

PS: bonne nouvelle pour les lecteurs francophones: le message sur les bonus a été traduit.

Thursday, May 28, 2015

Pendat turned dizzy (done)

Got it working ^_^ Pendats turn dizzy when they're jammed at some place they don't belong, and while they dizzy-walk backwards, they either fall to their doom or return to a place where they can safely walk.
Now I need to ensure they react to ink pits and don't try to walk there.


Nous y voilà. Forcez un crayon-soldat à quitter son chemin de ronde et le mode "titubant" lui permettra d'y retourner (ou de tomber encore plus bas). Le dernier hic, c'est le comportement ridicule lorsque le crayon atterit dans l'encre en bas du niveau. Je voudrais qu'il puisse alors s'y enfoncer et disparaître (comme les taille-crayons) mais sans pour autant sombrer dans l'encre qui monte à moins d'en avoir jusqu'au yeux.

remaining todo items:

  • [done] ink droplets no longer stopped by spongebop ? why? wrong flags for collision test
  • [script] Pendats drown in ink
  • [done] Bilou can grab with DOWN+HAND even when facing left
  • [code] Bilou don't get that deep in the ink, please.
  • [done] Fix carried bladors
  • [done] Show Bilou's hands when carrying SpongeBop
  • [code] Intuitive difficulty selection
  • [code/gfx/script] Some sort of scoring

Monday, May 25, 2015

Pendats get dizzy

Première étape vers des crayons "plus autonomes": le compteur de désorientation est implémenté. N'ayant pas encore transféré l'animation "titube", j'ai repris celle où le crayon est éjecté (quand il cogne un mur, par exemple). Le résultat n'est vraiment pas celui attendu :-/

I wrote some gobscript to enforce a "dizziness counter" on pendats. They should be able to walk for 2 blocks after they turned back if they don't want to end up dizzy. But since I haven't transferred the animation itself to my PC, I used "stunned bounce" as a placeholder. The result is some very emergent behaviour, possibly due to some incoherence in body-boxes of the pendat.

Saturday, May 16, 2015

pendats in the detail.

 Avant la release finale de School Rush, il faudra que je corrige un glitch dans le comportement des soldats. En ajoutant la possibilité aux crayons de prendre Bilou en chasse, je leur ai aussi donné la possibilité de quitter la petite cage dorée dans laquelle le level design les avait placés. Du coup l'approche "façon frogatto" de faire dans le simple plutôt que de chercher à faire des personnages ayant une IA capable de s'en sortir dans toutes les situations.

I believe the game engine issues are now fixed. That gives me the time to go through the remaining gameplay issues and glitches. One thing that may easily occur is to get Pendat stuck at some ridiculous place when he's beeng chasing Bilou, jumped off its designed platform and lands in some place where it cannot walk around. That could either be because the place is too small for a full walk cycle or because it is some area designed to force the pendat to turn back.

Pourtant, il est évident qu'un crayon-soldat devant un intrus ne s'arrêtera plus à son petit chemin de ronde. Difficile de faire en sorte que l'ensemble du niveau puisse accueillir un pendat atterri par erreur quelque-part. Je me retrouve avec des crayons-soldat qui font la toupie parce qu'incapable de se mettre à avancer sur un sol trop incertain.

At first, I thought it was something wrong with the state machine but no. It's just I'm missing an "escape move" that would be valid in place where the regular walk doesn't work, and that can be perceived by the player as a valid excuse for seeing the pendat doing silly things like jumping down a cliff, reaching either safety or sink. Being dizzy could explain that. I have temptative animation in the pipeline.

J'ai commencé une animation d'un soldat ayant la tête qui tourne, donc incapable de se rendre compte s'il y a ou non du sol sous ses pas, et donc pouvant quitter la zone inconfortable même si c'est pour se jeter dans le vide.

Good thing, I don't necessarily need to add new test-points: I simply need to add a sort of "temperature counter" that increase after each turn back and cool down while walking.