Sprite animation system design

This is a discussion on Sprite animation system design within the Game Programming forums, part of the General Programming Boards category; I am re-working the sprite system in my Direct3D 3D engine and my XNA 2D tile engine. There are a ...

  1. #1
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,590

    Sprite animation system design

    I am re-working the sprite system in my Direct3D 3D engine and my XNA 2D tile engine. There are a few API-centric questions that I would like some input on.

    The sprite system is composed of a sprite frame object, an animation object and a sprite object. A sprite frame is composed of normalized rectangle coordinates and texture ID information. A sprite animation is a collection of sprite frames. Each sprite then is a collection of sprite animation objects that are called animation tracks. Each track is assigned an integer ID so they can be played, stopped, etc.

    My question is when adding an animation track to a sprite I have two options. I can allow the client to pass in the animation or I can have them pass in an animation name, grab the animation object from a collection in the engine and add it to the sprite.

    Should the engine maintain the collection of animation objects or should I leave this up to the client? The less memory the engine manages the better in my book. I'm currently opting for letting the client worry about this since it does not feel like a responsibility the engine should have.

    So in short:

    bool Sprite::AddTrack(unsigned int trackID,Animation &animation)

    or

    bool Sprite::AddTrack(unsigned int trackID,const char *pAnimationName);

    Often I find myself wanting to maintain this type of data in the engine but lately I've come to the realization that it might not be the engine's responsibility to do so. When the engine does not maintain this data and/or is not responsible for cleaning it up the engine code becomes much simpler and results in much fewer edge cases and cleanup related issues....at the expense of being a bit more unfriendly to the client.
    Last edited by VirtualAce; 01-16-2013 at 11:14 PM.

  2. #2
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,451
    How many clients do you have?

    Or more directly, how many times is the client code going to get re-invented?

    If the client side code is pretty simple, and can be cribbed from some boilerplate example code, then I'd say leave it to the client.

    But if it's a large chunk of code that needs crafting from scratch (or tricky code to debug), multiplied by N clients, then perhaps consider adding some additional features in your API.

    However, the argument for not doing that is that it would make the delivery of your API later rather than sooner (an important point if this is a commercial thing).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  3. #3
    Bored Programmer
    Join Date
    Jul 2009
    Location
    Tomball, TX
    Posts
    407
    The more power you give a client the more power you lose.

    This may be arbitrary but halo 2 really represented how much you can lose by a client processing everything.

    I think in this answer ace you probably already noticed the cost (money) in between the two is what will make the real difference here.
    Does it cost more to run a server that makes all the calculations for you, or does it.cost you more (in loss of clientele) to allow for the security breaches.

    Now honestly I don't know your engine so I don't think it would be a security breach to let them run animations ect, unless your collision detection is all based on the size of that animation. But I do know if you give gamers an inch they will take a mile.

  4. #4
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,172
    Should the engine maintain the collection of animation objects or should I leave this up to the client?
    O_o

    Do you have an engine that is content aware? (Does the engine "lease" objects from a factory based on named content? Or is the client responsible for giving the engine everything it needs?)

    Do you have an engine that streams content? (Does the engine request new objects "automagically" from a factory based on what resources a "scene" needs as it is experienced? Or is the client responsible for telling the engine when to load more content?)

    Do you have an engine that caches resources at the appropriate place based on the used resources? (Does the engine make decisions about where, as in hardware or software, to put content? Or is the client responsible for caching any content?)

    Do you expose an interface such that `Animation' is unaware of these things? (Are the engine bits from above transparent? Or do they require client notification/interaction?)

    I only ask because, odds are, you'll need something of the same nature as the "middleware" level `Sprite::AddTrack' to handle any of the above situations in a reasonable fashion, and more to the point of the question, if you plan on doing the above stuff well it doesn't matter which one you start with because you will ultimately provide a means of allowing a client to take control of some decisions from the engine.

    Simply put, if you don't provide reasonable defaults, your engine is underpowered, and if your engine doesn't allow an interested client to take control of specific aspects your engine is restrictive.

    If you aren't planning on doing any of the above, you have the option of pursuing a very "bare bones" style engine which almost by definition means the engine doesn't own anything so the only real choice is putting the client in control.

    The less memory the engine manages the better in my book.
    Okay.

    So, the question is, why do you think that? Are you trying to provide only the essentials?

    (Making wise decisions about where to stick resource, when to cache them, when to expire them, and when to move them from one area to another depends on enough information that you'll need to provide a callback for streaming this information to the client.)

    You've implied that the engine is already aware of textures, sprites, and animations.

    You also implied that textures at least are owned by the engine.

    Are sprites any less of an engine resource? If sprites are an engine resource, how are animations any less of a resource?

    Really though, this may be, and probably is, a simple case of "You don't have enough separation between resource management and the game engine.". The engine has no business knowing how to fetch a sprite, an animation, or even a texture. The resource manager has no business knowing when these things should be created, cached, expired, or even where to put them when they are cached.

    If you do that properly, you can get far along both options with relative ease by altering the flow of resources.

    With this flow in mind, the client, of the library, shouldn't invoke a `Sprite::AddTrack' interface with an `Animation'. Ever. The `Animation' object should have already been added to a pool of resources. (This can be done via a "lease" such that the client owns the object. Who owns the object and so is responsible for its deletion is thus irrelevant.) The sprite, and every other type or resource that combines other resources, can behave with respect to the pool in the exact same way. The client is also then allowed to treat every resource with respect to the pool in the exact same way. All clients, the library client and other engine code, of the pool registers a given resource to the pool and requests them by identifier.

    At that point, both "middleware" level functions are trivially simple to code as they do the exact same job with almost the exact same consequences. It is, in fact, such a trivial matter that it isn't worth having them at all because the "sameness" breeds familiarity with the core functionality.

    So, my advice, based on what you've asked, is to provide neither functionality in one function. Make registering a client owned object with the resource manager (or engine proper) simple. Make associating an animation resource with a sprite simple by always requiring the resource identifier so no "fetch" type operations is necessary.

    If you are feeling forgiving, you can make registering a factory instance with the resource manager (or engine proper) easy so that resources can be created "on the fly" without explicit client instructions. In this way, even if the `Animation' resource doesn't already live in the pool the resource manager will attempt to create one that it will own because the client didn't care to own that particular object.

    Soma

  5. #5
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,590
    Do you have an engine that is content aware? (Does the engine "lease" objects from a factory based on named content? Or is the client responsible for giving the engine everything it needs?)
    Neither. An editor outputs a level data file that contains all content to be loaded. Neither the game nor the engine ask for content to be loaded or know about the content at startup. It is all data driven.

    Do you have an engine that streams content? (Does the engine request new objects "automagically" from a factory based on what resources a "scene" needs as it is experienced? Or is the client responsible for telling the engine when to load more content?)
    The engine does not stream content. It does not create new objects internally. The loader reads the data file and creates new assets and adds them to the engine. This memory is managed by the engine and is cleaned up at shutdown. The loader can be overloaded via a callback that the client can use to load custom content.

    Do you expose an interface such that `Animation' is unaware of these things? (Are the engine bits from above transparent? Or do they require client notification/interaction?)
    The animations are not engine aware. The animations are not graphics aware. The animations are sequences of frames which are composed of a texture ID and rectangle information. No other information is present in animation frames. The sprite class does offer a SpriteListener class that supports client notifications of important Sprite-based events such as starting, stopping, looping, completed, etc.

    I only ask because, odds are, you'll need something of the same nature as the "middleware" level `Sprite::AddTrack' to handle any of the above situations in a reasonable fashion, and more to the point of the question, if you plan on doing the above stuff well it doesn't matter which one you start with because you will ultimately provide a means of allowing a client to take control of some decisions from the engine.
    The engine 'sprites' are only accessible via a plugin DLL that plugs into a renderable object. This plugin accesses the underlying sprite objects but never exposes it beyond itself. The game is not engine sprite aware but rather plugin sprite aware. The client cannot ask the sprite to do anything that the plugin interface does not expose or allow.

    If you aren't planning on doing any of the above, you have the option of pursuing a very "bare bones" style engine which almost by definition means the engine doesn't own anything so the only real choice is putting the client in control.
    This is the direction I am leaning for the entire system.

  6. #6
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,172
    O_o

    It seems to be that you have a confused design without a belief of your ultimate goals.

    Neither.
    "Neither" is not an option. "It is all data driven." is meaningless in this context.

    You've simply not answered the question.

    To put it in your terms, who is responsible for "loading" the "level data" for new scenes as one scene transitions into another?

    The engine does not stream content.
    I believe this to be a mistake. The engine usually has a more elaborate and sophisticated understanding of the host environment and resources, virtual and real, consumed.

    You must, at the very least, export an API yielding enough information that a client can do an intelligent job of it.

    The loader reads the data file and creates new assets and adds them to the engine.
    Yes. Okay. Now, who is responsible for telling the loader to read the data file and create new assets in response to live events?

    When level one is completed, when Mario drops the flag, who is responsible invoking the loader with the "level2.zip"? Alternatively, if you don't support levels and everything is a unified layout, who is responsible for unloading "Upper_Crust" textures and loading "Hell_Pit" textures? Does the engine manage these transitions? Are there, perhaps, triggers in the level data created by your editor? Or is the client responsible for saying "You don't need those textures in video ram anymore; use these other textures instead!"?

    This memory is managed by the engine and is cleaned up at shutdown.
    If your engine already manages resources, from a loader and level pack or from anything else, there is no reason to distinguish between resources. It will only be confusing to a client. Why design an engine so that `SpriteAnimation' is a resource the engine doesn't own when `Texture' and `Sprite' are owned by the engine? That's just gagging for technical support entry and your not even done.

    The animations are not engine aware.
    I always find it useful to make abstraction agnostic, but you are saying that engine is aware of animations as both a resource and a facility so again, why would they be a resource the engine doesn't own?

    The sprite class does offer a SpriteListener class that supports client notifications of important Sprite-based events such as starting, stopping, looping, completed, etc.
    This leads me to think that you are fibbing about your goal, but it could go either way so I'll just ask.

    Is `SpriteListener' an object managed by the client and queried, or notified by callback, by the engine? Does the engine simply report input so that the client can say "This sprite should be displayed with a walking animation!" to the engine?

    Or is `SpriteListener' an object managed by the engine and queried, or notified by callback, by the client? Does the engine understand actor movement, possibly via scripts loaded into a VM by your level loader, such that the client doesn't have to tell the engine what to do with events?

    The game is not engine sprite aware but rather plugin sprite aware. The client cannot ask the sprite to do anything that the plugin interface does not expose or allow.
    Yes. You have an abstraction over resources. I assumed.

    My question isn't "Can the client ask a sprite to do something?". My question is "Does the engine know how to ask a sprite to do something?". It doesn't matter, as again, if the engine has a cooperative relationship with a VM or anything else that may be "data driven" as tied to a level pack of some kind. I'm not asking if the engine knows about animations either as you've already said that. Does the engine "know" when to play an animation by context? Or must it be explicitly told by the client code?

    This is the direction I am leaning for the entire system.
    Fine. There is nothing wrong with "bare bones" systems.

    Based on what you've said though, you don't have that or even really want it.

    *shrug*

    But then, based on what you've said you want a sophisticated an engine as is possible without the engine to growing unmanageable.

    Soma

  7. #7
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,590
    To put it in your terms, who is responsible for "loading" the "level data" for new scenes as one scene transitions into another?
    Clearly answered this already. Data comes from file resources which load other file resources. Who do you think is responsible for loading the data if the engine does not know about the files???
    The only system I know of that I have worked with that is data file aware is Unity where it auto loads all data within specified folders which allows you to alter the data files for new games. Other systems appear to provide loading capability but do not auto-assume where or when to load the data. The client alone is responsible for utilizing the loading functionality when and where they want. I prefer this type of system.

    I believe this to be a mistake. The engine usually has a more elaborate and sophisticated understanding of the host environment and resources, virtual and real, consumed.
    You must, at the very least, export an API yielding enough information that a client can do an intelligent job of it.
    Explain what you mean when you say 'stream content' since that is quite vague in itself. Perhaps this is a simple issue of semantics.

    Yes. Okay. Now, who is responsible for telling the loader to read the data file and create new assets in response to live events?
    Clearly answered. The client.

    If your engine already manages resources, from a loader and level pack or from anything else, there is no reason to distinguish between resources. It will only be confusing to a client. Why design an engine so that `SpriteAnimation' is a resource the engine doesn't own when `Texture' and `Sprite' are owned by the engine?
    Clearly answered. There are only a few resources that any engine must absolutely own in any given environment. It can choose to take control of more but I prefer not to take this approach. You can either take the approach that the system provides functionality that clients can create on their side and use...and be responsible for or you can take the approach that the engine handles it all. The second approach leads to numerous factories inside of the engine as the engine factories out various resources. The approach I am taking is there are a set number and type of resources the engine will handle and the rest is up to the client. As long as this is clearly documented I see no issue with a partial management of resources. I have seen it done both ways in various systems and I prefer less in the engine and more in the client. In my experience this appears to give the client more flexibility in working with the engine as a whole. There are several systems out there that provide structures and classes to be used by clients with the caveat that the management of said objects is left to the client. There are other systems that take an all or nothing approach in which all resources are managed by the engine and there are others that managed certain specific resources and leave the rest to the client.

    Keep in mind my engine is NOT platform agnostic. I do not have a layer below the graphics portion that handles I/O, memory, etc. via interfaces and impls for various platforms. I did not design the system down to this level and do not plan on it any time soon.

    I always find it useful to make abstraction agnostic, but you are saying that engine is aware of animations as both a resource and a facility so again, why would they be a resource the engine doesn't own?
    The engine is not animation aware. The engine never calls into any animation interfaces and is not aware of them. By the 'engine' I mean the core rendering. By aware I mean when Render() and Update() are called the engine doesn't know if its object A or object X and does not care if object A is of type T or type T2. I am saying should the engine be aware of animations as a resource....b/c currently it is not.


    Is `SpriteListener' an object managed by the client and queried, or notified by callback, by the engine? Does the engine simply report input so that the client can say "This sprite should be displayed with a walking animation!" to the engine?

    Or is `SpriteListener' an object managed by the engine and queried, or notified by callback, by the client? Does the engine understand actor movement, possibly via scripts loaded into a VM by your level loader, such that the client doesn't have to tell the engine what to do with events?
    SpriteListener is created and managed by the client and is purely optional to the Sprite. SpriteListener is called from the Sprite class when certain events occur within the sprite. Scripts are not yet implemented in the current version but will be handled via Lua scripts. However the engine will still not be aware of actor movement other than it will see more AABBs to test for collisions. But the engine will never know that object A moved from point P1 to P2. It doesn't care. The client can create whatever abstractions they want to manage this. Sprites do not move unless told to do so by the client or by scripts (not yet implemented).

    Or must it be explicitly told by the client code?
    In its current state it must be told. I plan on creating an event system to handle this to ease the burden on the client and later it will all be handled through Lua scripts. The new system is not mature and I'm still pondering some of the design for this. I have done this multiple ways both for hobby and professional code and I'm mulling around in my mind which approach I think is the best. Ultimately I believe it will be a hybrid approach. I am being intentionally vague here.

    Based on what you've said though, you don't have that or even really want it.

    *shrug*

    But then, based on what you've said you want a sophisticated an engine as is possible without the engine to growing unmanageable.
    I think you summed up my post great there. Truth is I am in the design phase for this so I'm looking at all options. Based on what I have written and what we have talked about it is clear that my system is bare bones at this time. Part of the reason for that is I am the only developer on my engine so I can really only tackle issues that are achievable with 1 developer....which forces me to take a hands off approach. If I had a team of 4 or 5 people I could delegate out various systems all the while working on the overall integration and collaboration between the systems and would come out with a much easier to use and more robust engine. I simply do not have that luxury at this time.

  8. #8
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,172
    Clearly answered. [blah blah blah] Clearly answered. [blah blah blah] Clearly answered.
    O_o

    [Edit]
    And yes, I did stop reading after the third "Clearly answered.".

    If my questions are going to be met with only that, why bother reading something which is only make me ask more questions?
    [/Edit]

    You were being vague and intentionally not answering the questions you were asked.

    Let's look at this little example:

    Who do you think is responsible for loading the data if the engine does not know about the files?
    You said these two bits of nonsense:

    Neither the game nor the engine ask for content to be loaded or know about the content at startup.
    The loader reads the data file and creates new assets and adds them to the engine.
    Which leaves the relationship between the loader, client, and engine unfulfilled because you are drawing a vague line. I'll tell you why: the "loader" is part of the engine by definition if the only interface the client has to engine resources is the "loader". That relationship is exactly what you've implied.

    So all you told me: the "engine" that doesn't know about files, except for the fact the "loader" is a crucial part of the engine because it represents the core client level interface to "engine" resources, may or may not be responsible for automagically loading files.

    Am I suppose to interpret "engine" as "renderer" for these purposes? If so, who do you think is responsible for loading the data if the engine does not know about the files? It could be that the "engine" proper, of which both the "renderer" and "loader" are facilities, automagically loads these resource files. It could be that the client is responsible for telling the "engine", using the "loader" interface which is part of the "engine" proper, explicitly when to load files. You see? It could still go both ways just because of your idiotic, vague little line. But that's not all, it could also be that I'm not supposed to interpret "engine" as "renderer" which leaves some of your comments mutually exclusive because, again, your vague little line as it is trying to separate the "loader", which is part of the "engine", from the "engine" leaving the question of who operates the "loader" ambiguous.

    Honestly though, absolutely none of that matters because I was genuinely interested in supporting the effort and didn't understand the situation as you presented it. Instead of clarifying the situation you regurgitated a bit of nothingness with a knee-jerk reaction.

    You should know better.

    But hey, you don't want to discuss this to my satisfaction, that's fine and dandy.

    If you didn't want to answer my question, you should have just said "I don't want to talk to you.". You would have saved me a few minutes I could have spent talking to someone who did want advice.

    Soma
    Last edited by phantomotap; 01-27-2013 at 03:48 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 5
    Last Post: 01-13-2013, 10:30 AM
  2. Allegro sprite animation?
    By godly 20 in forum C++ Programming
    Replies: 2
    Last Post: 01-20-2011, 09:18 AM
  3. Embedded system design
    By andyhunter in forum A Brief History of Cprogramming.com
    Replies: 3
    Last Post: 02-19-2005, 06:10 AM
  4. solar system GIF animation needed
    By beely in forum A Brief History of Cprogramming.com
    Replies: 3
    Last Post: 06-11-2003, 09:36 AM
  5. any good way to write sprite/animation classes for a game?
    By compjinx in forum Game Programming
    Replies: 2
    Last Post: 03-28-2002, 12:22 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21