GB101:Sprites
GB101 Class Notes | |
---|---|
|
Introduction[edit]
In addition to the background tiles, the GBA features hardware sprite handling. Sprites and backgrounds are similar in that they are built out of 8x8 bitmap tiles. Instead of a tile map, sprites have object attributes which are stored outside of video ram. These attributes describe where in memory to find the graphics, the palette, the position on screen, as well as other bits. The part of memory where these are stored is generally referred to as OAM, and each entry is referred to as an OAM entry.
Sprites[edit]
Converting images[edit]
Because we'll be loading a bitmap with several tiles in it we'll need to convert it into an array so that the GBA can read it sequentially. That is, each tile should be able to be read sequentially so we can memcpy the whole thing into VRAM.
We'll be using the utility grit that comes with devkitPro. To use it, use the following syntax:
grit image.bmp -gB**COLOR DEPTH** -Mh**TILES ACROSS** -Mw**TILES DOWN** -ftc -W3 grit image.bmp -bB4 -Mh2 -Mw2 -ftc -W3
A switch to TONC[edit]
At this point I will be introduction an alternate library to libgba called TONC. The TONC library used througout the TONC tutorials and samples. It is a much cleaner and more organized library, and the sprite handling is much more straightforward.
Implementation[edit]
#include <tonc.h>
#include <string.h>
#include "link.h"
#include "tiles.h"
// The buffer to store the OAM entries between vblanks
OBJ_ATTR obj_buffer[128];
// This is our main loop
void obj_test()
{
// our position
int x= 96, y= 32;
// tile id, palette bank
u32 tid= 64, pb= 0;
// Get a pointer to the first OAM entry
OBJ_ATTR *link= &obj_buffer[0];
obj_set_attr(link,
ATTR0_SQUARE, // Square, regular sprite
ATTR1_SIZE_16, // 8x8px sprite
ATTR2_PALBANK(pb) | tid); // palette 0, tile 64
// position sprite (redundant here; the _real_ position
// is set further down
obj_set_pos(link, x, y);
while(1)
{
// Wait for VBlank
vid_vsync();
// Get the state of the input controls
key_poll();
// move left/right
x += 2*key_tri_horz();
// move up/down
y += 2*key_tri_vert();
// increment/decrement starting tile with R/L
tid += bit_tribool(key_hit(-1), KI_R, KI_L);
// change the sprite tid and/or flip bits to
// face link the right way
if (key_hit(KEY_LEFT)) {
if (tid != 64)
tid = 64;
BIT_SET(link->attr1,ATTR1_HFLIP);
}
else if (key_hit(KEY_RIGHT)) {
if (tid != 64)
tid = 64;
BIT_CLEAR(link->attr1,ATTR1_HFLIP);
}
else if (key_hit(KEY_UP)) {
if (tid != 128)
tid = 128;
BIT_CLEAR(link->attr1,ATTR1_HFLIP);
}
else if (key_hit(KEY_DOWN)) {
if (tid != 48)
tid = 48;
BIT_CLEAR(link->attr1,ATTR1_HFLIP);
}
// toggle mapping mode
if(key_hit(KEY_START))
REG_DISPCNT ^= DCNT_OBJ_1D;
// Change the tid and position
link->attr2 = ATTR2_BUILD(tid, pb, 0);
obj_set_pos(link, x, y);
// Copy the bufferred OAM entries to the actual OAM memory
oam_copy(oam_mem, obj_buffer, 1); // only need to update one
}
}
int main()
{
// Load the link sprite into tile memory vram page 4
memcpy(&tile_mem[4][0], linkTiles, linkTilesLen);
// Load the palette memory into palette memory
memcpy(pal_obj_mem, linkPal, linkPalLen);
// Load the backgrounds
memcpy(&tile_mem[0][0], (u8*)TS_Zelda, 256*256);
memcpy(pal_bg_mem, (u16*)PAL_Zelda, 256*2);
memcpy(se_mem, (u16*)MAP_Zelda, 32*20*2);
// Set up our OAM entry buffer
oam_init(obj_buffer, 128);
// Set mode 0, bg 0, sprites enabled, 1d sprites
REG_DISPCNT = DCNT_OBJ | DCNT_OBJ_1D | DCNT_MODE(0) | DCNT_BG0;
// Set bg 0
REG_BG0CNT = BG_8BPP | BG_CBB(0) | BG_SBB(31);
// Start the demo
obj_test();
return 0;
}