Showing posts with label uml. Show all posts
Showing posts with label uml. Show all posts

Thursday, May 20, 2021

PatchedReader

 ça fait un moment que le projet me trotte en tête. Des années en fait: faire un éditeur de texte pratique pour Nintendo DS. Pas pour écrire une 2eme thèse avec, mais simplement pour pouvoir corriger facilement les scripts quand RunME me râle dessus. Il y a quelques jours, j'ai pris conscience que je n'avais pas nécessairement besoin d'un éditeur de texte complet: un patcheur de ligne pourrait déjà être bien utile. 

Que je m'explique: le ScriptParser lit notre texte ligne par ligne et lance une exception quand la ligne ne lui plaît pas. Actuellement, je dois alors sortir mon laptop, avoir le même fichier .cmd, trouver la ligne défectueuse, écrire une version corrigée et la ré-uploader sur la DS pour faire un deuxième test.

I had the idea of making a convenient text editor for Nintendo DS trying to find its way out of my head for some years. Not something you'd use to write a novel, but at least to patch game scripts when RunME spots something wrong instead of having to do WiFi transfers back and forth until things are fixed. But a few days ago, I realised maybe a full editor wasn't needed : what I actually need (since my parser processes things line-by-line) is a way to *patch* those lines if they're wrong.

Bon, pendant mes tests, je me suis mis en place un runME-autorun.nds qui permet de répéter les choses sur ordi à moindres frais, mais pour peu que ce soit les nouvelles animations ou qqch comme ça qui coince, je suis bon pour re-télécharger des .maps et autres .sprs avant de commencer à étudier le problème.

Donc, et si au lieu d'interrompre violemment l'évaluation du script, on basculait de la CmdWindow (qui exécute le script) à la PatchWindow, qui nous remontre la ligne ayant posé problème, nous permet de l'éditer et éventuellement de retourner dans CmdWindow ?

I gave myself a 'runme-autorun.nds' derivative of the real 'runme' that can start tests faster, but as soon as issues are with poorly defined animations or specific to the data files hosted on the NDS, the need will be back.

The idea would be to switch to the edition window as soon as the parser fails (instead of killing the whole level). With help from a new sub-class of InputReader, I should be able to serve the patched line of text instead of the original one.

Rather than trying to insert new lines into a single-block of memory, PatchedReader would maintain a patches lists, each replacement lines associated with their position in the file and either serves lines from the original source or from one patch line, depending on where we are.

Pour permettre ça, on introduirait une classe dérivant de InputReader qui suivrait la ligne en cours et la remplacerait par une chaîne présente dans sa liste de patch si on a effectué une édition. On aurait la fonction nécessaire sans devoir s'embarasser à scroller dans un fichier potentiellement longuet, avec un besoin réduit de fonctions de recherches, et une gestion de la mémoire simplifiée par le fait qu'on a jamais besoin d'insérer des caractères au milieu d'un bloc-mémoire existant...

C'est plus ou moins là que j'ai laissé le développement NDS avant de me faire ré-avaler par le royaume d'Hyrule.

Evidemment, si je veux que ça donne un jour quelque-chose, il faudra que j'accepte de ne pas utiliser tout de suite le système de reconnaissance d'écrite manuscrite, mais plutôt de partir vers un clavier virtuel un peu dans la veine de celui envisagé pour l'éditeur d'expressions à l'intérieur de LEDS.

edit July '21 ... get a first draft with better error reporting including word wrapping ... that almost works.


Tuesday, February 25, 2020

fakeMetaWindows

Bon, après un week-end assez "rock and roll", j'ai fini par pouvoir essayer un peu mon nouvel atout: un exécutable NDS alternatif pour la mise au point de l'interface graphique de LEDS. Parce que débugger SEDS c'est déjà pas rigolo mais il n'y a que "START + L + A" à taper pour charger un fichier. Dans LEDS, ça se fait avec les p'tits widgets d'exploration de répertoires. On clique par-ci, puis par-là, puis enfin l'émulateur charge le script principal, les spritesheets, le niveau. Et là tu peux faire A, réactiver tes breakpoints et commencer à débugger.

https://twitter.com/pypebros/status/1230601848022847494
Mais ce sera bientôt du passé. J'ai pu extraire en tous cas les dépendances de la "MapeditWindow", la "fenêtre" principale à travers laquelle on voit et modifie le niveau dans une structure qui lui prépare un niveau rien que pour le test qu'on pourra faire défiler, modifier et pour lequel on pourra aller regarder le contenu de la VRAM pour s'assurer qu'on a bien affiché ce qu'il fallait à chaque étape.

