Showing posts with label dyngobs. Show all posts
Showing posts with label dyngobs. Show all posts

Monday, February 10, 2020

GameEngine design: script-to-code

Somewhere in 2009, I added support for actions triggered by the script-part of my game engine but implemented in C++. This is the cornerstone of "GEDS" game engine. This is how run-time monsters spawning and sound effects work. This is also how level load request are processed.

The design survived the years, so let's see how responsibilities are split.

  • Anything that will start invoking code upon game event (collision, new input, animation completion, etc.) is captured in a *Gun instance. The instance carries all the parameter needed for firing a specific kind of code. E.g. An instance of the LevelGun capture the specific level script to load. An instance of GobGun captures which type of monster to spawn, etc.
  • Configuring the *Gun instance happens at script parsing time. In other terms, most of the *Guns could actually be constant objects.
  • The c++ code instanciating an *Gun must be located from the name of the action on the script (with a using [action-name] ([arguments]) as [holster-slot-number] statement). That requires every type of "gun" to have its associated "factory" class, so that an instance of each "factory" can be registered into an std::map to be the link between actionname and the *Gun constructor.
  • Amount of support code for a new *Gun or a new *GunFactory is minimal. Each class have only one (virtual) method, either create() or shoot().
  • *Gun instance typically forget about what they 'shot' as soon as shooting is done. Often, the created object is registered as an animated item at the game engine, which will take care of running its code periodically. This may lead to the need for an additional "progress" object when there isn't any yet, like with the TrackSequence following the instructions (e.g. shooting more guns) as a sound track unrolls in the music player.
  • when processing script expressions, a palette of "guns" (the multi-slot holster, if you want) is received in addition to the set of variables accessible to the script. However, the transitions between states are the one capturing those palettes.
  • The GameScript is responsible for recording every *Gun instance created, so that they can all be reclaimed when the level is destroyed and we switch to something new.
  • There is one guns palette per "state machine file", with the constraint that all the states used by a single "character" in the game have to be described within the same file, this means that a "character" can only use up to 16 different sounds+special effects.
  • The GameScript has the ownership of all these palettes. Reusing guns from parent's palette is explicitly requested. The GameScript knows when to stop using a given palette for new transition and switch to a new/old one because it has seen input/end statements. There is room for improvement here.
Lots of guns. But anyone in GEDS can at most carry 16 of them at a time.
Clearly, the major limit comes from fixed-size palettes of gun, which itself comes from the byte-code nature of the (parsed) script expression where only 4 bits are dedicated to the storage of which-gun-to-use. This is perfectly ok for a Mario-like game, where the distinct number of actions per character remains low. I would definitely need to extend this (and other parts of the game engine like sprite memory management) if I was to create a run-and-gun game where you can pick up lots of different weapons, each requiring a different kind of amno sprite and sound effect.

Thursday, April 09, 2015

iScriptException ...

Something uncomfortably wrong occurs in the game engine. Objects I'm trying to restore have invalid state attached. I believe this is the reason why there has been "guru meditation" screens during last playtests with friends. It seems linked to abnormal use of the memory: while the infringing object seems to have proper structure, it seems linked to a state that is absolutely not looking like a state structure, but rather some animeds content...
That could quite match with some earlier dig into the issue where I had invalid pointers at some delete() operators, leading to red "guru meditation" screens. I unpacked my gdb-remote-analyzers-and-setup-perl scritps. It takes ages to launch the game in that fashion, but I should get a list of stack trace for those locations that shouldn't have been released. I may need to find a proper path to reproduce the issue first.

Meditate on this I will...

3 days later, with 2 runs on the first level, I managed to trigger the exception again in the "demulator", producing 1GB worth(?) of log. I have hopefully a shorter summary of the 11 addresses involved in operations that looked suspicious. I need to program the software eyes that will scrutinize those operations and explain what happened.

2 more days and "PERL's eyes" are ready. I get detailed reports with stack trace of the last allocation, the last sound deletion and the offending "double-free" issue. But what should I think about some memory block that is first allocated in "GobState::addOnDone" (thus should be a transition, somehow, or the vector of transitions), gets deleted as GobState is destroyed, and then destroyed again as a GobAnim ?_?

