GB101:Sprites
From NYC Resistor Wiki
| GB101 Class Notes | ||
|---|---|---|
|
| |
[edit] Introduction
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.
[edit] Sprites
[edit] Converting images
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
[edit] A switch to TONC
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.
[edit] Implementation
#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; }


