Showing posts with label animation. Show all posts
Showing posts with label animation. Show all posts

Friday, December 05, 2025

Funnier Apples

Depuis le début de mon carnet en cours, j'ai un objectif "rendre les pommes plus fun". ça passera par des interactions révisées mais aussi par des compléments d'animation. Entre autre, quand on lance un appleman et qu'il arrive par terre. Le comportement actuel est tiré de dumblador, qui glisse légèrement sur les surfaces planes de l'école avant de s'immobiliser assez rapidement.

Finally! that little sketch of an appleman rolling away when hitting the ground has been teasing me for month at the start of my notebook, but now I've finally sketched something in AnimEDS. Hopefully I could try to integrate it in the prototype this week-end.

It should trigger when you've thrown an appleman and its hitting the ground. The current way it slide for a few pixels before settling feels incompatible with the spheroidal nature of an apple but I still have to decide whether it will bounce-roll or just roll. Likely "just roll" will work better with slowing it down. Or maybe it should just keep rolling until off-screen or stopped by a wall ? 

Mais soyons clair: ça ne donne rien de convaincant avec une pomme sur le sol de la forêt. D'où l'idée que la pomme roule un peu en atterrissant ce qui 1) est fun et 2) lui donne un peu plus de portée qu'un projectile classique, ce qui est toujours le bienvenu dans un monde 1.

Alors tant qu'à faire dans le fun, on pourrait même laisser rouler la pomme jusqu'à ce qu'elle rencontre un obstacle, non ?

(En tous cas,  J.L.N approuve ... et apprécie le fix qui évite à Bilou de se retrouver figé dans un mur pendant qu'il nage) 

edit: The pull mask feature should allow me to make eyes and stem either in front of or behind the apple's "body" more easily. I had forgot it exist and made a messy animation where sprites are swapped, which makes it blink in the editor ^^"

Now, that simple animation opens up a lot of new options in terms of gameplay and interplay. What happens if an apple rolls into another apple ? and into a bopping funky funghi ? 

Game design brainstorm from 2022 suggested that you could "push" a funghi by throwing an apple at him when it's mid-air, but shouldn't it bounce the apple back at you if he's grounded ? and what if you're hit by an apple that's rolling back at you ? shouldn't that hurt ?

That starts making the appleman looking a bit more like a koopa and a bit less like a goomba, doesn't it ? My brother even suggested that it could be the core mechanics of a dedicated puzzle game ^_^

Ah. None of these are available yet, of course ^^"

 

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 ;)
 

Friday, February 16, 2024

Sand "waves" completed.

Bien. Ce coup-ci, je pense qu'on y est enfin. Le sable tombe, il fait un petit tas, le tas croule le long de la pente, puis se "dissout" au moment d'arriver à la chute suivante. ça reste "mode démo", celà dit: le code pour la pente à contresens n'a pas été testé et la longueur de la pente est hard-codée dans la "l'animation" de la vague qui descend. Mais ça fera l'affaire.

At last. Sands falls down, piles up, flows down slope and then falls again. The illusion is complete. The code is partly production-grade, partly demoshow-grade. Just what I need for a new release of the 3-rooms demo ... if only there wasn't that just-popping-up bug in the School room >_<

Wednesday, January 10, 2024

Nager mieux

I like to release a demo on special occasions like new year or my birthday. It is twice unfortunate that I had none to show by the end of 2023 since it was the 30th anniversary of Bilou's original design. But there was something still lagging behind: for an untrained player, it takes countless trials to get out of the water in the green room. When the season holidays started, I thought I could just change the state machine a little bit so that Bilou would jump out of water if we hold the FOOT button.

Il y a un élément qui m'empêche encore de faire une nouvelle démo avec les améliorations de l'an dernier: c'est difficile de sortir de l'eau. Je m'en suis rendu véritablement compte en laissant un peu la démo actuelle entre les doigts de J.L.N ... Je m'étais donc donné la mission d'essayer de faire fonctionner ça pendant le congé, mais avant même le premier essai, j'ai compris que ça n'irais pas comme je voudrais. Parce que pour qu'on puisse "jaillir de l'eau si on a appuyé sur le bouton de saut près de la surface", j'ai besoin de pouvoir mémoriser que ce bouton a été enfoncé. 

It didn't work as I expected though. Maybe it could be adjusted with some cleaner input buffering, but since I intend to use some different SWIM mechanics to help the game being fun, it seems silly to hack something else first. So I went on, picked my animation editor and started crafting swim left, right and up animations, each split so that they player would have to chain button pressing to reach full speed and Bilou could come back to some "rest position" otherwise.

ça pourrait être réglé avec une peu de tuning sur l'input buffering, j'imagine. Mais comme j'ai aussi prévu de passer à un autre système de nage dans lequel Bilou reste dans l'équivalent d'un dash sous-marin pendant quelques frames quand on a appuyé sur "pieds", ce serait naturel que l'on jaillisse automatiquement si on est dans cette phase de dash. J'ai donc passé deux petites soirées à faire des animations dans MEDS pour que notre brave Bilou brasse mieux.

Manque de pot, une animation supplémentaire s'est invitée dans le fichier. J'ai prévu 4 "pages" d'animations pour bilou.spr, mais cette nouvelle animation est sur la page 7, décalant toutes les nouvelles animations

- code avant la nage avec les sprites avant la nage:
  - démarrer la pyramide: ok
  - passer de la pyramide à l'école: ok
  - sortie de l'école: gros crash.

Une petite modif' plus tard (là, ce soir) pour éviter que l'animation excédentaire soit à la fois sous le contrôle du jeu et sous le contrôle du reste (sinon, ça fout un chaos digne de Jurassic Park dans le gestionnaire de mémoire) et j'ai de quoi commencer à utiliser toutes ces jolies nouvelles animations. Sauf que ça fait bizarre de voir Bilou essayer de rejoindre la surface la bouche grande ouverte (animation "super jump" recyclée) puis fermer la bouche une fois qu'il arrive à l'air libre :-P Edit et il va falloir que j'en fasse une ou deux de plus pour permettre au joueur de quand-même avancer. Sur base des animations de Fury ? Pourquoi pas ...

