Showing posts with label special block. Show all posts
Showing posts with label special block. Show all posts

Saturday, July 12, 2025

Mario in Godot

Refaire Super Mario World dans le game-maker "Godot" ... j'ai envie de dire à la fois "tout ça" et "rien que ça". Pourtant, l'idée de Wye n'est ni de proposer un Mario World Studio ni son Mario World 3. L'idée, c'est de comprendre le fonctionnement du jeu d'origine en le reconstruisant dans un nouvel outil tout en apprenant l'outil lui-même. Et ça, ça me parle. C'est le genre de bouquin que je dévorerais mais ici, ce sont des vidéos youtube.

"In Super Mario World, Mario was considered fully underwater if both his head and body interaction points are touching water tiles. [...]

That's the kind of things you can learn by watching Wye's series on re-making Super Mario World in Godot, and learn how to use Godot in the process

I've been following the videos roughly since episode 1 or 2, but as Wye now address the water physics, I cannot just remain a silent watcher. I've spent too much time working on water physics myself, and I need to compare the approaches. Of course, Mario isn't using the "cando"  function. Instead, interaction with the world are guided by "interaction points" which remember the type of tile they're on. So for instance, 

"When Mario body is in the water but not his head, that means he is near the surface."

Du point de vue des collisions avec le niveau, Mario n'est pas une boîte. Il est ... une sorte de constellation de points qui ont chacun leur préférence sur le type de terrain 8 en tout, mais dont certains ne seront évalués que dans certaines conditions. Pour déterminer s'il faut nager ou non, ce sont par exemple ce sont les tests du milieu et de la tête qui entrent en ligne de compte. Et pour déterminer si on peut sauter hors de l'eau ? Bin il faut que le corps de Mario soit dans l'eau mais sa tête hors de l'eau. On évite en fait les complications du type "la surface est à la fois de l'air et de l'eau" dans lesquelles je me suis embarqué.

And only when Mario is near the surface is it possible to jump out of water ... and only if pressing UP in addition to pressing the JUMP button ...

The concept of interaction points comes from the disassembly of SMW itself and was discussed in an earlier video. They replace hitboxes when it comes to interacting with the world and there are 8 of them for Mario. But as usual with 16-bit games, not all points are tested on every frame. What is interesting is that rather than testing e.g. "left side" when moving left, the game tests "left side" only if the left side is "smaller" than the right side, as a way to detect "new" things, assuming that what covers most of Mario's box has been tested in the past. "When Mario is on the right side of a tile, the two points on the left are ignored" is possibly a better way to describe what happens, indeed ^^".

I'd be curious to find out to what extent that keeps working where your level grid isn't exactly one hero wide ...

edit: while you need to *press* the jump button to make Mario jump when he hits the ground from a fall, you just need to be *holding the button down* when reaching the water surface to trigger "jump out of water".  (from the "extra bits")

Sunday, May 28, 2023

special properties

While thinking at 'how to implement conveyer belts', I end up investigating some currently incomplete code in special blocks handling. They have correct implementation of their collision areas, but since the migration to the new tile types engine, they can no longer act as 'doors' because they all have the same cando() properties.

There's some code in the parser to change that, and some code in 'FlatWorld' to return BlockInfo::props when we encounter one ...

Wait ... BlockInfo::props is precisely what this last `siscanf()` updates ... so ... that means the code is not incomplete at all ? it just needs to be tested ?

Saturday, January 29, 2022

Les bonus s'emmèlent...

J'étais tout content de voir que Bilou savait aller dans l'eau, et je ne me suis pas rendu compte qu'il y avait un soucis avec les bonus: on pouvait carrément marcher dessus. Quelque-chose lié à la nouvelle propriété F_START_FALLING, sans doute ... sauf que non. c'est surtout lié aux bytes 'regarde à côté'.

C'est que l'ancien moteur de jeu utilisait le numéro du 'bloc spécial' pour décider s'il devait être solide ou non, et la fonction qui indique la 'hauteur du sol' essayait toujours de faire comme ça. L'ennui, c'est que j'ai utillisé les codes 0xfc à 0xff pour les fameux 'regarde à côté' qui permettent aux blocs spéciaux d'être des blocs, et pas juste des pavés de 8x8.

Jan.24. Managed to have Bilou switch to 'swim' state when it gets in contact with F_WATER tiles. It's as swimple as $LFALL->$INWATER on fail [H WATER ?] ...

Jan.25. It uses the new H GobExpression 'operator' that puts type of the tile under character's hotspot on stack, where it can later be compared with a constant flag (WATER). That operator will expect an elevation value on the stack first. like [2 H WATER ?] to tell "check 2 pixels above the hotspot"