Finally, one object, shot during some state transition is delete twice, with a time locality pattern that makes it look like a real issue, not some side-effect. Both deletion happens during Engine::animate(), likely at a few frames interval. How has that occured ?

What transition create that object ? What object is it ? Which object created it ? ... At least those questions can be answered with the whole recording of memory allocations. I know from stack trace the address of the transition that created the "faulty" object. From there, running "Perl's eyes" once again, I find it belongs to a "fall->hit" transition of Bilou, and the object generated is a "power-down" object. That might help reproducing the error ... tomorrow.

Question: while there has been only one "constructor" call, could there be two "reganim", making the object linked twice in the objects list ?
Question: if there's a single "reganim" for two "delanim", what is the cause ? Who messed up with the list's invariant ?

Saturday, October 25, 2014

Automated OAMs management

Over the summer, I crafted plans for managing larger levels, that would use more than 128 hardware sprites (the OAMs in DS parlance) for all the monsters. Some of those plans use the notion of a "Gob Group", that could be used to spawn several objects at once, at level-specific locations by having them statically placed (unlike shoot-able "dyngobs") but wouldn't be active unless their group is enabled.

Browsing through the game engine code for another purpose on my cybook, it struck me that it would be so easy to have lazy allocation of the hardware sprites as we approach on-screen area and early recycling of those OAMs when we're going far enough from that area. It's now coded. Funny enough, it doesn't affect activation and movement of GOBs in any way: only whether they have hardware sprites assigned to them or not.

done: find a way for Bilou to keep its priority (displays over monsters)

Saturday, October 11, 2014

Palette Sonore : CJ à la rescousse!

Un point sur lequel je peux facilement donner raison à Kirby Kid, c'est le désert sonore dans lequel on évolue dans le jeu. Un petit "p'tcha!" quand Bilou se fait toucher, un "bop" quand on rebondit sur un monstre et un 'ting' quand on chope un bonus. Et c'est tout. Le lancer de taille-crayon, les encriers qui se préparent, les éponges qui bougent ... tout celà est aussi silencieux que si vous étiez sur Mars.

Kirby Kid also pointed out the lack of sound in the game. Especially, the fact that you don't hear anything when you jump makes it a curious jump-and-run game. I tried converting more of CJ's samples into sound effects, but it didn't really took off. I'll need dedicated samples so that we clearly hear the jump as not being a part of the background music. I also want dedicated sounds when you stun something, when you 'hap' in the air trying to grab something, when you bounce on a pink eraser or when you're interacting with an inkjet.

All this also stems for some code refactoring. As of writing, there is a limited palette of 16 special effects (including sound effects) you can use in the level. It is close to 75% of use, and the major problem comes from the fact that it is _global_. Much like each .cmd file now has its own palette of animations, I need to give dedicated effects palette to each character.


Il est donc grand temps que j'appelle CJ à la rescousse. Mais ça ne suffira pas. Actuellement, je suis limité à 16 effets spéciaux pour l'ensemble du jeux. Celà reprend les sons mais aussi les créations d'ennemis comme les petites étoiles qui indiquent que Bilou s'est fait assomer ou les pieds des Bladors quand on les assomme. Si je veux pouvoir proposer des bonus quand on dégomme un crayon ou une gomme sauteuse, il faut que je fasse d'abord disparaître cette limite.

Ah, par contre:
  • étourdir les encriers à coup de dumblador: ça marche;
  • moduler la force du lancer de taille-crayon par la vitesse de Bilou: mauvaise idée

Btw, I allowed bladors to stun inkjets but turned away from "blador are thrown faster when Bilou moves faster" -- this is just a nightmare for aiming.

Wednesday, July 30, 2014

Ink Swamp Worm


The ink swamp worm
Now *this* is looking better. It tooks two "masters" (one to the left, the other to the right) to ensure that I have a chain of wavelets GOB looking still, and looking to occupy the whole level. I will definitely need a wider GOB for the wavelet so that the spawn rate is enough to cover the screen even when the camera accelerates, and I'll need to investigate the camera offsets (currently, some values curiously refuse to work). But at least I get spawning and termination of wavelets as expected.

