SGDK学習メモ:No.8、SCROLLとWINDOWのVRAMアドレスが重複している場合の挙動を確認してみる
*以下SGDKは記述時点で最新版のSGDK 2.00 (january 2024)を使用しています
前々回、前回の補足事項です。
VRAM内のメモリマッピングは(ある程度)自由に変更が可能で、更に複数の項目に同じVRAM領域を割り当てることも可能です。
今回はSCROLL BとWINDOWに同じVRAMアドレスを割り当てた場合の挙動を確認してみます。
正直想像通りではありますが、実際に試してみたということで。文字に起こしてみるとちょっとまどろっこしいです。
SCROLL BとWINDOWに同じVRAMアドレスを割り当て、それらに背景画像(タイル)をセットしてみる
以下はSGDKデフォルト時のVRAMマッピングです。
今回SCROLL BとWINDOWに同じアドレスを設定します。
この状態でSCROLL BとWINDOWに背景用の画像(タイル)をセットしてみます。
前々回は画面上部にWINDOWを表示(横分割)したので、今回は画面左側(縦分割)を試します。
今回のソースコードです。
#include <genesis.h>
//VRAMアドレス
#define HSCROLL_TABLE_ADDR 0xA800
#define SPRITE_LIST_ADDR 0xAC00
#define WINDOW_ADDR 0xB000
#define BGA_ADDR 0xC000
#define BGB_ADDR 0xE000
static const int sciSlash = 0x05AF; //word"/" , 1455
static const int sciA = 0x05C1; //word"A" , 1473
static const int sciOne = 0x05B0; //word"1" , 1456
static const int sciComma = 0x05AC; //word"," , 1452
static const int sciDot = 0x05AE; //word"." , 1454
static const int sciUScore = 0x05DF; //word"_" , 1503
static const int sciVBar = 0x05FC; //word"|" , 1532
s16 currentScreenX=0;
s16 currentScreenY=0;
//背景初期化
//BG_Bの表示範囲に値を埋める
void bgInit(){
//BG_B , "_"を敷きつめる
VDP_fillTileMapRect(BG_B,TILE_ATTR_FULL(PAL0,FALSE,FALSE,FALSE,sciUScore),0,0,39,27);
//BG_B,A(右端、垂直)とB(下部、水平)とC(AとBの交差点)を置く
VDP_fillTileMapRect(BG_B,TILE_ATTR_FULL(PAL1,FALSE,FALSE,FALSE,sciA),39,0,1,27);
VDP_fillTileMapRect(BG_B,TILE_ATTR_FULL(PAL1,FALSE,FALSE,FALSE,sciA+1),0,27,39,1);
VDP_setTileMapXY(BG_B,TILE_ATTR_FULL(PAL1,FALSE,FALSE,FALSE,sciA+2),39,27);
}
//VDP アドレスログ出力(デバッグ用)
void logVramAddresses(){
kprintf("VDP_getBGAAddress(): %x,(%u)",VDP_getBGAAddress(),VDP_getBGAAddress());
kprintf("VDP_getBGBAddress(): %x,(%u)",VDP_getBGBAddress(),VDP_getBGBAddress());
kprintf("VDP_getWindowAddress(): %x,(%u)",VDP_getWindowAddress(),VDP_getWindowAddress());
kprintf("VDP_getSpriteListAddress(): %x,(%u)",VDP_getSpriteListAddress(),VDP_getSpriteListAddress());
kprintf("VDP_getHScrollTableAddress(): %x,(%u)",VDP_getHScrollTableAddress(),VDP_getHScrollTableAddress());
}
//VDP アドレスセット(未使用)
void setVramAddresses(){
VDP_setBGBAddress ( BGB_ADDR );
VDP_setBGAAddress ( BGA_ADDR );
VDP_setWindowAddress ( WINDOW_ADDR );
VDP_setSpriteListAddress ( SPRITE_LIST_ADDR );
VDP_setHScrollTableAddress( HSCROLL_TABLE_ADDR );
}
//キーイベント(コールバック)
void myJoyHandler( u16 joy, u16 changed, u16 state)
{
if (joy == JOY_1){
//Aボタン
if (state & BUTTON_A){
//WINDOW(BG_Aの一部)に0~3をセット
VDP_setTileMapXY(WINDOW,TILE_ATTR_FULL(PAL3,FALSE,FALSE,FALSE,sciOne),0,0);
VDP_setTileMapXY(WINDOW,TILE_ATTR_FULL(PAL3,FALSE,FALSE,FALSE,sciOne+1),0,27);
VDP_setTileMapXY(WINDOW,TILE_ATTR_FULL(PAL3,FALSE,FALSE,FALSE,sciOne+2),3,0);
VDP_setTileMapXY(WINDOW,TILE_ATTR_FULL(PAL3,FALSE,FALSE,FALSE,sciOne+3),3,27);
}
//Bボタン
if (state & BUTTON_B){
//WINDOWをセット
//縦は2CELL単位の指定となる = 2だと4CELL分がWINDOWになる
VDP_setWindowHPos(FALSE, 2);
}
//Cボタン
if (state & BUTTON_C){
}
//Xボタン
if (state & BUTTON_X){
}
//Yボタン
if (state & BUTTON_Y){
}
//スタートボタン
if (state & BUTTON_START){
}
}
}
//キーイベント(VBlankごと)
static void handleInput()
{
u16 value = JOY_readJoypad(JOY_1);
if (value & BUTTON_UP){
currentScreenX++;
}
if (value & BUTTON_DOWN){
currentScreenX--;
}
if (value & BUTTON_RIGHT){
currentScreenY++;
}
if (value & BUTTON_LEFT){
currentScreenY--;
}
// VDP_setHorizontalScrollVSync (BG_A,currentScreenY);
VDP_setHorizontalScrollVSync(BG_B,currentScreenY);
// VDP_setVerticalScrollVSync(BG_A,currentScreenX);
VDP_setVerticalScrollVSync(BG_B,currentScreenX);
}
// main
int main()
{
JOY_init();
JOY_setEventHandler( &myJoyHandler );
kprintf("*** 0:vram address bofore changed");
logVramAddresses();
//VRAMのアドレスをマッピングを変更する
//WINDOWにSCROLL Bと同じ 0xC000 をセット
VDP_setWindowAddress ( 0xC000 );
kprintf("*** 2:vram address after changed");
logVramAddresses();
bgInit();
while(1)
{
handleInput();
SYS_doVBlankProcess();
}
return (0);
}
【了】