DS Sprite Specs

The normal 2D hardware in the DS is capable of displaying 128 sprites on each screen or engine, for a total of 256 different sprites on both.

Each sprite can be horizontal or vertical, can be moved across the screen, can be animated (by updating the image used), can become partly transparent, or even become a patchwork!

Sprite rotation and zooming is also possible, but with a special catch: you cannot set a rotation / zoom setting for each sprite, but instead you must assign the sprite one of the 32 “rotsets” available. Therefore, all the sprites can rotate, zoom, or both, but only in 32 different ways at once. Several sprites can share the same rotset, and will be rotated and/or enlarged in the same way.

DS Screen Sizes

Thanks to Bennyboo for the image. www.palib-dev.com_wiki_images_ds_screen.jpg

So the max is 256 pixels wide and 192 pixels high. Given that the first pixel is the number 0, not 1, it means 0-255 and 0-191, as shown in the diagram.

In addition, the position of a sprite is limited to certain values. X can only be between 0 and 511, and Y between 0 and 255. That means putting a sprite at the position X = 512 is equivalent to putting it in position X = 0! That is called sprite wrapping.

Color Modes

The Sprites can have 3 different color modes:

16 color palettes, with a total of 16 different screen palettes. This is widely used in GBA, but disappeared in DS. 16 colour sprites can use all 16 palettes, meaning if you decide to, you can choose different colour palettes for sprites, so you create different looking sprites by only using one sprite, just by changing the palette. Each tile of a 16 colour takes up 32 bytes.

256 color palettes with a total of 16 types of palettes per screen. 256 color pallets use twice the memory of 16 color.

16-bit sprites do not use palettes. These sprites take up much more video ram than the rest.

In the end 256 color sprites are recommended in terms of color possibilities and video ram usage.

Sprite Sizes

The DS can handle quite a few different sprite sizes, but are limited to specific sizes due to the hardware. The chart below illustrates the sprite sizes the DS hardware can handle.

8 16 32 64
8 8×8 16×8 32×8
16 8×16 16×16 32×16
32 8×32 16×32 32×32 64×32
64 32×64 64×64

To use sprites of odd proportions, simply put them in a sprite with the size that closest reflects the actual sprite size. For example, if you have a 48×48 pixel sprite, you would place it in a 64×64 box within your paint program of choice, and set the unused area the transparent color of choice.

Transparent color

If you have a round sprite, like a Frisbee, you wouldn't want the square border to show. In order for the background to be 'removed', set it as the transparent color. There can only be 1 transparent color per sprite.

Here are some common colors used for transparency:

R G B
Magenta 255 0 255
Black-red 1 0 0
Off Black 1 1 1
Off White 254 254 254

PAlib Sprites

For sprite conversion, please refer to the Using PAGfx section.

Displaying

The following examples are updated from the latest palib release.

This example can be found in: palib\examples\Sprites\Basics\CreateSprite

#include <PA9.h>
 
// PAGfx Include
#include "all_gfx.h"
int main(void){
 
	PA_Init(); //PAlib inits
 
	PA_LoadSpritePal(0, // Screen
					0, // Palette number
					(void*)sprite0_Pal);	// Palette name
 
	PA_CreateSprite(0, // Screen
					0, // Sprite number
					(void*)vaisseau_Sprite, // Sprite name
					OBJ_SIZE_32X32, // Sprite size
					1, // 256 color mode
					0, // Sprite palette number
					50, 50); // X and Y position on the screen
 
 
	while(1) // Infinite loops
	{
 
	}
 
return 0;
}
}

Everything is pretty clear here. If you are having trouble please refer to the template guide in the installation section.

// PAGfxConverter Include
#include "all_gfx.h"

This includes all the graphics that have been converted, the bin files must be in the data folder, or another folder defined in the makefile to be included. The all_gfx.h file must be in the source folder or includes folder where all the .c files can include it.

PA_LoadSpritePal(0, // Screen
		0, // Palette number
		(void*)sprite0_Pal);	// Palette name

