Friday, July 13, 2018

whipseey

A lovely setting, charming character, platforming action in pixel art, and above all, a "whip/ninja rope" mechanics I'm in love with since Fury of the Furries and Mickey Magical Quest. You bet I'm following @whipseey in his quest recovering the Lost Atlas ^_^. And the fact it is drawing inspiration from the legendary Mr. Gimmick is just the perfect spice to complete the gift.

Yet, while watching I realised that one of the sceneries had an issue that also existed in Bilou School Rush and that was pointed out by Kirby Kid when he gave feedback on the early version of the game: one-block-wide pillars. For the untrained player, these will put strong stress on the player's knowledge of the game engine's intimacy, like how much exactly gravity and momentum there is, so that one can land her favourite pink avatar on such a tiny spot.

One think I like to do on Twitter is to dream how I'd approach those short video  sequences myself. Preferably in the original character's abilities set, a bit like how Myamoto and his team decided to make Popeye be able to jump over barrels in the early prototypes of Donkey Kong as it was the most natural thing to do if it wasn't a videogame.

And what would be the most natural thing to do if you barely missed a jump to a pillar while carrying a magical yoyo/whip/rope thing ? Well I bet I'd try to wrap the rope around the pillar to be safe again.

That in turn raised the question of "how would I do such a thing for Bilou in my own engine?"  Should the 'whip' be an extension of the player's gob (that is, the internal software element ruling the sprite's behaviour) or be a gob of its own ? Should the pillar be made of special tiles or would the whip-end object (if any) be able to detect a pattern of solid-but-small-enough area ? Both approaches would be valid in each question, but as you may have guessed from the way I ask (or read in the sketches), I'd rather opt for the second answers if I was immediately ready to introduce that ;-)



Tuesday, July 10, 2018

contretemps

Non, ce n'est pas juste de la procrastination, ni juste des hunger games, ni de la démotivation ni juste ma déclaration d'impôts. Pas même une diablite mundialesque.

C'est le fichier de l'été. Tendinite à soigner. La semaine dernière, tenir un crayon était une torture. ça va un peu mieux.

Friday, June 29, 2018

Grand nettoyage de printemps ?

Bon, j'ai presque fini avec la révision des "évènements" provenant des contrôleurs de comportement (juste encore un peu de cleanup). Les histoires de signe sont réglées, Bilou fait à nouveau ses pirouettes comme il faut... et oui, j'ai encore fait du débugging avec des p'tits dessins.

Le dernier sur la liste des "grands nettoyages de printemps" devrait être l'élimination de GobExpression::xcontext, et je devrais avoir quelques notes là-dedans sur mon boox.

Après ça, il sera temps de tourner la page (parce que ça devient limite trop long, comme "printemps") vers de nouvelles aventures. J'ai bien progressé dans les recherches sur l'évolution du langage de scripting. Suis-je prêt pour attaquer le "behaviour editor on DS" ?

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, June 22, 2018

deep blue InfiniMap

CommonMap revision changed the lookAt/scrollTo interface of background layers to take unsigned positions. After all, it shouldn't be possible to set the center of the screen into negative coordinates when the top-most corner is (0,0).

But I will need to keep internal computation of signed integers anyway. else I get blue meditation screens...

