#author("2023-04-24T12:55:48+09:00","","") * スプライト [#le1275f0] スプライトとは8x8~64x64サイズの画像を最大128個まで表示します。シューティングゲームでいう自機や弾、RPGでいう主人公キャラなどに使います。今回登場するメモリ領域は以下のとおりです。なお、図のとおりキャラクタデータはタイルモードとビットマップモードでは''位置が変わる''ので注意してください。早速、パレットデータ、キャラクタデータ、属性(Object Attribute Memory)の3つをそれぞれ見ていきましょう。~ | 名前 | アドレス | | パレットデータ(256色1パレット or 16色16パレット) | 0x5000200~ | | キャラクタデータ(タイルモード時) | 0x6010000~ | | キャラクタデータ(ビットマップモード時) | 0x6014000~ | | 属性(Object Attribute Memory) | 0x7000000~ | #ref(1.png,nolink) *** パレットデータ [#fc633cc4] データフォーマットはmode3で使った色データと同じです。データ構造はそのままに、16色をパレット16個か、256色をパレット1個で指定することも可能です。~ - Color Palette RAM BG and OBJ palettes are using separate memory regions: 05000000-050001FF - BG Palette RAM (512 bytes, 256 colors) 05000200-050003FF - OBJ Palette RAM (512 bytes, 256 colors) Color Definitions Each color occupies two bytes (same as for 32768 color BG modes): Bit Expl. 0-4 Red Intensity (0-31) 5-9 Green Intensity (0-31) 10-14 Blue Intensity (0-31) 15 Not used *** キャラクタデータ [#rdc6f6b1] キャラクタデータは、パレット番号を指定した集まりです。単位は1キャラクタを8x8ドットとしています。~ | 色 | ドット単位の格納方法 | サイズ | | 16 | 横2ドット=1byte(下位4bitが左、上位4bitが右) | 32byte | | 256 | 横1ドット=1byte | 64byte | 16色の場合、4bitでちょうど16色指定できるのでピッタリのサイズですね。~ 256色も0x0~0xffまでなのでデータを無駄にすることなく使うことができます。~ ** キャラクタデータの格納 [#t400ad4d] たとえば以下のキャラクタデータがあったとしましょう。~ - 256x128 #ref(clip_2.png,nolink) このとき、キャラクタ番号は~ 空白 - 0 ! - 1 " - 2 # - 3 (以下略・・・) となります。8x8単位のみを扱うのでしたらこのキャラクタ番号を指定し、~ 表示するだけで話は終わります。ところが8x8単位以上のものを表示したい場合、~ 格納方法に工夫がいります。~ #ref(clip_3.png,nolink) こちらは先ほどの画像を2倍表示して8x8単位に点線を加えたものです。~ 取り出し方法には1次元、2次元があります。仮に32x32で、1次元の取り出しを~ キャラクタ番号96から行うと、次のような結果になります。~ #ref(clip_4.png,nolink) 96, 97, 98・・・と取り出した為、円がきれいに表示されませんでした。~ では224に変えてみましょう。~ #ref(clip_5.png,nolink) うまく行きました。~ 個人的には1次元の取り出し方を推奨します。なぜならデータが切れ目なく~ 連続しているため、キャラクタデータを入れ替えるときに便利だからです。~ シューティングゲームなどでは頻繁にキャラクタデータの変更を行います。~ ボス戦なら画面いっぱいにキャラクタデータを使うので今のうちに~ 1次元の方法に慣れておくのがいいでしょう。~ 入れ替えがない場合は2次元が使えます。~ 画像データを8x8単位に加工する必要がないのでうまく使い分けでください。~ 取り出す時の形状には、以下のようなサイズがあります。~ // スプライトの指定サイズ enum SPRITE_SIZECODE { Sprite_8x8, Sprite_16x16, Sprite_32x32, Sprite_64x64, Sprite_16x8, Sprite_32x8, Sprite_32x16, Sprite_64x32, Sprite_8x16, Sprite_8x32, Sprite_16x32, Sprite_32x64 }; *** 属性(Object Attribute Memory) [#a58b52c1] スプライト1つ1つに対して、属性という単位で取り扱います。~ 構造体を表すと次のようになりますが、attr0~2までの中には~ 様々なパラメータが存在して、いきなり覚えようというのは難しいと思います。~ 今は軽く読み流す程度で結構です。~ typedef struct { u16 attr0; u16 attr1; u16 attr2; u16 dummy; } OBJATTR; #ref(clip_6.gif,nolink) OBJ Attribute 0 (R/W) Bit Expl. 0-7 Y-Coordinate (0-255) 8 Rotation/Scaling Flag (0=Off, 1=On) When Rotation/Scaling used (Attribute 0, bit 8 set): 9 Double-Size Flag (0=Normal, 1=Double) When Rotation/Scaling not used (Attribute 0, bit 8 cleared): 9 OBJ Disable (0=Normal, 1=Not displayed) 10-11 OBJ Mode (0=Normal, 1=Semi-Transparent, 2=OBJ Window, 3=Prohibited) 12 OBJ Mosaic (0=Off, 1=On) 13 Colors/Palettes (0=16/16, 1=256/1) 14-15 OBJ Shape (0=Square,1=Horizontal,2=Vertical,3=Prohibited) OBJ Attribute 1 (R/W) Bit Expl. 0-8 X-Coordinate (0-511) When Rotation/Scaling used (Attribute 0, bit 8 set): 9-13 Rotation/Scaling Parameter Selection (0-31) (Selects one of the 32 Rotation/Scaling Parameters that can be defined in OAM, for details read next chapter.) When Rotation/Scaling not used (Attribute 0, bit 8 cleared): 9-11 Not used 12 Horizontal Flip (0=Normal, 1=Mirrored) 13 Vertical Flip (0=Normal, 1=Mirrored) 14-15 OBJ Size (0..3, depends on OBJ Shape, see Attr 0) Size Square Horizontal Vertical 0 8x8 16x8 8x16 1 16x16 32x8 8x32 2 32x32 32x16 16x32 3 64x64 64x32 32x64 OBJ Attribute 2 (R/W) Bit Expl. 0-9 Character Name (0-1023=Tile Number) 10-11 Priority relative to BG (0-3; 0=Highest) 12-15 Palette Number (0-15) (Not used in 256 color/1 palette mode) #ref(clip_7.gif,nolink) ** スプライト操作の汎用関数 [#bfa170c7] こちらで用意した関数を通して簡単な(大雑把な)扱いを知ってください。~ void SpriteInit(void) { u32 i; for(i=0; i<128; i++) { SpriteMove(i, 240, 160); } } すべてのスプライトを画面外に移動させます。~ 非表示にするといった機能はありますが、念のため必ず初期化時に実行します。~ void SpriteMove(u32 num, s32 x, s32 y) { OBJATTR* sp = (OBJATTR*)OAM + num; sp->attr1 &= 0xfe00; sp->attr0 &= 0xff00; sp->attr1 |= (x & 0x01ff); sp->attr0 |= (y & 0x00ff); } スプライトの移動処理です。~ 範囲はGBAの液晶画面サイズ240x160と同じではなく、512x256となっています。~ void SpriteSetSize(u32 num, u32 size, u32 form, u32 col) { OBJATTR* sp = (OBJATTR*)OAM + num; sp->attr0 &= 0x1fff; sp->attr1 &= 0x3fff; sp->attr0 |= col | form | (160); sp->attr1 |= size | (240); } スプライトの形状と色数を変更します。~ 引数は''gba.h''の説明にあるものから選択して使用します。~ 詳細はソースコードを読んでください。~ void SpriteSetChr(u32 num, u32 ch) { OBJATTR* sp = (OBJATTR*)OAM + num; sp->attr2 &= 0xfc00; sp->attr2 |= ch; } スプライトで使用するキャラクタ番号を指定します。~ このほかにもいろいろな関数を用意できますが、今回はこれだけを使います。~ | 関数名 | 用途 | | SpriteInit | 初期化 | | SpriteMove | 移動 | | SpriteSetSize | サイズの設定 | | SpriteSetChr | キャラクタ番号の設定 | ** スプライトの表示例 [#h37e14bc] #include "lib/gba.h" #include "res.h" //--------------------------------------------------------------------------- void WaitForVsync(void) { while(*(vu16*)0x4000006 >= 160) {}; while(*(vu16*)0x4000006 < 160) {}; } //--------------------------------------------------------------------------- void SpriteMove(u32 num, s32 x, s32 y) { OBJATTR* sp = (OBJATTR*)OAM + num; sp->attr1 &= 0xfe00; sp->attr0 &= 0xff00; sp->attr1 |= (x & 0x01ff); sp->attr0 |= (y & 0x00ff); } //--------------------------------------------------------------------------- void SpriteSetSize(u32 num, u32 size, u32 form, u32 col) { OBJATTR* sp = (OBJATTR*)OAM + num; sp->attr0 &= 0x1fff; sp->attr1 &= 0x3fff; sp->attr0 |= col | form | (160); sp->attr1 |= size | (240); } //--------------------------------------------------------------------------- void SpriteSetChr(u32 num, u32 ch) { OBJATTR* sp = (OBJATTR*)OAM + num; sp->attr2 &= 0xfc00; sp->attr2 |= ch; } //--------------------------------------------------------------------------- void SpriteInit(void) { u32 i; for(i=0; i<128; i++) { SpriteMove(i, 240, 160); } } //--------------------------------------------------------------------------- int main(void) { // モード設定 SetMode(MODE_0 | OBJ_ENABLE | OBJ_1D_MAP); u16* oam = OBJ_BASE_ADR; // キャラクタデータ u16* pal = OBJ_COLORS; // パレットデータ u32 i; for(i=0; i<sprTilesLen/2; i++) { oam[i] = sprTiles[i]; } for(i=0; i<16; i++) { pal[i] = sprPal[i]; } SpriteInit(); // !(ビックリマーク)の表示 SpriteSetSize(0, OBJ_SIZE(Sprite_8x8), OBJ_SQUARE, OBJ_16_COLOR); SpriteSetChr (0, 1); SpriteMove (0, 20, 20); u32 x = 40; u32 y = 40; // 円の表示 SpriteSetSize(1, OBJ_SIZE(Sprite_32x32), OBJ_SQUARE, OBJ_16_COLOR); SpriteSetChr (1, 224); SpriteMove (1, x, y); for(;;) { WaitForVsync(); if( !(REG_KEYINPUT & KEY_UP) ) y--; if( !(REG_KEYINPUT & KEY_DOWN) ) y++; if( !(REG_KEYINPUT & KEY_LEFT) ) x--; if( !(REG_KEYINPUT & KEY_RIGHT)) x++; SpriteMove (1, x, y); } } SetMode(MODE_0 | OBJ_ENABLE | OBJ_1D_MAP); スプライトを使用するにはOBJ_ENABLEを入れます。~ OBJ_2D_MAPは、OBJ_1D_MAPとの2択で、取り出し方が1次元か2次元か指定します。~ // !(ビックリマーク)の表示 SpriteSetSize(0, OBJ_SIZE(Sprite_8x8), OBJ_SQUARE, OBJ_16_COLOR); SpriteSetChr (0, 1); SpriteMove (0, 20, 20); 引数の1番目はスプライト番号を表しています。ビットマップモードの場合、~ メモリマップが変わる為、先頭番号が512番目からになることは忘れないでください。~ *** 動作画面とデバッグ画面 [#m9a1ff76] #ref(clip_8.png,nolink) #ref(clip_9.png,nolink) キー入力できます。適当に動かしてみてください。 ** 履歴 [#v77dd331] - 2014/12/23