Hmm. J'aime mieux ça ^_^ Un "maître" de chaque côté, qui s'assure qu'il n'y ait plus de vagues à une extrémité et qui en génère une nouvelle s'il n'y en a pas au-dessus de lui. Il me restera des règlages avant que ça n'ait une belle tête de mer d'encre, mais on s'approche de l'objectif.
Il faudra aussi que je trouve un moyen d'arrêter la montée implacable de cette encre, au fait ^^"

Wednesday, October 23, 2013

Some bugfixes in progress

After a couple of days checking the stats, I opened the editors again. I wanted to experiment alternative collisions for Spongebop and improve the readability when falling down. I updated camera control so that UP/DOWN DPAD directions can be used to adapt camera (that was quite simple)

I think I tracked down an unpredictible crash on level loading. The crash only occured when reseting the level just after some droplets (the only object that turns into nil) gets deleted. Engine::delanim() should remove the object from the deleteme list in that case, not from the todo list. I also fixed another potential source of silent random crash linked to the lack of dedicated "you're dead / level clear" tracks :P .


Allez, quelques petites modif's avant d'aller au lit. Le nouveau comportement des collisions avec l'éponge, pour commencer, suivi d'une meilleure gestion de la caméra pendant les chutes (Morukutsu appréciera ;) puis la possibilité de regarder en haut et en bas quand on est à l'arrêt ... c'est toujours sympa, dans un jeu d'exploration.

J'ai du débugging sur la planche, aussi. Certains effets de glissés de la musique ne passent pas, les notes en questions restant du coup silencieuses et une sorte de condition de course logicielle pouvait planter la console si on avait le malheur de changer de niveau juste après qu'une goutte d'encre n'ait été retirée (à quoi ça tient, quand-même!)

I could also point out that the inconsistences in the music comes from module effects to be ignored. They should explicitly be supported! that's a task for ddd and --arm7gdb=7777 ... As soon as I got that sorted out and get the confirmation by early downloaders that the game can be launched, I'll post a fix.

All this reminds me, of course, of the "last minute panic" I got when I tried to enable throw-bladors-anytime (3 days before the release) and observed  curious effects: parsing the second level would then corrupt memory (most likely) and make the level loading impossible. On one of my machine, that made the std::map that holds BlockInfo to have an invalid pointer.
Hopefully, once that bug turned "stable", identifying the root cause was a mere "sherlock holmes game": list all the possible causes for one more state transition to corrupt memory, rule out those that are incompatible with the observed behaviour and you get pointed at a "owned" bitfield that has incoherent value (and still rules which transitions are deleted when).

Sunday, September 29, 2013

1 day left

I have quirks in moving inkjets and the pendat doesn't feel like progressing forward right now (nor left now, afaik). There's a more concerning issue, however: I will have to cut the number of monsters present in the level. With pendat reaching up to 6 or 7 "limbs", and each limb being an individual OAM, and all those OAM (i.e. hardware sprite) being statically assigned to objects, I regularily (e.g. when inkjet throws droplets) hit the "128 OAMs" barrier of the hardware that makes some sprite becoming invisible. Another engine update will be requiredwelcome to fix that. That shall be the road ahead.

J-1, bonjour les pépins. En plus des effets curieux lors des déplacements d'encriers et du pendat qui fait la grève, je me retrouve régulièrement avec le moteur de jeu qui se plaint qu'on dépasse la limite des 128 sprites hardware. Il faut dire qu'à lui seul, un pendat en consomme déjà bien 6 ou 7, et que le moteur les pré-alloue pour l'ensemble du niveau. Du coup, quand les encriers décident de lancer de l'encre je suis trop court.