But unfortunately, some bits got twisted, and I ended up with an undesired 'temporary' animation stuck in the bilou.spr file. Then I picked the wrong decision of ignoring it while loading rather than fixing the editor and saving the file again. It worked when I tried the animations in the green room, but when I tried to 'move' between rooms later on, everything blew up. I had HDMA experiments catching my attention, so I was all out of holidays when I finally understood why it broke and how to fix it. Sounds like you'll see the swimming another time ^^"
Edit: one more thing ... Dash-swimming might be fun, but I also need something to use when player just navigates with the DPAD. Maybe Fury's swim sheet will be the template I need for that ... 

Edit²: give it a try in the latest demo

Sunday, October 22, 2023

done transition on looping animation

I've been crawling on the dark side of hobby game development lately. Dark because it mostly involved too much hex numbers and too little pixels to feed enjoyment while doing it. Dark because it implied admitting that I have not been paying enough attention to things like "whether unit test still pass" and "whether it might be the right time to merge that into default". Things that make the difference between coding and coding as a job. Now I have to repay that attention debt, right after the buggy-tool debt and even before I can look at that memory leakage debt. Given how long it took, how little motivation I had to do it more than 1h per day, I wonder whether I shouldn't have opted for something less useful but more enjoyable first...

Anyway, I went on with cherry-picking bits of the 'newmap' branch that ought to have been on independent branches and merged into default long ago until I finally identified the fix that stabilizes on what pages animations are actually loaded.

Y'a les jours où le développement de jeux, c'est fun. Puis il y a les jours où le programme supposé anticiper les défauts du moteur de jeu vous crache de l'hexadécimal à la figure. Tout ça parce que j'avais espéré pouvoir remonter dans le temps avant la décision "allez, on va faire évoluer le moteur de jeu pour qu'il puisse supporter plus de pentes, plus de types de sol et encore plus de folies!" ... parce que je n'avais pas pris la peine de vérifier que la modification juste avant ("allez, on va autoriser la fuuusiooon de fichiers graphiques au moment du chargement pour permettre d'avoir un monde 2") ne cassait rien de ces fameux tests automatiques.

Et encore: l'hexadécimal, il a presque fallu aller le chercher dans les boyaux de la bête qui se contentait sinon de nous roter un "transition sur fin d'animation en boucle". Eh oui. Et j'avais beau reprendre les fichiers dans mon éditeur, vérifier à coup de MD5 que j'utilisais les bons, vérifier l'état du GobTransition dans le débuggeur, rien ne parvenait à expliquer comment l'animation d'inkjet se retrouvait tout à coup avec une boucle.

I have small scribbled characters and notes about it all over my yearly notebook, but I thought it might be worth another "big picture" sketch page to summarize all the things I had forgotten about my own code and re-discovered while working on this specific bug.

Like how you can load two files in the sprdo helper tool to see which animation #543 truly is ... I should have remembered that earlier on. As soon as I noticed that the the commands I could see in the debugger were not matching what they should (they were ending with a 'LOOP' command, just to start with. I tried comparing them with the line above, the room above, but I should really have just compared them with the next page ^^". Then I've been distracted by that "meds+4" extra token on some files, but it was just a hint for Level Editor. I guess that would have been obvious if I had refreshed memories of "world 2" by reading my own blog posts again. But for some reason, I only thought about that tag now, when blogging about how I eventually figured out that I was missing some fix written long ago, but not merged on "default" ^^".

Au final, ce que j'aurais du faire, c'est comparer cette animation incompréhensible à celle se trouvant au même emplacement, mais sur la page *suivante* dans mon fichier school.spr ... parce qu'il me manquait sur la branche que je cherchais à corriger un malheureux patch corrigeant un décalage d'une position au moment d'enregistrer les animations du fichier supplémentaire à côté du fichier de base :P

Saturday, August 12, 2023

Swinging animations

Plus le design de Bilou: Dreamland avance, plus la possibilité de s'accrocher et se balancer prend de l'importance dans le gameplay envisagé. Et c'est tant mieux sauf pour une chose: mon moteur d'animations est actuellement très mal adapté pour ce genre de chose. Comprenez, on risquerait plus de se retrouver avec quelque-chose de raide comme Mickey Magical Quest plutôt que les mouvements souples de Fury of the Furries. Ce serait d'autant plus dommage que Spongebop ne souffre pas de ce genre de limitation et que ça rend furieusement bien. Mais voilà, l'image de Spongebop est indépendante de l'angle de sa corde.

The more I sketch some design ideas for Bilou: Dreamland, the more swinging with a rope-like object occurs. I won't claim it will be a primary game mechanic, but it will certainly be an important one. There's just one drawback : so far my game engine offers no support for that kind of animation. Oh, sure, I could go the Mickey Magical Quest way of hard-coding a few frames and the positions Bilou should take to swing, but given that I have a freely-swinging Spongebop in the previous game, I'd prefer go for something like what I've enjoyed in Fury of the Furries: game physics that allows 360° swinging, with free positioning anywhere on the circle defined by the current rope length and almost free extension / reduction of the rope length (Mickey can only climb).

One picture every 10° to swing a tiny
Pour Fury on a pas moins de 36 images différentes et la possibilité de faire un tour complet de son point d'accroche si la physique le permet, soit 10° entre chaque image. Mickey n'offre que 7 images différentes pour un angle de balancier de 90°, soit 15° entre chaque image. La différence devrait être légère (on passe quand-même de 60 fps à 40 fps avec un rapport pareil), mais là où ça change tout, c'est que les angles de la corde elle-même sont discrets à 15° près avec Mickey, dû au fait du hardware 'par tiles' de la super NES. Du coup, les positions de Mickey deviennent elle-même discrètes (bien qu'il puisse remonter sa corde). 

