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.

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

{ $* | 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

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,

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, 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). 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/ -r ../dsgametools-hg
# git log
# git push --dry-run
git push
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 >_<


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.

Saturday, February 17, 2018

Histoire d'encre

Eh bien, le fait de se déplacer dans un encrier n'est décidément pas intuitif pour le joueur lambda de School Rush. J'en prends pour témoin les réactions des membres de "e-magination" à mon screenshot:

Le pot d'encre dans lequel sauter, tu l'amènes comme ça dans le LD ? Parce que j'aurais pas envie de sauter dessus personnellement, il ressemble trop à un piège  ...

Peut-être qu'il faudrait rendre l'encrier plus amical ? Perso avec ce regard, je lui ferais pas confiance. ^^

Ce serait une approche assez classique du problème, c'est vrai. Mais l'encrier n'est pas amical,

 sans être pour autant fondamentalement méchant:

Il s'agit d'un gardien, et d'un gardien face à une invasion. il ne sait pas de quel côté est Bilou. Il ne cherche pas à l'aider quand il le projette, juste à s'en débarasser. Il est dangereux (à cause de ses gouttes d'encre plutôt toxiques), pas franchement engageant (parce que entrainé à être gardien), mais peut être utile si on sait s'y prendre. C'est une dimension que j'aime bien (les carapaces de koopa, notamment) et que j'ai envie de développer dans mon jeu.

Friday, February 16, 2018

typedef u16 pageno_t

J'avoue que quand j'ai fait ma transition de l'assembleur vers le C, je faisais une mimique assez cocasse à la vue de uint32_t et size_t. Quoi, c'est un 'dword' (double-mot, jargon intel dans les assembleurs). Pourquoi aller lui donner un nom à coucher dehors pareil ? Bref, j'étais pas un fan de typedef, à part pour éviter de devoir écrire "struct" devant le nom de mes structures.

Mais sur l'année écoulée, j'ai eu droit à plusieurs situations du genre "int bitrate". Ah oui? en quelle unité, s'il vous plait, le bitrate ? bit/seconde ? kilobit/seconde ? megabit/seconde ? Et dans le code de mon moteur de jeu, "int x" ou "int width" est à peu près pareil. Est-ce que x est une coordonnée absolue (dans le niveau) ou relative (à l'écran) ? est-ce qu'elle est exprimée en pixels ? en tiles (si, si, souvenez vous, les petits pavés élémentaires de graphisme) ? en 256eme de pixel pour les calculs de déplacement avant affichage ?

Alors bien sûr, on peut tenter "int kbps, int x_in_tiles", etc. Mais pourquoi. Pourquoi faire rentrer dans le nom de la variable une information (l'unité de mesure) qui dénote plutôt de son type (on peut additionner deux valeurs en kbps entre elles, mais pas des Mbps et des kbps sans faire une conversion au préalable). Bref, j'ai pris l'habitude de construire des types qui expriment des unités de mesure. Beaucoup. Au point que je me méfie presque maintenant du code qui annonce juste un "int" parce que dès qu'on va commencer à intégrer des morceaux de code qui viennent d'horizon différents, on aura aucun moyen de se souvenir si le "* 1000" qui est là dans l'appel de fonction est justifié ou non.

Et comme je viens d'atteindre le point ou la branche "revisite pour cause de tutoriel" de mon moteur de jeu est prête à recevoir le code servant à charger des fichiers .spr, ce serait peut-être le bon moment pour y introduire des types comme "numéro de page, numéro de bloc, numéro de tile", etc.

Sunday, February 11, 2018

It's Cube Time!

Among all the hidden anti-cubes of fez, the four ones to collect at the clock tower were clearly the less interesting one. As soon as you've learned how to read your world map aud made your way up to the tower, you know you're missing something and that it isn't in a hidden room.

Parmi tous les anti-cubes de Fez, il y en a 4 à récolter autour de l'horloge, et selon moi, ils sont malheureusement les moins intéressants du jeu. Une fois qu'on a appris à "lire" la carte du monde, on sait qu'on a raté un truc à cet endroit (la petite icône ne disparaît pas), et on sait aussi qu'il n'est pas dans une salle cachée (l'icône est sur le noeud de la tour lui-même, pas un noeud annexe).