(edit: heureusement, ce n'était qu'une fausse alerte liée au fait qu'un des morceaux de runME s'auto-alloue la moitié des sprites hardware et n'en laisse que 64 pour les niveaux du jeu ^^" voir les détails dans les commentaires)

edit: fixed with automated OAMs management. It took over 1 year, but hopefully, meanwhile I had realised that I was far from the hardware limit and just experiencing issues in runME because it pre-allocated half the OAMs "for internal purpose"

Wednesday, December 12, 2012

GobAnim vs. GobAnim

Something went 'oops' when trying to upgrade the 'bouncing feet' behaviour for dumblador's behaviour. I edited new animations for the feet in AnimEDS (mostly to take advantage of the bounding box edition feature), but when I injected that into the ongoing test level, I simply didn't see any feet anymore.

Armé de mes nouvelles petites anim' pour les pieds baladeurs de Dumblador (et des zones de collisions associées), je venais tout juste de faire les ajustements à blador.cmd, mais en lançant le jeu dans l'émulateur, j'ai juste eu droit à une avalanche de "oops? endless looping" sur la console de débugging. Un p'tit breakpoint bien senti sur iprintf (oui, carrément) m'a permis de voir que je faisais fausse route: ce sont des GOBs "simples" (comme dans AppleAssault) qui sont créés pour les pieds et non pas des CompoundGobs comme Bilou et Dumbladors. Du coup, l'interprétation des données d'animation est erronnée. Je vais devoir passer plus de temps que prévu sur ce point-là.

I had to rely on some DDD to figure out that gob shooting currently systematically create a SimpleGob instance, but that attaching a AnimEDS animation to a SimpleGob just results in non-sense (and likely no display). I thus have to merge a bit more those two co-existing animation parsing (binary and textual) and rendering (compound or simple). The easy way out would be to claim "oh, I can also shoot compound gobs", but the reality is that 90% of shots (weapons, dustballs, feet) will be simple gobs. Only monster generators and Bosses may need something else.

  • [done] GobAnim::parse() should use AnimUser encoding, rather than AnimCommand {} structs. Keep the API (GobScript syntax) unchanged.
  • [done] SimpleGob::play() should align to that new encoding.
  • [done] enable BBOX, origin and pageno's colours bits from anims.
  • [ok] ensure a 1-limb AnimEDS encoding can be used to create SimpleGobs in GameScript::GobCommand() 
  • [done] GameScript::setGobState() no longer blindly cast to SimpleGob to call setstate()
  • [done] GobGun::shoot() no longer blindly generates SimpleGob()s

Monday, November 19, 2012

gob->attach(that)

J'ai trouvé un cas de figure pour tester la fonction "attacher un GOB à un autre" qui doit me servir entre-autres pour transporter Dumblador ou pour faire de SpongeBob une plate-forme mobile.
Je veux dire, "un cas de figure qui ne dépende *que* de cette nouvelle fonction".

Starting to work on a set of new features such varied as "grab bladors and throw them onto other ennemies" usually raise the problem of "where do we start". Among all the features (aligning Gobs onto each other, tracking them, etc.), I need a first one that is simple enough and demonstrate the bare bones needed in the code logic: attaching objects at run-time. It seemed that bladors feet could be a candidate. When I draw Bilou bopping a dumblador, blador's feet are stretched away from its body. And when Bilou throws bladors at pendats, the feet are gone, leaving just a large chunk of steel ... a living weapon.

It would be easy to have feet "thrown away" when blador gets bopped on, but then, what should we do when the blador recovers? It magically rebuilds up wherever its feet are gone, like New Super Mario Bros' drybones ? I'd rather not.

Actually, I'd rather have feet attached to their blador although they have been thrown, and guided by a controller that pulls them back in place. The blador's body (the initial GOB) would then stay stunned until both feet have returned. Not only that sounds funny to do and play with, but it also means that the terrain surrounding the dumblador will affect how long it will stay stunned if you stomp it, and thus how tricky it is to grab it before it recovers. A nice interplay approach, imho.


Je m'étais amusé à imaginer Dumblador perdant ses pieds au moment où Bilou lui saute sur la tête ... eh bien, c'est exactement ce dont j'ai besoin. Les pieds deviennent des GOBs autonomes, mais restent "attachés" à leur Dumblador d'origine, ce qui permet de définir des contrôleurs qui les ramènent vers celui-ci. On verra par la suite si celà crée un gameplay intéressant, mais pour l'instant, ça semble un test prometteur.
  • Le mécanisme "pending" qui garanti que l'objet auquel on fait référence a déjà été traité n'est pas encore complètement opérationnel.
  • Lors de la génération des "tirs", ceux-ci sont assimilés aux objets passifs d'une collision alors que le "tireur" est l'objet actif.

Tuesday, June 01, 2010

AA : early gameplay draft

Vous vous souvenez de la présentation "onirique" d'Apple Assault la veille de mon aniversaire ? J'ai remis la main sur un petit croquis nocturne dans le carnet qui contient les précieuses mesures de ma cuisine. Je vous en dirais bien plus, mais ma fée m'attend pour descendre chez I<ea ... il faut vraiment qu'on change de cuisine.

Remember how the Apple Assault gameplay came to my dreams ? I eventually sketched up the idea that night, but then the sketchpad has been burried down, used to plan my new IRL-kitchen, moved to Sweden and back. Today, it's about time I make a decisive move towards that "new kitchen" thing before *deline gets a hand on frypans... So the sketch got dug up, just when I was using a scanner. Voilà. Here it is online. enjoy it.

PS: oh, btw, it looks like the sketch has later been used to help thinking about dyngobs and their management...

Wednesday, May 12, 2010

0_o still 42 zombies

Making funghi-generated applemen EVIL wasn't such a hard task. Now I need to ensure they are properly destroyed when the level is over. It looks like it's something I had postponed when writing ClearDynGobs() ... Resulting in an enigmatic "still 42 zombies" message in the middle of parsing logs.

I don't like zombies. They believe their iWorld still exists but it doesn't. They mess up with the real world instead, poking and peeking here and there. They follow NuLL pointer ... chaos and madness await them at its end.


Avec 3 jours 3/4 de congé commençant ce soir et les bouts de code qui s'assemblent comme des pièces de puzzle, je sentais bien une pre-release d'Apple Assault avant de décoller pour la Suède ... Un petit message "42 zombies restant" fixé sans trop de soucis (en nettoyant convenablement les "dyngobs"), enfin la possibilité d'assommer les ribanbelles de pommes. Let the sun shine, quoi.

Ouais. C'était compté sans malloc et ses effets à retardement. Cette fois, même gedsdemo, la version autonome du moteur de jeu utilisé pour les release, est affecté. Desmume lui même en reste sans voix: impossible d'effectuer du débugging puisque le "serveur GDB" qu'il intègre semble s'être bloqué lui-même. J'ai quelques pistes à tenter, mais ça prendra du temps, du papier et quelques tasses de thé. Je vous tiens informés.

Btw, 42 apples in a level doesn't slow the engine down in any way, and it produce funny "wiggler" or "lemmings" behaviours. And it sure keeps the doctor away ^_^

I see coming more "debugging sessions darker than night itself", though. For some unclear (yet) reason, the current game engine crash in bowels of the memory manager after two runs. I can only guess this means something is freed twice or some similar issue. The codebase has grown since the last (not so succesful) attempts, and today not only runme is affected, but also the game engine demonstrator. It's the most stable memory bug I've seen ever, and I hope I'll at last be able to pinpoint what's going wrong.

Tuesday, May 11, 2010

Round 1! Fight!

Première véritable tentative de passer à un "véritable" Apple Assault, avec les Funky Funghi dans le rôle (intérimaire) du générateur-de-pommes. Ils maintiennent un nombre à peu près constant d'applemen sur la zone de jeu par l'intermédiaire d'un compteur partagé -- le même mécanisme que celui qui permettait aux "portes" de "s'ouvrir" lorsque Bilou a ramassé 16 pommes ou de relancer le niveau lorsque Bilou n'a plus aucun point de vie.

First attempt to build the 'Apple Assault mod' out of the game engine, using the Funky Funghi as appleman throwers ad interim. A global counter enforces a maximal amount of applemen on the playground (so if you manage to dismiss one, a new one will appear near a Funghi) -- that's the same mechanism that already allowed key-and-doors mechanism in the .999 release or that triggers a level restart when Bilou runs out of energy, actually.

The 'doh-of-the-day', unfortunately, is that dynamically-generated GOBs all have the same cast "DYNGOB", while it is required that they bear "EVIL" if we want Bilou to stomp them. Pretty hard to try out bops-and-shots in that setup, thus. Oh, and by the way it's also the first (fairly succesful) test of release-jump-button-to-modulate-jumps-height feature.

Petit soucis, par contre, le moteur de jeu considère ces applemen comme des "dyngobs": de simples "tirs", qui ne figurent pas dans la liste des monstres pouvant être écrabouillés par Bilou, et qui du coup sont invincibles. Il faudra ajuster ça. Probablement en fixant la caste d'un monstre au moment de l'importation des états vers le script-maître.

Oh, et c'est aussi le premier test avec un saut dont la hauteur peut être modulé en relâchant le bouton de saut ... ça peut expliquer que j'ai eu un peu de mal à m'y retrouver.

Thursday, April 15, 2010

Bat Attack!

Almost everything is in place to build Apple Assault except arenas. Yet, I only had "little stars" to check I can shoot something... So I did a silly thing and started shooting berrybats out of applemans when the appleman is surprised to see Bilou. You may think of it as a performance test ... somehow.

Eh bien voilà: techniquement, le code est prêt pour un "Apple Assault". Je n'ai plus qu'à faire quelques "arènes" à coup de level editor. En attendant ... eh bin, j'ai bidouillé le code de l'appleman pour qu'il jette de petites étoiles et des berrybats lorsqu'il apperçoit Bilou. Ca ne sert à rien, mais c'est marrant, et ça me permet de tester les performances du moteur de jeu. De ce côté-là, rien à signaler.

Par contre, dès que j'appuie sur "START", c'est la galère. Avec autant de GOBs qui apparaissent, et vu le comportement des BerryBats (suivre Bilou), je suis régulièrement en contact avec une demi-douzaine d'entre-elles ... Et InspectorWidget essaie de remettre à jour son affichage à chaque fois, avec un "trashing" inévitable, puisqu'il ne peut m'en montrer plus que 3 à la fois. Je prends donc note de ces 2 ou 3 petites choses à règler mais qui n'empèchent pas pour autant de se lancer dans la réalisation du mini-jeu.

A few things have to be fixed, though they do not prevent the Apple Assault game to be started.

  • [done] Appleman remains too often "stuck in the air" after a fall.
  • [done] InspectorWidget should not break more than once per frame when a new monster enters the collision area. Plus I implemented a simple way to switch the focus to other GOBs (just click their "headline").
  • [wish] I need to randomize somewhat the behaviour of berry bats, which tends to "glue" to each other rather than tracking Bilou individually.
  • [done] make sure I can step-debug without having Bilou to jump. now START = debug, L (when debugging) = step and L+START = continue. That allowed me to inspect the stop and to figure out that the "slowing down" of Bilou was not accounting for walls. So you indeed receive a "stop" signal when hitting a wall, but still advance by one pixel into that wall when "stopping". That was enough to have Bilou then "glued" to the wall. It interferes with usual "L+click" commands, though... maybe I should've used R+START.
  • [done] When something land on ground, its speed is adjusted so that it exactly hit the ground. The "impact speed" -- that we'd like to use for bouncing -- is lost. We should keep that in a specific var. Bounces make Bilou harder to control, though.
  • [done] there is a 1-frame lag between sprite positioning and screen positioning that gets visible when falling at high speed (baddies get 'sucked' by the ground). We may want to delay camera move by one frame so that computed GOB coords is indeed valid.
  • [wish] replacement of a "gun" by a new one doesn't seem to work very well. I've got enough "spare guns", though.
  • [done] I miss something to perform x-align-against-block when a horizontal move is cancelled. That's why it's so hard to climb in the tree. There's interference with animation-controlled movements here.
  • [done] Work out a fail-proof initial state for Appleman and Funky Funghi. such failures interfere with game debugger.

Wednesday, April 14, 2010

oamstack from XeO³

Bion, ajouter des sprites dans tous les sens, c'est sympa. Continuer à avoir des sprites dans le 2eme niveau, c'est mieux. L'ennui, c'est que le GuiEngine, comme son nom l'indique, a été au départ conçu pour gérer des interfaces graphiques (SEDS et LEDS), et pas des jeux, ce qui signifie qu'il n'y a pas la possibilité à ce niveau de libérer des sprites -- ou plus précisément, les OAM, c.à.d. les zones en mémoire vidéo qui décrivent l'emplacement et les propriétés des sprites. Qu'à celà ne tienne: m'inspirant du "stack allocator" pour 6502 du projet XeO³, je rajoute une petite surcouche ...

I was making sure that sprites could be reclaimed and that you keep seeing little stars even if you got hit > 60 times ... Just one problem here : Engine::allocate is the only way to inform the GuiEngine of how much sprites it should sync to the DS video memory ... As the level is reset, that number is reset to 0, but since all the Gobs of the level have just been "pushed" in the oamstack ... well ... Engine::allocate() is never called and thus no sprite show up ... at all. Trivial to fix, but reminds me that you should always think twice when you alter the behaviour of something ... And that was a nice occasion to mention Dailly, Kekule & Russel's work on XeO3 : the Ultimate shoot'm'up for Commodore Plus/4 (which has some armalyte taste, if you ask me) and how this code gets inspiration from the 6502 "stack allocator" for bullets in that game.

Ca n'a pas tout à fait marché, mais presque: le GuiEngine retient le nombre de sprites qu'il a effectivement alloué et ne copiera en VRAM que ceux-là. Or, lorsque le niveau recommence, tous les OAMs précédemment restent dans la "pile de sprites recyclés" alors que le GuiEngine pense qu'il n'y en a aucun en service. Le résultat ? Bin le jeu tourne, mais plus aucun sprite ne s'affiche. C'est plutôt bête comme chou à régler, donc je vais aller règler ça pendant que vous découvrez en détail cet étonnant projet XeO³ mené par Mike Dailly, un (ancien ?) programmeur de chez DMA design dont je suis le blog depuis un moment.

edit: Btw, yes, this implies u8 oamstack[128] because there is at most 128 OAMs per screen and that the game is only on one screen. I can't think of another allocation scheme that would save me more and don't disturb run-time operations. I'd love to extend the mechanism to GameObject structure themselves (which have higher allocation overhead)

edit++: funny, they seem to use the same kind of "script-encoded-into-asm-constants" approach than I used in 2000 for Out'm'UP :).

