GBA探索日记(二)

来源:互联网 发布:日本人 知乎 编辑:程序博客网 时间:2024/04/30 04:09

GBA探索日记()

OBJOAM

OBJ就是指的一个个的精灵,或者说就是GBA中的小块小块的图片.它其实跟BG差不多.只是它要小一些.它也算个图层.比如GBA中的RPG游戏就喜欢把一个个的人物用OBJ来实现.这样方便控制他们的位置.当然,GBA探索日记(-)中也可以看到BG的控制其实也是很方便的.OBJBG的差别就是大小.

 

设置显示模式

如果你的程序里要用OBJ那么,

在设置显示模式的时候需要把DISP_OBJ_ONDISP_OBJ_CHAR_1D_MAP加进去

*(vu16 *)REG_DISPCNT = DISP_MODE_1 |  DISP_OBJ_ON | DISP_OBJ_CHAR_1D_MAP;

#define DISP_OBJ_CHAR_1D_MAP    0x0040      // OBJ Character Data 1D Mapping

#define DISP_OBJ_ON             0x1000      // OBJ ON

 

 

下面就直接来看看OBJGBA中怎么实现的.

首先要说明的就是OBJGBA中显示也是由一个个8x8的小图块拼成,BG一样.

共有下面12种大小.

0000: 8  x 8         1000: 8  x 16

0001: 16 x 16        1001: 8  x 32

0010: 32 x 32        1010: 16 x 32

0011: 64 x 64        1011: 32 x 64

0100: 16 x 8        

0101: 32 x 8        

0110: 32 x 16       

0111: 64 x 32       

OBJ的数据分三部分.

1.Character

它跟BG的数据格式是一样的,都是由8x8的小图块的图像数据.而且你也可以通过转换BG的工具来转换OBJCharacter.所以说BGOBJ的数据结构基本是一样的.不过所有的OBJ总共的Character不能超过32K.

256色的OBJ能有512Characters,每个Characters8*8=64bytes.16色的Characters能有1024.每个Character8*8/2=32Bytes.似乎比一个BG256Character?但是BG可以有多个,不同的BG可以有不同的Character,而所有OBJ只能共用这512Charater.

2.Palette

调色板就不用说了,它跟BG一样,支持一个256色调色板或1616色的调色板.

3.OAM

OAM就是OBJ Attribure Memory的缩写.它就是控制OBJ属性的数据部分.比如OBJ的位置,大小等数据部分就放在这里.每个OBJOAM8个字节,OAM是从内存中07000000h070003FFh,1024=8*128,所以OAM总共能有128.

 

如何创建一个OBJ?

前面我就说过通过转换BG的工具也可以用于转换OBJ.

以前转换BG我建议使用的是AgbLib里的bmp2map.exe,同样,转换OBJ也同样用bmp2map.exe这个工具.

比如我把Character Data放到sprite_gfx这个数组里,Palette放到sprite_pal里面.(OBJ中没有Map Data,你的转换时可以把Map data也转换进来,只不过后面用不着)

然后在程序里写入:

 

DmaArrayCopy(3,            sprite_gfx,OBJ_MODE1_VRAM,32);

DmaArrayCopy(3,            sprite_pal,OBJ_PLTT,32);

 

sprite_gfx,sprite_pal拷贝到指定内存中去.

这里又设计到OBJ_MODE1_VRAMOBJ_PLTT两个内存地址

还是看看AgbLib中是怎么定义它们的吧.

#define PLTT                    0x05000000          // Palette RAM

#define PLTT_END                (PLTT +      0x400)

#define BG_PLTT                 (PLTT +        0x0) // BG Palette RAM

#define BG_PLTT_END             (PLTT +      0x200)

#define OBJ_PLTT                (PLTT +      0x200) // OBJ Palette RAM

#define OBJ_PLTT_END            (PLTT +      0x400)

#define VRAM                    0x06000000          // VRAM

#define VRAM_END                (VRAM +    0x18000)

#define BG_VRAM                 (VRAM +        0x0) // BG Character/Screen RAM

#define OBJ_MODE0_VRAM          (VRAM +    0x10000) // OBJ Character RAM

#define OBJ_MODE1_VRAM          (VRAM +    0x10000)

#define OBJ_MODE2_VRAM          (VRAM +    0x10000)

#define OBJ_MODE3_VRAM          (VRAM +    0x14000)

#define OBJ_MODE4_VRAM          (VRAM +    0x14000)

#define OBJ_MODE5_VRAM          (VRAM +    0x14000)

#define OBJ_VRAM_END            (VRAM +    0x18000)

这里我把BG中的地址也包含近来了,你可以对比一下BGOBJ中的地址.

 

然后就是设置OAM(OBJ Attribure Memory).

这里先看看官方文档中是怎么说这个OAM的数据结构的.

特别指出的是上面表格中Character Name是指这个OBJ的起始Character的引索

 

我将介绍两中方法来设置.

 

 

 

 

第一种方法很直观,也很简单.这是我在网上看到最多的.

首先定义了数据结构

typedef struct tagOAMEntry

{

            u16 attribute0;

            u16 attribute1;

            u16 attribute2;

            u16 attribute3;

}OAMEntry, *pOAMEntry;

//attribute0 #defines

#define ROTATION_FLAG                        0x100

#define SIZE_DOUBLE                 0x200

#define MODE_NORMAL               0x0