This loads a palette on the bottom screen in the first palette number of 16 (0-15). Forgetting to load a palette will cause the sprite to load invisible, or with wonky colors if you forget to delete an old palette.

PA_CreateSprite(0, // Screen
		0, // Sprite number
		(void*)vaisseau_Sprite, // Sprite name
		OBJ_SIZE_32X32, // Sprite size
		1, // 256 color mode
		0, // Sprite palette number
		50, 50); // X and Y position on the screen

Everything is self explanatory here.

  • Make sure the sprite palette is loaded on the same screen of the sprite you are loading. In this case we have it on the bottom screen.
  • The sprite number identifies which sprite the hardware should control(moving, loading, priorities, etc). The DS can have up to 128 sprites (0-127). As each sprite is loaded, its priority is decreased. Sprite 0 will always show on top of sprite 1 and so on and so forth.
  • The object size is actually two arguments in the function which can be easily defined using the macro OBJ_SIZE. The sprite sizes are explained previously.
  • The color mode determines what kind of sprite to load. 0 is for 16 color sprites and 1 for 256 color sprites. Select which ever mode you used to convert your sprites within PAGfx.
  • Then comes the palette number. As explained above, using the wrong palette will cause wonky colors and if the palette isn't loaded, your sprite may not appear.
  • Last but not least, X and Y coordinates. These values are in pixels, 0,0 being the top left of the screen and 256,192 being bottom right.

And that is it, the sprite will load up.

For a 16color sprite, you would use the following:

The palette:

	PA_LoadSprite16cPal(0, // Screen
			    0, // Palette number
			   (void*)sprite0_Pal);	// Palette name

And for creating the sprite:

	PA_CreateSprite(0, // Screen
					0, // Sprite number
					(void*)vaisseau_Sprite, // Sprite name
					OBJ_SIZE_32X32, // Sprite size
					0, // 16 color mode
					0, // Sprite palette number
					50, 50); // X and Y position on the screen

Note the color mode is set to 0 for 16 colors. If the mode is set wrong, you may have sprite corruption.

Moving

Moving sprites are important for game play.

PA_MoveSprite

This example can be found in palib\examples\Sprites\Movement\MoveSprites

for (i = 0; i < 16; i++) PA_CreateSprite(0, i,(void*)vaisseau_Sprite, OBJ_SIZE_32X32,1, 0, i << 4, i << 3);
// This loads sprites a bit everywhere

This loads a few sprites on the screen. If you are unsure of the for loop and what « or » are, please refer to your favorite C or C++ tutorial.

while(1)
{
 
	// Use the MoveSprite function on all sprites...
	for (i = 0; i < 16; i++) PA_MoveSprite(i);
	// The MoveSprite function checks if you are touching a sprite, and moves it around if*    
        // *you are... Pretty nice if you have multiple sprites around
 
	PA_WaitForVBL();
}

PA_MoveSprite is used for stylus movement of sprites. It automatically sets which ever sprite is selected and moves it to the stylus coordinates. Again a for loop is used to loop through all the created sprites to check which ones to move.

PA_SetSpriteXY

PA_SetSpriteXY(screen, sprite, x, y);

This is a fairly important function. Just put in the screen, the sprite number of the sprite to move, and then a new position (x and y), then the sprite is moved to the new position. Positions are based on the sprites top left corner so setting a 32×32 sprite at 240,176 will only show the top left 16×16 of the sprite. On another note, you can also use PA_SetSpriteX(screen,sprite,x) and PA_SetSpriteY(screen,sprite,y) if you do not want to set the x and y positions at the same time.

X and Y limits

There are 2 more functions available : PA_GetSpriteX(screen, sprite) and PA_GetSpriteY(screen, sprite) which return the sprite's coordinates in the PAlib sprite system. The first thing you'll notice is that these values will always range between 0 and 511 for X, 0 and 255 for Y, because these are hardware limits.