But this is not the point of this post. The point is, looking at the video I captured (bottom left on the toot panel below), I noticed I was walking on disappeared apple before going into the water.

Jan.29. When you pick up a bonus, a MapAnim is spawn, that will edit graphics to get that sprinkling animation. It should clear "properties" as well, as soon as you get in contact with the collectible.

Yet, the change to newmeta changed what 'cleared' means on the map. Now, the clear value 0 means 'lookup World::properties[0] to know what you can do'. Another trap was that, when checking ground height, you might find yourself on one of the new "lookup one tile left" or "lookup one tile up" that are used to make special *blocks* of adjustable size (not just special mini-squares of 8x8 pixels). If that happens, code was still lacking "locate the actual block defining corner" and then use that special blocks's properties set to decide whether it has ground or not.

Pas le choix, donc: ici aussi, il faut retrouver le 'coin actif' du bloc spécial et aller chercher ses propriétés dans le BlockInfo correspondant.

Deuxième farce (voir l'animation): une fois le bonus effacé, il a laissé derrière lui un bloc à travers lequel il est possible de continuer à tomber, mais aussi de continuer à marcher. La faute cette fois au tableau des propriétés pré-encodées pour les blocs à définition indirecte (prévus pour les physiques particulières, essentiellement).

edit: if you don't have a twitter account, here's what the videos looked like:

Saturday, December 07, 2019

Rush to Flatworld

It took me some time to get all the special block types working again with the new collision engine for GEDS. Partly because there were places in the scripts that referred to some block identifiers which I had to squeeze from 8-bit to 6-bit. I managed to make it a lossless squeeze, but some bits had special meaning. 

Like all the blocks identified 1xxx or 3xxx triggering actions even when collided by a monster while 0xxx and 2xxx would require a HERO cast. Or like the second character of the id xXxx indicating whether the block would act as sky (x0xx), water, block (x2xx) or floor when not interacting.

Avec le recul, ça me fait un peu penser à un donjon Zelda où on viendrait de trouver l'objet-clé. J'ai un nouveau mécanisme pour gérer les types de blocs sur DS, conquis après une lutte opiniâtre contre les vilains bugs (pensez aux wall masters) et les émulateurs récalcitrants (grosses statues à déplacer vers une dalle-interrupteur au hasard dans la pièce).

Et du coup, je dois retrouver les différents endroits où je peux à présent reprendre le développement. Editeur de niveau amélioré ? Programme de conversion vers un nouveau format de map ? Plus de types de pentes ? chacune de ces "petites clés" supplémentaires seront nécessaires au final pour pouvoir faire une version jouable de la maquette "desert zone" que j'ai en tête, et un bon nombre est aussi utile pour débloquer une conversion correcte de la "green zone". Mais là, je suis dans la salle avec trois portes et je dois choisir la bonne.

But well, it finally works fine for level 1 of school rush, and adapting other levels should now become easy as I patched the "rules.gam" shared file instead of patching directly the level commands.

And while working on it, I also mapped the whole set of "tile properties" that were in use in School Rush. That will help for introducing the new tile types. In addition to the 'special' blocks, some will have direct flags for the 'cando' operations and some will have indirect flags (i.e. you have to lookup a table to know their properties). The idea is to reduce the comparison stress for the 'normal', 'empty' tiles. We may keep the 'monster cage' tiles, but they would be seldom tiles compared to plain 'air' tiles and allow an extra table lookup.

Well, that last part is not yet done. And to be honest, I feel so tired that I'll need to go back to my little "remember you had no blog" notebook to see what has unlocked with the newest achievement and which target should be my next goal. I can't even dare to do that on screen :-/


Friday, March 22, 2019

Level Editor vs new engine

Mes cogitations pour rénover la gestion des maps dans mon moteur DS commence à porter ses fruits, au point que je peux commencer à réfléchir à l'impact que ça aura sur l'éditeur de niveaux. ça me tient à coeur parce qu'avec le système actuel, je ne vois de bonne solution pour réaliser les cours d'eau souterrains que mon frère avait mis dans les niveaux historiques de la Grande Aventure.

Je me dirige vers un système avec uniquement un byte par tile de 8x8 pixels, et quatre grande classes de blocs:
- les morceaux de blocs interactifs, provoquant des collisions auxquelles le personnage doit réagir (pics, bloc-question, bonus, portes ...)
- les zones non-solides mais succeptibles d'affecter le comportement de certains morceaux de code (eau, échelles, courant d'air ...), dites "medium"
- les blocs de "sol" (solides) qui encodent la forme des pentes
- les blocs solides qui encodent les propriétés physiques (friction, déplacement forcé, etc.)

With about 2 more months to think about a better tiled engine, I start having fewer questions and more plans. I'll migrate away from 4-bit-palette being used as tile type and opt for an 8-bit type information per 8x8 tile. I'd have fewer (64 instead of 256) unique codes for "special/interactive" blocks, but the code to handle them would scale to 24x24 or 32x32 pixels blocks easily. I would have 64 different slope-type identifiers and it would be much easier to write the slope-handling code than initially planned.

And to make sure I have required flexibility, I'll split physics-hinting tiles from slope-angle-tiles. Some part of the code will read the pixel immediately under the character's feet and find the angle, while other part of the code will read past the slope and figure out whether we're on ice, solid ground or mud.


ça signifie que la petite palette de blocs utilisée dans LEDS va devenir plus complexe, avec un bouton "montrer les autres options", et que je pourrais bien en avoir trois tranches plutôt qu'une seule pour éviter les opérations de navigation fastidieuses.

ça signifie aussi que c'en est fini de l'encodage de petits "0" et "2" dans la map pour former un code entre 1 et 256 en base 4: l'éditeur de niveau ne pourra plus proposer que les blocs qui auront été décrits, ce qui devrait au passage rendre les choses plus lisibles et plus faciles pour des gens qui auraient envie d'utiliser LEDS pour leur propres projets (on peut rêver, non?)

LEDS will have to adapt this, of course. I won't have to enter digits and cross fingers with hope I remember correctly the codes for a bumper or a spike. The editor will have to know them, now. And it will have to be able to set 'medium' flags individually or pick appropriate slope types. I don't know yet how I'll handle all that.

Autre truc intéressant: puisque l'information concernant un bloc spécial (mettons des briques cassables) n'est plus encodée que sur 1 tile, je vais avoir besoin de tiles qui disent "suite du bloc, cf. à droite" ou "suite du bloc, cf. en haut", etc. Chose qui devrait être plus simple à étendre à des blocs interactifs de 24x24 ou 32x32 si le besoin s'en fait sentir...

Friday, September 07, 2018

Retro-game mechanics explain: golden!

I just went into a super video (link below) about how collision code can be exploited in Super Mario World to beat the game faster. I'm not much into speedrunning myself, but I love whatever can teach us how those old games where built and what is the logic behind their engine. And tool-assisted speedrunning quickly gets quite deep into those subjects. So let's go.

C'est du tout bon. Une vraie pépite. Une fois encore, "retro-game mechanics explained" confirme que même quand on a pas l'intention de pratiquer le speed-run intensif, les découvertes des speedrunners sont une mine d'or pour qui s'intéresse aux techniques de programmation utilisées par les anciens de l'ère 8/16-bit. Et cette fois, c'est Super Mario world qui s'y colle.

When a tile is activated, it is deleted, and a sprite version of the block will displayed in its place. When that sprite returns to its initial position, it is removed, and another tile is set in its place (usually a brown block).
Well, that was an expected one. And as he explains, it was already used in SMB3 (and probably also back in SMB1). It is something I'd like to put into my own game engine as well, although the closest I have so far is simply the "mapanim" to replace tiles of a specific location on the map along an animation triggered by a collision.

Si vous avez déjà un peu cogité la manière dont les consoles nintendo construisaient leurs images à base de mosaïques de "tiles" et des "sprites" par-dessus, vous aurez aussi deviné que pour faire sursauter un bloc-question quand on le touche, il faut effacer le bloc de décor (à base de tiles, donc) et le remplacer par un graphisme librement positionnable (un sprite) le temps de son sursaut, puis remettre à nouveau des tiles pour le bloc transformé. C'est sympa d'en avoir une confirmation depuis l'analyse du code (et oui, j'ajouterai ça dans ma todoux-liste un de ces quatres).

The next one is a bit more unexpected.

Which tile is activated during sprite/tile collision is determined by a point that is a mix (blue) between the the sprite's position (green) and its clipping box (red). If that point is not within the tile that was activated [...] there will be block duplication.
Of course, that duplication is the whole point in SMW - Level End Glitches video by RG Mech EX:  the location where to spawn the bopping block and set the new brown block won't match the original question block location, which will remain unchanged. Interrestingly, this is partly because sprites that are located inside a solid tile are ejected outwards so that they don't get stuck. I always thought that would be mario-specific, but actually no: it applies to all objects.

Un peu plus inattendu: en plus de leur zone active -- la hitbox, en rouge sur la carapace -- qui doit rester en-dehors des zones solides du jeu, les objets ont un point unique qui sert à déterminer quel bloc a été touché. Si on cogne un bloc-question avec une carapace lancée vers le haut, c'est d'abord le carré rouge qui va renseigner qu'il y a collision puis le point bleu servira à trouver avec quoi il y a collision. Chose intéressante, tous les objets subissent le traitement "repoussé par les murs" qui autorise Mario à contourner un bloc lors d'un saut plutôt que de s'y cogner méchamment comme une Giana sister.

En revanche, le fait d'avoir mis le point-test en dehors de la zone de collision m'intrigue. Quelle est la raison ? ou est-ce juste un bug ? et cette possibilité d'avoir changé de position entre les deux opérations du test de collision (boîte et point) trahit-elle une optimisation du genre "on ne teste les blocs-question qu'une frame sur 4" ?

A few wonders ...
- is there a good reason for that blue hot spot not being with the red box (other than saving computation cycles) ? It just sounds like a bug to my ears, since the red box is what triggers the collision.
- is that "ejected first but still triggering the initial block" linked to some lower rate for the collision code compared to the motion code ?


And did you know ?

In order to reduce the number of distinct objects, some power-up blocks have different contents depending on their X coordinate on screen.
The limit on the number of objects you can have in a game engine is a old opponent. I know him a bit too well myself. But still ... Thinking of editing your level and having to shift that key pick-up one block to the left or one to the right so that it actually contains a key feels just mind-blowing. Naturally, it might not have been a big deal for Miyamoto's team who already knew player needs wide enough areas to move their avatar around ... and possibly went for "aha! guess which of those 4 ?-blocks hold a key and which are mere coins ;-)". But still. That's pretty unexpected.

Mais il reste le plus croustillant. Le truc que explique qu'un bloc supposé contenir une clé peut tout d'un coup donner des ailes à yoshi. Visiblement, je ne suis pas le seul à avoir choisi trop peu d'information par bloc dans mon format de niveau, et pour pouvoir représenter tous les power-ups et bonus possibles dans Super Mario World, l'équipe de Myamoto a choisi d'utiliser la position du bloc au sein du niveau pour choisir quel objet serait offert au joueur. Pas la position absolue, hein, mais le fait qu'il soit sur un bloc pair, multiple de 4, impair, etc.

C'est à la fois génial et complètement déroutant. Dans un commander keen, je ne me serais jamais attendu à un truc du genre "si le bonus est au 2eme étage du building, alors c'est une glace à 2000 points. S'il est au 1er c'est un donuts à 1000 points et au 3eme un nounours à 5000". Mais ici, dans un contexte où les blocs-question sont souvents présentés alignés comme les gobelets d'un jeu de hasard, le truc prend tout son sens. Il reste à considérer le "numéro" stocké dans le niveau non plus comme un identifiant d'objet à créer mais plutôt comme l'identifiant du générateur d'objets correspondant. Au moins, ils ont évité les contraintes du genre "un niveau peut offrir soit les ailes, soit une clé, soit un ballon, mais jamais une combinaison de ceux-ci."

Saturday, August 19, 2017

Les autres pentes

Du point de vue du moteur de jeu, un niveau est avant tout une grille dont chaque case reçoit des propriétés: solide, solide uniquement quand on tombe, pente, spécial, etc.

