A Tour of SpriteWorld
Volume Number: 14
Issue Number: 7
Column Tag: Tools Of The Trade
by by Stefan Sinclair
Edited by Peter N Lewis
A Review of the SpriteWorld Animation Library
Most of today's computer games fall into one of two categories, based on their graphics
model: games with two dimensional, scrolling graphics, or those built on a three
dimensional graphics system. While the growing power of home computer systems has
allowed an explosion of new 3-D based products in recent years, 2-D games such as
Command & Conquer and WarCraft remain a popular segment of the computer gaming
market. A large percentage of these 2-D games employ what is known as "sprite
animation" - the use of graphic objects consisting of a number of pixel-map images
shown in rapid succession to simulate movement on the screen.
To accomplish sprite animation on the Macintosh, you can either develop your own
sprite animation code from scratch (which can be a time consuming endeavor) or make
use of one of a number of existing Mac OS sprite animation libraries available to the
Mac OS developer. Popular sprite animation libraries include SpriteWorld, the Sprite
Animation Toolkit (SAT), and Apple's Game Sprockets (DrawSprocket in particular).
This article will introduce one such library, SpriteWorld, and show you how to use it
in your applications.
What is SpriteWorld?
SpriteWorld was originally developed in the early 1990s by Tony Myles as a library
of C routines and special pixel blitters (custom high speed drawing routines) to
implement fast, smooth sprite animation on the Macintosh. In 1996, Karl Bunker and
Vern Jensen added a number of their own enhancements to the original SpriteWorld,
including the ability to have a scrolling animation, tiled backgrounds and many new
680x0 and PowerPC blitters and released the new package as SpriteWorld 2.0.
Shortly thereafter, a Pascal interface to SpriteWorld was released, as well as a
C++/object-based version of SpriteWorld. There is even a version that builds under
X-Windows and Win95/NT systems. SpriteWorld remains actively supported; at the
time of this writing a new version (2.1) is undergoing beta testing. The source code
remains freely available, and comes complete with API documentation as well as
several sample programs. The current version of SpriteWorld requires a Macintosh
with Color QuickDraw and System 7 or higher.
The SpriteWorld API is built around four basic data structures: SpriteWorlds,
SpriteLayers, Sprites, and Frames. The SpriteWorld is at the top of the hierarchy,
driving the animation and providing the means with which to display the animation in a
graphics device (either on or off-screen). SpriteLayers are an organizational data
structure used to group Sprites. Sprites are the graphic objects that move about and
animate on screen. Frames are the individual animation frames contained by Sprites,
consisting of a pixel map and a mask image. An application may contain any number of
SpriteWorlds, a SpriteWorld may contain any number of SpriteLayers, a SpriteLayer
may contain any number of Sprites, and a Sprite may contain any number of Frames.
For the remainder of the article, the words "SpriteWorld", "SpriteLayer", "Sprite
and "Frame" will be capitalized when referring to the actual SpriteWorld data
structures for clarity.
SpriteWorlds
SpriteWorlds are the master data structures used to control the animation. A
SpriteWorld contains three Frames used internally for drawing; a background Frame,
a work-area Frame, and a window Frame into which the final animation image is
displayed. A SpriteWorld also contains a list of the SpriteLayers that it holds.
SpriteWorlds which employ a tiled background (a background comprised of several
smaller, repeating images which can be animated themselves) will contain a tile map
data structure. SpriteWorlds which employ scrolling animation (animation in which
the visible area is smaller than the total area of the animated world) will maintain
additional data structures to track the movement of the viewable area of animation
with respect to the total animated world.
SpriteWorlds control the erasing and drawing of sprites as they move about and iterate
through their animation frames, updating the data structures of its SpriteLayers and
their Sprites accordingly. They can do so at regular time intervals if the programmer
requests that a specific animation frame rate be used via a call to the function
SWSetSpriteWorldMaxFPS(), or the SpriteWorld can be left to animate as fast as the
hardware will allow. By default, a SpriteWorld uses CopyBits() for all drawing, but a
number of custom blitters are included with the SpriteWorld package and are easily
implemented for increased speed if desired. To aid in the creation of SpriteWorlds,
there are a number of routines available to the programmer; for instance, to create a
SpriteWorld from an existing window, SWCreateSpriteWorldFromWindow() can be
used.
SpriteLayers
SpriteLayers are essentially nodes in a linked list used to provide a method of sorting
Sprites, very similar in concept to the layering schemes found in higher-end graphics
programs. A SpriteWorld will have one or more SpriteLayers, and each layer can
contain any number of Sprites. The ordering of SpriteLayers determines the order in
which drawing occurs; the bottom layer is drawn first, and the top layer is drawn last.
In addition, Sprites within individual layers are drawn in the order which they have
been added to that layer. Therefore, a Sprite on one layer can be covered by Sprites on
higher layers as well as Sprites on the same layer which were added after that Sprite,
providing a sense of depth.
As an example, refer to the following illustrations which depict a SpriteWorld
containing four SpriteLayers. A scene has been painted in the SpriteWorld's
background Frame, which is drawn first. Then the sprites on each layer are drawn,
from the bottom layer (containing the car sprite) to the top layer (containing one of
the character sprites). Note that the same visual result could also have been realized
by instead using a single SpriteLayer with the car sprite added first followed by the
three character sprites.
Figure 1. Sprite Layer Conceptual Illustration.
Figure 2. Animation As Displayed On Screen.
Finally, SpriteLayers are also the basis for the collision detection methods in
SpriteWorld. When one wants to check for a collision between Sprites in SpriteWorld,
the collision detection is done against two layers (or one layer against itself to check
for collisions between Sprites on the same layer) using the SWCollideSpriteLayer()
routine. As an example, one could have two SpriteLayers, one for enemy space ships
(call it enemyLayerPtr) and one for friendly space ships (call it friendlyLayerPtr).
To check if any enemy space ships have collided with friendly ships, the code used
would be:
SWCollideSpriteLayer(enemyLayerPtr, friendlyLayerPtr);
To take this a step further, one could check to see if any friendly ships had collided
with each other:
SWCollideSpriteLayer(friendlyLayerPtr, friendlyLayerPtr);
If a collision is detected between Sprites, each Sprite involved in the collision will
have its collision call-back routine called (if it has one), which will determine how
the Sprite reacts to the collision. If a Sprite has not had a collision call-back routine
installed, it will simply pass through other Sprites regardless of any collisions which
take place.
Sprites
Sprites are the workhorses in SpriteWorld. In addition to containing the image
information used to display the animation graphics on screen in the form of an array of
Sprite Frames, a Sprite contains data used to define its position in the SpriteWorld, its
velocity, the frame rate of its animation, and other internally used information.
Sprites may also contain a number of callback routines used to control such things as
the Sprite's movement, response to collision, behavior when there is to be a change in
the currently drawn animation frame, and the implementation of custom blitters for
drawing the Sprite.
A number of routines are available to the programmer to create Sprites from standard
Macintosh resource types, namely 'PICT' and 'cicn' resources. These include:
• SWCreateSpriteFromCicnResource() which will create a Sprite from a
series of 'cicn' resources to be used as the sprite Frames.
• SWCreateSpriteFromPictResource() which will create a Sprite from a
series of 'PICT' resources to be used as the sprite Frames.
• SWCreateSpriteFromSinglePict() which will create a Sprite from a
single 'PICT' resource, which contains a number of images, either varying in
size and location within the 'PICT' or of identical size arranged in a horizontal
or vertical strip, to be used as the sprite Frames.
• SWCreateSpriteFromSinglePictXY() which will create a Sprite from a
single 'PICT' resource, which contains a number of images arranged in rows
and columns to be used as the sprite Frames.
On 68k Macintosh systems which will be displaying a SpriteWorld animation in 8-bit
depth, the programmer has the additional option of using compiled Sprites for
maximum possible speed. Using compiled Sprites causes the Sprite to be drawn off
screen with binary code generated specifically for that Sprite's pixel map images.
Frames
Frames are data structures that store the actual image data used in the animation. They
consist primarily of a pixel image stored in a GWorld and a mask used when drawing
the pixel image. Think of frames as being similar to the individual frames on a reel of
film, which when shown in rapid succession one after another provide the illusion of a
smooth display.
Programming with SpriteWorld
There are typically six steps to creating and running a SpriteWorld program:
• Initialization of the SpriteWorld package with a call to
SWEnterSpriteWorld().
• Create the components of your animation - SpriteWorld(s),
SpriteLayers, Sprites and the Sprite Frames.
• Assemble the various components - add the Frames to the Sprites, add the
Sprites to the appropriate SpriteLayers, add the SpriteLayers to the