Et ce sera bien utile, parce que là, tout de suite, je me suis attaqué à "permettre de masquer/afficher les boutons qui définissent les propriétés des tiles sans corrompre le niveau, mais du coup, je casse le niveau dès le départ >_< Vous le voyez, ce gros pavé jaune dans la zone "radar"? et toutes ces petites flèches noires sur l'écran du bas (par-dessous le texte de debug blanc, c'est difficile, je vous le concède) ? Bin c't'un bug.

Friday, December 06, 2019

FlatWorld.artmap

Bon, bin j'ai finalement réussi à trouver les erreurs que j'avais glissées dans mon code et à les corriger. Je peux donc reprendre une des "maps" de School Rush et la convertir à la volée pour qu'elle tourne avec la nouvelle classe "monde" et ses données de collisions séparées des blocs de VRAM du fichier .map. Par contre, ce faisant, j'ai cassé la possibilité d'animer le contenu de l'écran en réaction à une collision avec un bloc spécial.

Je dois reconnaître que j'y vais à tous petits pas, là. Entre autres à cause de la faible quantité de temps libre qu'il reste après les transports et les opérations de maintenance domestiques ... et encore, je suis loin du compte.

Bref, on va commencer par ré-établir un lien entre la "méta-map" et les map-à-images puis il faudra ajuster les changeblock() et autres clearblock() pour que tout passe. Mais caser ça avant St-Nicolas ? Je dirais qu'on est à un niveau d'improbabilité de 3.14 ou pis.

Tuesday, July 09, 2019

Toolset and MonsterPropWindow

I've got less free-reading time during my vacation this time, and likely, I should be not blogging right now, but cleaning up all the mess that going to vulcan(eifel) and back brought to the house. When I did get some time, I spent it clarifying some obscure parts of my Level Editor which puzzled me when I initially tried to add some additional monster edition features, like being able to decide within LEDs whether a given game object belongs to the 'hero' cast, the 'evil' cast or none of them.


I refactored a few things to make that possible already and I hope I'll get some time to continue working on it within the upcoming days.

I also took some time documenting one of the more elaborate (but arcane) widget that I might have to use to do that: the 'ToolSet' meta-widget, which is truly a bunch of buttons hacked to behave like the typical radiobuttons of point-and-click GUIs.

Tuesday, September 11, 2018

Truly Testable Level Editor

There was one annoying thing with the scripts while adding 1-up, and  that was I had to add the new rules in every level. This is the kind of things that should be written only once, and as far as the script parser is concerned, it could be written once, in the "rules.gam" file. The problem is, this file would be ignored by the level editor, and thus is not used so far.

And unfortunately, there are some design flaws in the way LEDS' own parser is written, making any change in that part pretty tricky to do right. It would be nice to refactor that a bit, but such a refactory with no easy way to test things would be errors-prone. My next move must be towards testable LEDs logic.


And I realised my first idea for the tests, with modified readers and all, was over designed.