The core of the problem is that processors have two main way to understand numbers: one where the top bit of the number has no special meaning (we call them 'unsigned' numbers and they're all positive), and one where it tells whether the number is positive or negative (with some tweaks, and we call them 'signed' numbers). And among the operations the CPU can perform on number one behaves very differently on signed and unsigned numbers: division. Divide an unsigned number by two, and you'll always have to insert a zero in the top bit. Divide a signed number by two and the top bit remains sticky.

If you mess with the numbers signedness (issue unsigned operations when you should have used signed operations) and you may easily turn a small, negative number into a big, positive number during a division. That's what I did with my update ... this is what I have to fix now... hmm... tomorrow. It's time I give my eyes and brain some rest.

once upon a skunny

Ok, il y a les jeux qui vous motivent à les imiter, puis il y a les jeux qui vous motivent à faire mieux qu'eux pour prouver que c'est faisable. D'aussi loin que ça remonte, Skunny in the Wild West appartient à cette deuxième catégorie. Alors qu'on rêvait de pouvoir faire nos preuves sur Super Nintendo dans Bubsy, mon frangin ramène une diskette du supermarché avec la version shareware de Skunny. Une sorte de Mr Nutz pour PC ?

côté graphismes, Skunny nous démontre par l'absurde l'importance de la cohérence du style au sein d'un jeu. Un grand nombre des principes que je me suis juré de suivre du point de vue du pixel art vienne d'une négation de ce qui se passait dans ce jeu
- Tu ne numérisera pas des photos pour mettre dans ton jeu
- tu n'utilisera pas des lignes noires pour le contour de tes personnages.
- tu n'abusera pas des dégradés ni des tramages automatiques.

Rien que sur la séquence d'intro, Skunny fait tout l'inverse

Alors oui, ce dégradé pour le ciel est superbe. Et le canyon rend pas trop mal du tout pour du 256 couleurs. L'ennui, c'est que ça ne correspond absolument pas aux personnages ni au terrain du jeu. Exactement comme si vous preniez les playmobils des gamins et que vous les mettiez devant la peinture à l'huile de mamy pour tourner un mini-film avec des arbres en pâte à modeler.

Les personnages aux lignes noires (qui tuent le contraste et les applatissent) donnent un effet grotesque et décalé, style "bip-bip et le coyote". Le jeu devrait donc être humoristique et pris au second degré. Mais le décor, lui, est réaliste et avec perspective et profondeur, ce qui induit une forme de dramatisme. Au final, le mélange a un goût d'artifice. Comme un tour de magie dont on verrait le truc.

Autre exemple, le sol suggère que le les plate-formes se rétrécissent sur les bords gauche et droite. Un peu comme si on était sur un de ces plateaux circulaires. Mais la partie "verticale" de ce même sol reste elle parfaitement plate, sans aucun effet de luminosité ou de torsion de la texture pour soutenir ce que suggère la partie horizontale.

Alors oui, quand Morris dessine son "Canyon Apache", il utilise de l'encre de chine noire pour les traits. Mais l'épaisseur de trait par rapport à la surface du personnage n'a rien avoir avec du pixel art en 320x200. Et il n'a pas non plus besoin de faire de l'anti-aliasing. D'ailleurs, si on zoome sur une des cases de la BD, on se rend compte que les traits ne sont plus noirs, une fois la numérisation accomplie. Ils se sont mélangés avec la couleur de ce qu'ils entourent. Pour donner du brun le plus souvent. Et la résolution des sprites de skunny est 3 à 4 fois plus faible.

Je tente donc d'appliquer ça rapidement au screenshot de skunny. Et j'en profite pour essayer de corriger le dernier problème: l'équilibre entre le contraste de l'avant plan et de l'arrière plan. Les structures sur lesquelles ont doit se déplacer sont extrêmement délavées dans le jeu original, alors que le décor lui est dans des tonalités chaudes.

Or notre oeil à l'habitude que la distance "bleuisse" les choses et atténue les contraste. Il faudrait donc faire l'inverse: pousser le contraste et la saturation de l'avant-plan (et le ramener vers le rouge) tout en atténuant le contraste de l'arrière plan, diminuant également sa saturation en couleur (aller plus vers du pastel, quoi) et le décaler légèrement vers les bleus. Je n'ai pas touché au ciel lui-même: il est suffisamment en-dehors de la zone de jeu.

Et bien sûr, on s'abstient de faire pareil avec les masques gauche et droite. Ils avaient le gros défaut d'utiliser à peu près les même couleurs que le sol dans l'image originale, ce qui augmente encore la confusion.

Bon, ça ne sauverait pas le jeu dont le gameplay est infogramesque au possible (n'espérez pas ramasser plus d'une demi-douzaine de mouton lors de votre première partie), mais au moins on y verrait plus clair.

Bon, en dépit de tout ça, je dois reconnaître un sacré talent de programmation sur le moteur de jeu. Du scrolling parallaxe en 256 couleurs et fluide avec des sprites de cette taille-là, en 1994, j'aurais aimé en voir plus souvent. Et si la musique est répétitive, elle est présente et entraînante comme il se doit. Je ne peux pas m'empêcher de me demander ce que ça aurait donné si j'avais disposé de cette technologie pour réaliser Badman et Bilou... parce que le jeu est Belge! eh oui!

Saturday, June 16, 2018

iris mouse to the rescue

It is pretty handy to have the boox to draw sketches, but I don't find them as nice as the one I draw on paper. . Plus, when I'm using the boox to read the code, I can't update notes too. If I ever try, I'll have to face a near-minute swapping time every time.

So as I found the 'IRIScan Mouse' near my boarding gate, I just bought it. It's pretty funny. It's a hand-moved scanner (like the very first one I had) but fit into a mouse, and it can do both ... on Windows at least.

So it won't really make the USB printer/scanner obsolete at home, but it will certainly be helpful at the office. it has pretty nice rendering of my tiny handscript, avoids doing JPEG-by-default (afaik) and makes export of captured files pretty easy.

Or well, it should have been useful. Unfortunately, plugging the dongle into my Windows7 workstation didn't let me use the scanner feature. The mouse remains unreachable through the WiFi.

On my Linux laptop, all I see is a USB device with vendor ID 274f (Systech Electronics, according to dmesg) and product ID c001 (Zcan Wireless). no text identification of the device. The "mouse" feature does work, though. but I don't get an additional WiFi interface. So what is in the dongle exactly ? Some forum post suggests it is using the uvcvideo driver. It indeeds gets loaded. It doesn't seem like the USB device offers multiple

The dongle could be featuring just one NRF LU1P16 chip (there's one additional 1101GE marking), possibly made by NORDIC, although I couldn't find such a chip in their catalog.

But the original manufacturer's manual is clear:
Scan function requires Wi-Fi connection between computer and Zcan Wireless directly. Please add a Wi-Fi adapter (802.11 n is recommended) if Wi-Fi function is not available in your computer
my workstation at the office doesn't have any WiFi, and the dongle won't provide it. It also explains why scanning would fail on the office's laptop I've used so far when I had wifi enabled. When I'm actually connected to a network with my WiFi, the scanner can no longer reconfigure the WiFi interface to communicate with the mouse. Looks like I'll have to do some more shopping ...

Sunday, June 10, 2018

simplifying events engine

I want to get rid of some static pointers in the management of events. The idea turned cleaner as I was flying over Denmark. But the result isn't convincing yet.
- you can't jump out of inkjets anymore (event from dpad controller is ignored - apparently because TrackAttached produced an event too -- although it has no corresponding transitions)
- you might get pushed away from spongebops when you try to grab them -- weird things still occur here with my best solution for inkjets.
- if Bilou starts swimming up, he'll keep swimming up forever -- that's fixed with swapped-priorities
- the little stars shining around you when you pick a health bonus keep shining forever. -- seems fixed with swapped-priorities too.

The thing is, when I want to combine the "thoughts" of two controllers, only one events list can survive. And of course, things don't get fixed if I swap the order in which they are produced (unless I swap them properly, that is). Weird things remains with that swapped-priorities, though. Like why don't we play the 'roll-in-the-air' animation anymore when Bilou's direction is changed while jumping ? I'll have to re-activate InspectorWidget and use the combined powers of InspectorWidgets and DDD to find out.

By the way, did you know that we could have methods, operators overloading and constructors for unions ?

Friday, June 08, 2018

GameObject::useEvent() should go away.

https://sourceforge.net/p/dsgametools/hg/ci/refactory-engine/tree/libgeds/include/GameObject.h#l175
That shouldn't happen. The way controllers fire an event is not satisfying. A static pointer set by class X so that it is used by class Y with no restriction on who does what and that merely works because we know X calling ::useEvent() and Y checking *::doevents happens to take place with the right timing ? No.

I mean, look at the documentation: "assumes no re-entrance until gobRunController". That has turned false the minute I introduced 'attach-to-other-game-object' feature where you might have to run the object you're attached to before you can run yourself.

I'd like to convert {NONE, FAIL, EVENT}  enum into something else that allow "EVENT" to carry the list of transitions to check by itself.

Sunday, June 03, 2018

bubsy

I think I was 20 years younger the last time I need a SNES gamepad to press start on Bubsy title screen. After a month of training, I was able to reach world 4 and found a few 2"continues". I couldn't beat the level 3 last week-end, but at least I got the confirmation that Bubsy "claws encounters" is a fun game.

It might be the only fun thing made with that character (I do not expect much of Black Forrest's "woolies strike back"), it may have arguable pixel art, the tunes are catchy, the atmosphere is playful, the character is fun, and there is enough variety in the level design to keep us entertained.


It is clearly difficult and sometimes even frustrating without becoming utterly unfair or boring. As far as I've played it, it is challenging.


It is far from being a masterpiece in terms of game mechanics, though. The air control is sometimes a bit awkward, Packing precision, - and the "GLIDE" mechanics isn't always sufficient to save the day, But what really seem broken is what happen when you jump off a slope. First, you don't move purely upwards (if standing), but slightly backwards on a climbing slope. You'll have to compensate that with more air control. I've never seen that happening to any mammal in the real world, presumably because we feel the slope and compensate when jumping. But I can accept it: it makes sense from a pure physics perspective, and it echoes a similar mechanics in Sonic. What is broken is that if you then release the directions pad, you will find yourself pushed backwards again!

Saturday, May 19, 2018

Un p'tit bug?

Dans l'éditeur d'animation, dernière mouture ? Je m'explique, je voulais prendre quelques captures d'écran pour expliquer comment se faire un petit personnage à partir de "composants" simple, puisque la "branche tutoriel" sur github est maintenant capable de gérer aussi bien les personnages simples que composés.

Malheureusement, un des widgets (normalement sur la gauche) n'affiche plus rien. Particulièrement ennuyeux puis qu'il s'agit en fait de la "palette de composants" qui permet de sélectionner un pied, la tête, le corps, etc.

J'ai du louper quelque-chose lors du refactoring.



Doing some bug-hunting on AnimEditor so I could do a 'setup your compound character' tutorial for the github tutorials series. Some flat facts:
- the thumbnails are on the "sub" screen, the timeline and sprite pages preview are on the main screen.
- the 'limb table' is actually rendered, but only on BG3, which appears to be hidden.
- clicking limbs properly switch sprite pages
- clicking the sprite page does weird things with the cursor on the top (sub) screen.
Oddly enough, if the layer with limbs table is hidden, how comes we see the sprite page ?


Somehow, it looks like the widget I'm using to show what is selected when clicking on the sprite page was hard-wired to the sub-screen, instead of letting the window creating it telling which resource to use. That's easy to fix.

It also looks like AnimEditor didn't get its dedicated LayersConfig, and still use the default layers setup combined with some custom register programming. That doesn't help. And we still see the SpritePage because, unlike the limbs table, this one is truly made of sprites.

Finally, it looks like the 'limbs table' is initially empty. It only fills when I drop new sprites there. It should be pre-loaded with the animation's skeletton when I load an animation.

So, some more flat fact:
- in the old approach, fill_anim_thumbs_16() is the code that copies pixels from the spriteset into a spritesheet used by the limbsTable. Exactly one 'block' of data per limb.
- only other calling site fill_anim_thumbs_16() is AnimWindow::restore().

Q: do we still call fill_anim_thumbs_16() on FileWindow::event() ?
A: yes.

Q: what is the target spritesheet then ?
A: one pointing to main-screen background tiles.

Q: did loading an anim changed the limbs table in medsgama.nds ? 
A: no. Only "opening" the animation on the AnimWindow did. And it still does. With a spritesheet using some main-screen BG memory.

Friday, May 18, 2018

Tuto branch update.

A few weeks ago, I found myself pressing the direction pad of my DS to keep
that little character onscreen. It had the most basic behaviour could think of because its sole purpose was to demonstrate how we control things in my game engine. Somehow, it felt a bit like an empty level in Space Taxi.
today, that same character moves around a place that comes from the level editor, with blocking tiles effectively blocking you. What it misses is a target. Snake-like pellets, if you want.

That requires me to revise:
- collisions between Gobs
- counters
- in-game level changes.

Monday, April 30, 2018

Même pas peur

J.l.n a grandi. 5 ans maintenant. Il ne se contente plus de regarder papa raconter des Zelda comme si c'était un livre interactif. Il a envie de prendre la manette. Oh, bien sûr il a déjà un peu chipoté dans Rayman Origins ou New Super Mario Bros Wii, mais surtout en mode "bac à sable" ou en mode "ouhla, ça devient dur, j'me mets en bulle".

Son premier vrai jeu est donc Boing! Docomodake un petit jeu mignon qui m'avait été recommandé par Pierrick, à mi-chemin entre lemmings et Rick Dangerous à la sauce bisounours (comprenez, sans les pics qui sortent du sol, et sans que les lemmings n'avancent sans vous). Tout à fait adapté à son niveau, même si moi, perso, le jeu m'avait lassé très rapidement tellement tout était lent dedans.

Pourtant, niveau interactions, c'est assez riche. On bouge avec la croix, on fait apparaître des petits champignons qu'on déplace pour faire des ponts, des échelles, des contre-poids, etc. on bouge encore. On en ramasse pour les lancer sur les (rares) ennemis. Il avance pas trop mal.

Puis l'autre jour il fait un blocage "papa, il faut que tu tires sur la libellule". Papa gribouillait, il encourage le fiston à essayer lui-même "tu te prépares, tu vois, tu t'avances". Rien n'y fait. "mais j'ai peur"!

Et là, j'ai compris la grande puissance du jeu vidéo pour affronter ses peurs. "Regarde, le jeu il est là. Toi tu es ici. Tu es en sécurité: il ne peut rien arriver. Au pire, il y a des petits pixels qui vont un peu changer de couleur, mais tu ne risque rien. Allez, c'est l'occasion parfaite pour apprendre à être plus fort que ta peur".

Beaucoup plus difficile pour lui, par contre, c'est de faire face à la frustration quand il se rend compte qu'il a loupé un coffre (généralement en fin de niveau) et qu'il est impossible de faire marche arrière parce que le développeur a voulu que seul celui qui réfléchit et planifie puisse l'avoir. Là, au bout d'un quart d'heure de concentration pour passer tous les obstacles et récupérer les pièces d'or, ça peut facilement éclater en crise de pleurs qui confirmeront qu'il est temps de jouer à autre chose...

Sunday, April 29, 2018

definition files in geds3

The refactoring keeps going. I'm about to show the "load a map" feature, and then I'll have to show "how characters interact with the ground through properties".

Meanwhile, I'm digging what sort of additional definitions a "Behaviour Editor on DS" should read, and how that would be translated into .h files that convert the "level 2" scripts into plain "level 0 scripts" that can be parsed by the runtime engine on the DS. I'd allow e.g. BEDS to do more lookups in symbol tables while all symbols should normally be translated into values or expressions in level 0 when loading levels in a game.

Maybe you wonder "but what is level 1?" ... well, level 1 is what I'm doing right now with Bilou School Rush, with the C pre-processor expanding symbols for us so that I can write "$RUNLEFT->$RUNRIGHT on eDpad [D_RIGHT]" instead of "statl12->statr13 on event0 [v2 $20 &]".

Sunday, April 22, 2018

to $(AR) or not to $(AR)

During the preparation of the "controllers" tutorial, I faced a weird linking problem. I wanted to split the huge "controllers.cxx" file so that every controller would be in a sub-file that could be compiled separately and no longer depend on the code from other controllers unless there is a good reason for that. And all of suddens, I had no more factories registered.

Just before that, I had reviewed the factory registering system so that it was enough to just write "MomentumFactory mf("momentum");" as a top-level declaration to get everything up and running. But that meant there was no more reference from the main .o files of the game/demo that would require .o files with the factory code (and instance declaration), so they wouldn't be packed in, and certainly wouldn't be initialized either.

So I started thinking about weird mechanisms invoking bool pointers to dummy variables, or no-code functions, and even why not "UsingPlatformer" empty class that would extend UsingMomentum, UsingDpad and others... Then I realized that all this happened because the .o files (compilation output, that is. Equivalent of your *.OBJ if you're on MS-DOS) are packed into a static library and only pulled to populate the .NDS file on-demand at link-time. If instead I explicitly say "link Demo/*.o Controllers/*.o", they are put into the binary and no trick is needed anymore.

Wednesday, April 18, 2018

shell functions

For so long, I have been creating aliases for my shell. "dir" would be "ls -la" and things like that. TCSH even had ways to retrieve some attributes to the aliases. building 20 student programs and testing them would have merely required me to type N (for next), B (for build) and T (to launch simple tests). Do I need to fix something to better evaluate their program ? B again, then T again.

But it had its drawbacks, and it was pretty ugly to code. Nowadays, I'd do that with shell function instead. Rather than trying to rewrite the statement, it truly allows me to extract all the arguments (either separately or together) and then calling one or more commands

cl()
{
    color.pl $* | less -R
}


One last place here I used aliases is with the "quick cd" tool I use to keep my brain sane and my screen not-excessively-cluttered
#!/usr/bin/bash

export CITY=$(pwd)
echo "You are in the City. $CITY"
echo "You can set 4 locations. North, South, East and West."

alias setN='export NORTH=$(pwd)'
alias setW='export WEST=$(pwd)'
alias setE='export EAST=$(pwd)'
alias setS='export SOUTH=$(pwd)'
alias setC='export CITY=$(pwd)'

alias N='cd $NORTH'
alias S='cd $SOUTH'
alias E='cd $EAST'
alias W='cd $WEST'
alias C='cd $CITY'

And yes, it pretends that you're running an old-fashioned, text-based adventure game instead of crawling directories. Because i found it easier to thing of thinks as "west", "north", etc. rather than trying to remember what letter I used for "gstreamer" and what letter was for "alsa".

Saturday, April 14, 2018

Dear ImGUI,

I hope you enjoyed the week-end. It sure was a pleasure to have you around, and getting some pixels rendered without having to bother with ./configure, plugging events into sockets or any kind of new classes.

Sure, I wish you had time to stay for tea and I would have shown you my SpritePages, but I suppose that can be kept for another encounter. I'm pretty sure you and I are meant to meet each other pretty soon.

Everyone was amazed when you just returned "true" in the line of code that painted a new button. Imagine the face they'll have next time when we'll show them GobState representations live and pop up new windows as one explore the state machine...

Stay Safe,
/PypeBros.

PS: okay, the unit-tester requiring 32-bit (so that DS registers addresses are out of the .text segment) and SDL requiring 64-bit won't simplify early integration tests ... we'll find some workaround.

Monday, April 09, 2018

Tutorial revision goes on.

I reached the point where you can write very simple scripts and have them processed on the "tutorial" branch. Of course there isn't much follow-up at the moment despite the 3 forums on which I comment stuff. That doesn't really matter, although I'd love to get feedback on whether it reads well.

What is really interesting here is that it forces me to get rid of many odd things. Hopefully, that will lead to a code base that will be easier to extend. Things like "rules.gam", for instance.

Being busy reviewing the expressions system, for instance, make it obvious that some static array could be gone now that I have the gob collision structure. the "game counter al so cry for a refactoring out of the GameScript class. And making the 'guns/controllers' system easier to understand (esp. by automating the registration system) made it obvious that I need to re-think the way classes access the Camera object.

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.

Monday, March 19, 2018

Biggest Refactory Ever

For me, at least. I wanted to make the scripts occur as soon as possible in my tutorial series, since the GEDS engine is meant to allow game-making even for those who don't know about C++ programming. But I also want to be able to introduce a behaviour editor, which suggests that the same script-parsing logic should be able to drive either the game engine or the state machine model in the editor.

So this last week, I've been busy splitting the big singleton "GameScript" that had both the parsing logic and the engine intimacy into two classes, the ScriptParser that knows the language rules and the Game* objects well enough to create them but has no knowledge about the Nintendo DS resources or the game engine per se, and the GameScript, that knows about the engine's runtime, last as long as the level does, hold resources and the like.


ça bosse ferme ... restructuration du lecteur de scripts pour pouvoir introduire un éditeur de machines d'état ...

I've finally reached a point where all my automated tests work again. Of course, School Rush isn't running fine in this branch ... yet.

edit: Okay, SchoolRush runs fine again in the emulator. Just some un-initialized arrays. -Weffc++ should have caught that, though.

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.

Wednesday, March 07, 2018

libgeds tutorial

I have just started a github with one branch of the dsgametools project: the 'tutorials' branch, where I'm reconstructing and detailing step by step the components of the (refactored) game engine... together with Creative-Commons pictures and sounds to make demos on a regular basis.

Additional chatting and promotion of the tutorials happen in gbatemp and e-magination forums.


Cette fois-ci ça y est. J'ai transféré la branche "un tutoriel après l'autre" sur github. Pour que chacun puisse facilement suivre ma tentative de réécrire le moteur des jeux Bilou. Histoire que les différentes fonctions disponibles soient capturées clairement, et non pas éparpillées sur une demi-douzaine de patches.

On verra bien si ça intéresse du monde...

the mercurial-to-git conversion is performed by the fast-export tool from Frej. The process looks as follows:

cd hg2git/
cd dsgametools-hg/
# hg incoming -r $(hg id -b)
hg pull -r $(hg id -b)
cd ../tutorials-git/
../fast-export/hg-fast-export.sh -r ../dsgametools-hg
# git log
# git push --dry-run git@github.com:PypeBros/libgeds-tutorials.git
git push git@github.com:PypeBros/libgeds-tutorials.git
cd ..

Thursday, March 01, 2018

The "last" map

Allez, je me suis bricolé une dernière map pour School Rush: la récompense pour ceux qui seront parvenus à grimper jusqu'en haut du "niveau secret". Il y aura une présentation des monstres, bien sûr, mais aussi une petite surprise qui m'a pris du temps à mettre au point. Au niveau de l'idée, je veux dire.

I sketched up a last map for School Rush, that will be the final reward to players who beat the secret climbing challenge. It took me some time to nail down the idea I wanted to have, but I think all I have to do now is some pixels and some scripting. And making sure I can restrict the part of the level that the camera can show. I'll have to keep the todo list off-line, though so that you have a real surprise ;-).

Côté réalisation, je vais avoir besoin, pour la première fois, de restreindre les mouvements de la caméra. Il me faudra aussi une petite variante de la gomme, quelques graphismes sur tableau vert et un mode "calmos" pour les encriers... Pas facile de se faire une todo liste pour un truc qui doit rester secret >_<

__lock_jiffies

Perdu dans un petit coin d'un driver Linux, une fonction sympa qui augmente un des verrous avec un chronomètre ... histoire de voir combien de temps on est resté en section critique.

Je devrais peut-être bien ajouter quelque-chose de ce genre avec parseLine() dans GameScript, tiens.

Tuesday, February 20, 2018

Ideas for a handwriting recognition on DS


Il y a un moment que je retourne l'idée dans ma tête : un système permettant d'écrire librement (du code, pour l'éditeur de comportements) sur DS. Le système serait basé sur une grille 3x5 visible par l'utilisateur. Parce que les claviers virtuels, c'est pénible et qu'un système qui autorise l'utilisateur à écrire n'importe où et n'importe comment, ça n'aura aucune chance de marcher avec 66MHz


That is another idea that has been laying on paper for a while. I lack text and script editors at the NDS.  I don't want to go for a virtual keyboard, because they are really too slow to work with. I can't afford a complex recognition system, and even Google's handwriting system would suck on code expressions.


But I feel like it would be easy to recognize letters when they have been written on a grid. A bit like if we were painting a low-resolution font.


Every letter drawn corresponds to a 15-bit map that can be quickly tested against a small database of features and suggest letters to pick when the decision is fuzzy.

 Additional features could be the starting and terminating coordinates, as well as the number of strokes.

Cette petite grille fait que chaque lettre tracée correspond à un code sur 16 bits unique. A partir de ce code, on pourrait rapidement identifier un groupe d'entrées dans une petite base de données qui traduit les traîts en lettre (p.ex. à partir de la position du point d'origine et du nombre de traits). Je ne veux pas me limiter aux lettres, évidemment. L'idée est de reconnaître l'ensemble des caractères ASCII pour pouvoir éditer du code n'importe où le plus facilement possible. 

I hope the result will be an interesting compromise between
- early PDA "one-weird-stroke-to-write-them- all" (Palm's Graffiti system)
- sharp Zaurus "Free-letters-one-by-one"
- OCR from scanned text.


I know segmenting is a complex task in letters recognition. With pre-drawn grids, the user is guided to start a new segment or stay in the current one. We can also tell apart uppercase and lowercase Eg. "p", punctuations, etc. locally rather having to rely on some line-level calibration. And we can naturally move to the next space for the next letter.



Avec cette grille, je m'affranchis d'un des problèmes les plus costauds de la reconnaissance de caractères (la segmentation) tout en permettant d'utiliser le plus naturellement possible l'espace disponible (sur Zaurus, on devait presque toujours revenir au même endroit pour tracer la lettre suivante ou le mot suivant). Et c'est toujours plus pratique à apprendre (encore qu'on pourrait essayer d'apprendre de nouvelles écritures à la DS) d'écrire "comme Pype/Zaurus" plutôt que "comme en Grafiti", même si grafiti avait le bon goût de ne demander qu'un trait par caractère.

Granted, the hand script writing I use when I want maximum readability already separates letters a lot and uses only one stroke for most lowercase. Because I reformatted my writing for the Zaurus already. But it's not like I had a huge user base to take into account ^^".

The granularity of the grid should help making tricky characters like braces-versus-digits-versus-C easier to deal with.