Milestone 2: Loki
NOTE: This is an outdated PLANNING docmuent and may not be entirely accurate.
Having implemented a system for storing and loading groups of Animations, our attention is now turned to the management and manipulation of these Animations on the display.
This milestone is named simultaneously in honor of Loki Games and in jest after spammers of our wiki Loki001 and Loki002.
An Animation will be represented as a spritesheet of the type SDL_Surface. The spritesheet will be a grid of stills which can be clipped from algorithmically. The formula for accessing a still n goes as follows:
still_x = [ (n-1) % stills_per_row ] * still_width still_y = [ (n-1) % stills_per_col ] * still_height
The width and height is always the same for each still of the Animation. Therefore, width and height must be members of Animation. So, in order to get the coordinate pair of still 9, simply set n=9 and evaluate the formulas above.
Advancing is a trivial incrementing operation that wraps back to 0 when the maximum number of stills has been reached for the Animation.
A still will be displayed for a certain duration of screen frames before the Animation is advanced to the next still. The total number of screen frames per each still of the Animation can be computed as follows:
number_of_frames_per_still = floor(still_count / sps) * fps
fps is a constant defined in the system. It will probably be 25 or 30.
Each Animation will have a frame counter which will track how many screen frames have lapsed since the last time the Animation was advanced. This frame counter will be managed by a method that will increment by one and wrap around to 0 when the frame counter equals the sps value.
Entities that appear on the screen can be thought of as a collection of Animations. For example, a tree could be blowing in the wind, on fire, blooming in the spring, or dropping leaves in the fall. Each of these are different animations, but ultimately the same entity on the screen. We will call these entities Drawables.
Drawables will control these aspects of the Animations:
- which Animation is loaded?
- is the Animation playing or stopped?
- when will it be asked if it's ready to update?
Updating a Drawable causes the process described in the Animation section.
Grouping Together Drawables
There should be a way to separate Drawables from each other in order to represent depth and to create logical groupings for area designers. These groupings will be called Layers. For example, consider these Layers:
- grass and road
- plant life
- NPCs and PCs
- birds flying above.
To facilitate depth, the Layers will be drawn in a stacking order. In the example above, each Layer would be drawn in the order listed. Clearly you wouldn't want to draw the grass and road last; they would completely overlap the other Layers.
The Screen Display
The display of the game is ultimately a continual series of frames drawn to the screen. The system used for managing the display will be called the Screen object. Generally, Screen will prepare the next frame by asking each Layer to redraw themselves on the next frame. Afterwards, this newly prepared frame will be drawn to the display via a call to SDL_Flip(). This is a standard mechanism in SDL for the double buffering technique.
Note that the process of preparing a frame and the process of flipping the display are separate methods. Also note that this design does not specify how these methods are controlled. Conceivably, in Milestone 3 there should be interface message commands for preparing the next frame and flipping it.
Preparing the Next Frame
This part is tricky. We want for the next or current still of each Animation to blit to the Screen's next frame. Simultaneously, we want to protect Screen's next frame from being written to by any object or process. How do we satisfy both of these requirements?
We'll introduce a single friend class, AnimationBlitter. As the name implies, AnimationBlitter will be responsible for providing Animation blit access to Screen's next frame. Screen will honor friendship with AnimationBlitter if AnimationBlitter promises not to mess with it's internals any further than that.
AnimationBlitter will also be mutual friends with Animation since it will access to Animation's spritesheet. This interaction will be accomplished by Animation::blitCurrentStill() which will grab an instance of AnimationBlitter and pass its this pointer to the private method AnimationBlitter::blit().
If you need to make a change to this document, please be sure to update the diagram as well. You'll need Visual Paradigm to edit.