(note to English reader: the handwritten text on the pictures is part of the post's text this time).

... A grid, with tiles telling "solid" or "sloped", or "jump through, but don't fall". And sometimes just "special block".


Les "blocs spéciaux" ne sont pas compris par le moteur de jeu lui-même (d'où leur caractère "spécial") mais décrits dans les scripts qui définissent les règles du jeu.

Ainsi, quand Bilou touche par exemple un Bonus, le moteur de jeu récupère quelques bits d'information pour chaque pavé (8x8) de la grille constituant le bloc (16x16) et reconstruit un numéro de bloc spécial (de 0 à 255) qui permettra de retrouver les instructions à exécuter (faire un son, déclencher une animation, donner des points, etc.)

... each "special block" tile provide two bits that are combined to define the "block number" used to retrieve collision properties, hit box and script expression that makes a bonus play a sound and spikes hurt Bilou. The game engine itself, to some extent, doesn't know anything about the special blocks except how to delegate block/object collisions to the appropriate script sections.

Quand Bilou touche une pente, en revanche, le moteur de jeu sait qu'il doit aller regarder une petite table indiquant la hauteur de chaque pixel de la pente. A priori, la forme de cette pente pourrait être n'importe quoi. Mon éditeur de niveau connaît les pentes à 45° et à 22.5°

The height array tells how high is each pixel in the tile. The game engine knows very well what to do, this time. Some tuning could provide an alternate height array to support a different kind of slope, but I haven't used that so far in the game.


Mais voilà: j'aimerais pouvoir avoir plus de souplesse: des escaliers, des coudes, par exemple. Un petit schéma de rien du tout qui traîne depuis des années (2010?) sur un bloc de brouillon en atteste.
"Le mieux serait d'avoir deux boutons 'pente' [dans l'éditeur de sprites] qui forcent le remplissage d'une ligne de 64x16 pixels avec des pentes suivies (les modèles)"
 ajoute encore le calepin.

That "sprite editor / stripe of sloped tiles" approach hangs around in draft mode for years. Because each tile has a unique address in video memory, I had plan to use that address to extend "advanced slope-to-the-right" into "start-of-slope, 0° to 22°". The issue is that the Sprite Editor has no real control of which blocks goes where in memory. Just filling a row of the tile sheet with slope patterns doesn't guarantee that the corresponding tiles will all receive consecutive (and not even aligned either) numbers in the tile set. The solution was in realising that the Level Editor is the component that should solve the more-slope-types problem.

En effet, la technique que j'envisageais alors consistait à utiliser comme information supplémentaire la position du graphisme au sein d'une ligne de blocs dans l'éditeur de niveau (une "tranche" de 16 pavés de 8x8 successifs). On pourra alors convertir l'information de la grille "pente compliquée vers la droite" en "transition douce de 0° à 22°" parce qu'on est dans le 6eme pavé sur une tranche de 16.

Sur les dernières années, ça n'a jamais été mis en service et mes derniers tours d'horizon dans le code de l'éditeur de Sprites me confirme que travailler "par tranche de 16 pavés" serait un vrai casse-tête (le mode et le moment de l'allocation des pavés dans la mémoire vidéo n'étant absolument pas prévu pour ça).

Et cet été vient une idée qui jette un autre éclairage sur ce problème: "Les pentes douces, c'est un problème pour l'éditeur de niveaux. Ce n'est pas quelque-chose à régler dans l'éditeur graphique.

Et l'éditeur de niveau sait par contre traiter des groupes de chiffres pour montrer qu'un bloc spécial est soit un bonus, soit des pics, etc. En prenant donc un type de pavé qui dit "pente compliquée, regardez les chiffres en-dessous pour en savoir plus", je peux diriger le moteur de jeu vers une autre table de hauteurs qui définit la pente (parmi 16 pentes possibles), mais aussi éventuellement fixer le coefficient de friction (sol dur, glissant, boue-qui-ralentit, etc.)

"Special Slope" type merges the behaviour of "sloped tile" and "special block": it will have less bits available to encode the type of slope (e.g. "only" 16 possible slopes), it will require collaboration of multiple tiles, but instead of creating a BlockArea and trying to match collisions, it will just provide an alternate height arrays.

Il me tarde d'essayer ça ^_^




Sunday, June 25, 2017

rules.gam

Plus proche de nous, mais en partie lié avec ce nouveau projet "behaviour editor",il y a le besoin de pouvoir utiliser un seul même fichier pour définir certains morceaux des scripts qui décrivent les niveaux. Ce n'était pas trop un soucis avec Apple Assault, un jeu dont les "règles" était assez simples, mais qui devient plus pénible à gérer avec School Rush.

Un niveau de School Rush décrit plusieurs types de choses: des resources (map, planches de sprites), des personnages (à travers les fichiers .cmd de comportement à charger), les positions et paramètres des personnages (définis par l'éditeur de niveau) et ce que j'appelle "les règles du jeu": réactions quand un compteur arrive à zéro, valeur initiale des compteurs (p.ex. le nombre de point de vie restant pour le joueur) et les propriétés des blocs spéciaux.

Pour l'instant, ces règles sont répétées à chaque niveau, et plus le projet avance, plus le risque augmente d'avoir un niveau ou p.ex. il est impossible de reprendre de la vie parce qu'il y a un bug dans les règles dans ce niveau-là.

Et le nombre d'animations pour les bonus augmente encore la pression sur ce point chatouilleux.

Extraire tout ça en un fichier qui serait "importé" par chaque niveau devrait être possible sans trop de difficultés, de la même façon que les machines d'états ne sont décrites qu'une seule fois et importées dans les niveaux où on a besoin d'elles. Par contre, pour pouvoir continuer à utiliser les indices graphiques dans l'éditeur de fichier, il faut qu'il sache qu'il doit y chercher les descriptions des blocs spéciaux.

Cela dit, en refaisant un peu d'exploration dans les sources de LEDS, j'ai noté que c'est simplement sur base de l'extension de fichier (.spr, .map, .cmd) que le code destiné à charger le niveau décide de ce qu'il va faire de chaque "fichier supplémentaire renseigné par le script du niveau). On devrait donc pouvoir utiliser un autre type d'extension (.gam ?) pour que l'éditeur de niveau s'y retrouve. Tout simplement.



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, July 14, 2014

pinky LEDS

I've spent too much of my hobby time trying to figure out why one object of my levels didn't work as expected, partly because properties were only encoded as obscure quadnary codes in the level editor. Now, I can give a nickname and a cpc-like SYMBOL statement to illustrate the block behaviour. Whenever a 0-3 special tile is found, the editor will investigate the surrounding tiles for a 16x16 full-block with all special properties, decode the quadnary value and retrieve the corresponding symbol. I thus have pink-ish 'plus' for bonuses that will work in-game, waves for ink, triangles for spikes, etc. At the moment, I still have to encode them with 0-3 tiles and will get the confirmation that they're properly encoded only when moving the screen around. I have plans for better than this, but the first step-stone is in place.

Voilà donc le premier pas vers un nouveau mode d'encodage des blocs spéciaux: chaque bloc peut se voir assigner un "symbole" (façon CPC basic) qui apparaîtra dans une jolie (?) couleur rosée lorsque l'éditeur fait le rendu du niveau. Il faut toujours faire l'encodage "à la main" (c'est même un peu plus délicat que précédemment, puisqu'on ne peut plus loucher sur les codes existants :P) mais dès qu'on déplace la vue, l'éditeur nous confirme que les règles du moteur de jeu ont bien été respectée (numéro de bloc spécial connu, un bloc tout entier a été utilisé, etc.) ... et le petit symbole pointu ne laissera plus de doute sur le fait qu'on a encodé un picot et non pas une fin de niveau ou un bonus.

Ce n'est qu'un premier pas, mais comme ça, je peux enfin trouver et corriger le problème d'interaction avec les taille-crayons dans le "niveau de *deline". J'espère pouvoir du coup aligner 2 ou 3 autres niveaux-courses d'ici la deadline de la neocompo (s'il y en a une cette année).

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




Wednesday, June 25, 2014

Rick Dangerous design documents

J'adore les documents originaux des concepteurs de jeux. Dans un article Pix'n'love, un manuscript sur le tapis, c'est automatiquement des étoiles plein les yeux. Simon Phipps, nous ressort les petits croquis utilisés pour présenter son concept de pastiche d'Indiana Jones à ses collègues ... Et là, je dis ÜberDanke!

The author of Rick Dangerous published some original design documents for his game. Exactly the format I love to discover, with sketches annotated with how-to-play, how-it-works and possible implementation. Within a few pages, we're introduced to the theme (character, locations, motivations) and the structure of the levels. Then you get primary (jump, gun, dynamite) and secondary (stick) mechanics. Thanks a lot

En quelques pages, il nous présente le thème du jeu (le personnage, les emplacements, les objectifs) et la structure des niveaux, puis les mécaniques primaires (sauts, pistolet, dynamite) et secondaire (le baton).

Le côté technique n'est pas en reste:
Simon appuye son concept avec les quelques éléments qui permettront l'intégration d'évènements scriptés qui mettront la mémoire du joueur fortement à contribution par leur caractère imprévisible mais facilement reproductible, qui prennent finalement la forme de "boîte de test" maintenant assez classiques.
Bonne lecture ^_^

edit: these documents and more are now covered in a video Interview with Simon Phipps, where we get advised to start our game with level 2 instead level 1 so that we can revise the difficulty when we'll be done with level 1 and come back to level 2 to polish it... and where we discover that it wasn't the developer's intention to create a game putting that much emphasis on muscle memory (because developers "see the matrix" when testing their game).

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 13, 2014

runme3D

Toujours aussi tendu dans --IRL, au point que j'ai fait les modifications il y a bien une semaine mais que je n'ai toujours pas eu le temps d'en parler. Assez curieusement, j'ai des triangles flashy blancs qui apparaissent dans tous les sens quand je m'approche de l'emplacement d'une éponge sur DS, chose que je ne parviens pas à reproduire dans l'émulateur... et qui ne se produisait pas avec la version intégrée "SchoolTest.nds" ToT

So runme theoretically now support 3D layer when running a game. Theoretically as in "it works in the emulator, it crashes the real hardware, and I have to find more time to figure out why". It has been initialized somehow, since it starts displaying random triangles when one approaches a spongebop, but either I'm dumping incorrect coordinates to those triangles or something was mis-initialised.

Wait a minute. If I download back the copy that's ready-for-self-update, it doesn't display anything 3D in the emulator, while the version I have rebuilt this lunchtime do display it fine. Looks like I'll have to double-check I'm indeed testing my latest build on the RealThing... It sounds like I should have set a stronger separation between "introduce 3D" and "change the web host for self-update" phases ...



Another interesting update on the "broken bonus" issue. I had already noted that only the screen content was bogus. If you move far enough and come back, the bonus are completely removed. I noted this lunch time that we could see some *other* location being cleared. In other words, clearblock() function might not properly handle odd-tiled blocks that sits on the seam of the onscreen texture. Restoring the original screen location to the left of the level makes the bug disappear.

Je pense bien avoir mis le doigt sur ce qui provoque ce curieux bug de bonus-à-moitié-disparus, par contre... et à reprendre le fichier construit proprement, la 3D passe aussi dans runme. Cafouillages de téléchargements, j'imagine. Il faut dire que le "nouvel hébergeur" (le site web de sourceforge) est d'une lenteur affligeante à l'heure des CDNs. Il va falloir que je trouve un autre plan B ou que je parvienne à prolonger mon occupation du serveur qui marchait si bien jusque là.

Thursday, March 26, 2009

BBL metadata.

Voilà. Une fois qu'on dispose de tout un jeu de .BBL avec les tileset correspondant, c'est bien plus simple de reconstituer le rôle des 20 bytes de contrôle ... C'est ce que fait de son mieux ce petit outil "bblmeta.pl" que je vous offre également.

Chaque ligne rappelle le numéro du bloc (en hexa) et sa position dans l'image générée par bbl2png (le premier, par exemple, r02 c12 correspond au premier canon, tourné vers la gauche sur la 3eme ligne de l'image). Suit ensuite les "flags" tels que lus dans le fichier .BBL puis l'interprétation de ces flags par le script bblmeta.pl

J'ai repris la technique des répertoires UNIX: un '-' chaque fois qu'il n'y a rien à signaler, une lettre sinon. Ainsi "B--a-K" serait un bloc solide (B) animé qui interagit avec une clé (probablement une porte). "--g-+-" est un bonus qui rapporte uniquement des points, etc. Pour être exhaustif, je dirais que le programme reconnait:

  1. Bloc, Floor, Wall ou ciel (-)
  2. Pickme : l'objet peut être ramassé pour l'inventaire
  3. g, l ou r : gravité normale, vers la gauche ou la droite. Les autres combinaisons ne sont pas reconnues.
  4. a : bloc animé,
  5. t: réagit au contact
  6. bonus/malus : H=hitpoints, x=kills, + : score
  7. L = 1UP, K=clé/porte.
En plus de ces "flags", certaines valeurs sont indiquées dans une liste entre parenthèse, comme la succession des blocs pour une animation, le nombre de hitpoints ou de clés, ou de points modifiés lors d'un contact , le numéro du monstre tiré (pour les blocs qui tirent des monstres), etc.

Here comes a second funny PERL script. It extracts meta-data from .BBL (Background BLocks), .CBL (Character BLocks) and .MBL (Monster BLocks) produced by RSD Game-Maker. If you used to write games with that editor, feel free to use that tool to retrieve all meaningful elements and port your old funware to some new platform. If you do so (or just plan to do so), please share the joy and post a comment.

This tool is a kind of "preliminary" reverse-engineering tool. It can tell you roughly what are the properties of individual blocks but detailed information may need to be looked up in the 40-digits hex string. Each line describes a block. Right to left you'll have the following information :

1c (r01 c13): 400100000000000000ffff1b64001c0400010000  --ga-x-  (a1b,100)(h-1)
^    coords   |--- complete hex dump of meta-data ---|  |flags|  |---details--|
+- block number
On the right side, "flags" tell you roughly what are the properties of your block. here you see an Animated block that has downwards Gravity and that hurts the player (x) on contact. Details tell you that it animates to block 1b after 100 ticks and that hitpoints are reduced by 1 on contact. On the left, you have block number (block #x pixels are located at bytes x*420..x*420+399 in xBL file) and the row/column coordinates on the picture generated by my former bbl2png.pl script.
Bref, ce n'est certainement pas aussi souple que l'éditeur du game-maker (et d'ailleurs, ce n'est pas un éditeur, juste un outil d'inspection), mais ça capturera la plus grande partie des cas que l'on retrouve dans un jeu de plates-forme comme les Badman.

Hope it Helps ^_^
PS: 1st byte is the index of the generated monster (0x40 = no monster generated), thus byte 2 is likely the delay between two such generations.

Thursday, November 22, 2007

Scrollons encore

On discutait scrolling avec Cyril hier midi, et il m'a fait remarqué assez justement que je m'inquiétais inutilement pour les scrolling à grande vitesse. Bin oui, tant qu'on ne scrolle que d'un pixel à la fois on peut s'en sortir très bien avec seulement 512 pixels de large dans la mémoire vidéo. Au cours du décalage, on finira bien alors à se retrouver avec un morceau de 256 pixels appartenant à un seul bloc de VRAM à l'écran et on a les mains libres pour changer le contenu du deuxième.

example of what concerns me
Mais si la vitesse devient trop élevée, on risque de se retrouver à passer d'un 'bloc' à l'autre mais en gardant toujours plus d'un bloc de VRAM à l'écran, ce qui nous empèche de mettre l'image à jour sans prendre le risque d'un affichage inconsistant. Mais c'est là que Cyril est intervenu: rien n'empèche d'arrêter le scrolling plus tôt que prévu juste pour ce 1/60eme de seconde... On a alors de nouveau les mains libres pour copier le bloc suivant en VRAM, et au coup suivant, on scrollera un peu plus. L'un dans l'autre, ça devrait être invisible (edit 26.11) J'ai testé sur le temps de midi: c'est indécelable.

Hypothesis: scrolling code will be better if we can do one-big-DMA-copy into a contiguous VRAM block (that is, one 32x32 tiles square in the 512x256 pixels setup I envision)
Problem: at speeds higher than 1px/frame, we might never have one of the squares fully off-screen because we switch from "still showing some pixels from the logical square on our left" to "already showing some pixels from the logical square on our right.
Proposal: snap the camera to the squares grid when a transition is detected. That snapping will affect the scrolling speed, but only for 16.6ms so it shouldn't be noticeable.
Result: that looks smooth, indeed. I cannot notice when the snapping happens.

types de blocs pressentis pour Bilou, et leur encodage sur 4 bitsReste un autre problème: l'encodage des "types" de blocs. Si je faisais une copie élément par élément à la main (jouable si on remet un bloc de 8x8 pavés à jour d'un coup), je pouvais chiper les bits "miroir" pour encoder les types dans la carte "offscreen", et les remettre à zéro avant la copie dans la surface "onscreen".
Mais pour remettre tout un bloc à jour (2K), il serait franchement préférable de passer par le DMA.
Mais bonne nouvelle, on peut s'en sortir avec un encodage un peu plus subtil. Imaginez: on a besoin d'encoder si chaque tile est solide, traversable, incliné, etc. mais aussi s'il s'agit d'un bonus, de pics, de lave, etc. Trop pour 4 bits ... sauf si on encode que 12 types de tiles et que l'on se sert des numéros 12 à 15 pour des blocs plus "spéciaux", par exemple ceux dont seul le personnage du joueur doit s'occuper.

Now a more important issue: I also need to encode some properties about each tile, and my plan so far was to use palette and mirror bits for that. That means 64 different properties, which sounds good.

Issue: Palette bits won't hurt unless I enable multi-palette modes (no such plan at the moment), but mirror bits will affect how things show on screen
Idea: Let's have 12 "direct" properties for slopes, ground, air, etc. and have only other properties for 16x16 pixels blocks. That means we can combine the palette bits of 4 tiles to know what block (out of 256 possible special blocks) we use.

Alors, quel est le truc ? Eh bien voilà. Notre niveau n'est pas construit à partir de tiles 8x8 mais à partir de blocs 16x16. On peut donc supposer que la lave prendra bien 16x16, et ce n'est pas juste 2 bits (de 12 à 15) que l'on a pour faire la différence entre les picots, la lave ou les bonus, mais bien 4x2 bits (2 dans chaque tile faisant partir du bloc 16x16). Soit 256 types de blocs spéciaux possibles. De quoi voir venir...

2024 #choice reality check: scrolling code went for 64x64 pixels "square" instead of full blocks. DMA copies are used only for vertical scrolling, but it does not require such pause-and-resume scrolling logic.

2024 #choice reality check: a newmeta" effort has been started after 2 games have used the 'palette bits", so we could have more slopes and more colours with multi-palette.

edit : au final, seul le scrolling vertical utilisera des transferts DMA.