Main Page | Related Pages

Using Sprites

Todo:
(A03) Document how to use sprites in the various graphics modes.

(A03) Document Sprite OAM attributes.

(A03) Document 1D vs. 2D sprites.

Sprite Overview

OAM

Sprite Mapping Modes

Examples

List of examples:
Sprite Example #1 -- Simple 16 Color Sprites Most basic example. Presents the minimum amount of code with relationship to activating registers to present sprites on the screen. Supports basic user input.
sprite02

Sprite Example #1 -- Simple 16 Color Sprites

The first example will feature a very simplistic user interface. A simple letter "A" sprite is displayed on both screens. The bottom screen sprite will move based on where the user places the pen on the screen. The top screen sprite will move as directed by the user using the D-pad. This examples uses Mode 0 graphics.

Start by copying the template directory to sprite01 for this example.

cd ~/ds_projects cp -R template sprite01

Creating the Sprite

The initial sprite is simply a 16x16 graphic of the letter A. Start The GIMP and create a new image using File->New. Specify that the width of the image should be 16 pixels, and the height should be 16 pixels and click ok. Next, double click on the foreground color to bring up the "Change Foreground Color" dialog and specify the "Hex Triplet" FF00FF and click ok. This specifies a pink color which will be the background/transparent color for the sprite. Click on the view menu of the new image, and zoom the display to 16:1. Now click on the buck and fill the background of the new image with the pink color. Now click on the "Add TExt to Image button. In the Text Options dialog, click on the font button and select a nice looking font, such as "URW Chancery L, Italic". Then type the letter A and change the size of the font until it takes the entire 16x16 area. In the case of Chancery, this requires a size of 30 and results in the following iamge:

230let_a.png

The Sprite.

Now, generate the LetA.h and LetA.c files by running the "Python-Fu/NDS/Create Sprites" script from the image manu. A dialog is displayed prompting for information about the sprite being created. Specify the output .c/.h file as ../arm9/LetA. Depending on the current directory for gimp, specify the path to the arm9 directory. In the screenshot below, gimp was run from the sprite01/graphics directory. Next, select the sprite size as 16x16. Set the palette to use as "Use Specified" and then place "NDS Text" in the palette name area. Finally, specify to generate 16 color tiles.

230create_sprites.png

CreateSprites Dialog

Coding the Sprite Display

Managing sprite data is complex enough that creating a base class to handle loading sprite tiles is the best solution. For this example, much of the sprite specific code is in sprite.cpp.

main.cpp

The main function for the sprite01 application is exceedingly simple.

int main(int argc, char** argv) {
  Tutorial01Sprite& app(Tutorial01Sprite::theApp());

  app.go();

  return 0;
}

The constructor for Tutorial01Sprite starts by clearing all of the palettes by setting all colors to black.

Tutorial01Sprite::Tutorial01Sprite()
{
  unsigned int i;

  for(i = 0; i < 0x200; ++i) {
    BG_PALETTE[i]=0;
    SPRITE_PALETTE[i] = 0;
    BG_PALETTE_SUB[i]=0;
    SPRITE_PALETTE_SUB[i] = 0;
  }

Next, it turns on the screens, enabling VRAMs A and C, and sets the display for use with Mode 0.

VRAM_A is associated with the touch screen and is the sprite video memory. VRAM_C is associated with the top display and is the sprite video memory for that screen.

  // Turn on the screens and 2D cores and switch to mode 0

  POWER_CR = POWER_ALL_2D;
 
  vramSetBankA(VRAM_A_MAIN_SPRITE);
  vramSetBankD(VRAM_D_SUB_SPRITE);

  DISPLAY_CR = MODE_0_2D | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D_LAYOUT;
  SUB_DISPLAY_CR = MODE_0_2D | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D_LAYOUT;

The call to initOAM initializes our copy of the OAM memory (both the touch screen and the top screen) to values that cause none of the sprites to be visible. This disabling of the sprites is accomplished by using the ATTR0_DISABLED define.

  //Turn off all of the sprites in OAM.
  initOAM();

Next, the sprites are initialized. An entry in the application copy of OAM memory is assigned to a sprite in the oam member variable. Next, the x and y location of the sprite is set. Finally, the gfxID indicates the position of the first tile of the sprite in the sprite graphics memory. Later, the MoveSprite command will use these values to set the copy of OAM memory to correct values in preparation for moving the copy of OAM memory into the actual OAM memory.

  //init our sprites.
  letA.oam = &OAMCopy[0];
  letA.x = 50;
  letA.y = 50;
  letA.gfxID = 0;

  letASub.oam = &OAMSubCopy[0];
  letASub.x = 50;
  letASub.y = 50;
  letASub.gfxID = 0;

Now the sprite must be described. Here, the sprite is specified as a 16 color sprite and noted that the sprite is a square. The next attribute speicifes the size of the sprite as 16 pixels. So at this point, the application has specified that the sprite is a 16 color 16x16 pixel sprite. Finally, the application specifies which graphic image is associated with the sprite. The same graphic image can be used by many sprites in many positions.

  //set up our sprites OAM entry attributes.
  letA.oam->attribute[0] = ATTR0_COLOR_16 | ATTR0_SQUARE;  
  letA.oam->attribute[1] = ATTR1_SIZE_16;
  letA.oam->attribute[2] = letA.gfxID;

  letASub.oam->attribute[0] = ATTR0_COLOR_16 | ATTR0_SQUARE;  
  letASub.oam->attribute[1] = ATTR1_SIZE_16;
  letASub.oam->attribute[2] = letA.gfxID;

Now the sprite palette is moved into the sprite palette memory. While it is not required in general, the application specifies that the letter should be drawn on the screen in a green color rather than leaving the color as black.

  //copy in the sprite palettes
  for(i = 0; i < sizeof(LetAPalette) / sizeof(uint16); ++i) {
    SPRITE_PALETTE[i] = LetAPalette[i];
    SPRITE_PALETTE_SUB[i] = LetAPalette[i];
  }
  
  SPRITE_PALETTE[1] = RGB15(0, 31, 0);
  SPRITE_PALETTE_SUB[1] = RGB15(0, 31, 0);

Finally the sprite graphics are loaded into memory.

  //copy the sprite grahics in obj graphics mem
  for(i = 0; i < sizeof(LetAData) / sizeof(uint16); i++) {
    SPRITE_GFX[letA.gfxID * 16 + i] = LetAData[i];
    SPRITE_GFX_SUB[letA.gfxID * 16 + i] = LetAData[i];
  }

And lastly, the interrupt handler is initialized and configured.

  // Enable the V-blank interrupt
  IME = 0;
  IRQ_HANDLER = &InterruptHandler;
  IE = IRQ_VBLANK;
  IF = ~0;
  DISP_SR = DISP_VBLANK_IRQ;
  IME = 1;
}

The Tutorial01Sprite::theApp method simplay returns a reference to the one and only Tutorial01Sprite object for the application.

Tutorial01Sprite& Tutorial01Sprite::theApp(void)
{
  static Tutorial01Sprite app;
  return app;
}

The Tutorial01Sprite::go method invokes MoveSprite, which updates the application copy of OAM memory, setting the attributes correctly so that the sprite will appear at the appropriate place on the screen. Finally, the application lets the interrupt handler take over processing for the application.

void Tutorial01Sprite::go(void)
{
  MoveSprite(&letA);
  MoveSprite(&letASub);

  while (1) {
    swiWaitForVBlank();
  }

sprite.cpp

sprite02


Generated on Fri Apr 22 13:47:40 2005 for Homebrew Programmers Guide to the Nintendo DS by doxygen 1.3.6