Je me suis donc repenché là-dessus pendant mes p'tites vacances, à l'abri dans mon épave de bateau pirate et j'ai peut-être bien une solution. L'idée serait de compléter les deux modes d'animation actuels (l'un qui suit une ligne du temps, l'autre qui colle à une série de déplacements) pour faire un système dans lequel on va choisir d'avancer ou non dans l'animation selon le vecteur-déplacement actuel. En gros, je fais une animation dans laquelle Bilou se balance autour de sa main et le moteur passera à l'image suivante quand Bilou va dans la même direction que celle suivie par cette image dans l'animation.

The summer idea about it was to handle that with a new way of playing back an animation: rather than enforcing a delay between two frames or a specific motion, we would compare the in-game speed vector (xg, yg) against inter-frame motion vectors (xa, ya). You'd then step to the next frame in the animation only if (xg, yg) is "beyond" the expected motion to the next frame. A bit of maths done in a sandbox (literally) shown that we can tell that just by two integer multiplications per frame. It will need separate animation for swing-to-the-left and swing-to-the-right, but I'm perfectly fine with that.

Mais comment savoir si un vecteur effectif (xg, yg) est plus proche de l'ancien vecteur de l'animation (xa, ya) ou de celui de l'étape suivante (xa', ya') ? Je suis parti de mon vieux cours d'analyse math avec "l'extrémité du nouveau vecteur (xg, yg) doit être au-dessus de la droite définie par k*xa' = k*ya' (que l'on peut réécrire y = (ya' / xa') * x). Mathématiquement parlant, on sera au-dessus si yg > ya' / xa' * xg. Programmatiquement parlant, c'est moins drôle, à cause des divisions par zéro dans les verticales et du manque de précision des divisions / multiplications quand on se contente de travailler avec des nombres entiers. J'ai donc voulu ruser et faire un peu d'algèbre pour passer à yg * xa' > ya' * xg, qui ne fait que des nombres plus grands que 1. En fait, je venais de retomber sur l'expression de l'aire signée d'un triangle, bon vieux truc du cours d'algo II à l'unif (merci, feu PAdM). ça tombe bien: elle sert justement à calculer si un point est à gauche ou à droite d'un vecteur donné.

Il faudra vérifier expérimentalement si je dois modifier le sens de l'inégalité pour le balancier-retour, trouver un moyen d'intégrer ça au scripts (probablement avec un 'speedmove' comme on a déjà un 'selfmove'). La bonne nouvelle, c'est que le même système pourrait probablement marcher aussi pour une voiture vue du haut, des segments de lianes qui se balancent et segments de ponts qui s'inclinent :-P

extra bonus with the anim.x * gob.y > anim.y * gob.x expression, is that a faster motion (e.g. longer rope) or a slower motion (e.g. shorter rope) will not affect things, because it would affect both gob.x and gob.y by an identical factor k and thus their effects will compensate in the comparison.

Saturday, January 28, 2023

How it is bashing

Mon agenda étant en vadrouille le week-end dernier, je suis retombé sur mon cahier bleu, celui qui se concentre sur le game design de Bilou's Dreamland. De page en page, je reviens en arrière dans le temps ... je fais une pause sur la révision du niveau de Rémi, toujours en attente avec ses nombreux bangbash, puis tout naturellement, je tombe sur la page dédiée à Bangbash

Et il se trouve que quelque jours plus tard, ma fée m'a retrouvé du temps, alors j'ai attrapé ma DS et j'ai essayé de reproduire sur une grille de 32x32 les mouvements que j'avais capturé sur mon calepin.

I couldn't find my agenda, last week-end, but I did flip the pages of my blue design notebook ... I stopped on Remi's level thoughts and from there, to that page where I wrote down decisions about how to make BangBash come back. The next day, my fairy gave me some time and my Lime DS was sitting near, with a battery ready. So I opened the school zone file and tried to sketch some of the BangBash poses I had drawn in the notebook.

So here's what I've got so far. one idle animation, one jump split into prime/apex/landing sub-animations and one front smash that is Bangbash's signature move. That one could use one or two extra frames, and I'll have to draw the eyeslids directly over some of the frames to better slant with the move (and have one sprite free for the mouth ?), but I'm pretty satisfied of how it came so far.

Voilà ce que ça donne après le montage de quelques animations dans AnimEDS. Il y a encore un peu de détails à peaufiner, mais je crois qu'on peut dire que l'un dans l'autre, les animations marchent plutôt bien et qu'on peut effectivement s'en tirer sans avoir besoin de 3D. Peut-être même sans rotations. (bon, entre-autres parce que je laisse tomber l'attaque tournoyante du design originel)

Friday, March 11, 2022

Animating the Undead Cell

 

I admit one of the reason for playing Epic Mickey again was to see how they had dealt with the sands and desert things in the Agrabah level, but I was far from imaginating that it would unlock my animation issue for the UndeadCell. One of the ennemies we face in the game is a mushroom species that has level-themed variation.

J'avoue: une des raisons pour lesquelles j'ai rejoué à Epic Mickey, c'est parce que j'ai réalisé qu'il y avait là la meilleure version graphique de l'univers d'Aladdin, tout en sable fluide et pierres jaunes. Quoi de mieux comme source d'inspiration pour ma pyramide bilouteuse ? Mais je ne m'attendais pas à ce que ce soit le champi-turban qui me serve le plus de source d'inspiration.

Conveniently enough, the sprite table was available on the Spriter resource, but let's be clear: if you can rebuild the animation from the sheet, you're the original animator. But at least, there was one thing I could extract from it: the sine motion for the pot of the character and the fact that the 'hat' more or less follows the slope of the sine. Colors for the turban are h30s18v99, h31s40v87, h27s51v75, h29s60v62, h25s59v55, just in case I wouldn't be satisfied with the current ones.