You have likely disovered that there is more to do in the game than hunting for
cube bits. Some anti-cubes are revealed by moving/stacking blocks, some by reading hints in the levels and turning them into secret codes to input through your game controller, konami-style.
All of these mechanics have been introduced over the "normal" gameplay, through switches, levers to manipulate .and doors with cryptic engraving. Granted, the d-pad language isn't easy to grasp and decode, but it is introduced with simple sequences of turn left/turn right.

Au moment où vous en arrivez là, vous vous serez très certainement rendu compte que la chasse aux petits cubes dorés ne représente qu'une petite partie du jeu. On trouve des anti-cubes en déplaçant des blocs, ou en lisant des indices pour exécuter des "cheat codes" à la manette. Le plus souvent, ces mécaniques ont été enseignées à travers des manoeuvres "normales" pour activer des interrupteurs ou des portes au inscriptions mystérieuses.

The clock anti-cube work like no other in the game. One of them had appeared with no apparent reason, then disappeared before I could grab it. Then I noticed one of the clockish and was moving and predicted time where the anti-cube Pops. Then the moving hand disappeared as I grabbed the anti-cube.
you will barely notice that all the four hands move, Imho. Not unless you stay idle, not even rotating the world for a few minutes. But why would you? There is a wrapper portal just above the clock and absolutely nothing to keep you thinking nearby. (not even script to translate). The odds that you see another cube pop there while passing by is 1/30 at best. And that map is no hub. You're never returned there. it's not as if it was the village's clock...

Mais les anti-cubes de l'horloge ne sont définitivement pas de ce genre. Tout d'abord parce que pour la seule fois du jeu, il y en a un qui apparaît, comme ça, sans prévenir. puis qui disparaît avant qu'on ne puisse s'en saisir. Je me rends compte qu'il se synchronise sur la seule aiguille qui bouge. je me synchronise aussi, je m'en empare. Par contre, chapeau à celui qui aura remarqué que les autres aiguilles bougent elles aussi (nettement plus lentement, il faut bien dire). Si au moins il y avait eu quelque-chose à faire ... une inscription à traduire .. n'importe. Mais non. Le portail pour le retour est juste au-dessus ... Et il aurait fallu être retardé plusieurs minutes. Et on est pas sur un noeud central, mais en "bout de branche": on ne reviendra pas là par hasard.

Your best hint comes from Dot, actually. But
by then, you've learned not to take care of Dot's comments. Dot doesn't remember, she's afraid of owls, etc. She's only helpful for basic stuff like knowing .what is interactive. When Dot says "it is cube time", its sounds like cheap humour.
And even then, she never says "it is quarter to Cube" nor "half past cube". The link is static, not flowing as the time.
If only that clock was behaving differently from our regular clocks, et with the "hours" hand doing one full revolution over Gomez's day and night cycle, giving you some more chance to understand that you are not expected to find anything to do there, just meet the date...

Notre meilleur indice (sur le fait que les couleurs de l'horloge n'ont rien à voir avec les couleurs des boutons de la manettes et qu'il ne faut pas essayer de lire des chiffres sur l'horloge, etc) nous vient de Dot, le cube volant qui nous accompagne. "C'est l'heure du cube" semble plaisanter Dot. Mais le joueur aura appris -- une fois la phase tutorielle passée -- à ne plus tenir compte de ses remarques. Dot ne sait pas, a oublié, n'aime pas les hiboux, etc. Peut-être aurais-je été plus attentif si Dot avait annoncé qu'il est "cube moins le quart" ou "cube et demie" selon la position des aiguilles ...