Wednesday, March 31, 2010

- * aouch * -

I'm not going to claim that 'it works! I can't believe it". It's a little too early for that, but at least I've got the framework set up and the boring stuff done. I can have little stars shot away from Bilou when he's stomped by Funky Funghi. There are still weird things to be investigated such as "why doesn't they disappear as expected?" or "why do they look like coming out from Funky Funghi rather than from Bilou?"

Il est encore un peu tôt pour crier victoire, mais ça prend forme. Ces petites toi-toiles s'échappent de Bilou lorsqu'il se fait écraser par Funky Funghi ... les éléments permettant de gérer des objets dynamiques s'assemble ... l'objectif "apple assault" se rapproche. Il me reste à comprendre et corriger quelques effets curieux. Ce serait aussi bien qu'elles disparaissent lorsque leur animation est terminée par exemple ... et qu'elles proviennent effectivement de Bilou.

Source-checking and cross-checking doesn't seems sufficient. I'll have to meditate this.

edit: les petites étoiles sont supposées rebondir quelques fois sur le sol puis disparaître grâce au code suivant:

state19->state19 on fail [v1 $20 >] (v1 $40 - ~ :1)
state19->nil on fail [t]
mais curieusement, ça ne marche (presque?) jamais avec [v1 $40 >] comme gardien et seulement de temps en temps avec le code ci-dessus. Je viens de réaliser que le contrôleur "gravity" ajuste la vitesse verticale lorsqu'on rencontre le sol de manière à ce que la chute se termine sur le sol. Ca casse évidemment tout mon beau mécanisme puisqu'au moment de l'évaluation des transitions, ce n'est plus la vitesse de l'impact étoile-sol que je lis, mais la distance à laquelle l'étoile se trouvait par rapport au sol. Je vais réviser ça. Ca pourrait bien expliquer quelques autres bugs dans le comportement de Bilou et de l'Appleman.