So I tried to sketch that and it looked nice on paper. I redrawn it in my SpriteEditor and it looked interesting (although I couldn't loop 'walking' animations properly). Getting it to work in AnimEditor was a bit harder: you can lock a sprite in the world while you're animating the rest, but the undead cell has no thing such as a foot that could be locked and moved backwards (pushing the rest of the character forward) like dumblador had.

C'est que, voyez-vous, l'animation actuelle de la pile-momie est tellement peu concluante que je ne l'ai toujours pas intégrée dans le niveau-test. Mais ce champi mélange pixel art et technique d'animation "cartoon-ancestrale" qui me montre la voie à suivre. Je gribouille donc une sinusoïde qui servira de repère. Je note que dans leur animation, l'orientation et l'étirement du chapeau suit la pente de cette sinusoïde. Je fais de même.

Il y a encore une 'pose iconique' dont je veux m'inspirer: cette manière dont le personnage fait une courbe montante au moment de se redresser. Comme s'il se déplaçait en utilisant le poids de sa coiffe qu'il laisse d'abord tomber vers l'avant puis qu'il doit courir pour la redresser telle la pile de livre de Lagaffe.

Hopefully, while animating in SEDS, I made the character actually move within its 32x32 frame. Part of why it moves now is because I kept that, but scrolled the frame backwards so that the eye always remained at the same spot within the bounding box.


So here it is, in a "how it started / how it is going" sort of animation (from a file beamed before I could fix the forward motion). As you can see, it still need to be significantly polished, and I got barely any time to work on it this week, as my kid had to finish a show-and-tell for school.

ça me fait pas loin de 11 étapes d'animation pour la pile qui avance. de 32x32 chacune, mais bon j'ai 256K de sprites à ma disposition... ce serait dommage de faire le gripsou et ne pas en profiter à ce stade-ci.

J'ai du chipoter un peu pour trouver comment adapter le mécanisme de 'verrouillage de sprite' qui avait bien marché pour dumblador sur un personnage qui ici n'a pas de pied. Est-ce la bonne vitesse ? Bah, dans le pire des cas, je la mettrai sur du sable qui coule, et ça justifiera une vitesse plus élevée, hein ;) La voir revenir en arrière dans les premiers temps de son développement m'a donné l'idée que la vitesse d'écoulement du sable devrait être telle qu'elle reste immobile à contre-courant.

edit: ouaip. C'est bien beau tout ça, mais une animation qui "marche" dans AnimEDS n'équivaut pas forcément à une animation qui marche dans le jeu. En particulier, l'éditeur joue en réalité l'animation à la vitesse indiquée, forçant le déplacement correspondant. Le moteur de jeu, au contraire, asservit l'animation au déplacement. Ce qui donne ici une pile qui reste immobile un long moment puis joue presque toutes ses frames d'un coup parce que j'ai abusé du 'mov#1' et du 'mov#0' (enfin, je crois).

Sunday, February 06, 2022

tuning de branche ...

Ben ça aura été une semaine de gros débugging pour ... pas grand-chose au final. Enfin, la bonne nouvelle c'est que la branche rebondissante a bien évolué. On avait quelque-chose de peu logique le mois dernier, là, j'ai repris le contrôle.

Le premier truc, c'était de re-définir le timing des interactions entre la branche et Bilou: quand on tombe dessus, la branche s'abaisse d'abord, puis nous envoie vers le haut. Evidemment, c'est seulement pendant la phase "remontante" de l'animation de la branche qu'on a envie qu'elle puisse propulser Bilou.

Il y a déjà (et depuis longtemps) ce qu'il faut pour ça dans AnimEDS, mais j'avoue qu'au moment de créer l'animation, j'avais un peu oublié comment ça marchait. En fait, au moment où on active le mode 'box', la ligne du temps en bas l'écran permet d'indiquer dans quelles frames la boîte est active.

A week spent in debugging because I had forgotten how my tools define over what part of the animation a collision box is active. I had also forgotten that the same keyword 'area' describes the sensitive-and-passive role of a collision for 'sprites' and the offensive-and-active role for special blocks.

Well, at least, it's almost clean now. I should be able to build a new demo version next week-end. But first, I will have to make a check list of the things that are still a bit weird in the current state.

Mais quand j'ai voulu faire les essais avec cette nouvelle animation, plus rien ne marchait. Enfin, la branche détectait l'arrivée de Bilou, provoquait un rebond et activait son animation, mais impossible de se faire projeter en l'air.

Tout ça parce que j'ai mélangé deux mots-clés dans la définition des blocs interactifs (dont la gomme-qui-rebondit qui a servi de modèle à la branche): dans les définitions de machines d'état, area introduit une zone sensible (et passive) pour les collisions alors que test introduit une zone offensive (et active). Pour les blocs spéciaux, il y a un seul mot-clé -- area -- mais il définit une zone offensive. Je l'avais oublié. Du coup, j'ai passé les soirées en mode 'guru meditation' ... pour rien.

Je ferais bien une nouvelle démo pour fêter ça, mais il y a deux ou trois trucs louches aux entournures ... je vais repasser par la case "faire une todo list", donc.

I did some playtesting with J.L.N and *deline ... They mostly wouldn't fall off the branch (I made sure that one wouldn't happen too often), but it wasn't obvious to them how to make big jumps. The thing is you don't need to press JUMP when stomping the branch, but *when it throws you back*. Maybe I should trigger a 'super-throw-back' if player hit JUMP when stomping ? so you don't have to bother too much about bumper timings in level 1 ?

Wednesday, January 26, 2022

à l'eau ?

J'imagine que ça devait être la prochaine chose à faire: s'assurer que Bilou sache rentrer dans l'eau et que les mouvements quand il s'y trouve soient différents de ceux dans l'air. C'est encore assez primitif, mais ça commence à marcher.