If a sprite is moved off screen, it will eventually wrap around. At X position of 512, the x position will be set to 0, and a negative x position will wrap to 511. Y values work similarly but do not have the same distance to wrap

These functions are debug only and are not recomended for use. It is better to keep track of your sprites positions through variables you have created.

Keys

Now we can move sprites using the keys on the DS now that we understand the SetSprite functions. This example can be found at: palib\examples\Sprites\Movement\MoveSpritewithKeys

Only the important lines will be covered.

s32 x = 0;    s32 y = 0; // sprite position...

These two variables are used to keep track of the X and Y position of the sprite we are moving.

x += Pad.Held.Right - Pad.Held.Left;
y += Pad.Held.Down - Pad.Held.Up;

When Pad.Held.Right is held, it is given a value of 1, Pad.Held.Left is 0 as it is not true. So it ends up looking like this:

x += Pad.Held.Right - Pad.Held.Left;   -> x += 1 - 0;

This moves the sprite 1 pixel per frame. To give you an idea of speed, the DS runs at 60 frames per second, 256/60 = 4.22 seconds for a sprite to cross the screen horizontally at one pixel per frame.

You could also do the following:

if (Pad.Held.Right) x = x + 1;

How ever it is not as efficient and requires more typing to achieve a similar effect to that of the first example.

The same idea applies for moving up and down.

Now that we are manipulating the x and y position of a sprite, we need to update its location on the screen:

PA_SetSpriteXY(0, // screen
		0, // sprite
		x, // x position
		y); // y...

The movement can be manipulated to move at different speeds rather than just 1 pixel per frame.

x += (Pad.Held.Right - Pad.Held.Left) * speed;
y += (Pad.Held.Down - Pad.Held.Up) * speed;

Speed can be set to any integer of your needs. Since Pad.Held.Right-Pad.Held.Left = 1, the equation is 1*speed. Setting speed to 6 for example will move the sprite at 6 pixels per frame.

Stylus

Stylus movement works similar to moving sprites using the keys.

PA_SetSpriteXY(screen,sprite number,Stylus.X,Stylus.Y);

Instead of manipulating x and y variables with keys, we set the sprite to the Stylus' coordinates.

Stylus Touch

There are two functions for detecting if the Stylus is touching a sprite, PA_SpriteTouched and PA_SpriteTouchedPix.

*PA_SpriteTouched just checks if a sprite is touched, including transparent areas.
*PA_SpriteTouchedPix checks if only the non-transparent areas are touched on a sprite.

Other then that they work exactly the same.

The example can be found in: palib\examples\Sprites\Basics\SpriteTouched

u8 i = 0; 
for (i = 0; i < 8; i++) PA_CreateSprite(0, i,(void*)mollusk_Sprite, OBJ_SIZE_32X32,1, 0, i << 5, i << 4);
 
PA_OutputSimpleText(1, 0, 10, "Please touch a sprite");
 
while(1)
{	
	// Now we'll test every sprite to see if we touch it...
	for (i = 0; i < 8; i++) {
		if (PA_SpriteTouched(i)) PA_OutputText(1, 0, 15, "Sprite %d  ", i);
		// If we touch the sprite, returns 1...
	}
 
	PA_WaitForVBL();
}

PA_SpriteTouched(sprite) is a simple function that returns 0 if touched and 1 if it is touched. There is a slight problem though because the function doesn't detect if the stylus is on screen and is touching. So to prevent unwanted results:

     if(Stylus.Held && PA_SpriteTouched(sprite))

Rotation and Zoom

Sprites can be rotated and zoomed using the hardware. However, there are limitations. There are only 32 Rotation sets (rotsets) per screen. That means you can only have up to 32 different rotations for all sprites. Multiple sprites can use the same rotset. All sprites within a rotset will be controlled exactly the same as each other, so rotating one sprite within a rotset rotates them all.

Rotation

We'll start with Sprite Rotations. The example is Sprite_Rotation.