Oh, and btw, here's a small UML snippet of the classes involved in such "extra actions". The 'red path' show interactions when an action definition is parsed, and 'blue path' how the actual "shooting" occurs.

Tuesday, March 30, 2010

Gobs Dynamiques

Pour permettre que Bilou soit assailli encore et encore par (e.g.) des Applemen, il me faut ajouter à mon moteur de jeu le support des objets dynamiques. Jusqu'ici, chaque élément "vivant" du jeu (les "GameObjects" ou "gobs") est déclaré dans le script produit par le level editor. Il possède un numéro d'identification unique qui détermine sa place dans la "table" des gobs. Si ça marche plutôt bien pour les ennemis classique, c'est évidemment insuffisant pour les tirs (pensez à un shoot-m-up), les bonus mobiles (le champignon de super-mario), les petites animations sympa (la petite étoile qui apparaît quand Kirby se cogne trop fort) ... et ... les monstres créés à la volée par un "générateur" (qui sont une variante des tirs, finalement).

J'ai déjà en partie la logique qui permet d'invoquer la construction d'un objet depuis la logique du jeu, je dois encore m'assurer que j'ai la possibilité de décrire le fait qu'un tel objet peut disparaître ... et mettre en place un petit test pour vérifier que tout ça fonctionne bien.