Instead, it would be interesting to have two simple programs that run checks on parsed levels (eg. what are the coordinates of game object #42 , or how to display special block#3) or that do simple changes and then write back the result. Test cases are then simple shell perl scripts combining calls to those tools and to standard file comparison tools.

What I still need to figure out is how I'll extract specific information (e.g. what gob another gob links to) out of the full data. And how to compare the extracted data.

Thursday, January 11, 2018

Engine Refactory

The Big Refactory has started (I could pretend it is a new-year resolution). And it even went pretty far, like abstracting away the animated objects list so that only the code for animated objects need to know details of the animation scheduler.

I was about to try changing the VRAM allocation system so that only classes deriving from using Resources could request items, and I got stuck in the animation editor.

Unlike SEDs and -to some extent- LEDs, AniMEDs still use a lot of global variables. Things like the sprite set or the animation being editted are used almost directly in many places, instead of being captured as "structural singletons". And at some places, it also means that we were calling Ressource Manager directly at top-level code, and that contradicts what a common base class can do.

There is one other peculiar thing about the animation editor: the set of pixels used in the game isn't uploaded to the video memory. Instead, we keep it in main memory, and only some bits of it go tothe VRAM through a Sprite sheet that map some sprite memory.  These sprite sheets are linked to a specific widget, such as the timeline or the frame preview. I must not try to make them part of a "model": they truly belong to the implementation of the widgets.

And yeah, although I have a digital sketchpad and an e-boox, I still enjoy some good paper and fine (erasable) pens for such things.

Tuesday, December 19, 2017

Refactoring de dingue!

J'hallucine. J'ai pris une de mes plus vieille classes -- InfiniMap, responsable à la fois du scrolling et des collisions sprites/map. J'ai renommé ça en "CommonMap", appliqué les changements partout sauf aux sites de construction. J'ai ensuite déplacé le code utile dans un nouvel InfiniMap, déclaré l'une ou l'autre méthode comme purement virtuelle dans CommonMap ... et recompilé.

I can hardly believe it. I picked of my oldest classes -- InfiniMap, that controls  scrolling and  -sprite-vs-world collisions -- and renamed it common map, everywhere but on lines of code building some instances. I then moved the "real" code into a new InfiniMap, mentioned a few ."pure virtual" markers in common Map, and rebuilt...

Et ça marche ! C'est du délire à l'état pur. Ok, j'avais une classe iWorld mais je ne m'attendais pas à ce que le truc ne réclamme aucune autre intervention. Nada.
Allez, demain, je déplace le maximum de variables membre.

And it works! I can't beleive it! (dott). I knew I had some interface class already, but I wasn't expecting it to work that easily, not requiring any fix or whatever !

Tuesday, December 12, 2017

branches, reviews and cannelloni

The idea is hanging around. It has been for some times, now. Possibly since I re-started exporting code to e-book readers through Doxygen, or since I tried to use apple assault as a tutorial to libgeds. I'd like to go for some in-depth review of my engine code. I'd like to use powers of code versioning system to slice code into readable, purpose-supported chunks, which would help the reader which components bring what feature and how they interact together.


Plus les choses avancent, et plus j'ai envie de pouvoir proposer quelque-chose de plus didactique pour encourager d'autres amateurs de développement de jeu à s'essayer à la plate-forme NintendoDS. Pour ça, il me faudrait pas mal de réorganisation du code, et (idéalement) une branche mercurial qui approcherait les techniques nécessaires une par une, mieux documentées et testables. Et là, maintenant, c'est parti.

But now, I started it. I've got a "bare minimum" DS application with corresponding library code (mine or 3rd-party), and its build system.
[done] found the source of Noda's EFs tool again.
[done] have it built as part of the dsgametools host-tools binaries, buildroot-style.

Saturday, December 02, 2017

spriteram vs . Resource

Using InspectorWidget to understand buggy situations has become abnormally hard. Just look at the picture we got earlier this season. Compare that to what it used to look like. I've got the "boxes" area all messed up. Of course: in School Rush I now have two things trying to use the sprites of the bottom screen: Inspector Widget and the HUD.

I needed to change a bit the code for the HUD (which uses a SpriteRam to load hud.spr) so that it tells the GUI engine that it used some resources, which are thus no longer available to the InspectorWidget... and let the Engine give some other tiles to Inspector Widget.

One thing I had overlooked is that I devoted up to 256KB of VRAM to background tiles on the main screen, leaving only 16KB for HUD sprites. At 256 bytes per 16x16 block, that means I can have at most 64 different blocks at all. I have 20 different sprites used, 44 left.

Inspector Widget uses 1 such block for "box-borders" (with 4 different flips), and then it has 4 areas-reporting sprites (made of 64x64, 16-color sprites that get scaled up and down to match the effective area shape). That's 32 "tiles" count each for the engine, or 8 of the "blocks" I've used above. So with proper values, I can get it right.


Tuesday, July 25, 2017

simplifions le HUD

J'ai attaqué une révision du code de contrôle entre le moteur de jeu et l'affichage de l'écran du livre-magique. J'ai déjà remplacé les tests douteux sur des variables obscures supposés indiquer si on est sur le menu ou dans le jeu par une commande explicite "hud.mode=%c"

The code controlling the HUD logic deseperately needed some refactoring. It smells it has been written with a "oh, come on: this is just testing X and doing Y". As the rules for the game status display became more complex (different pictures for the menu, then custom behaviour for power-ups, then a complete different behaviour for the credits level ...

Je continue avec une simplification des relations entre "GameScript", "GameWindow" (qui s'appelle toujours CmdWindow parce qu'elle s'occupe des fichiers .cmd) et "Hud". Le Script et le HUD sont maintenant créés avant le chargement du niveau, le "setup" qui permet au HUD de savoir quel objet est le héro, où sont les compteurs, le score, etc. se produit explicitement lors du dernier "end"

So I started with making the behaviour of the HUD explicit through hud.mode=xxx in the scripts -- since both menu, credits and game levels are separate scripts. Then I refactored the way the HUD is constructed and linked to the GameScript so that parsing hud.show "xxx.spr" can lead to some Hud::showScreen() although the HUD isn't ready to run its play() function yet (i.e. because it doesn't know the pointer to Bilou's state and to game stats, which will be taught by the GameScript through the Hud::setup() call).

Once again, all this was made possible thanks to doxygen-on-cybook where I could annotate code with refactoring thoughts until I was ready to sketch the desired behaviour as UML. Once this is done, I'm ready to code it in small chunks, one evening at a time.


Enfin, je suis prêt pour un 'hud.show "somefile.spr"' qui me permettra de raconter une petite histoire sur l'écran du bas avec une image différente pour chaque niveau.

Wednesday, June 28, 2017

UML_LOOK = YES ?

Voilà un des schémas que Doxygen peut produire si je le mets en mode UML (ce qui est sympa, parce que du coup, je peux comprendre les flèches) pour une des classes de mon éditeur de niveaux. Je peux limiter le nombre de "champs" pour chaque catégorie (histoire de garder la taille des boîtes sous contrôle), mais malheureusement pas la profondeur d'exploration. Résultat, le graphe devient vite immense, inutilisable.

When I come back to some code I've been writing long time ago (hey, the project is 10+ years old, now, remember?), I usually take some time with my cybook to study the code through doxyge-rendered documents and sketch in UML what is meaningful for the feature I want to add/change. So it would make sense to have doxygen do some UML for me, wouldn't it ?

Well, doxygen indeed has an UML_LOOK setting that turns available as soon as you declare to have the "dot" graph tool from graphviz package on your (linux) system. Neat. It also has -- took me some time to find them -- settings to reduce the amount of classes that are explored, and the amount of items that are reported for each class.

This is all quite nice, but I'm afraid it will not work nicely with cybook viewing. Whatever I do, the collaboration graph remains very large, both in pixels (and I'm unsure the cybook could pan in a bigger image) and in bytes (10x bigger than doxygen's defaults -- which had only inheritance graph, I admit).


Non configurable ? vraiment ? Voyons, et DOT_GRAPH_MAX_NODES, alors ? et DOT_GRAPH_MAX_DEPTH ?

Eh bien ils font plutôt du bon travail, mais je reste avec près de 3Mo de fichiers .svg pour LEDS, contre 500Ko de .png quand je reste aux graphes de base. Pour la lecture sur tablette, je crois que je préfère ne pas prendre le risque.

What would the perfect feature set be ?
- having the inspected class at the center of the diagram
- be able to specify a canvas size, instead of a maximum amount of nodes
- don't say "and ## more items" when you drop some items
- have a separate "depth" setting for inheritance and for structure/composition
- only show "meaningful" methods/fields of surrounding classes
- still show when a class has relationships with multiple classes of the graph
- don't show "obvious" common ancestors (e.g. the Widget class for all the widgets)
- don't show "obvious" type of data that everyone uses (e.g. std::vector) as a compound.

But let's be pragmatic: this is not the job of a heuristic filter: this is the job of an interactive exploring program. Sure I wish such an interactive tool could be running on my e-ink device, but this is not part of Cybook's business plans, unfortunately. And it is unclear that this could be achieved solely through e-pub documents structure. (would more require an HTML5 canvas or dynamic SVG + JavaScript)

Saturday, April 29, 2017

Adding the MapAnim

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

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

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

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

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


Monday, March 27, 2017

Bamboo Spark to the rescue

J'avais envisagé m'offrir une noteslate pour mon anniversaire. Mais même un an après la date de sortie annoncée dans l'appel à pré-commandes, il n'y a toujours pas de Noteslate disponible. Par contre, j'ai reçu la très sexy et un peu curieuse "bamboo spark". Une tablette graphique nomade et autonome, en somme.

I have a dream of an electronic device that would not hurt the eye. It would be as easy to use as a sketchpad. It might be crude, but it could capture drawn information as naturally as a keyword captures typed information.

I had hope that noteslate would match that dream. I had hope that staedler digital pen would fulfill that dream. I had hopes that hacking code for the cybook would make that dream close to reality. It didn't worked. This week-end, my family gave me a Bamboo Spark unit. Something that captures pen strokes, even when there is no computer around. You just write on plain paper with a modified rollerball pen. When close to an Androïd/iOS device, you can then swap pages that are in the device's memory.

From there on, you can send your notes to different data-sink applications on the phone/pad you have, though unfortunately, with my fairy's pad, twitter and blogger applications don't seem to work.


On trace, ça enregistre. On synchronisera avec un appareil Androïd (ou iOS pour les autres) plus tard. Les traits sont nets, bien plus précis et fiables qu'avec le décevant stylo numérique de chez Staedler, malgré la présence ici et là de "lignes fantômes" que je dois encore retoucher dans gimp. C'est aussi beaucoup plus propre qu'une photo de bloc-note et même que la plupart des scans.

 The result is clearly more appealing that whatever I come up with using a scanner or shooting a picture, but it is unfortunately not yet perfect. First, I cannot crop without downloading the file on a full-blown computer (or maybe I could do that in Androïd's Image Gallery ?). Second, the device introduce random "ghost strokes" that impact readability and better have to be deleted. It's a shame the "draw" feature of the androïd application can only paint white (or black) pixels over the captured strokes, and not delete a stroke as a vector object.

Pour les schémas du type "UML" et sans doute pas mal de croquis d'études, c'est assez chouette. Par contre, peu probable que je puisse m'en servir au bureau pour encoder directement les comptes-rendu de réunion: la reconnaissance d'écriture n'est présente ni dans l'application Android, ni dans l'appareil lui-même, mais uniquement sur les serveurs de chez Wacom. Pas sûr que le boss apprécierait que tout ce qui se dit en salle de réunion termine là... Et pour le contenu du blog, on repassera: la fonction n'est disponible que moyennant abonnement premium :(

If sketching UML documents works fairly well, there is no default handwriting recognition. For that, you have to upload to wacom's cloud and pay the premium subscription to their services. That means the device can't be used as a write-to-report short cut, unfortunately. Not if the meeting whas somewhat private, as any meeting at work would be:


Wacom may disclose all of Your Personal Data to service providers [for data processing, storage and transmission, and other form of support for the application] and to legal authorities [in case wacom believes this is required by law]. Wacom will not sell or disclose your personal data  to other third parties.
I thought I had found a windows application that would allow me to skip the need for a android device at hand (for use in the office, that is), but it is apparently for another device. I also find it strange that it leaks usage information through Google Analytics. The era of Micro Application is so far away ! (in any case, as mentioned in the Inkspace license contract, "You can withdraw your consent by opting-out the use of Google Analytics. The opt-out is available under /Settings/About/Google Analytics/ within the Inkspace App").


Sunday, February 05, 2017

class LayersConfig

All my DS tools share the same "GUI engine", but all somehow have custom requirement on what the hardware compositing engine -- the "layers" system -- should do.

Yet, so far, they do that by peek/poke-like custom lines of code hacking into the video registers of the Nintendo DS. Because the hardware is so elegant, I had no real appeal to hide it between an abstraction layer, but now I run into issues where console can't be read anymore.

So let's try to make it more structured. Capturing all code that access the layers control register into one class would be nice. I think that class -- let it be "LayersConfig" -- could be associated with *Windows classes that define the different "modes" of the application. Switching between the drawing-on-grid and the Palette-edition of the Sprite Editor implies changing the active window. Same for swapping between files picking and map editing of LEDS or swapping between downloads and playtesting in RunME.

I think I should stop trying to optimize which character is updated on such window switches and consider that there should be a clearscreen followed by a full repaint, if that's not yet the case. That could make Window::clearscreen an interesting place to do tricks like letting only some part of the console show through, for instance.

Tuesday, May 31, 2016

ChannelState.CurrentCell

Je replonge un peu dans le code de libntxm. L'idée, c'est d'ajouter à ChannelState une référence directe à l'emplacement dans le pattern.  La bonne nouvelle, c'est que comme les patterns sont stockés piste par piste (plutôt que ligne par ligne), il est assez facile d'avancer dans une de ces "pistes spéciales", l'idée étant bien sûr de les configurer pour qu'elle jouent le contenu d'un des "effets sonore sur pattern" de mon frère... pas de murs à défoncer pour cette-fois ci ... par contre, pour l'instant, on entend rien ^^"

Let's go for some more libntxm hacking. I added years ago a "ChannelState" structure to capture what effect processing code needs to know about the running player. What I want to have now is a way to "lock" some channels to a specific place in the tune indepently of where other channels are (that is, current position in song), so that I could have channels 1 and 2 of a sound effect playing temporarily on channels 14 and 15 of the NintendoDS. Well ... enough blogging, it's time to run ddd and figure out why I don't hear anything.

edit: oh, well. I guess with 'unmute()' function silently skipping action past the 12 official channels of the song, I'll have no hope to see it working :P

edit++done.


edit: according to my computation, this was the 1000th posted entry. Roughly 10 years after I decided to Bilou on Nintendo DS.

Sunday, May 24, 2015

The Ultimate Scrolling Analysis.

Huge thanks to Itay Keren for having written his essay that creates a clear nomenclature of camera techniques in (mostly) platformer games, ranging from Pac-land's position locking to Mario's platform snapping to linear interpolation and beyond.

Grâce au développeurs de Frogatto, j'ai pu découvrir l'existence d'un excellent article sur le scrolling des jeux de plate-forme publié il y a quelques jours sur Gamasutra. Eh oui. C'est ça, l'après Google Reader. Je ne vais pas repasser en revue toutes les techniques qu'il présente, du premier platformer à nos jours -- pour ça, il y a l'article d'origine, mais j'en profite pour mettre à jours mes propres références.

Lerp in action. (C) Itay Keren.
Back then, when I started researching how to move Bilou's camera, my colleague Cyril suggested "an elastic string that would draw back the camera to Bilou's position". One close match is Donkey Kong Country's linear interpolation technique. It still has some "wobbly" effect but much less nausea-inducing than when you lock to the player's position. But this is far from being the only camera mechanic in DK games. Anyone who played the game has noted that some areas of the level are apparently "scripted" with cameras behaviour and that entering some hitbox may suddenly allow the camera to move past some artificial barrier, revealing a hidden area. More subtly, this can also be used to enforce "bottom-locking" in some part of the level, or change the horizontal tracking to the type of gameplay (rush, explore, climb...) of a specific area.

Commençons par une technique que j'avais laissé sur le côté quand elle m'avait été proposée par Cyril -- une "sorte d'élastique qui ramènerait la caméra vers Bilou" -- que j'avais tenté d'implémenter avec le code de poursuite des BerryBats. J'aurais mieux fait de procéder comme dans Donkey Kong Country avec une "interpolation" linéaire qui déplace la caméra d'autant plus vite qu'elle se trouve loin de son point de destination.

When I tried myself to analyze the horizontal scrolling of Super Mario Bros, I thought that there was two 'push-the-screen' positions, depending of the speed at which Mario moves. The reality is a bit different.
two triggers in SMB. (C) Itay Keren.
There is indeed two trigger positions, one -- walking barrier -- that forbids Mario from entering the rightmost part of the screen, and a second that smooths camera movement when Mario starts running. The "early-scroll" trigger doesn't try to keep Mario at its left, though, so he eventually "escapes" to the walking barrier.


Passons ensuite à SMB1, avec son interdiction de revenir en arrière. Ici pas de soucis pour faire demi-tour, mais Miyamoto a quand même pensé à nos jeunes estomacs et a ajouté un démarreur de caméra deux blocs avant la position 'naturelle' de Mario. On y gagne pas pour autant en visibilité pendant la course comme je le pensais au départ, mais on évite un départ trop brusque de la caméra si on revient en courant.

This is what smooth out the movement of the camera by reducing the instan(aus)eous acceleration of the image. I'd be tempted to say screen will move at walking speed until the real barrier is hit. I guess with more CPU cycles and memory, miyamoto's team could have even tried to linearly over time in that region rather than having two-steps, but I doubt most of us would notice the difference, so it's not bad to keep it simple. But no, you don't really have more headroom when running in SMB.

Finally, Itay's model of Super Mario World's camera nicely complement the video document I already found (and not yet re-blogged so far). The camera here clearly has multiple mode, that Shaun categorizes as "platform-snap", "bottom-locked" or "free-moving". I tried and mapped these as an UML state machine, but it lacks one component: the fact that in some levels/parts of the level, some transitions are forbidden -- e.g. in some levels, you will not enter platform-snap and stay bottom-locked.

Les différents mode de suivi vertical de Super Mario World, j'avais déjà étudié par l'entremise de Shaun. Le code est assez sophistiqué pour mériter une machine d'état à lui tout seul. En plus de ça, certaines transitions sont interdites dans certains (morceaux de) niveaux, forçant par exemple la caméra à rester au niveau du sol à moins que Mario ne s'envole dans les niveaux plats. 


What Itay adds to that, is a clear illustration that the camera in SMW has a direction state of its own (moving leftwards or moving rightwards) distinct from Mario's movement. In each direction, there is one barrier that will make you push the screen if you try to go past it, and a trigger that will switch to the other mode if you touch it. When the camera is "heading right", the two yellow lines are active -- Mario is confined within 2 blocks. As soon you hit the dashed line while turning back, the camera switches to "cyan mode", and then you have the screen adapting as quickly as the camera's max speed tolerates because you're about 64 pixels away from the push barrier for that direction (still picture shows a point in time where such catch-back occurs).

L'analyse de Itay est plus précise en ce qui concerne le scrolling horizontale. Il illustre parfaitement le mécanisme des deux "poussoirs horizontaux" décentrés (un pour chaque direction de caméra) et les déclencheurs qui forcent la caméra à changer de direction quand Mario a fait demi-tour de plus de 2 blocs. Il semblerait qu'on ait ici aussi utilisé une "interpolation linéaire" pour adoucir le mouvement de la caméra quand elle atteint à nouveau la position de Mario.

With this scheme, the player always have at least 1/3rd of the screen in the direction he face and half-a-screen-plus-one-block in most of the cases. That works quite well with exploration games like Commander Keen, imho.


If you're doing game design in some way, I strongly recommend you to spend some of your "research points" reading Scroll back : the Theory and Practice of Cameras in Side Scrollers.


Friday, July 11, 2014

Un nouveau mode d'action pour LEDS

Ajuster les propriétés des blocs d'un niveau, ça devient fréquent et c'est loin d'être une partie de plaisir dans LEDS. L'encodage par tiles spéciaux numérotés de 0 à 3 est techniquement suffisant, mais c'est une vraie plaie pour l'édition de niveau et encore pire pour la maintenance du genre "faire en sorte que l'encre réagisse aussi avec les monstres" ce qui suppose de passer tous les blocs d'encre de 2002 à 3002 >_<.

Tout celà serait plus efficace avec un mode "inversé" où l'utilisateur peut préparer un bloc de 2x2 tiles avec les propriétés souhaitées puis toucher un des blocs proposé comme graphisme pour que l'ensemble des blocs similaires à l'écran voient leurs propriétés mises à jour. L'idée est simple en apparence, mais on est dans du C++ et donc ce genre de modification est à peu près aussi confortable que de déplacer une porte dans une maison: mieux vaut d'abord faire un bon relevé des murs porteurs ...

Hey there. I hope I will find time to introduce a handy feature in LEDS this summer: the ability to quick-update the properties of blocs appearing on-screen. I spent some time identifying constraints and spotting the locations in the code where I'll be able to insert hooks for this. Wait and see. I have to apologize for the poor picture quality this time. I want to focus my available time on actually *coding* the modifications ^^"

J'avais fait, au moment d'ajouter "l'appel transient du tileset" une cartographie des "fenêtres" de LEDS qui n'est pas loin d'être le plus complexe de mes 3 éditeurs pour DS. Cette semaine "offline" fut l'occasion de me re-familiariser avec tout ça, retrouver les bouts de code correspondants (imprimés sur 25 feuilles de brouillon, vu l'état de mon cybook), de compléter avec les dépendances entre classes et d'essayer de trouver le meilleur emplacement pour la véranda ... pardon ... pour la nouvelle "fenêtre d'édition rapide des propriétés du niveau".

Les contraintes sont donc les suivantes:

  • SpecialsWindow doit s'enchaîner sur MapeditWindow, qui s'enchaîne elle-même sur TilesetWindow pour avoir l'affichage souhaité. Faire des sous-listes de widgets au sein de TilesetWindow aurait pour effet de rendre la map invisible pendant l'utilisation du nouvel écran.
  • SpecialsWindow doit être créé par TilesetWindow qui lui donnera l'accès à deux de ses SpriteTables (sprwidgets)
  • L'activation de SpecialsWindow ne peut être décidée que par MapeditWindow, seul composant capable de dire si on se trouve ou non en mode "édition des propriétés du niveau". On peut déléguer l'exécution de cette décision au TilesetWindow ou à la fenêtre-racine de l'application.
  • MetaLayer (widget) est le mieux placé pour effectuer le remplacement des données une fois que la SpriteTable aura lancé l'évènement indiquant quel est le bloc-cible.
  • [done] J'ai 96 caractères disponibles pour des affichages adaptés (p.ex. un bloc fendillé plutôt que 0202). Le nom apparaissant en (2) sur le mockup et les caractère spécial affiché sur la map sera défini via le fichier .cmd et ses structures 'bloc $no { @commands } '
Je crois qu'on peut dire "heureusement qu'on aura pas besoin du mécanisme "transient windows" cette fois-ci" :P (qui permet d'avoir le GuiEngine qui produit un évènement 'GUI_ANYKEY' aussi lorsqu'on relâche les boutons).




Saturday, April 05, 2014

Collision avec le monde

Au milieu de ma série de scans sur le thème "Critical Link", je retombe sur un diagramme UML représentant la séquence d'action qui découle d'une collision entre un personnage et un bloc spécial. Comme il va prochainement me falloir gérer des collisions entre crayons fixes et taille-crayon, je blog en stock ...

This is how collision between a Game OBject and the tiled world occurs in my current Game Engine for DS library.  Scribbled note next to the dotted line says "collide(c)" and comments "current code enforces
  • block disappears only if extra & 0x80 is set
  • block reacts only with HERO when extra & 0x40 is set.
where "extra" is the  8-bit reconstruction of the free bits in each special tile
.

Thursday, February 27, 2014

LEDS refactoring

I noted an annoying bug/missing-feature in LEDS that limits the creation of new maps: monsters list is unchanged when you start a new map. That doesn't please the game engine that may end up with a large number of GOBs that sits outside of the level limits, triggering high number of movement failures, etc.
Voilà. Je m'attaque à cet agaçant problème des monstres-hors-monde qui ralentissent à l'extrême l'exécution de RunME. Un cas qui ne se produit que lorsqu'on construit une nouvelle map (plus petite) à partir d'un modèle qui contenait déjà des monstres. Avant de procéder au "filtrage" proprement dit, j'ai réorganisé un certain nombre des classes à travers les fichiers: si je dois sortir cscope pour trouver quel fichier contient GobBlock, c'est qu'il n'est pas dans le bon.
L'écran de sélection des fichiers à aussi eu droit à sa restructuration pour rendre le fonctionnement par "modes" plus clair tout en évitant les accesseurs redondants.

I've gone through some refactoring of the "WelcomeWindow" code (the part where you pick which file you want to operate on), mostly giving each "state" a dedicated function for its specific processing. That introduce some level of redundancy, but it will make the doxygen-navigation through the code more comfortable, with smaller functions and more precises "called from" relationships. I'm also preparing a modification of the "Block-based parsing" of command: most the issues I'm encountering in the Monsters-to-GobBlock link comes from the fact that monsters are kept in a vector while they should be kept in a list. Once in a list, I can keep long-distance iterators e.g. so that you can delete one object when the user says so or when it's cropped out of the new map.


PS: Some UML for this finally got uploaded, a bit late, since I'm moving to a new office, and I've had plenty of cardboards boxes with O'Reilly books in the house, stacks of magazines that wait for being relocated and such. I don't want cheap-mobile-phone-shot for 

Saturday, September 15, 2012

Doxygen & Cybook : round 2

That's for sure: doxygen output on a cybook is a great thing to plan the next update on my tools. I can do that any time while commuting, take simple notes and then just commit the changes into code when I get to a keyboard-enabled computer :)

Still, that requires a bit of tweaking of my Doxyfile configuration:

COLS_IN_ALPHA_INDEX    = 3
ALPHABETICAL_INDEX     = YES
REFERENCES_LINK_SOURCE = NO
REFERENCED_BY_RELATION = YES
FULL_PATH_NAMES        = NO
Au fil des mois, mon cybook odyssey se révèle de plus en plus un puissant allié pour la programmation de projets-hobby. Toujours en poche (ou presque), il me permet de planifier les évolutions de mon projet à tête reposée, dans mon fauteuil, sans nécessiter de réimprimer à chaque fois la dernière version du code. Il a évidemment fallu un peu chipoter pour avoir des documents "pratiques" sur cet écran 600x800, en enlevant les numéros de ligne ici, changeant la structure du document là, etc. Mais le résultat est plutôt satisfaisant.

J'aimerais juste que l'Odyssey soit capable de détecter les "clics" sur les schémas en mode "image map" (cf. p. 1629, par exemple) et que doxgen propose un mode "epub" natif qui m'éviterait de faire tourner "calibre" pendant près de 10 minutes pour la conversion html->epub.

Once the doxygen files have been created, I need to post-process them to strip out line numbers in the code. There's unfortunately no configuration setting to do that *in doxygen* itself, and I lost the patch that forced doxygen to avoid generating them altogether.
fe class*.html "mv % /tmp/% ; sed /tmp/% -e 's:/a>0[0-9]*:/a>:g;' > % ; echo % stripped"

Last step is to get rid of <namespace>:: prefix in some classes name (in the class index) so that it actually fits 3 columns.
mv classes.html /tmp/ ; sed /tmp/classes.html -e "s/>[A-Z][a-zA-Z]*::/>/g;" > classes.html

Unfortunately, calibre is still über-slow processing this, and it looks like the Cybook Odyssey doesn't support clickable image maps. Anyway, if you want to give it a try (and have the hardware as well), here's the file.