Non. Rien de tout celà. Le joueur qui passe une à deux minutes dans cette partie du tableau a entre une chance sur 30 et une chance sur 60 de voir apparaitre le deuxième des quatre anti-cubes de l'horloge. Pour le dernier, il faudra que je repasse mardi, entre 1h30 et 2h30 du matin. Et non, ça n'est pas drôle. Quitter puis relancer le jeu après avoir changé l'heure de la playstation une demi-douzaine de fois non plus. Si au moins les aiguilles avaient avancé "plus vite" (une 'heure' de 10 minutes, une journée d'une heure, etc). Et peut-être un moyen d'entrer dans la tour pour modifier l'heure actuelle sans quitter le jeu ?

Finally, even if all that had been clear, understanding that the anti-cube I need to beat the game will show up next Tuesday between 1 AM and 2 AM is no fun. I really missed some way to enter the clock and start messing with its gears to force the last two cubes to my convenience. That would have felt awesome and fun.

Tuesday, February 06, 2018

gource and reDS

C'est un outil super: gource. Transformer les fichiers logs d'un gestionnaire de versions en une animation interactive où les développeurs deviennent des jardiniers taillant, soignant, élagant, greffant...

Et facile à utiliser, en plus! Bon évidemment, ici c'est assez moyennement intéressant puisque je suis tout seul sur le projet depuis le début ...

Mais au moins, ça met bien en valeur les efforts pour restructurer le code et permettre à d'autres (au cas où) de faire des projets à base du moteur de jeu GEDS plus facilement.
Au passage, j'ai franchi un cap avec le code d'AnimEDS. Les "modèles" sont maintenant activés. Je regrette un peu d'avoir quand même dû passer par l'émulateur et une exécution pas à pas pour corriger les bugs introduits lors du refactoring alors que j'avais des programmes de tests pour l'architecture native juste à côté... mais bon, les erreurs étaient dans le setup des objets, pas dans leur logique.
Maintenant, il reste à sortir la gestion des "callback" hors de la classe "Engine" (je les verrais bien en gestion autonome, avec un objet complètement interne qui assure la gestion et qui est caché derrière les méthodes "register" et "unregister" de la classe-maîtresse). edit: c'est fait.

Wednesday, January 31, 2018

School Touch?

My brother comes back again with the idea of School Rush on Android platform. Porting issues set aside, I guess he means "on the bare device", and not assuming one bluetooth dpad and buttons attached, Nintendo-switch-like. That implies converting touch and taps and gestures into valid SNES inputs.

Mon frangin n'en démord pas: la plate-forme qu'il faudrait attaquer pour un portage de School Rush, c'est les smartphones & tablettes. Androïd, donc. Au-delà de l'aspect purement "portage", ce qui va manquer le plus sur Androïd, ce sont bien sûr les boutons et le D-PAD. Je doute qu'il avait en tête qu'on se bricole quelque-chose avec des contrôleurs bluetooth en plus du téléphone lui-même. Bon, la bonne nouvelle c'est que la DS elle-même a un écran tactile. On pourrait donc imaginer faire une version "School Touch" pour essayer le potentiel du jeu avec cette interface-là avant de se lancer dans des longues soirée de méditation sur les interfaces Androïd.

Good news: the DS also has a touchscreen. So as a preliminary test, I could just try to use the touchscreen to see how the game feels. Imho, a specific area to emulate the d-pad on having to hold a finger on the screen as we do for the (A) button would be terrible. No one could complete the game in those conditions. I've tried that with e.g. Sonic 2 back then and it was really degrading the gameplay.

Ce qui est déjà clair, c'est que je ne ferai pas une espèce de pad virtuel à travers l'écran tactile. C'est généralement une catastrophe. Il faudra plutôt que j'aille vers une sorte de mélange entre "platform panic" de Nitrome (glisser à gauche ou à droite pour changer le sens de la course avec Bilou qui continue à courir tout seul) et Phantom Hourglass (tapper un monstre pour utiliser les mains de Bilou)

Ideally, we should be constantly running when playing School Rush. That means in the School Touch game, Bilou should start running forward as soon as we trigger RUN, keep running until we give a contradictory input. Similarly, just tapping Jump should do a max-height jump. modulating dump height on distance would be additional inputs rather than timing on the initial input.

No idea when I would do that,... though.

Là où je sèche plus, c'est pour le saut. Dommage, pour un jeu de plate-forme, j'en conviens. Dans School Rush, on dose son saut par la durée de la pression sur le bouton. Faire pareil sur un écran, c'est risquer d'avoir toujours les doigts dans le chemin quand on veut regarder la suite du niveau. Je partirais plutôt vers un système où on fait de base le saut maximum, que l'on "interrompt" si Bilou arrive plus haut que l'endroit où on a tappé  / l'endroit où est le doigt. Enfin, il faudra trouver quelque-chose pour pouvoir atterrir avec assez de précision sur des plate-formes parfois assez étroites.

I liked the idea of "tap another GOB to trigger the "punch" button: it works for picking up bladors, throwing them on baddies, grabbing spons and punching things.

Saturday, January 27, 2018

J'adore le mauve

 Parce que dans Fez, le mauve est synonyme de mystère et d'intrigue. Généralement une petite pièce qui semble en-dehors du monde "normal", une atmosphère de trans-dimensionnalité... du fez quoi.

I love than purple shade of mystery Phil introduced in his Fez game. He mostly used it in small, indoors location that feel a bit disconnected from the "overworld". It usually looks bigger inside than it should be given the exteriors' dimensions. We first encounter it in the strange place where the cube gives us power, and it was absent completely from the village, to find it again just when we cross the door to "the world beyond" the village.

L'introduction du personnage à son nouveau pouvoir se fait dans le mauve, couleur presque absente de son village. On la retrouve pourtant derrière la porte qui mêne "au monde au-delà du village.

Et quel monde! les cascades tombent de nulle part, les blocs flottent dans les airs, il y a des portes partout et pourtant elles n'ont nulle part où mener (enfin, ça devrait chaque fois être une autre porte vers la même salle qui fait au mieux deux fois la chambre de gomez, mais en fait non. Ici, l'intérieur, c'est l'extérieur).

That first hub is the goal of our game: we want cubes to open those doors. The mystery color is used again, which makes the room feel unique, with floating blocks and Cascadas flowing from nowhere. There seems to be which echoes the duality of the gameplay: the normal, outerworld is for exploring, and the purple, inner world is for riddles.  Indeed, past that first hub, purple rooms will mostly be locations where we took for anti-cubes.

Il y a donc deux couches de réalité dans Fez: le monde extérieur, propice à l'exploration, et le monde intérieur, mauve, propice à ...

Eh bien propice aux énigmes. On va essentiellement le retrouver dans des salles "cachées" où il va falloir faire quelque-chose pour faire apparaître un anti-cube. C'est d'ailleurs probablement dans ces salles que vous avez le plus de chance d'y trouver votre premier si vous n'avez pas encore jeté un oeil sur la liste des "achievements" du jeu.

Un des aspects du jeu qui m'avait vraiment plu dès ma première "vraie" partie, faisant un peu écho aux puzzle qu'on pourrait trouver dans un Zelda.

Mais le mieux, c'est que le jeu nous met la puce à l'oreille. une salle-mauve en-dedans a sa porte d'accès sur un mur mauve au-dehors. De quoi provoquer l'anticipation du mystère mais aussi pouvoir la repérer plus facilement parmi les autres portes d'un noeud (on ne peut pas parler de monde ni de niveau pour fez) et simplifier un peu le back-tracking.

One clever design idea about those riddle-rooms is that their purple status tends to contaminate the outerworld. The door to the room itself will be purple as well, and sometimes, even some of the bricks around are purple, too.  This helps quickly identifying the right door when we backtrack to riddles we had not yet solved.