So far, most of the sprites in Bilou are statically defined in the game script produced by the level editor. They have a unique ID, well-established initial coordinates and so on. And that works pretty well, mostly because I haven't introduced anything like "shots", moving bonuses or any run-time generated monsters. One of the key elements of "Apple Assault" is precisely that there will be more and more monsters coming like in a Game&Watch.

I've got some of the logic to bring new monsters to life during the game ready, which has been tested for sound effects. I need to check that such monsters can also be terminated, both during the game (e.g. at the end of an explosion animation) and when the level is completed/restarted.
Then I'll need to put this all together and check it indeed works as expected in a small "gedsdemo".

I'm not pretending it's a tedious task. I'm just a bit overwhelmed IRL to start coding something that allocates memory dynamically after office hours.


Et pour être tout à fait honnête, les parts de Munchkin et autres pizza-buffet initiés par mes collègues sur le temps de midi ne sont pas complètement étranger à l'apparente lenteur sur cette tâche.

Wednesday, June 17, 2009

gun.shoot(this)

Tout comme les contrôleurs, les "générateurs-d'objets-en-cours-de-jeu" (baptisés iGun, pour faire simple) sont des classes C++ paramétrées par le script et associées à certains états ou transitions pour ajuster le comportement du jeu.
Pour les contrôleurs, je les avais associé à l'état courant. Facile (presque trop). Pour les "guns", j'hésite. Le script ? une transition ? un objet graphique ? Qui aura accès directement à la classe, et qui n'y accède qu'à travers les méthodes d'un autre ? C'est le genre d'indécision que je déteste en POO, typiquement parce qu'en programmation impérative, le problème ne se pose pas.

  • C'est au niveau des transitions que les guns sont utilisés. Je peux éventuellement capturer ce qui m'intéresse lors du parsing.
  • Je n'ai droit qu'à 16 guns dans une 'palette' d'effets
  • Je veux éviter de devoir ré-instancier des guns identiques (contrairement à ce qui se passe pour l'instant avec les contrôleurs où je dois avoir autant de GravityController que d'états affectés par la gravité).
Not quite "analysis paralysis", but still not enough time after lunch to figure out the best way to add iGun into the object-oriented game engine. It is used by Expressions (after all, guns are used to shoot new GOBs into the playground), but it's only one of the 16 guns an expression has, and it is likely to be shared by many states. What scope should it have ? which object will 'host' it, etc.

I'm undecided. I'll have to leave it for further code refactoring.

Bref. Je devrai revoir cette partie-là un autre jour: mon temps de midi touche à sa fin...