Let's dive in: the last demo was nice, but it sure felt awkward to have the water behave as a solid platform. I suppose it's a mandatory to-do item before I release something new: make sure the water feels more like water. It will be perfectible, of course. I don't intend to make it look more like water at this iteration, but at least ensure that I can detect when Bilou is entering water and make him act differently. And that is slowly getting in shape... 

J'ai finalement pris l'approche envisagée dans mes notes de l'an dernier (ou 2 ans ?): une bande de tiles haute comme Bilou qui autorise à la fois de tomber et de nager. La surface est dessinée à peu près à mi-hauteur de cette bande.

Du coup, quand Bilou rencontre enfin de "l'eau profonde" dans laquelle il n'est plus possible de tomber, il est déjà capable de nager là où il se trouve.

ça ne fonctionnerait pas aussi facilement avec un personnage plus gros comme ce poisson, mais on y est pas encore, au gros poisson (je n'en ai même pas dans mes cartons pour 'Dreamland', alors ...)

trivia: the animated gif above is about 100KB. The one I initially captured was over 1.5MB due to scrolling. I had to create a 'dontmove.cmd' object and give it the focus so I could capture the proper sequence. If you look carefully above the water surface, you can spot it.

There's one thing I'd like to get fixed soon: when you reach back the surface, you're stopped straight. That should not happen, but I do not seem to be able to fix it with a transition. This is a job for a revived "muad-debugging" session: it would let me see step by step why no transition is taken by re-playing the think() function after I detected yspeed == 0.

edit: I'll have to write a dedicated 'in-water' controller: hacking with 'increase' and 'freemove' doesn't produce anything convincing even after freemove is fixed so that it fails at the surface.

Tuesday, December 14, 2021

And after all ... here's my waterfall

After almost 3 weeks of quarantine, I knew I was going to see my brother again. He stated the new 'release' looked fine, and I wanted him to see the animated version I had in mind. So I did my best to get that done by the end of the week, although this is hardly of any emergency in the not-yet-written list of things to fix in that build. I mean, yeah, the water is more convincing if the falls flow, but we can walk on it anyway, so ...

Premier changement par rapport à la démo téléchargeable: animer la cascade. Ouais, je sais c'est clairement pas le truc le plus prioritaire, mais c'est un projet-hobby, donc la priorité, ça doit rester de se faire plaisir. En plus, je tenais un créneau pour montrer ça à mon frangin, alors autant lui en mettre carrément plein la vue, non ?

I wanted the waterfall not to look like a simple scrolled tile, so instead I scrolled two layers independently, at different speeds. Yeah, I know this is quite cheap. Well, I also gave 'noise' variations in the frames of the fore layer and I intend to add 'wavy' animation to the back layer. That produced something I'm proud of, even though it's far from being perfect. It also has the bonus advantage that I can make characters looks 'in the water' by being between the two layers ^_^.

Comment éviter que la cascade n'ait l'air d'un tapis roulant bleu ? Ma p'tite idée était de jouer sur deux plan, avec deux vitesses de scrolling différentes et deux niveaux de détails différents. à l'avant, c'est "haute fréquence" et vitesse de chute élevée. A l'arrière, "basse fréquence" de détails et vitesse faible. Mais un cycle de 16 pixels pour la face avant, c'était trop court par rapport à l'effet désiré.Qu'à celà ne tienne: il me faut de toutes façons aussi un "pied de chute" où l'eau mousse. Si je garde la mousse sur le demi-bloc du bas, je peux utiliser le demi-bloc du haut pour avoir un cycle de 24 pixels de haut et un pied de 8 sans que le moteur d'animation par blocs de 16x16 n'y trouve à redire.

Les bords, eux, n'existent que dans la face arrière, y compris le dessus de la cascade. ça me fait 45 kB/s à streamer entre la RAM et la VRAM, et la NDS donne l'impression de parfaitement tenir le coup. Pourtant, il se pourrait que j'introduise malgré tout du palette cycling pour la "couche de fond". Bin oui, la je n'ai que de l'eau qui tombe, mais je veux aussi de l'eau qui coule au sol et qui entraîne Bilou avec elle. Et pour la faire couler malgré un dénivelé doux, je vais soit devoir sortir des sprites, soit multiplier le nombre de blocs animés au-delà du raisonnable.

There's a catch remaining though. I have plans for flowing water *on the ground* too, including on sloped ground. With the current setup, I have used 6 animated tiles with 12 to 16 frames each. If I ever try to expand that to ground tiles, I'll quickly blow up my DS resources before I'm half-done with the game I intend to make. I might have to animate all but the foreground layer using palette cycling instead.

Monday, August 23, 2021

walking kritter

A large part of the 'walk' effort is to have characters' feet sticking on the ground while walking. It may not always be a good idea but I always grimace when I see walking characters half-sliding on the ground in games with no obvious reason. At least for monsters, it should almost never occur.

In my current engine, this is achieved by hints in the animation sequence about how much pixels the character would travel with the new frame. Animator code then ensures the game character has already accumulated that much 'deferred moves' before switching simultaneously to both the next frame and the next position.

Quand je fais marcher un personnage, j'aime généralement mieux qu'il soit bien ancré dans le sol. Ce n'est pas toujours forcément une bonne idée, mais les personnage qui donnent l'impression de patiner au lieu de marcher alors qu'ils ne portent pas de patins, ce n'est pas ma tasse de thé. Du coup, mon moteur de jeu est prévu pour des animations qui contiennent des indices sur le nombre de pixels (plutôt que de frames) à attendre entre deux images.

But checking the walk cycle for the 'Kritter' monster in DKC makes me realise that there might be an easier approach, in which the motion speed for the character is constant while its animation still features a 'natural' motion where it speeds up and down: just offset the monster graphics within the buffer. This might sound like advice from a nightmare from a one-hardware-sprite-per-object point of view, where pixels would have to be effectively shifted in video memory to accomodate for the partly-moved object, but for a SNES-like sprite that re-codes the relative OAMs positions with every frame anyway, it could be nice to have.

Now there's a catch: the hitbox for your character will move at constant speed and your graphics will not. That might be source of other (Infogramesque) collision issues.

ça a aussi l'avantage de fonctionner avec des cycles de marche qui ne sont pas uniformes. Les boîteux, les excessifs, les discrets ... toutes catégories de personnages qui viendraient sans problème peupler l'univers de Bilou. Et où regarder après un exemple de ce genre de persos mieux que dans la série Donkey Kong Country ?

J'avais donc repris l'animation d'un Kritter et choisi un point de référence qui devrait rester ancré au sol (un orteil) pour voir comment il se déplaçait de frame en frame. Chose assez intéressante: on est souvent autour de la même valeur de 5 pixels par frame d'animation, mais pas tout le temps. Et vu les faibles déviations, vu aussi que l'image doit de toutes façon être reconstituée à partir de plusieurs sprites hardware, on pourrait probablement ici avoir un game object qui avance à vitesse constante et avoir un léger décalage sur la gauche ou la droite de l'image par rapport à la hitbox. Attention quand-même à ne pas pousser ça trop loin sous peine de créer des situations infogramesques.

Friday, June 11, 2021

Running like Mario

I had my 'Mario Story' book in hands again a few weeks ago and met a quote that I wasn't expecting from Miyamoto-sensei. He was explaining that Mario's walk/run cycles deliberately not match the speed at which they move on the ground. I'd have expected it to be linked to the first Mario Bros game where "ground is slippy", but actually, the ground truth is that if they tried to make Mario's feet stick to the ground like a lemming, controls feel less responsive and gameplay isn't that fun.

Yes. You read it well. Mario's frantic feet speed and instant flip may make him feel slipping, but at least he's instantaneously responding to our controls, unlike some Prince I wouldn't name. And unlike my own character, to some extent.

Amusing timing, somewhat later, I discover 'New Super Mario Land', a homebrew title trying to rebuild Super Mario Land (GB) for SNES using graphics from New Super Mario Bros and a custom engine.

Eh bin, y'a des gars qui sont passés maîtres dans l'art de mettre une ROM pour SNES dans la cartouche d'une autre. Et ils ne se limitent pas à en profiter pour avoir une version 'hardware' d'un jeu introuvable plutôt qu'une énième copie d'un nanard à grand tirage. Non: ils peuvent aussi décider de faire ça avec un mod d'un jeu existant (disons Secret of Mana II traduit en Anglais ou Kaizo Mario World), une ROM homebrew comme le dernier titre d'Alekmaul ou en l'occurence, un remake de Super Mario Land avec des graphismes tirés de New Super Mario Bros.

And Nagler-- the homebrew author -- did what Nintendon't: they adjusted animation speed to the pixels
Mario travels. It's tricky to to say anything about the feel without playing it ourselves, but from the look of it, it definitely seems heavier to control than our usual mustachied plumber.

So finally, I'm pretty glad on only used the 'stick-to-the-ground' for walking and went for a more Mario-styled dont-care-the-ground for the run cycle. Still, I prefer Bilou's bending feet over Mario/Kirby 3D models with feet that hit the ground at weird angles, unaffected as if they were walking __through__ the ground instead of __on__ it.
Nagler, à qui on doit ce homebrew, a repris les étapes d'animations de Mario telles qu'on les trouve dans la version NDS mais a recodé toute la partie 'moteur de jeu', et en partie 'quelle image jouer à quel moment'. On aurait pu trouver meilleure illustration du choix de Miyamoto-sensei rapporté dans l'Histoire de Mario (p. 240)

Lors du développement de Popeye, il avait d'abord tenté de reproduire les gestes du marin en calquant le dessin animé image par image, mais le rendu [...] ne convenait pas au rythme frénétique d'un jeu vidéo. Plutôt que de modifier son allure, Miyamoto décide d'accélérer le mouvement des jambes sans toucher à la vitesse.

 Tout l'inverse de ce que j'ai cherché à faire avec la marche de Bilou, en fait. Heureusement j'ai changé d'approche pour la course.

edit: eh bien par contre, si on fait bouger les jambes trop lentement plutôt que trop vite, ça donne vraiment des résultats peu convaincants (vidéo de Aer où l'animation de la course est jouée au ralenti par rapport à la vitesse de déplacement).

Monday, October 15, 2018

Bug Punch

I have one last bug (hopefully) to fix in School Rush: with the latest builds, there is an unexpected additional Bilou head showing in addition to the big punch, and stays until the “shot sprite” takes over the regular animation..

Doing some more testing, it appears that the latest unaffected build is last year’s “xmas” release. It could be something that went wrong with the refactoring, or it could be an accidental modification of the site sheet itself.

Ce n'est pas si inhabituel de voir des têtes de Bilou partout, quand mon moteur de jeu buggue, et il a remis ça. La release-de-Noël est la dernière à ne pas en soufrir. Erreur de refactoring ? modification accidentelle de la spritesheet ? A moins que ça ne soit lié à la manière dont je gère les sprites "invisibles". Il faudra vraiment que je me rajoute une commande pour ça dans les animations.

A look at the source shows that I implemented an “invisible” sprite by not picking any sprite until the 6th frame. This isn’t clean and chances are that I was exploiting some undefined behaviour. I should definitely have a dedicated command that hides the sprite through the animation that works whatever the contents of the sprite page.

Well at last, in the refactored code, there is a clean INVALID_BLOCKNO value that is set to the frame number as the GOB is created. All I need now is to make sure the sprite remains hidden until we give it another value.

edit: likely the root cause is that I just used unassigned page entry to have a transparent image. Of course, if I accidentally add an image to that page, things that once were transparent might no longer be transparent.

Friday, March 30, 2018

Aladdin Sources Analysis

They made a wonderful job at gamehistory.org, based on an in-depth analysis of the sources of the Mega-drive game "Aladdin". The game was made by David Perry's team who also brought us Cool Spot. At the core of their work is a technique and a toolset to allow more flexibility in animating graphics on 16-bits system that had read/write video memory on-board (as opposed to NES with read-only video memory alone, on the cartridge) and fixed-size sprites (e.g. 16x16, 16x32, 32x32).

https://gamehistory.org/aladdin-source-code/#sect_36Everything else will seem silly to you if you do not accept that, by then, getting more KB of memory for your game was very - very - hard. The size of your game was decided by non-technical people based on how much the console vendor would charge for a 2Mbit chip, when the game should came out and how much kids would be allowed to spend given which license you'd be using. So they have early planning deciding how much to dedicate to sprites, levels, code, maps, etc. Based on that, they'll decide how much levels there will be in the game, etc.

Of course, game characters animation all started by having characters whose size fit the hardware requirements (mario nicely stands within a 16x16 box and a 16x16 mushroom makes him 16x32), flipping from one sprite to another within an all-in-VRAM bank. Then some special characters (the hero) would get a special status and only get one or two VRAM slots dynamically updated. To crunch more animation frames, one could use run-length-encoding compression that does wonders on row of pixels of identical color. Others have used 2/3-bit-to-4-bit decompression once realizing that Link sprite (and all others) only need 8 colors per palette, not 16. But all this requires CPU, and the CPU resources too, were limited (Not even 8MHz. Less than my good old 80386).


If we could instead keep the same binary format between the ROM and the RAM, having the right picture in video memory at the right time is all a matter of "blasting" them through the Direct Memory Access chip. See that big line on my notes ? that's the DMA doing its job, while the CPU can focus on crunching numbers to make the game physics stunning and fun...

To make that possible with fun stretch-and-squash, cartoon-like animation, they ultimately relied on their chopper tool that cuts pictures into hardware-sized sprites. Just like the one I imagined for Titus's Prehistorik II sprites.

Ok, granted, it doesn't look completely automated. But the idea is clearly there. And ultimately, it would run on a system that has 1/4 of the power of my Nintendo DS.

So, am I allowed to dream of porting some libgeds game on 16-bit engines ? Well, with the engine refactoring that splits script parsing, it is pretty tempting to see what we could do about it.


Let's start with the animations, thus. What is weird with the animations is that their code has to interrupt every here and there when there is some delay. In high-level language, we'd likely use a switch construct branching you to frame T or frame T+1 code depending on some argument we'd pass to the function. But if we're generating machine code instead, we can do much better. We can then have the actual next animation instruction remembered, rather than an index into an array of virtual instructions. No more conditionals and branch delays on that non-speculating old CPU. Just one jump.

Implementing "keep that state for N screen refreshes" is then looking a lot like software multi-threading: you have a call to some yield_animation micro-routine (and saving your current position into the generated animation code on the stack), which will pop that resume position into some CPU register (an internal scratch variable, in case you didn't know yet), and then return to the code that called animate_aladdin, letting it save the next animation position where it sees fit. Looping animation ? super-easy ! Have you seen how much boilerplate the current virtual-RISC-processor-for-animations of libgeds and AnimEDS must deal with instead ?


What else ? State machine of course. State machines are built with simple expressions used either to guard transition (only let them used when some condition is met) or to define what to do when the transition occur (besides changing states, that is, like playing a sound, changing speed, etc).

The collision system currently will follow a list of GobExpressions calling eval(guard_predicate) until one returns true, then proceeding with eval(action) and changing state. Instead, with generated machine code, that would all be packed into a sequence of predicate code that branch to the appropriate action code or keep testing until we hit the "okay, then nothing happens" terminator that returns to the collision system itself.

One day ... maybe. That would be much more interesting on 16-bit than it would be on DS or native x86_64 code, anyway.

edit: for more background information about how things actually came into existence, seeing tools and teams in action, don't miss the excellent "Splash Wave" episode on the game.
 

Friday, March 09, 2018

libgeds Animator system

Je pensais réécrire une partie du système d'animation. Il est inspiré d'un gestionnaire d'évènement à retardements pour systèmes d'exploitations. Sauf que dans le cas des sprites dans libgeds, à peu près tout est exécuté à chaque image. Ne serait-ce que parce qu'il me faut compenser les mouvements de la caméra.

I had somehow convinced myself that the animation scheduler system of libgeds needed a rewrite, that scanning through the list of animators to push new content in the middle everytime some new object was shot was a mistake, and that everything would work better, faster and stronger if I had a list of 'play every frame" in addition to the current list of "play when delay expires". But actually, the insertion policy is somewhat different: we insert _before_ any item that has the same delay, therefore making most in-game insertion as trivial as 'insert at the head of the list'.

Je craignais qu'il y ait régulièrement des éléments qui doivent inutilement être placés en bout de file d'attente parce qu'il y a de nombreux autres sprites à animer, et tous avec le même délai. Mais en fait, il n'y a pas besoin de modification. A cause d'un tout petit détail dans sa définition "place a après tous les animés qui ont un délai strictement inférieur". Donc tous les éléments qui ont le délai minimum (les objets et personnages du jeu) seront placés en tête de liste, temps d'exécution minimum aussi.

Friday, May 26, 2017

SaturdayScreenshot

Et voilà. J'ai un petit effet sympa pour attirer l'attention sur les boules bleues redonnant de l'énergie au joueur. Ça aura été un peu de chipotage pour intégrer les nouvelles animations dans les 4 niveaux existants, par contre. Pour la suite, il va vraiment falloir que je veille à ce qu'on puisse inclure les déclarations de bloc spécial de la même façon qu'on inclut les machines d'état pour les personnages.

Demain, je pourrai mettre ça sur Twitter et participer au micro-évènement "postez un screenshot de votre jeu en cours de développement".

Don't you love that blinking effect on the healing bonus ? Not as hypnotic as bouncing on a pink eraser, but i'm quite satisfied with the result. I'll have some work to do to allow such things be used in multiple levels without having to rely on manual copy-and-pasting across multiple script files.

Monday, May 01, 2017

MapAnim : done

Once again, properly mapping the codebase before starting to program got a loong-delayed-feature added to the engine within an afternoon. The code was actually written bottom up, starting with the revision of the "clearblock" function up to the script parsing code. 

I love so much the new little bounces and stars, I couldn't play the game without them anymore :P

Et donc les voilà, ces petites étoiles qui accompagnent la disparition des bonus et cette gomme rebondissante que l'on me recommandait. Je vais bien vite me refaire une version de School Rush qui intègre tout ça, parce qu'on y prend terriblement vite goût ^_^

Le nouveau système me permet aussi d'affiner un peu le comportement de la gomme rebondissante: elle ne projette plus Bilou immédiatement en l'air: au départ, elle n'est qu'un détecteur et devient un rebondisseur uniquement avec la première étape d'animation. Du coup, ça permet au joueur de mieux ajuster ses mouvement avec ce qui se passe dans le jeu (enfin, je trouve). 

QuickLinks: implementation notes and early specification sketches

Saturday, April 29, 2017

Adding the MapAnim

 Allons-y donc pour l'ajout d'un nouveau type d'animations dans mon moteur de jeu: la modification du contenu de la map elle-même dans le temps. Jusqu'ici, c'était limité à "faire disparaître le bloc en (x,y)" ou "retire-lui ses propriétés, mais laisse-le visible" (pour les bonus cachés). ça peut marcher pour certaines choses, mais ça suppose que les éventuels effets liés à la disparition soient entièrement pris en charge par un sprite supplémentaire. Idéal si l'image doit quitter son emplacement (un morceau de pont qui tombe, un décompte des points qui monte, etc), celà dit.

Let's have one more way of animating things in my game engine. One that would be suited to special blocks, and that update the map content at a specific location over time. The only thing I could do so far would be to shoot a sprite-manipulating game object and make the block disappear. That's mostly appealing if you want a picture to move away, like broken bricks, falling logs and the like. 
The "BlockAnim", used to animate the ink, is not interactive and apply simultaneously to all the instances on screen. It can make SMW coins spin, but it cannot leave a trail of sprinkling sparkles behind.

Now, let's resume the coding, I'll keep you updated on the outcome. I already love the animation I designed last night for the bouncing erasers ^_^.

Il y avait aussi les "blockanims", qui permettraient par exemple de faire tourner les pièces de Super Mario World sur elles-même. On procède alors par une mise à jour de la mémoire "tiles" et toutes les instances de l'objet sont mises à jour simultanément sur l'image à l'écran.

Le nouveau "MapAnim", lui, correspond plutôt aux besoins pour faire bouger un buisson devant lequel on passe, mettre des petites étoiles là où il y avait un bonus, etc. Comme vous pouvez le constater sur les diagrames, le mécanisme qui permet de mettre à jour le niveau (les données gérées par la classe InfiniMap) n'est pas particulièrement simple. Il met en jeu une description de chaque type de bloc spécial (les BlockInfos) et un objet temporaire capturant "tel bloc à tel endroit" (le BlockArea) qui permet d'interagir avec le personnage (GameObject) qui vient de passer par là. C'est finalement InfiniMap lui-même qui procède à l'effacement sur base du résultat du test de collision. La seule bonne nouvelle, c'est que c'est assez souple pour permettre des (petites) portes, des bonus, des bumpers et même les guides invisibles qui font faire demi-tour aux encriers.


Thursday, April 27, 2017

pauvre Game Feel

Je n'ai pas de définition de "Game Feel" à proposer. C'est juste un mot pour parler de ce qui fait que le jeu semble attrayant, divertissant. Les petits nuages de fumée de Rayman, les bananes qui s'envolent vers le compteur de DKC, la pièce d'or qui bondit hors des blocs-question dès Super Mario Bros sur NES...

Toutes des choses dont mon School Rush est actuellement dépourvu, comme le faisait remarquer Romain Claude:

Après le feeling avec le jeu c'est une tonne de choses à soigner : les réglages des paramètres physiques, les animations, tous les petits détails de feedback à droite à gauche qui rendent le tout "rewardant" et jouissif. Pour le moment le jeu est assez dépourvu de tout ça. Les gommes rebondissantes par exemple, si elles étaient animées cela rendrait le rebond plus satisfaisant et plus clair sur le fait que cet objet réagit.
Et qui est repris également sur le forum "e-magination", même rien qu'en regardant les images d'accroche:
Ce serait chouette que les bonus affichent un petit effet quand on les récupère, selon moi, ce serait moins "tristoune"
 J'y ajouterais bien un peu de secousse de caméra quand on donne un coup de poing au sol, si jeu peux.

It seems like people have dedicated the words "game feel" for all those little details that make a videogame feel more alive and reacting to player's actions. Dust clouds, sparkles, bananas flying towards their counter and things alike. It is becoming a recurring comment on current School Rush that I lack such little animations that should provide important feedback and make the player smile. 

Unfortunately, I have considered them as unimportant for most of the development and I'm now near the limits of the current game engine, especially when it comes to new graphics for the sprites. Both eraser-bumpers and disappearing bonuses will thus have to be implemented that patching the tilemap according to some animation commands ... something for which I haven't got code for. So far, the closest I had was pushing new graphics into the sprite/tilesets, which animates all the instances simultaneously.

Pour les bonus et les gommes animées, par contre, ça demande d'ajouter au map elle-même (et pas le remplacement des images du tileset comme c'est le cas pour les animations non-interactives : l'encre, les pommes qui se balancent dans la Green Zone, etc). J'avais pensé un temps m'en sortir avec un sprite temporaire, mais ma planche de sprite est trop remplie pour que ça puisse passer.
Je vais donc devoir rajouter au moteur de jeu un composant que j'ai retardé depuis probablement trop longtemps: l'animation d'un objet par manipulation du contenu de la map elle-même.