Some level of backtracking is impossible to avoid with Fez, but to be honest, the more you can focus on the things immediately reachable, the best. I wished I could close doors towards rooms I couldn't understand, To reduce the amount of trials when I'll have to go there again.  understanding how the map system works was a Key factor in bearing he game, and I eventually. picked up a sketchpad to take notes of my progress, and scribble anything that could be useful later, like the location of owls, obelisks and interesting paintings. without it, I think I would still be running that maze for final cubes. Likely, I should have depicted the secret doors as well.

Bien que, je vous l'avoue, j'avais déjà fait l'expérience assez désagréable de constater que Fez est beaucoup moins pratique quand on doit retourner quelque part que quand on y fait son premier passage. En fait, il aurait été pratique de pouvoir refermer une porte quand on se rend compte qu'elle mène vers une énigme qu'on ne sait pas encore résoudre, de sorte qu'elle apparaisse comme "à faire" au prochain passage.

Si bien que l'on doit assez vite apprendre à se servir de ce qui tient lieu de "carte" pour ce monde. garder un oeil sur ce qu'il y a à l'arrière-plan quand on tourne le monde dans telle ou telle direction, vérifier si la salle marquée d'un '?' est bien sur la "face" visible, s'il y a plusieurs portes sur cette face, etc. (et tenir compte du fait que la carte s'autorise à changer la position d'une porte si elle est sur la face par laquelle on arrive dans le noeud). Sans ça, c'est l'effet labyrinthe garanti.

Et oui, j'ai finalement pris un carnet à spirale pour y prendre note des choses sortant un peu de l'ordinaire (en particulier dans les salles mauves) y compris par où on y parvenait pour pouvoir y retourner facilement.
J'aurais probablement dû faire pareil avec les "portes dérobées" (marquées d'un double-carré) qui ne marchent que dans un sens la première fois mais qui offrent des raccourcis en cas de re-parcours.


Donc, j'ai fini Fez (enfin, j'ai 64 cubes) mais ça, je vous en parlerai plus tard. J'ai aussi fini de réorganiser le code de mon éditeur d'animation de sorte que les manipulations effectuées sur la liste d'images puisse être extraites du code de l'interface graphique correspondante. Je ne vais pas qualifier ça de Model/View/Controller, mais c'est un pas dans la bonne direction, à mon avis.

At last, am done with one big chunk of nefactoring on the DS Animation Editor. Frames list can now be manipulared from any piece of code. It no longer requires emulation of the whole widgets/windows engine. 

It is probably not scleanly separated as MVC code, but it is definitely one step in the right direction. Now I can get rid of the ugly coupling between thumbs display and thumbs-bitmap filling when saving the file. I can get rid of global objects. I can introduce my new Resources class.

Tout ça parce qu'il était impossible dans l'état actuel de débarasser AnimEDS de ses objets globaux vu le couplage tordu et foireux entre la fenêtre qui fait le rendu des miniatures et le système de sauvegarde. Pensez un peu: pour sauver les miniatures (utilisées par l'éditeur de niveau), on allait devoir faire croire à cette "fenêtre" que l'utilisateur passe d'une page à l'autre pour la forcer à re-générer des prévisualisations en mémoire vidéo que l'on capture pour les placer dans le fichier.

Prévisualisations qui - au passage -- demandaient qu'on fasse croire à la fenêtre d'édition des animations qu'il y a une nouvelle animation à éditer pour qu'elle la décode, construise la liste de frames correspondante et qu'on puisse demander un rendu de la première frame à chaque coup.

C'est presque un miracle qu'on ait pu continuer à éditer des animations après une sauvegarde, à ce tarif-là.

Tout ça parce que si AnimEDS garde ses objets globaux, il est impossible de réorganiser la gestion des resources dans le Game/GuiEngine.