// Activate rotations for that sprite
PA_SetSpriteRotEnable(0,// screen
		      0,// sprite number
		      0);// rotset number. You have 32 rotsets (0-31) per screen. 2 sprites with*
                         // *the same rotset will be zoomed/rotated the same way...
 
u16 angle = 0; // Rotation angle...
 
while(1)
{
	++angle; // change the angle
	angle &= 511; // limit the range to 0-511. works only with 1, 3, 7, 15, 31, etc... (2^n  - 1)
 
	// Fast function for rotations without zoom...
	PA_SetRotsetNoZoom(0, //screen
			   0, // rotset
			   angle); // angle, from 0 to 511
 
	PA_WaitForVBL(); // Synch
}

First off, you create a sprite, just as usual, with its palette and all. Then, you need to activate the sprite in rotation/zoom mode and give him a rotset (from 0 to 31), which is done with PA_SetSpriteRotEnable(screen, sprite, rotset). Once this is done, the sprite is ready to rotate ! When you want to stop rotating it, you can use PA_SetSpriteRotDisable(screen, sprite).

The few lines of code directly following aren't too important, it's just declaring a variable for the angle, and adding 1 'degree' to it each turn… There is, though, a major thing to know about the angle. It's not a 360° angle, but ranges from 0 to 511, and it's counterclockwise. Why ? Because that's what is best for the DS, and it's much faster that way than with normal angles.

So what's the angle &= 511; all about ? You'll have a more complete tutorial on the & operation in the math tutorial coming up. All you need to know is that it limits the variables range to that value, but only takes 2^n - 1 numbers : 1, 3? 7, 15, 31, 63, 127, 255, 511, etc. So it limits the variable's range to 0-511, which is exactly our angle's limits ! What happens if the value goes over 511 ? It goes back to 0, and so on. So 512 will give 0, 513 will give 1, etc. This is also true for negative values, -1 giving… 511.

Next comes the important function, PA_SetRotsetNoZoom(screen, rotset, angle); . Never forget that here, you are manipulating the rotset (0-31) and not the sprite, that's why you don't use the sprite number anymore. You just give the screen, the rotset, and the angle (0-511) as arguments, and PA_SetRotsetNoZoom will rotate the sprite just like you want !

As this example has an angle to which 1 is added every frame, you can compile the example and see on hardware how it turns.

Last thing : the sprite is rotated from it's central point.

Zoom

Now that we have seen how to rotate a sprite, we'll see how to zoom it. It's fairly easy, once again, and the example, Sprite_Zoom, is really similar to the one we've just seen.

u16 zoom = 256; // Zoom. 256 means no zoom, 512 is twice as small, 128 is twice as big....
 
