dimanche, août 30, 2009

première photo du niveau 2 ...

appleman-photo Bon, on ne s'emballe pas : j'ai encore un paquet d'écrans à compléter dans ce niveau-là. Mais ça prend forme. Je teste des passages vicieux avec les Funky Funghi, etc.

J'essayais donc ce matin d'avancer un peu sur le comportement de l'appleman, et en particulier le faire "stresser" lorsqu'il aperçoit Bilou (une sorte de première phase d'attaque). J'ai donc ajouté une petite zone "déclencheuse de pièges" (cf. système de gestion des collisions) à Bilou (que je pourrais éventuellement désactiver lorsque Bilou a obtenu un bonus 'mode furtif'), et j'ajoutais une zone sensible à l'appleman. Bin pas de chance : ça n'a pas marché. J'avais oublié que si la zone active dans un test peut être plus grande que le personnage, il n'y aura vérification des zones passives que si l'objet lui-même est en contact. En d'autres termes, les zones passives sont toujours plus petites que les objets qu'elles recouvrent.

While I'm working on the improved behaviour of the Appleman, i have been tricked by the asymmetric nature of collisions in my own engine. While the *active* collision area can be larger than its own sprite, the *passive* area (that 'recieves' the collision, somehow) is inherently restricted by the bounding box of its sprite, meaning that the Appleman has to be active into detecting Bilou around (not the other way round). It requires a little more code to attach actions there that I'll write down as soon as we have sleep == (*deline && !me). I could also introduce a new kind of controller that simply fires an event when the player enters a given area, but for rectangular checks, it would just be useless work.
Alors on pourrait se dire "bah, il n'y a qu'à inverser" ... Le code n'était pas prêt pour ça, mais vous avez parfaitement raison. Alors cliquez sur un lien quelque-part pour continuer à lire, parce que moi ... bin Yaka.

jeudi, août 27, 2009

contretemps

Mon routeur @home est en rade. Depuis la naissance de *deline, ou presque. J'ai passé presque toutes les vacances à faire du "card swapping" (heureusement plus rapide avec une R4 que mon ancienne SuperCard) pour transférer les fichiers et faire mes tests. Evidemment, avec l'éclatement du gros script de niveau en plusieurs petits scripts, ça complique encore un rien l'affaire.

J'ai ramené ma petite clé USB, celle-là même que j'avais utilisé en Suisse comme point d'accès autonome ... aujourd'hui. Evidemment, dans l'intervalle, j'ai cherché des solutions pour éditer rapidement les scripts déjà présents sur la DS.
Et je dois admettre que je suis assez étonné du peu de programmes proposant un éditeur texte -- même tout simple -- sur nintendo DS. J'ai testé un Blargh en mode pre-alpha (sans sauvegarde :P), le moonshell "en lecture seule" et la combox de Lilou n'est pas fiable sur ce coup-là : j'ai régulièrement des lignes qui disparaissent, qui fusionnent, etc.

The day *deline came back home, both my car and my WiFi router decided to go on strike. The car was quick to fix, but i'm still in need of a 5V/2.5A power adapter for the router, making data & code uploads via runme unfeasible at home during the whole summer. I just brought back the USB access point i set up for my laptop in Basel, so since yesterday, i'm no longer forced to swap the micro-SD card in and out of my R4 to progress on Bilou.

Meanwhile, i've been tempted to edit my files directly on the DS. All i have to do is change a few things here and there, not to write down complete source scripts. Moonshell already allowed me to view files, but not to edit them. I gave BLARGH a try, an editor using a "keyboard" specially designed for efficient stylus input, but it's still a beta release that cannot save edited files. Pretty useless. I have thus used the text editor present in Lilou's combox, but it proved to be unreliable, randomly dropping or merging lines on edits.
Maybe i'll work on a TEDS text editor to accompany runme and friends later on, and it might be based on "tag clouds" derivated from the text's content.

Anyway, i'm not fully back, but the "maquis" weeks toying with SD card readers are hopefully over, and i've succesfully tested controller chaining feature. I can go on with appleman's behaviour.

Bref, quand j'aurai le temps, je me ferai mon propre petit "TEDS", probablement basé sur un "tag cloud" des mots les plus fréquents dans le texte existant, histoire de faciliter l'écriture dans des langages de programmations (au détriment du micro-blogging).

Enfin, tout ça pour dire que j'ai enfin pu faire un test de l'enchaînement des contrôleurs: ça demande encore un brin de mise au point, mais ça prend bien forme.

Uh ? It looks like nothing about controllers have been translated in English this far. I'll need to fix that.

mercredi, août 26, 2009

Toujours pas codé de clone de Chuzzle.

En décembre 2006, je me disais que je me ferais bien un p'tit clone de Chuzzle sur la nintendo DS.
edit '2009: Je n'ai toujours pas attaqué un clone de Chuzzle, et sincèrement, il y a peu de chances que je m'y attaque avant mes 32 ans. Mais ZeBlackOs nous a concocté un très sympathique Plop Invaders dont le gameplay se rapproche assez bien de chuzzle. Régulièrement, j'imagine un nouveau contexte dans lequel faire un clône de Chuzzle... un écran avec des pixels morts qu'un employé de PixTeX doit réparer ... des bestioles emprisonnées dans des bulles de couleur qu'un petit garçon doit faire sortir d'une vilaine machine du vilain Pr BubleGum... etc.

Au même titre que Seafox DS, ça restera sans doute encore un moment une idée en l'air, comme j'en ai pondu tant ... mais je dois tenir bon: l'objectif c'est Bilou, sinon je vais encore passer un temps indéfini à imaginer des tas de trucs possibles sans jamais avancer sur rien.

dimanche, août 23, 2009

Dans le Pied++

Je n'avais pas une grande expérience du C++ pendant les années où j'ai travaillé sur mon projet d'OS, mais j'avais suivi avec intérêt les investigations de DasCandy pour parvenir à faire fonctionner les objets globaux (cf. http://wiki.osdev.org/C_PlusPlus). Et j'en avais retenu une chose : n'utiliser ces choses qu'en cas d'urgence, et avec la prudence qui s'impose quand on manipule de la nitro.

D'un autre côté, pour pouvoir définir le comportement de mon appleman, il me faut beaucoup plus de contrôleurs, qui sont appelés en séquence pour définir le comportement réel pour un état. Au moment de la lecture du script qui définit le niveau, je vais donc traiter une série de lignes "using tracker(Bilou)" "using Momentum(5,-1)" "using walker()", chacune de ces lignes donnant le nom d'une classe de contrôleur à instancier. J'ai donc pour chaque classe dérivée de iGobController une classe dérivée de iGobFactory capable de construire le bon objet à partir de la chaîne de caractères entre parenthèses.

So i've started decomposing the former "big chunk" controller such as 'walk' and 'gravity' into 'micro-gob-controllers' and make sure they are published in the std::map used by GameScript to prepare the GobState objects according to the rules found in the script, such as "using tracker(Bilou) ; using Momentum(5,1)", "using walker". The corresponding output is a chain of controllers that each do a specific job, easing code reuse. The BerryBat and the Appleman can for instance share the same "tracker" controller that tell them where Bilou stands, while Bilou and the appleman share "Momentum" and "walker" controllers, but Bilou receives its input from "dpad" rather than from "tracker".

Bon. Mais il faut que ces factories -- qui sont du coup des singletons -- soient enregistrées dans une map pour que le script les retrouve (c'est pas du Java: exit le 'Class.forname("tracker")'). Et je voulais pouvoir ajouter encore et encore des contrôleurs à mon code sans devoir maintenir une grosse fonction du genre "register_all_controllers". Cyril proposait donc évidemment des objets globaux (qu'on appelle parfois aussi "objets statiques"), mais je n'étais pas chaud: avec eux, il y a toujours anguille sous roche ...

Comme je n'avais pas d'argument vraiment convaincant, j'ai essayé quand-même. Première surprise : les "printf" ne marchent plus de manière fiable! J'ai encore quelques messages imprimés quand j'utilise "printf" sans aucun argument, mais c'est tout... un problème que j'avais déjà rencontré.

Un peu de désassemblage, et je constate que les messages qui sont effectivement imprimés n'utilisent pas véritablement printf: ils ont été convertis en interne en puts. Conclusion: en appelant printf dans l'initialisation des objets globaux, qui a lieu avant ConsoleInit(), j'ai empêché l'initialisation correcte de la console et rien ne va plus.

I stumbled upon two issues while implementing those factories -- which i initially chose to build with static objects. The first problem is a "known issue" of my libnds version: if i ever invoke a printf() function before consoleInit(), i screw up the stdlib's internal state and all subsequent prints using this function won't output a single pixel >_<.

Je change d'approche: initialisation "en aveugle", et une petite méthode "test" indépendante, histoire de vérifier que mes contrôleurs sont bien présents, appelée juste avant la boucle principale du programme. Deuxième surprise: il y a bien des contrôleurs enregistrés mais pas tous. Pourtant, mon code est bien compilé, tel que je l'ai écrit. Et il avait été appelé, puisqu'il était capable de foutre en l'air l'affichage...

La map est une variable de classe, statique, initialement vide. "As plain as can be" ...
... statique ? ...

Eh là, une minute ... Et comment le compilateur sait-il que parmi ces objets statiques, la bonne initialisation des GobFactories dépend du fait que la map ait déjà été initialisée ? Bin il ne le sait pas, évidemment. Le code d'initialisation appelle tous les constructeurs dans un ordre qui lui convient, et si ça ne me plaît pas, c'est tant pis pour ma faute.

Once this was fixed, i realised that i was f00lish to use static objects to register things in a static map. When i say "static", here, i actually mean "some object defined at the top level that should be instanciated before main() is ever called". The problem with such object is that their initialization order is undefined. In other words, my factory F could very well inserts itself in the map and then the map itself initializes (and thus clears what F modified).

Retour temporaire à "register_all_controllers" pendant que j'évalue les options... Voilà qui donne un nouvel éclairage au dicton "In C++ it's harder to shoot yourself in the foot, but when you do, you blow off your whole leg." (Stroustrup himself ;)

mercredi, août 19, 2009

La gazette de Bilou

I've spent my young years waiting for the next issue of my favourite programming/gaming gazette to appear. PC-Fun, PC-Team, Dream, Login, Linux France Magazine ... I've so many times wished I were paid to write columns in such a journal. And when i write something that is not a progress report, i'm still virtually thinking of it as a small paper in that virtual journal.

With all the GoodStuff(tm) i've located and shared through Google Reader this summer, you could setup a real (and interesting) codezine. Here comes the front page. For the content, just head to my googlecast.

Tant de mercredi après-midi passés à dévorer des "prograzines" comme Dream ou Pc-Team ... Au point que quand j'écris quelque-chose d'autre qu'un "progress report" sur Bilou, je m'imagine toujours qu'il s'agit d'un petit article dans un de ces magazines dédiés à la pensée informatique créative. J'aurais évidemment aimé avoir plein de collaborateur géniaux pour faire de ce blog une version numérique de ce "magazine de rêve"... Plus besoin: les collaborateurs ont déjà chacun leur Blog. Retrouvez donc leurs articles grâce à la toute-puissance de Gout-Gueule (les bons tuyaux) ...

(ps: oui, je me suis laissé influencé par Stravingo: voilà que je fais des "fake", moi aussi.

This to give a little more visibility to those "Been Reading", "Blogs I Watch" and similar boxes in the right side of this blog.

samedi, août 15, 2009

Tobe's Vertical Adventure

Tobe nous prépare un petit bijou depuis quelques mois: "Vertical Adventures". Je suis avec intérêt les progrès graphiques sur pixelation, et une petite vidéo vous permettra peut-être de vous en faire une meilleure idée.

C'est le genre de projet qui me fait regretter d'avoir abandonner Windows (ou de ne pas avoir pris plus le temps de faire tourner Wine, c'est selon). Tout comme Spelunky (sorte de croisement entre Indiana Jones, BoulderDash et Cave STory), il représente le nouveau mouvement du "Indie Games", le développement de jeux indépendant, où faisant fi des demandes du marché, de petites équipes mettent tout leur talent pour réaliser un jeu qui leur fait plaisir, le plus souvent avec une composante "rétro" des plus délicieuses. Bref, je ne vais pas tenter de les couvrir tous: le Pixel Prospector s'en charge très bien.

Je suis fan de l'idée de Tobe (et al.) depuis ses premiers croquis de personnages. J'ai même tenté de m'en inspirer pour faire un peu évoluer mes techniques de graphismes/animation. Et la vidéo de gameplay suggère des bonus intéressants (se freiner contre les murs, s'accrocher aux lianes, etc.) que je me réjouis de voir à l'oeuvre.

I'm following the progress of Tobe, the graphist for Vertical Adventures, since his early sketch release. This project is a little jewel that shows great promise. Exactly the kind of little game that make me wish i still own Windows or an Xbox to play them (just like i wish i had a console years ago to play Twinbee or Flink ;-)
I spotted bonus-in-TV-boxes in the last (and first) teaser video, that suggest me the ability of climbing vines etc. could be modulated by those bonuses. An interesting line of action.


Anyway, much like Spelunky and Arachne's little platformer project (a while ago), Vertical Adventure makes me wish i could get a hand on Tobe's spritesheet and tileset to build a little proof-of-concept demo with my DS game engine... since i wish i was allowed to play the game on my DS. Maybe it's a little too early for that. I'll focus on coding the Appleman's aggressive behaviour and paying my bills first ^^"

jeudi, août 13, 2009

bilou.cmd

Ca y est. Une petite classe abstraite "InputReader", deux sous-classes BufferReader et FileReader et un peu de bricolage, et je peux ranger tous les éléments relatifs à un personnage dans un fichier séparé, inclus depuis le "script-maître" du niveau.

Ca fait plus propre ... je suis prêt à rajouter des niveaux dans tous les sens.
Mais j'ai aussi pas mal de fonctionnalités à béta-tester:

  • [done] composition de contrôleurs
  • [now][done] gobs dynamiques (tirs, étoiles-bobo, etc) et état "nil" pour les détruire, qui utiliseraient de nouveau un mécanisme de liste auto-itérée pour leur gestion
  • [done] utilisation d'actions externes dans les expressions de la machine d'état
Three tiny classes added, a few edits, and i can finally store everything related to Bilou in bilou.cmd, the bouncy logic of Funky Funghi in funghi.cmd, etc. Those files are then 'included' from the level script, and can thus be reused in as many levels as one wishes. Hooray. That's a major step towards a multi-level game, despite the actual coding is still a bit crude (e.g. you can't #include with blocks, and you *must* have 'end' statement in every file, including included files).

Am i going to do a release right now ?
Or am i going to toy a bit with chained controllers (useful for the appleman), dynamic Game OBjects (useful for shots and the like) and external actions invoked from the state machines (useful for sound effects) ?

lundi, août 10, 2009

loading ... please wait

howdy. I can now load and run level 2 when Bilou reaches "the end" of level 1. This brings me one step closer to my "grab-the-apples" milestone game. The only poor thing remaining is that you'll end up with the script code for Bilou, the bonuses, the monsters, etc. duplicated in every ".cmd" level script.
I'm in need for an "include" statement in those gamescripts, but once again, nothing had foreseen that your level would need pre-processing (or that you'd change the source of data while parsing the script). Some more design effort will be needed.

Bien. Je peux charger et jouer le niveau 2 quand Bilou atteind la fin du niveau 1. On se rapproche de l'objectif "petit jeu tout simple où on ramasse les pommes pour atteindre la sortie". Il reste un couac avant une release: la définition de Bilou, des monstres, etc. doit être répétée dans chaque script ".cmd". Il me faudrait une petite commande "include" que je n'avais pas anticipée . . .

(PS: l'illustration vient d'un t-shirt ThinkGeek, bien sûr. Il n'y a qu'eux pour en faire des comme ça ;)

vendredi, août 07, 2009

Aggressive Appleman

De retour du Vaudrée, alors que j'essayais de rafraîchir un peu ma chambre pour la nuit, j'ai bricolé quelques étapes d'animations supplémentaire pour l'Appleman.
Je garde la primeur des pixels pour la prochaine mini-démo, mais l'idée est de démontrer les possibilités du moteur de jeu en rendant l'appleman plus agressif en le faisant réagir à la présence de Bilou. L'animation donnait donc:
un pas ... attente ... deux pas ... attente ... stupeur! Bilou en vue. Deux pas courus.

Comme l'animation est jouée en boucle, ça a donné l'impression que l'appleman "ralentissait" après avoir un peu couru. J'ai joué le jeu et l'ai fait vraiment ralentir avec un résultat qui me plaît beaucoup: on dirait qu'il est hargneux, mais trop lourd pour pourchasser Bilou bien longtemps. Juste ce qu'il faut pour un premier monde. Restera à coder tout ça et à le faire sauter bas des plate-formes dans l'état "hargneux".

I was toying with Appleman animation, yesterday night. One step, wait, two steps, surprised to see Bilou and chase Bilou (actually, just faster walking). It felt right. I went further making his speed decrease over time until he returns to plain walk. I loved how it conveys the feeling that despites appleman's hate towards Bilou (see the comic book), he just can't run his overweight body for very long.

I have strong expectations towards the appleman as he's supposed to demonstrate the power of the game engine to build sophisticated behaviours (e.g. jump off a platform to chase Bilou only when Bilou is nearby and downwards) out of "simple" bricks (such as a timing block, a hero-in-approach block, etc.)

And, by the way, there is now an english translation of my last two "history" posts about Calimero and Logic Labyrinth.

Timewrap: retrospectively, this is the very first step (2%) towards the mini-game "Apple Assault".

mardi, août 04, 2009

Try Again ...

La bonne nouvelle, c'est que j'ai enfin un mécanisme me permettant de recharger un niveau quand Bilou s'est pris trop de coup. La mauvaise, c'est qu'à recommencer 20 fois le même niveau, je finis par mettre en évidence des fuites de mémoire dans mon code.
Il est temps de reprendre le code de mon prototype de manière un peu plus rigoureuse, de passer en revue mes classes en suivant les bons conseils++ d'Axel. Jusqu'à 300K qui partent en fumée à chaque vie, ça coûte vite cher sur une machine qui n'a que 4MB.

Good news first: I can at last reload a level when Bilou has been hit too much. The downside is, that this highlight a memory leak in my game engine. Most likely some machine state isn't properly reclaimed. It's time to print my code and read it back with a mop in hand ...

  • double invocation of GameScript ctor on reload : >280 K goes away
  • not taking care of transitions when cleaning the state machine : 5K
  • not taking care of cleaning "guns" : neglectible right now
  • other (under inspection) lost things : 5K
  • not taking care of OAMs allocation over iterations : invisible sprites after ~16 attempts
edit: fixing a stupid and obvious bug reduce the leak from 300K per live to 10K per live. Below comes the checkram() function i'm using to count available memory (that simply allocate as much as possible, then releases everything). Just refrain yourself from using std::whatever to store allocated chunks if you don't want to see a bad_alloc exception thrown in the middle of the process.

int checkram() {
int total=0;
iprintf("grabbing ...");
void **chunks=0;
void **chunk=0, **prev=0;

for (int chunksize = 1024*1024; chunksize>32; chunksize=chunksize/2) {
int n=0;
while((chunk=(void**)malloc(chunksize))) {
*chunk=(void*) prev;
chunks=chunk;
n++;
total+=chunksize;
prev=chunk;
}
iprintf("%i,",n);
}

iprintf("releasing ...");
while(chunks) {
void **chunk=chunks;
chunks=(void**) *chunk;
free(chunk);
}
return total;
}
Bien sûr, une telle fonction est une dépense de resources matérielles inutile si l'on connaît suffisamment l'implémentation de malloc dans l'environnement précis où l'on développe. En l'occurence, ludo connaît une méthode bien plus efficace et élégante pour libnds. And ludo's sources come from this gbadev post