#define MODE_TRANSPARENT      0x400

#define MODE_WINDOWED                     0x800

#define MOSAIC                         0x1000

#define COLOR_16                      0x0000

#define COLOR_256                    0x2000

#define SQUARE                         0x0

#define TALL                             0x4000

#define WIDE                             0x8000

 

//attribute1 #defines

#define ROTDATA(n)                  ((n)<<9)

#define HORIZONTAL_FLIP                      0x1000

#define VERTICAL_FLIP               0x2000

#define SIZE_8                           0x0

#define SIZE_16                         0x4000

#define SIZE_32                         0x8000

#define SIZE_64                         0xC000

 

//atrribute2 #defines

#define PRIORITY(n)               ((n)<<10)

#define PALETTE(n)                   ((n)<<12)

 

然后写入代码:

OAMEntry sprites[128]; // 这里把总共128OBJ都定义了,不过我们现在只使用第一个

void InitializeSprites()

{

            u16 loop;

            for(loop = 0; loop < 128; loop++)

            {

                        sprites[loop].attribute0 = 160;  //y to > 159

                        sprites[loop].attribute1 = 240;  //x to > 239

            }

}

void CopyOAM()

{

            u16 loop;

            u16* temp;

            u16* _OAM = (u16*)0x7000000;

            temp = (u16*)sprites;

            for(loop = 0; loop < 128*4; loop++)

            {

                        _OAM[loop] = temp[loop];

            }

}

 

u16 spriteY=100;

u16 spriteX=100;

InitializeSprites();

sprites[0].attribute0 = COLOR_256 | SQUARE | spriteY;

sprites[0].attribute1 = SIZE_16 | spriteX;

sprites[0].attribute2 = 0 | PRIORITY(0);

 

由于这个OBJCharacter是从OBJ_MODE1_VRAM的首地址开始写入的,所以它的Character Name就应该是0.所以sprites[0].attribute2 = 0 | PRIORITY(0);

 

由于GBA16色的OBJ256色的OBJ中对于Characters的寻址方式是一样的.那么无论是16色的还是256色的OBJ,它们的起始Characters都应该是OBJVRAM+Character Name*32(虽然256色下的Character64Bytes).

 

比如看看下面的例子:

 

如果传输256色的spriteCharacter DataOBJ_MODE1_VRAM+N*32的地址

DmaArrayCopy(3,sprite_gfx,OBJ_MODE1_VRAM+N*32,32);

那么它对应的的attribute2中的Character Name应该是N.

sprites[0].attribute2 = N;

N的范围是0-1023

 

对于attribute3,我们现在暂时不用.

 

接下来就是把sprites写到OAM

要在程序的主循环中不断更新OAM

while(1)

{

                        // 等待图像缓冲同步

                        WaitSync();

                        CopyOAM();

}

 

 

 

第二种方法是AgbLib里面使用的方法.

比如我要显示一个是OBJ

就直接定义个

vu32     bg_oam_buffer[2];

然后同样要写CharacterPalette数据进去

DmaArrayCopy(3,            sprite_gfx,OBJ_MODE1_VRAM,32);

DmaArrayCopy(3,            sprite_pal,OBJ_PLTT,32);

设置OAM的时候就这样写

bg_oam_buffer[0] = OAM_COLOR_256 |  OAM_SQUARE |OAM_SIZE_16x16

                                    | (100) << OAM_H_POS_SHIFT

                                    | (72) << OAM_V_POS_SHIFT;

bg_oam_buffer[1] = 0x0400;

下面给出AgbLib中对于上面的宏的定义:

#define OAM_V_POS_SHIFT         0

#define OAM_H_POS_SHIFT         16

 

#define OAM_COLOR_16            0x00000000  // Select 16

#define OAM_COLOR_256           0x00002000  // Select 256 colors

 

#define OAM_SIZE_8x8            0x00000000  // OBJ 8 x 8 dot

#define OAM_SIZE_16x16          0x40000000  // OBJ 16 x 16 dot

#define OAM_SIZE_32x32          0x80000000  // OBJ 32 x 32 dot

#define OAM_SIZE_64x64          0xc0000000  // OBJ 64 x 64 dot

#define OAM_SIZE_16x8           0x00004000  // OBJ 16 x 8 dot

#define OAM_SIZE_32x8           0x40004000  // OBJ 32 x 8 dot

#define OAM_SIZE_32x16          0x80004000  // OBJ 32 x 16 dot

#define OAM_SIZE_64x32          0xc0004000  // OBJ 64 x 32 dot

#define OAM_SIZE_8x16           0x00008000  // OBJ 8 x 16 dot

#define OAM_SIZE_8x32           0x40008000  // OBJ 8 x 32 dot

#define OAM_SIZE_16x32          0x80008000  // OBJ 16 x 32 dot

#define OAM_SIZE_32x64          0xc0008000  // OBJ 32 x 64 dot

你可以看出.

bg_oam_buffer[0]其实就是第一种方法的attribute0,attribute1的集合.

bg_oam_buffer[1]就是第一种方法的attribute2,attribute3的集合.

然后同样地在程序住循环里不断更新写入OAM

while(1)

{

            DmaCopy(3, bg_oam_buffer, OAM, 8 , 32);

}

这是OAM的定义:

#define OAM                     0x07000000          // OAM

#define OAM_END                 (OAM +       0x400)

 

原创粉丝点击