PS2 Linux Programming
2D Sprite Movement and Animation
Introduction
This tutorial will show
how to draw and manipulate 2D sprites. A textured 2D sprites will be drawn
using the sprite primitive. Simple sprite movement and animation will be
performed.
The structure PS2Sprite_t,
shown below, is defined in PS2Types.h to hold relevant information relating to
the drawing, movement and animation of the sprite.
typedef struct
{
int x, y; //
Position on screen (top left)
int z; //
z depth (big = near)
int w, h; //
Width and height
int u, v; //
Offset from texture top left
unsigned char r, g, b, a; //
Colour and alpha
int dx; //
Direction for x
int dy; //
Direction for y
int FCountMax; //
Counter max value
int FCount; //
Frame Counter
int NFrames; //
Number of animation frames
} PS2Sprite_t;
The parameters of the
structure are as follows. (x,y) is the position of the top left hand corner of
the sprite on screen and z is the z depth used for z ordering. w and h are the
width and height of the sprite. u and v are the offset into the texture, from
the top left hand corner of the texture area to be used for the sprite. r, g, b
and a are the colour and alpha value for the sprite. The other parameters are
added to the structure to aid with the game logic. dx and dy are used to store
the direction that the sprite is moving in the x and y directions respectively.
NFrames is the number of animation frames that are used to define an animation
sequence and FCount and FCountMax are used for timing of the animation.
The texture that is used
in this example is shown in the diagram below. The first row of the texture
consists of some tiles that can be used to draw a background and the next three
rows consist of animation sequences, two of characters with walking/running
animations and one explosion sequence. All of the sections within the texture
are based on a square grid of 32 x 32 pixels. Notice that only half of the 256
x 256 texture is used, the right hand half of the texture is filled with black
and can be filled with image data at a later time.
Much of the initialisation
that is performed in main.cpp has been described in previous tutorials and this
will not be repeated here. Before the render loop is entered, the sprite
structures are initialised with appropriate information. Within the render loop
there is a function to move the sprite across the screen, MoveSprite(), and a
function to animate the Sprite, AnimateSprite(). The GS packets are constructed
using the BuildSprite2D() function which is contained in the file packet.cpp.
BuildSprite2D takes two parameters, the first is a pointer to the structure
describing the sprite to be drawn and the second is a pointer to the start of
the area of memory where the primitive data is to be built. Once the primitive
data is built, it is sent to the GS using the DMAC operating in normal mode.
This could be extended to accommodate stitching if necessary but for the
purposes of the present tutorial normal mode transfer is sufficient.
The prototype for this
function is:
int
BuildSprite2D(PS2Sprite_t * pSprite, char *& pMem)
Notice that the actual
memory pointer, pMem, (rather than a copy of the pointer) is passed to this
function so that it can be incremented to reflect the amount of data written
into the packet memory ( this is the function of the *& operator). The prim
field of the GIFtag is set up to draw a sprite primitive and texture mapping is
enabled. The register data that following the GIFtag is the primitive colour
and the UV and XYX value for the two vertices. Notice that the UV and XYZ data
for the registers are constructed from the current information that is
contained within the sprite structure passed to this function – this means that
every frame the new position, animation data, etc for the sprite will be written
into the GS Packet. At the end of the function, the memory pointer, pMem in set
to point to the next free location after the written data.
On running the program,
two sprites are drawn on screen, one is static – e.g. a background tile, the
other is an animated character which walks back and forward across the screen.
In this tutorial 2D
sprites have been drawn using the sprite primitive. This primitive is
sufficient for generating background images and some very simple
movement/animation but it has many limitations. Two major limitations of the
sprite primitive are (1) that the z depth over the complete surface of the
sprite must be the same and (2) it is not possible to rotate the sprite. Considerably
more functionality and control is obtained if a triangle strip primitive is
used to draw a sprite and this will be introduced in the next tutorial.
Dr Henry S Fortuna
University of Abertay
Dundee