- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2023-04-24T12:27:43+09:00","","")
#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で使った色データと同じです。~
GBATEKから引用してみました。~
データフォーマットはmode3で使った色データと同じです。データ構造はそのままに、16色をパレット16個か、256色をパレット1個で指定することも可能です。~
Color Palette RAM
- 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
OBJ Palette RAMが今回のターゲットです。~
データ構造はそのままに、16色をパレット16個か、256色をパレット1個で指定することも可能です。~
*** キャラクタデータ [#rdc6f6b1]
キャラクタデータは、パレット番号を指定した集まりです。~
単位は1キャラクタを8x8ドットとしています。~
キャラクタデータは、パレット番号を指定した集まりです。単位は1キャラクタを8x8ドットとしています。~
| 色 | ドット単位の格納方法 | サイズ |
| 16 | 横2ドット=1byte(下位4bitが左、上位4bitが右) | 32byte |
| 256 | 横1ドット=1byte | 64byte |
16色の場合、4bitでちょうど16色指定できるのでピッタリのサイズですね。~
256色も0x0~0xffまでなのでデータを無駄にすることなく使うことができます。~
*** キャラクタデータの格納 [#t400ad4d]
** キャラクタデータの格納 [#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