lundi, avril 29, 2013

Ishisoft @ Lundum Dare

oh joie des flux RSS et de Google Reader: j'apprends sans effort que l'auteur du très bon Johnny Biscuit Romp nous a proposé un sympathique jeu de puzzle "Princess Chardonnay in Bomb Kingdom" pour la Lundum Dare de cet année. Je sens qu'on va se régaler ^_^

Yummy! Another Lundum Dare with another production of Ishisoft, author of one of my favourite puzzle-platformers. That definitely qualifies as a RSS-sunny day. I definitely need an alternative to the soon-dismissed Google Reader if I want to keep track of such good news.

(2016: we have a play-through video: confirmed, it looks great gameplay)

samedi, avril 27, 2013

emergent gameplay => higher replay value

Avec la "mise en page simplifiée" de mon cybook, je me refais la série "Mario Melodies" de Richard Terrel (aka Kirby Kid). Je venais de commencer le premier article "Interplay" quand je tombe sur:

Put simply, interplay is where actions and elements in a game aren't means to an end, but fluid opportunities that invite the player to play around with the changing situation.
Richard fais grand cas du "gameplay émergent", où les possibilités sont si nombreuses que jouer au jeu devient un mode d'expression de son moi profond. Bon, personnellement, je trouve ça limite fumeux, mais voyons-voir ... que donnerait un jeu dans lequel le concepteur a tellement cloisonné le gameplay qu'il ne reste aucun "moyen d'expression". 

Première scénette: le challenge est de passer à travers un parcours dangereux, de plate-forme en plate-forme. Par "dangereux", j'entends on ne saute pas et on ne tombe pas: y'a des picots partout. Pour passer de l'une à l'autre, il faut appuyer sur le DPAD ni trop tôt ni trop tard, c'est tout. Le challenge est donc une simple question de timing, bien qu'on puisse assez facilement en faire une question de réflexe ou de mémoire avec une plate-forme plus rapide dans un environnement légèrement différent... ça me rappelle Jet Set Willy et Adventure Island, ça ...

I was reading the "Mario Melodies" series again on my Cybook. I noted that Richard Terrel puts extreme importance to emergent gameplay and how it enables self-expression. I hadn't bought that at first. If I want to express myself, a pencil is better than a gamepad, isn't it? But let's give it a second thought: what would a game look like if there's no room for self-expression ? I sketched a couple of test scenes. In the one above, you have to move from one platform to the next, with appropriate timing. As there are spikes at the ceiling, jumping ahead isn't an option. You really have just one way to make it, with little buffer for compensating our reflex when pressing the DPAD. That just reminds me of things I didn't liked in Jet Set Willy and similar mole-featuring "exploration games" that never really convinced me. Super Adventure Island also had such moments, iirc. 

Bon, mais si on a des ennemis, c'est plus intéressant, non ? Bin pas forcément. Imaginons Badman aux prises avec un chevalier-boomerang. Celui-ci se protège de son bouclier sauf pendant qu'il lance un boomerang. Le seul moyen de l'atteindre serait de rester face à lui, le temps qu'il lance son boomerang, sauter par-dessus celui-ci, puis tirer et sauter de nouveau avant de se prendre le retour de boomerang. De nouveau, aucune autre des attaques de Badman ne passerait car le boomerang les fait rebondir. Terriblement Mega-Man (quand on a pas encore trouvé l'arme ultime qui gèle le boomerang ou attire le chevalier dans la lave en aimantant son bouclier).

But there was no monster in this example. With some monsters, it would be more interesting, don't you think ? Well, even monsters may enforce a strict gameplay to you, where there's only one valid strategy. If Badman face a boomerang-throwing knight in the middle of the statues swamp, his only option is to shoot while he's not shielding. So it's a reflex game where you JUMP just before he throws his boomerang, then SHOOT as you land and JUMP immediately afterwards to dodge the returning boomerang. That's fine from time to time, but if that's all the game as to offer, it stops being MegaMan, and becomes extremely no-chance-I-play-it-again.

That could be what is the value of "emergent" gameplay to me: invite to play the game again, later on. Through the POGO and SHOOT-DOWN mechanics, Commander Keen offers emergent encounters against ennemies while the levels themselves would rather invite to memorize the best path. But the following SMB-inspired example gets it even clearer. The appleman is the opposite force, the counter-point. Suppose that its trigger zone has been adjusted so that it will land on Bilou's head if the player simply walks straight to the right.
Through RUN, the game allows players to zoom under, unharmed -- something that skilled/experienced players will do more than novice. Of course, you can adjust your approach, relaxing the walk a little to let the appleman land and stomp it ... or you could try and stomp it mid-air to reach the higher area. 




Enfin, contre-exemple directement inspiré du niveau 1 de Mario Bros: Bilou peut courir et sauter, et les deux actions ont un rendu direct qui en rend l'impact ajustable. Le goomba/appleman a été placé de sorte que si le joueur se contente d'avancer normalement, il lui tombera sur la tête (parcours rouge). Bien vu. Celà dit, en courant, Bilou/Mario peut passer par-dessous l'Appleman (parcours vert). En sautant plus ou moins haut, on l'élimine ou on l'évite (parcours bleu). Subtilité supplémentaire, en sautant assez tôt avec assez d'élan, on pourrait même carrément atteindre la plate-forme d'où il est tombé en lui rebondissant dessus pendant sa propre chute. (parcours mauve).

In conclusion, a game with emerging gameplay is a game I'd happily play once again, while games with strongly guided gameplay is something that look like a thriller novel: once you've played it and aren't thrilled, you're unlikely to even open it a second time.

dimanche, avril 21, 2013

translucent ?

I managed to have some translucent effect through fast (60Hz) sprite flickering. That's mandatory if I want sprite-versus-sprite transparency. So if I want Bilou to look "inside" the inkjet, I need an extra patch of glass that will flicker over Bilou to partially obscure him.

J'étais tombé par hasard sur l'épisode "Spécial Disney" du joueur du grenier, dernièrement.  Après une bonne tranche de rire avec ma fée sur la partie "La Belle et La Bête", l'analyse (nettement plus grossière) de Fantasia par Infogrames me rappelle à quel point il est important de soigner la communication des règles du gameplay à travers l'aspect visuel. Le livre géant et menaçant qui est en réalité un bonus (et non un ennemi comme son aspect le suggère) et l'espèce de rond dans l'eau qui est en réalité une plate-forme.

Mais maintenant que j'ai le moyen technique de rendre les sprites transparents les uns par rapport aux autres, est-il intéressant de rendre l'encrier transparent ? C'est plus réaliste, sans aucun doute mais ça n'est pas forcément mieux pour autant. L'aspect d'Inkjet doit transmettre au joueur "solide, dangereux, mais pas blessant", et pas "fantôme immatériel mélangé à l'arrière plan". J'ai donc fort probablement commencé l'ajout des sprites rectangulaires (pourtant attendu depuis longtemps) sans que ça n'ait aucune utilité immédiate.

That being done, shouldn't the inkjet itself be translucent (against the background), and if so, how do I achieve that, given that the ink itself must remain opaque ? Basically, the only way is to separate the "glass" of the inkjet and the ink itself. That puts enormous stress on the vram as inkjet animation takes almost 1/4th of the spriteset so far. doubling it ? aouch. Hopefully, the ink only takes 16 pixels high, so that would be worth an update of SEDS to support wide (and tall?) in addition to square sprites.

Although its in progress, is it really wise to go that way ? Does the translucent inkjet on the right look better than the non-translucent (except for the patch) on the left ? Or does it rather look ghost-like rear object which you wouldn't expect to be solid and ride-able ? After all, form-fits-function is crucial in video games, and the only way to allow the player to have "eureka" feeling rather than progressing through frustrating trial-and-error.


Bref, c'est l'occasion de rajouter le terme "Form Fits Function" au tagtionaire... ce lien entre l'aspect et l'effet si cher à Miyamoto et qu'Infogrames a systématiquement ignoré.

PS: the DS also has 16-color sprites, and obviously, the inkjet shouldn't need more. Converting the whole sprite page into 16 colors could do the trick ... but that's not supported neither by the Game Engine nor by the Sprite Editor at the time of writing. At best, it's a wish.

mardi, avril 16, 2013

where to go ?

    L'encrier est presque prêt et l'éponge aussi ... Ne serait-ce pas le moment de laisser les dumbladors de côté et de se concentrer sur un "gameplay" dans la School Zone (à savoir Deep Ink Pit). Parce que peaufinages et expériences mis à part, on peut considérer qu'il n'y a pas eu de "nouveau" jeu impliquant Bilou depuis 2 ans et demi!  Voyons un peu où nous en sommes.
    • [done] We have bumper-like erasers on top of pencils. that means we're ready for inkjets that throws Bilou up.
    • [sketched] adapt Bilou's behaviour so that he's "in" the inkjet when the stomping the inkjet from the top
    • [done] Spongebop moves, it could use extra animations, but it still doesn't act as a platform it will be GRABable, instead.
    • [done] Bilou can recover from being stunned
    • [todo] verso's turnback on walls, track Bilous when in sight.
    • [todo] SpongeBop makes you bop higher and higher.
    • [NEED] fix Bilou/sponge collisions when Bilou stops grabbing a spongebop (InspectorWidget upgrade to set breakpoint on hero-driven collisions could be needed).
    • [think] land-when-falling and bop-when-pressing the button on contact ? Is that any possible ?
    • [d.i.p] recover from being hurt mid-air. 
    • [wish, n&b] stand on stunned bladors. Don't bounce.
    • [r1158] is there something wrong with jumping to the right ?
    • Bonuses ? providing an offset within block-anims for simple bouncing animations ?
      • [think, done] How do we make Bilou appear through the glass when inside an inkjet ? 
      • [wish] Bilou should be slower when walking up slopes (it's already faster when walking down, as it's moving at sqrt(2)*v). Can we use a negative "postponed move" to avoid messing up with speeds in such a way that speed drifts towards 0 ?
      • [done] Find a way to investigate the "stuck-in-walls" bugs with Inspector Widget.
        • when jumping along a left wall, coordinate displayed in IW is suddenly reduced by 2 pixels, and when Bilou lands, he's slightly on the left.
        • at that point, trying to turn back to the right make it move one more pixel to the left, and he's definitely stuck.
      What is still missing for deep-ink-pit 0.1 release ? Apple Assault is now roughly 2.5 year old, and it would be nice if I could present something with a goal and ways to win/lose the game for the summer coding competitions, so maybe it's time to fork out of "SchoolTest.nds" and focus on the features involved in Deep Ink Pit instead... bladors (and pendats ?) would return in Nuts'n'Bolts...


      On the other hand, we're so close to a running demo of "School Zone level 1", which never was possible in the BASIC version, that it almost sounds like a crime not to push the effort up to that level.

      dimanche, avril 14, 2013

      Start+R+A

      Reprise du boulot oblige, la progression de cette semaine est moins impressionnante, mais peut être tout aussi importante. Si DaySi a brillamment repris le flambeau depuis la chute de DarkneSs, elle se fait de plus en plus capricieuse avec son bouton R. Oh, il fonctionne, pas de soucis de ce côté ... mais il n'est plus très fiable. Il peut être nécessaire de pas mal le titiller pour déclencher quelque-chose, et quand il se décide, il n'est pas rare d'obtenir des "rebonds" du genre "on/off/on/off" en une seule pression du doigt.

      Pressing Start+R+A or Start+R+R in SEDS lets you chose between "Save" or "Save As", changing the way a back-up copy of your file is created. When your 'R' button may automatically read as "R+R+R" for a single press, it quickly becomes unmanageable to have coherent file history. So I finally took the time to add some LOAD and SAVE clickable buttons (plus a tool option to invoke cursor mode in SEDS from the stylus) to compensate hardware deficiences of the DS.

      Dans la mesure où ce bouton contrôle la "sauvegarde" dans SEDS et AnimEDS, c'est plutôt génant. A plusieurs reprises, j'ai du re-transférer d'anciennes versions de mes livres pendant que j'en faisais la mise à jour pour corriger une réécriture intempestive alors que je cherchais juste à activer le mode curseur (lui aussi déclenché par R). Mais voici donc une mise à jour de mes outils qui offrent des boutons cliquables (au stylet, donc) pour compenser ce genre de problème. A noter que le bon fonctionnement du bouton L, lui, reste incorrigiblement critique.


      mardi, avril 09, 2013

      Circularity

      Spongebop monster design was a way to convert the (imho) funny and interesting spider monsters of prehistorik 2 into Bilou's world. As such, they won't simply move up or down, or track Bilou while sliding (as suggested in the 20-year-old proposal), but also rock and roll, hanging by a thread. Another conversion of dangerous-but-useful NPC rather than an evil ennemy.

      Une éponge qui se balance au bout de sa corde ... une idée de monstre sympa et qui ouvrait pas mal de perspectives dans la "School Zone", mais techniquement plus délicate à réaliser qu'un "simple" monstre sauteur ou marcheur, en particulier avec les contraintes techniques de la DS. Depuis l'automne dernier je dois bien avoir gribouillé 3 ou 4 techniques succeptibles de rendre la chose possible sans jamais être allé jusqu'au stade de l'expérimentation. Mais maintenant que je peux attacher un objet à un autre au niveau du script, il est temps de monter un prototype.

      Now, it's time to turn this "nice idea" into some real code. Physically speaking, spongebop will act as a pendulum bob, oscillating as the result of gravity and counter-force originating from thread tension. We're taught that when 17 at school. There's just two major drawback to a "straight coursebook implementation":
      • it's full of angles, sin(x) and cos(x), which are pretty heavy for our 66MHz processor
      • It assumes a rigid, fixed-length rod between bob and pivot.


      Conservation de l'énergie, mouvement circulaire ... ce ne sont pas les approches qui manquent, mais chacune a aussi ses hypothèses de travail (notamment la présence d'un axe fixe que je ne désire pas). J'étais au départ prêt à utiliser une variante des algorithmes à la bresenham pour les cercles, mais la multiplication n'est en fait pas si coûteuse en terme de temps de calcul que je ne l'aurais cru. Je peux donc exploiter assez librement l'équation x²+y²<=r qui décrit tous les points à l'intérieur d'un disque. Dès que les la distance entre SpongeBop et son point d'attache ne valide plus cette contrainte, c'est qu'il tire trop sur la corde.
         Bilou would pretty much love that sort of predictable and massive pendulum platform, but spongebop's thread is instead fairly elastic and landing with excessive velocity triggers a rodeo session, says the comic concept art.
        In other term, I would like something more flexible, that can constraint Spongebop to stay within a certain circular area, but still allow Lissajous-like patterns when drawn away from its equilibrium path, as I explained this lunch-time to Cyril. So fundamentally, Spongebop's behaviour is defined by two controllers:
        • gravity, that takes care of the "free riding" when x²+y²
        • radius detects situations where x²+y²>r². As soon as that occurs, we use a 'unit' vector that points towards the pivot position and iteratively move spongebop back into the allowed area.

        Ce qui est assez amusant, c'est que si je parviens à faire en sorte que SpongeBop ne puisse allonger exagérément sa corde, j'aurai le mouvement de balancier par simple application du même contrôleur gravity que celui qui sert pour les sauts de Bilou. Je rejoins alors le "scénario BD" qui prévoit un comportement plus cahotique lorsqu'on atterit trop violemment sur le dos d'une éponge. J'utilise donc le vecteur "attache-éponge" pour définir une "direction de rappel" et ajouter un déplacement vers le centre tant que Bop est hors de son cercle de repos.

        Ideally, energy preservation should keep the sponge oscillating as long as the level runs, but there's something that looks very much like friction in the digital world: precision loss. Since we're working with fixed-point arithmetic here, we're losing some speed in rounding coordinates and angles, so that after about 3 cycles, there isn't much movement left. It's compensated by a refreshing impulsion generated everytime Spongebop arrives just below the pivot point, as if it had some muscles that helps it control its movement. That part is handled by some gobscript and the controller merely report "you're at (0,ymax)" through an event.

        it's a sponge bob ^_^

        MUL instruction on ARM9 merely takes 2 cycles. As a result, I ended up dropping my initial idea of using (x+1)²=x²+2x+1 and simply re-compute (x+a)*(x+a) whenever needed.
        I have at most one division per frame (per instance), to define the centripedic 'unit' (1/16th of pixel) vector. Yet, division isn't handled by the CPU, but by some extra software (the support library coming along with devkitpro's flavour of GCC). I think I'll live with it unless it turns out that I'm over my cycles-per-frame budget.


        Le résultat est plutôt satisfaisant. Ce n'est pas un arc de cercle parfait et je dois "relancer" le mouvement régulièrement, les erreurs d'arrondi en virgule fixe ayant tendance à l'amortir trop rapidement. Je m'en sors donc avec une division (software) par éponge et par frame au prix d'une progression itérative pour recentrer Bop lors de ses déviations. C'est plus erratique que le pendule du cours de physique, mais ça colle plutôt bien au personnage. Reste à maîtriser la 3D pour tracer l'élastique et le co-processeur mathématique de la DS pour avoir accès aux divisions et aux racines carrées la prochaine fois.

        Agreed, the trajectory followed by SpongeBop on the animation above is not quite a circular arc, but for some dizzy sponge on an elastic string, I think it does the trick. Now it's time I allow Bilou to "land" on SpongeBop, because solely bopping over is pretty tricky.


        Hmm ... tracing a GL_LINE between the spongebop and its pivot (not yet visible) would be a nice use case to introduce 3D support in the mix ...

        PS: all this was the last idea of a long list of dropped approaches. Maybe I'll discuss alternatives later on.
        PPs: of course, although the ARM processor on the DS has no support for division/square roots, the DS itself has extra hardware for such functions.  Since it says "square root takes 13 cycles", it could be worth to use the sqrt(dx²+dy²)/sqrt(R) ratio to properly compute the pullback force rather than relying on iterations here. (that's still an occurence of premature optimisation, imho)

        vendredi, avril 05, 2013

        LEDS update

          Mon filieul (12 ans) -- de passage chez moi -- s'est assez rapidement désintéressé de ses projets de monorail LEGO et m'a laissé entendre qu'il avait son AceKard 2 en poche pour que je lui fasse une mise à jour d'Apple Assault. Après des semaines passées sur Minecraft DS, il était mûr pour se lancer dans du dessin de niveaux et j'en ai donc profité pour lui transmettre l'intégralité de mes outils de développement, avec les spritesheet dernier cri... pour me rendre compte qu'il y avait un très désagréable "guru meditation" au moment de charger les derniers niveaux (variable non-initialisée dans TileTable).

          Je contourne le problème en lui installant plutôt la dernière version "stable", et après avoir essayé les techniques de contre-attaque d'Apple Assault, le voilà lancé dans la réalisation de "Thom.map". Il maîtrise plutôt bien les techniques de base pour placer des blocs sur la map, et a rapidement pigé le fonctionnement du "plan de collision". Le voilà donc qui place quelques blocs-code pour que ses crayons blessent et s'émerveille devant son premier niveau qui prend vie.
            Mon seul regret aura été de ne pas avoir pu lui permettre de placer des monstres sur sa map. J'ai un couac avec l'édition des monstres dans LEDS. Ils apparaissent complètement tordus malgré mes meilleures tentatives pour importer les "miniatures" d'AnimEDS. Après une série de tests en émulateur ce matin, j'arrive à la conclusion désagréable que le SpriteSet est trop grand pour pouvoir accueillir les 48 miniatures d'animation (1Ko chacune) ajoutées au sprites de base.
            One of my lil' nephews asked me to install my map-design tools on his DS earlier this week. And this led to some more flaws to be identified in the version of LEDS I shipped on my birthday. After I fixed a guru meditation error on level loading, I still had to figure out why monsters thumbnails couldn't work right. It's a bit tricky to tell a 12-year-old "don't trust those pictures you see in the level: this is a blador, and that's a sponge bop although they both look like shrunk-down version of Bilou".

            C'est un peu ridicule, parce qu'il n'y a pour l'instant qu'une dizaine d'états initiaux pour Bilou et les 3 monstres de la school zone (spons, blador et inkjet). Mais l'éditeur de niveaux ignore tout ça et tente de faire tenir toutes les miniatures d'animation plus toutes les images individuelles (des fois qu'une animation à l'ancienne les utiliserait). Je pourrais bien sûr rationaliser tout ça et faire en sorte que chaque byte en VRAM soit utile dans l'éditeur ... Mais si la DS n'est pas capable de traiter plus de 1024 images différentes pour les sprites, elle est en revanche parfaitement capable de traiter des sprites plus gros. Jusqu'ici, j'utilisais DISPLAY_SPR_1D_SIZE_64, soit 64 bytes par sprite (8x8 pixels ?). En passant à DISPLAY_SPR_1D_SIZE_128, je perds la possibilité d'utiliser des micro-sprites, mais je peux faire tenir mes 64K d'images dessinées dans SEDS plus jusqu'à 64K de miniatures rajoutées par AnimEDS sans compromis notable puisque SEDS travaille au minimum avec des sprites de 16x16 (donc DISPLAY_SPR_1D_SIZE_256 pourrait même s'envisager).

            After sufficient time was invested into documenting the multi-pass parsing of the command files in the editor, a lunch-testing-session revealed the naked truth: the amount of sprites supported by the video hardware was once again the root cause of the issue. More precisely, it wasn't an issue with the amount of VRAM (the game engine accepts up to 64K of sprites and all the thumbnails won't take more than 48x1KB) nor with the number of objects the hardware can handle, but merely with the number of individual graphics that can be addressed by the OAMs.

            Hopefully enough, it was a mere matter of re-configuring the GPU so that it uses coarser indexing. So far I could precisely point at a single tile (8x8 pixels) in sprite memory, which only used the first 64KB. Yet, it's possible to use up to 16x16 pixels per index (the size of the smallest sprite generated by SEDS. Even with an intermediate and conservative setting of DISPLAY_SPR_1D_SIZE_128, I immedately recover the ability to preview the monsters on the level. Too bad: my nephew is gone :P

            But that's not too much of an issue: as soon as his DS gets in range of a friendly WiFi, all he's got to do is launch his current version of LEDS, and press SELECT while holding L+R on the welcome screen (instead of clicking <go>. That should grab ledsgama.nds, the latest build.


            Seuls les pieds et les mains de Bilou tiennent dans une taille de 8x8 à l'heure actuelle, et ils ne représentent que 12 sprites sur les 1024 autorisés. Une perte d'espace probablement acceptable. Si nécessaire, je pourrais envisager de les transférer en 8x16 plutôt qu'en 16x16 ... on verra ça une fois que je saurai quelle quantité de mémoire vidéo la 3D me demandera ...
            • [done] fix guru meditation when entering edit mode
            • [done] keep VRAM for thumbnails
            • [done] properly render monsters
            • [todo] ignore duplicate GOB entries when reading a level
            • [done] ensure we don't generate duplicate entries.
            • [done, runme] ensure we can read the log as soon as there's an error.
            • [todo, runme] ensure we can move back to SEDS/LEDS/download mode at all time.
            • [wish] "generate .cmd" wizard window.
            • [done] clearer view of which file is loaded/saved/renamed

            mardi, avril 02, 2013

            AnimEDS updates

            Holly Bells! I don't think I've been waiting so hard for holidays since I graduated 0_0.
            And to celebrate that, here's the new "running" animation built in AnimEDS. I also animated Spongebop and added a few animations to inkjet, but there seems to be issues with AnimEDS itself, and which slot it decides to save your current work to, so those got overwritten ...


            Aah! Des vacances! enfin! Voilà une petite animation de Bilou occupé à courir réalisée dans AnimEDS. Profitez-en bien parce que je risque justement d'être occupé un bon moment à corriger le code d'AnimEDS qui me fait un peu trop de farces à mon goût. Du style "tiens, et si j'écrasais la dernière animation vue avec la dernière animation éditée avant d'enregistrer le fichier sur la carte mémoire }:-D"

            Let's recap the required upgrades so far:

            • [1145] use some overlay to show which limb is currently pulled, and make sure pulls are properly reset when loading an animation.
            • [1141] fix thumbs in the thumblist. set them to the content of the first frame everytime an animation is saved if needed.
            • [1142] fix the multi-sprites thumb generation, and automatically set the scaling factor for the 16-32 pixel sizes used in Bilou when that would be enough (i.e. frame fits a 32x32 bounding box)
            • [done] ensure setting "delay=1" in the animation editor means 60 frames/second. Otherwise, "split" time doesn't work properly.
            • [done] ensure we can hide *all* the crosschairs so that frame editor isn't hiding things and can preview the animation nicely.
            • [tryit] don't pause on the "animation terminated" pseudo-frame, and directly hop to first frame, for smoother looped animation edition.
            • [dream] crosschair that gets its due alpha-blending. -- there's no support for Sprite/Sprite transparency.
            • [1143] allow edition of color 0 and use that to tune the background colours. 
            • [1146] ensure we don't overwrite data when we've just loaded a new .spr file
            • [1141] don't overwrite data when saving animations.