(cross-posted from libtcod forums (
http://doryen.eptalys.net/forum/index.php?topic=1628.msg9184#msg9184), I'm interested in a wider view)
So here are a few thoughts on how to provide animation in a libtcod roguelike project, building on top of the data and structures used in the C++ tutorial (
http://codeumbra.eu/series/complete-roguelike-tutorial-using-c-and-libtcod).
Feel free to criticise and give feedback. Note this is probably incredibly *unoptimised*.
The basic idea is to use threads (sorry! :p). A worker thread would be used to handle animation of certain tiles during any time that nothing is happening.
I've split off any direct access to the TCODConsole::root into a singleton class called Console which is essentially just a wrapper around method calls to TCODConsole::root (and also allows me to work with std::strings in my code, and it handles the conversion to c_str() where possible). All calls to this need to be mutexed.
The update (i.e. AI/respond to player input)/render (draw on screen) methods in the Engine/GUI classes (which contain calls to change the screen) would be critical sectioned, and hence the animate thread would wait until such time as these were completed and flushed().
So, we will need a new class, let's call it Animate.
We can then add a Animate* pointer to the Tile struct and to the Actor class.
An animation object basically contains a vector of Frame structs, as well as a interval (int, in milliseconds, with a reasonable minimum granularity such as 0.1 seconds or so), screen x and y positions, and a Frame* NextFrame pointer. A Frame struct is a POD-object which consists merely of a char, a foreground TCODColor and a background TCODColor (note all these can be NULL/not set).
Essentially, this represents a situation where every interval, at the x any y position on screen, the glyph, background and foreground colours will change. (If the values are the same as previous, then no change in that value should occur).
So to animate a tile, one creates an appropriate Animate object and attaches it to the Tile (or Actor!), presumably at map creation.
So. The main thread maintains a vector of Animate* pointers. Every time the FOV is recalculated, this vector is populated (repopulated - again, room for optimisation here) with any Animate* belonging to tiles/actors currently in view. This needs to be critical sectioned/mutex off of course.
That's all the main thread does.
Meanwhile, the worker thread, every 0.1 seconds, or whatever we've decided the mininum granularity is, comes along, and starts at the top of this vector of Animate*. It checks if an animation is due (a simple mod on current time would work here?), and if so, updates the screen with the contents of the *NextFrame struct (and increases/wraps around the *NextFrame pointer to the "next" Frame*. One the entire list is processed it *flushes* the root console.
Note that the worker thread does NOT make any changes to *any* data other than the screen.
I'd probably implement this in Boost, to allow cross-platformness (is that a verb?).
So. Thoughts?