while(1)
{
	zoom -= Pad.Held.Up - Pad.Held.Down; // Change the zoom according to the keys...
 
	// Fast function for zoom without rotations...
	PA_SetRotsetNoAngle(0, //screen
			    0, // rotset
			    zoom, zoom); // Horizontal and vertical zoom. You can have a sprite*
                            // *streched out if you want, with the zoom only for x or y axis....

First off, you have the zoom variable… Why is it set to 256 ? Because… 256 means NO zoom. The DS zoom works the following way :

  • 256 is no zoom, or rather 100% size…
  • 512 is half zoom, 50% size…
  • 128 is double zoom, or 200% size…

To make it simple, the base zoom is 256, smaller values give a bigger sprite, and bigger values give a smaller sprite. Here, the zoom is modified by the Pad Up and Down keys, so you can check for yourself the result.

Now, let's check the important zoom function : PA_SetRotsetNoAngle(screen, rotset, zoomx, zoomy);. Why are there 2 zoom values ? Because you can zoom your sprite independently on the X and Y axis if you want ! Even though most of the time you'll want to zoom it the same way on both axis, it can be good to have different zooms, thus creating different effects

The sprite is zoomed from the central point, just like for the rotations…

If you're smart (or if you were careful when reading this tutorial and the Zoom example in PAlib), you should have 2 questions, which are in fact pretty much the same :

  1. What happens if a sprite is zoomed too big ? After all, when creating the sprite, you set its size, so having a too big sprite should go beyond this size, and not work ?
  2. Why wasn't PA_SetSpriteDblsize(0, 0, 1); mentioned?

Well, first : if your sprite is too big, everything beyond the sprite frame (like 32×32, for example), will just be cut off ! Ok, this is very limiting, but hey, Nintendo thought of everything !

And that's where question 2, PA_SetSpriteDblsize(screen, sprite, enable/disable) comes in. If you double-size a sprite, it won't actually zoom it to 200%, but rather double its frame size. So a 32×32 sprite becomes a 64×64 (with the 32×32 image in its center), and a 64×64 becomes 128×128.

Now that you know this, you see how to go beyond the sprite size limit if you want to zoom your sprite a little more. You have to consider one last thing, though : if you double the canvas size, and since the sprite position is the top left corner… it changes the sprite's center on the screen. So if you place 2 sprites at the exact same coordinates, but one double-sized and one normal, you'll see they're not placed the same way.

Both Rotating and Zooming

These 2 examples just taught you how to rotate or zoom, but in fact you can do both at the same time if you need to. The PAlib example is the Sprite_RotZoom one, and it's very much like the other ones, once again, but contains both the angle and zoom variables. Look at the example to see the code.

The only function this time around, is PA_SetRotset(screen, rotset, angle, zoomx, zoomy);. It's just like a combination of the 2 preceding functions, nothing terrible !

Sprite Flipping

Sprite flipping is really simple. There are just 2 functions to flip a sprite :

  • PA_SetSpriteHflip(screen, sprite, 1/0 for yes/no), for horizontal flips (left/right)
  • PA_SetSpriteVflip(screen, sprite, 1/0 for yes/no), for vertical flips (up/down)

That's all there is to it. 1 sets the flip on, 0 removes the flip, that's it. You can flip horizontally, vertically, or both at the same time.

Note, you cannot flip a rotsprite, it resets the rotation.

Mosaic Effect

The Mosaic is an easy effect to use. It was used in Super Mario Bros, for example, and changes the way the sprite looks by replacing single pixels by squares of a given size (from 1×1 blocks to 15×15 pixel blocks). What's so good about that? It can be used for transition effect on sprites, a sort of blurring effect, etc.

The DS and PAlib offer you a very simple control over the Mosaic effect. Once you have created a sprite, you can activate the effect for a given sprite using PA_SetSpriteMosaic(Screen, Sprite, Mosaic on/off (1/0));.

Once this is done, you can easily change the mosaic values, horizontally and vertically (so you could have like 1×8 pixel blocks if you want) using the following function : PA_SetSpriteMosaicXY(screen, horizontal block size, vertical size…);

You can control each sprite to activate or deactivate the mosaic effect, but the mosaic block level is the same for all activated sprites on a given screen. So you can't have one sprite with a certain mosaic, and another with a different one.

Transparency

Transparency, or Alpha-Blending, can be nice in a game or application. It looks great and professional and isn't hard to do.

PAlib uses the DS's hardware for alpha blending. There is one limitation however, all sprites share the same alpha blending level, you cannot individually set some sprites too have more alpha blending then another.

The code is fairly easy to understand, and you have an Alpha-blending example in the sprite examples…

PA_SetSpriteMode(0, // Screen
 		 0, // Sprite
		 1); // Alphablending
 
 
s16 alpha = 7; // Transparency level
 
// Enable the alpha-blending
PA_EnableSpecialFx(0, // Screen
		   SFX_ALPHA, // Alpha blending mode
		   0, // Nothing
		   SFX_BG0 | SFX_BG1 | SFX_BG2 | SFX_BG3 | SFX_BD); // Everything normal
 
while(1) // Infinite loops
{
	alpha += Pad.Newpress.Up - Pad.Newpress.Down;
	PA_SetSFXAlpha(0, // Screen
			alpha, // Alpha level, 0-15
			15); // Leave this to 15
 
	PA_WaitForVBL();
 
}

PA_SetSpriteMode(screen, sprite, mode); is used to enable alpha blending on a sprite. Be sure to check out the documentation for info on the other available modes. The next step is to set up the DS's special effects system using PA_EnableSpecialFx(Screen, SFX_ALPHA (Alpha blending mode), 0 (leave to 0 for now), SFX_BG0 | SFX_BG1 | SFX_BG2 | SFX_BG3 | SFX_BD);.

*Screen should be fairly obvious by now
*SFX_Alpha is the mode we are activating effects for
*the next argument where the 0 is, is the target for the effects to activate on. Due to setting the Sprite mode for alpha blending we do not need to set any target here.
*SFX_BG0, etc, are the targets to be seen through the effect, here we see bg layers 0 -3 and the backdrop meaning all backgrounds will show through the sprite.

PA_SetSFXAlpha(screen, alpha level (0-15), normal level (leave to 15));

*The first alpha level is how much of the sprite to show, adjusting it according to your needs will make the sprite fade
*The second alpha level value is how much of the targets(backgrounds) to appear through the sprite.

A value of 0,16, would make the sprite completely invisible, 16,0 would make the sprite completely solid.

Note, you cannot see sprites through alpha blended sprites.

Frames

Frames are useful for animations and sprite states. To use sprites with frames, each frame must be organized in a vertical sprite strip.

This example will show you how to change a sprites frame based on key presses and can be found in: palib\examples\Sprites\Animations\Frames

PA_CreateSprite(0, 0,(void*)frames_Sprite, OBJ_SIZE_16X32,1, 0, 128-16, 64);
 
while(1)
{
	if (Pad.Held.Up) PA_SetSpriteAnim(0, 0, 0); // screen, sprite, frame
	if (Pad.Held.Down) PA_SetSpriteAnim(0, 0, 2); // screen, sprite, frame
	if (Pad.Held.Left) PA_SetSpriteAnim(0, 0, 3); // screen, sprite, frame
	if (Pad.Held.Right) PA_SetSpriteAnim(0, 0, 1); // screen, sprite, frame		
 
	PA_WaitForVBL();
}

PA_SetSpriteAnim(screen, sprite, frame number); is used the change the frame, everything is pretty straight forward here.

Note
*Only the current frame is loaded in the vram, the rest are stored in the main ram until needed

Animations

Simple Animations

Sprite animations are simple, your sprite must be organized in frames like the example above for animations to work properly.

The sprite animation example can be found in: palib\examples\Sprites\Animations\SpriteAnim2

Here is the main difference between frames and animations:

PA_StartSpriteAnim(0, // screen
		0, // sprite number
		0, // first frame is 0
		6, // last frame is 6, since we have 7 frames...
		5); // Speed, set to 5 frames per second

Sprites animated with this function will loop indefinitely.

PA_StartSpriteAnim(screen, sprite, first frame, last frame, speed) Starts the animation from the first frame to last at the given speed in frames per second. One thing to note, using this function in a loop will continuously restart the animation making it appear to not animate.

You can use PA_StopSpriteAnim(screen, sprite) to stop the animation, or PA_PauseSpriteAnim(screen, sprite, pause (1 to pause, 0 to unpause)) to pause/unpause the animation.

Complex Animations

This section basically covers animations with different frames. The example can be found in: palib\examples\Sprites\Animations\SpriteAnim

The image here is similar to the frames example, but has more frames for animation in other directions. There are only 3 directions here because we can use the DS's hardware to flip the sprite for the 4th direction.

while(1)
{
	// Animation code...
	if(Pad.Newpress.Up) PA_StartSpriteAnim(0, 0, 0, 3, 6);
	if(Pad.Newpress.Down) PA_StartSpriteAnim(0, 0, 8, 11, 6);		
 
	if(Pad.Newpress.Right) {
		PA_StartSpriteAnim(0, 0, 4, 7, 6);	
		PA_SetSpriteHflip(0, 0, 0);
	}
	if(Pad.Newpress.Left) {
		PA_StartSpriteAnim(0, 0, 4, 7, 6);	
		PA_SetSpriteHflip(0, 0, 1);
	}
 
	if(!((Pad.Held.Left)||(Pad.Held.Up)||(Pad.Held.Down)||(Pad.Held.Right))) PA_SpriteAnimPause(0, 0, 1);
 
 
	// Moving Code
	y += Pad.Held.Down - Pad.Held.Up;
	x += Pad.Held.Right - Pad.Held.Left;		
	PA_SetSpriteXY(0, 0, x, y);
 
	PA_WaitForVBL();
}

As you can see, each button press starts an animation from different frames for the different directions.

if(Pad.Newpress.Right) {
	PA_StartSpriteAnim(0, 0, 4, 7, 6);	
	PA_SetSpriteHflip(0, 0, 0);
}

Due to there only being 3 directions of animation in the sprite strip, we use the hardware to flip the sprite for moving left and right.

if(!((Pad.Held.Left)||(Pad.Held.Up)||(Pad.Held.Down)||(Pad.Held.Right))) PA_SpriteAnimPause(0, 0, 1);

Finally we have this which pauses the animation when no pads are held.

Extended Animations

Extended animations are just functions with extended control over animations. They work exactly like the regular animation functions but have two extra parameters.

  • Animation Type, ANIM_LOOP (0) being normal, and ANIM_UPDOWN (1) being a back and forth animation between the frames
  • Cycle Number, how many times you want it to be played. Setting it to -1 will make it play indefinitly. Concerning the ANIM_UPDOWN, a complete back and forth animation counts as 2 cycles.
// First animation will be normal
PA_StartSpriteAnim(0, // screen
		0, // sprite number
		0, // first frame is 0
		3, // last frame is 3, since we have 4 frames...
		5); // Speed, set to 5 frames per second		
 
// Extended animations for the rest									
PA_StartSpriteAnimEx(0, 1, 0, 3, 5, ANIM_ONESHOT); // just play it once...
PA_StartSpriteAnimEx(0, 2, 0, 3, 5, ANIM_UPDOWN, -1); // back and forth, infinite number of times	
PA_StartSpriteAnimEx(0, 3, 0, 3, 5, ANIM_LOOP, 5); // Play it 5 times

The ANIM_ONESHOT is used to play an animation just once, when it ends it returns back to the first frame. To animate once and stay on the last frame, you can use the ANIM_UPDOWN animation type and have it run for just 1 cycle.

Depth/Priorities

Depth and priorities are used to control which sprites overlap what, like people overlapping buildings or sprites appearing under backgrounds.

PA_SetSpritePrio(screen, sprite, priority); can set the priority of any given sprite

*Sprites with a lower sprite priority appear over top anything with a higher priority.

In this basic priority mode there are 4 levels of priority, one for each BG layer. A sprite with a priority of 1 will appear behind BG layer 0 and in front of BG layers 1,2 and 3.

PA_InitSpriteExtPrio(on(1)/off(0)); An extended priority system can be initialized to offer 256 levels of priority on both screens.

PA_SetSpriteExtPrio(screen, sprite,priority); This is used to change the extended priority of a sprite

Both systems can be used at once,using the PA_SetSpritePrio(screen, sprite, priority); you can change which bg layer and PA_SetSpriteExtPrio(screen, sprite,priority); to change its priority on that bg layer.

Eg. A sprite with normal priority 2 and extended priority of 3, will appear below a sprite with a normal priority of 0 and extended priority of 200

Dual Sprites

Dual sprites are just macros that cover sprite functions for both screens. Essentially a Dual sprite is a sprite which is created on both screens, when the sprite is on one screen, the sprite on the other is hidden.

These macros make it easy to make both screens seem like 1 in terms of sprite usage. Rather than being limited to a 256×192 screen, you have 256×384 plain with 0,0 being the top left on the top screen, and 256,384 being bottom right of the bottom screen.

Creating and manipulating these sprites are exactly the same as the normal sprite functions however have the prefix Dual in their function names. Screen values do not apply as they use both screens. Eg. PA_DualCreateSprite(…)
PA_DualSetSpriteXY(sprite, x, y)

The space between the two screens can pose a problem for some. You can define the space between the two screens in terms of pixels. The default has it at 48 pixels, but you can change it with PA_SetScreenSpace(space in pixels).

Note Sprites smaller than the screen space will be hidden until they reach the other screen, in some cases it might be best to not use a screen space at all.

Examples with dual sprites can be found in: palib\examples\Sprites\Basics\DualSprite

DS Sprites Explained

FIXME grammar errors and some unneeded information

I guess there's a small part that was missing here : how the sprite system works… Knowing this will help you decide how to organize your graphics and optimize your code…

What is a sprite ? It's not just a single entity, but a mixture of several things :

In 2D programming, it is usually referred to an 2D image or animation. The Nintendo DS has dedicated 2D hardware which makes it very easy to use these.

1. The image, in 'raw format', which is your Name_Sprite array, converted using PAGfx or gfx2gba, grit or anything else… That's basically the graphics, which will be copied in the VRAM (Video Ram), in a specific part reserved for sprites (1 part for top screen, 1 part for bottom screen). Several sprites can share the same graphic, but as it has only 1 copy in that case, animating 1 sprite will change the graphics in the VRAM and thus animate all sprites the same way…

2. The sprite palette, which is shared for all the sprites. PAlib, by default, has 16 palettes for the sprite, so you could have 16 sprites with different palettes, or 10 with the first and other with the 15 others, etc… But in lots of cases (especially when you start out), you just use a single palette for all the sprites…

3. The DS knows all about the sprites thanks to the OAM (Object Attribute Memory), which is a place in memory to handle all the sprites. This is a huge array containing the basic info for all sprites, one by one… (numbered 0 to 127, 2 copies existing, one for each screen…). The infos are like : X and Y position, shape/size (square/rectangle, 8 pixels wide or more…), horizontal or vertical flips, etc… One important info : rotation/zoom on/off, and Rotset number (0 to 31).

4. The rotset contains how the sprite using that rotset will be zoomed/rotated. As there are only 32, you cannot have 128 sprites rotated 128 different ways :/ So only 32 sprites are available to be affine transformed. Seems like a limit, but in fact it doesn't matter that much, you can most of the time find a decent solution : several sprites can share the same rotset if needed to be rotated/zoomed identically… And you won't find that you would have more than 32 sprites anyway for most projects.

AJ

FAQ - Sprites

FIXME grammar errors, needs a rewrite

Q1. My sprite doesn't show up !!

  • Ok, a few things to check…
    • Have you loaded a palette to go with it ?
    • Is this palette on the same screen as your sprite ?
    • Does the palette and the sprite have the same palette number ?

Q2. My sprite has a background behind it!

  • Check these couple of things
    • see Q1
    • Make sure that the transparency colors are correct. If you're using Adobe Photoshop or any other 'professional' photo editing tool, the background color in some places can be off just by a minuscule amount. This is because these tools blend color in some places to reduce jagged edges, so you might get a tiny shade of the background color where you don't want it. The image converter is very picky about colors, so even if a pixel is just a tiny bit off, it'll judge is as a non-background color. This color difference might be totally unnoticeable to human eyes, so I prefer to go over the edges in a program like Paint (lol) which doesn't have anti-alias (edge blending). However, if you still feel like using a professional tool, you can turn off this feature. On Paint.NET, turn off anti-alias for the tools. On GIMP, use the pencil tool instead of the brush tool.
 
sprites.txt · Last modified: 2010/03/19 08:57 by deathscythe
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki