Padawan in need of guidance for an animation system

Hi, I would like to know how you would go about building a simple animation system in C with SDL. I don’t want you to do the job for me, what I badly need is high level guidance and to see how experienced people think about this because frankly i’m kind of lost. I’ve only half baked “solutions”, and looking back at what I did clearly showed me the main problem is i’m not sure about what I should build and why.

What may help you to know how to help me is clarifying my goals and my needs:

First, this is for simple 2D frame-based animated games, I plan to have a fair amount of low resolution sprites (nes-snes range resolution) in the whole game (say between 20 and 50) and a few (10 or 15 maybe) small 16*16 pixels tilesets. So what I want to get to is : the loading pattern of
my games would be load everything at the beginning, free everything before terminating the program.

I Would like to have a system (a module) to be able to say : draw this frame of this animation at this position and then the system figures out which part of which texture to copy to the screen at the position specified. I would like the caller code to be freed form thinking about these details (texture pointers, source and destination rectangles and so on). Something like draw_animation(int animation, int frame, int x, int y) - Edit: I’m using the renderer api / graphics card.

I’m also confused about how to define an animation. Should I define them by hand with handmade global tables (table of animations referencing tables of frames)?
Should I define them in disk files that are read by my code to populate tables that start empty / uninitialized ? Should I have functions that I call to add a texture, add an animation, add a frame and
use them at the initialization phase of my program ?.

Also, I’m confused about how to name things so that I could tell to some draw_animation function I write which one I’m talking about ? Enums are nice to use but incompatibles with a system that builds animations based on descriptions in text files on disk for example because the enum is a compile time
thing and the loading happens at run time.

I sometimes think the old programmers (those who pioneered video games), and the dos-era ones etc would have a way more efficient, simple and clever way to think about all of this. Even on the old consoles (It seems like at this time, memory was laid out manually - we cannot do that anymore I know -
but also lots of things were done in a manual and clever way youngster like me ignore. I know we can’t use exactly the same techniques, but the simple, pragmatic spririt… I’m feeling like young people like me (especially if you want to be autonomous and useful) should learn to think like that, and that I’m overcomplicating stuff because I’m missing things that are important and lack knowledge.

I already have books like Game Programming Architecture or the Doom Black Book which are wonderful, helped me a ton for other things, are full of insights but I’m struggling to use them in that case. I see cools useful things and concepts (like resource IDs/handles to be able to move around stuff without breaking things that reference what you move, ways to make sure stuff is not loaded more than one time etc). But I don’t really understand how to think globally about things like resource definition and management for example. Also, these books are about big ass games, and I feel like I need to build my skills with simpler games and that when you are doing simpler things, alone, the nature of the job changes and lots of things don’t apply.

Thank you very much for reading this, if you need any information about what I tried to guide me, just ask. I just figured it would help more to describe what I want because as I said, I’m not sure I actually understand what I should build to get where I want (what I have “works” but is half assed and incoherent).

PS: Also, the more I spend time with SDL, the more I realize how well its made, and how its designed to enable you to think about what you do without standing in your way or making decisions for you (like a framework for example). I would like to help maintain it when I’ll have the skills to do so. You know, give back what was given to me. Not necessarily the place to say it, but I wanted to say it for a long time, so there you go.

1 Like

I’m far from expert, and I’m exactly trying to achieve the same thing.

What I did for now is:

  1. Use a fixed size atlas with fixed size sprites

  2. Create a function that reads “rects” from left to right given some x,y atlas position n sprites and store them in a contiguous memory (malloc’d). For example if my atlas has 16x16 sprites each sprite has 32x32 pixels. I could call create_anim(manager, atlas, x, y, frames). Where manager is a data structure where I store all my assets. This data structure is simple. Like

struct anim_manager {
    char uuid[37];
    char name[256];
    GArray animations
};

Where GArray is a datastructure from Glib (is a regular array that grows if needed). It’s just a “smart malloc”, nothing fancy. I could use a fixed sized array or a flexible heap pointer.

Animations contains

struct animation {
   char uuid[37];        // Unique uuid
   char name[256];    // Animation name
   u8 nframes;             // Number of frames
   f32 time;                // Time to play this animation
   u8 w;                     // width each animation frame
   u8 h;                      // height each animation frame
   SDLTexture *frames;
};

To play the animation I just iterate over the SDLTexture all frames exist in a single texture, I think that is cheaper and faster than referencing different textures by array/malloc.

This animation is completely unsynced, it starts every time and transitions are ugly. Besides that everything is mostly hard coded, but I’m enjoying the learning.

To fetch/render data, I often prefer to use pointers instead names/uuids. In my code to search for uuid I use a binary tree (O(log n)) and to search by name (O(n)),with a pointer is O(1). Hence I just use name/uuids if I do not have the reference (I think that often that will happen in loading, after that pointers everywhere).

My code is far from working fine, there is some leaks her and there (and that gets me very upset, and I often completely refactor for “simplicity” or to remove leaks).

As far as I can tell reading from disk (either from host memory) is a slow task, and should be deferred or made in background somehow (haven’t written that yet).

I don’t use global variables anywhere. My game starts I return a pointer for the world datastructure and game data structure that contains the renderer and window. From that I start my animation subsystem (passing the components when needed), for example to start the animation I need to pass the game since the renderer is there. I could pass only the renderer, but since I’m just passing a pointer, don’t hurts.

Of course it’s always a pain to know the exact amount of abstraction that we should put in our functions, what is the difference to code just a single main() and a complete modular code? Where is the break point where too much modularity harms more than helps? I don’t know the answer.

I think we are both in same boat and there is many hidden secrets that professionals just don’t tell.

1 Like

Thanks you for you answer !

I have some questions :

  • What is the thing you call an atlas ? Is this just an image containing multiple animation frames ? (I assume it is because given the conventions you chose, you don’t need any more information since frame size and atlas size are fixed)
  • What does your atlas contain ? Just the frames for one animation or frames for multiple animations ? Or the frames for all your animations even (if its a small game)?
  • How do you create the layout of the atlas ? Do you do it manually with an image editor ? Or did you write code to take separate images and pack them into one big one ?
  • Is the frames member of your animation struct a strip (a texture containing all the frames of the animation and nothing else aligned horizontally, left to right ?)

I thought the same about names/uuids and pointers. Use names/uuids for loading and pointers for the main loop. But where to store these pointers ? If, say, an object can have only one animation, the object can store it. But what if it has many ? And what if you want to be able to threat animations like plain old data and use it independently of anything else, like draw_animation(animation id, int x, int y, int frame) ?
Where do the gameplay code store this id ? That was one of the things that made my brain crash.

The way I built my system is a little bit different, maybe it can help you too so I’ll explain the bulk of it.
Edit: I think it will be far easier to just give you the code. Its pretty small (241 lines setup code included - the actual useful code is pretty small and self explanatory). So I quickly created a GitHub and put the code there so you can have a look. If you have any questions, just ask me.

here’s the link https://raw.githubusercontent.com/Touchdown51/snippets/master/graphics.c
(I linked to the raw version of the code because for some reason GitHub broke the original code indentation and it was annoying to read).

PS: there is only a .c file and no header because I’m doing the “unity build” thing (mainly to save time for now) : I just #include the .c file in my main. I did it for my game file too. So basically after the preprocessor is done the compiler just gets one big file to process. I will probably make a proper interface with a .h file to this module this when I won’t be in experimental lab mode anymore :slight_smile: