nicotakuya.hatenablog.com
前回に続いて、「HuC」を使ったPCエンジンのプログラミング方法について紹介します。
前回はBGの表示に成功しましたが、今度はBGをスクロールさせます。単にスクロールするだけではなく、表示画面より大きなマップ内を動いているように見せたいと思います。これを「マップ機能」と呼ぶことにします。
マップ機能についてはサンプルの「SCROLL」が参考になります。
このプログラムではBGが横方向にスクロールします。表示サイズは32×24セルですが、96×24セルのマップを移動しているように表現しています。
画面下にある32×4セルのBGはスクロールさせません。この固定した画面を「パネル」と呼んでいます。
マップ機能ではBGは2×2セル(16×16ピクセル)で1つのパーツとして扱います。HuCではこれを「タイル」と呼んでいるのですが、個人的にはパターンのことをタイルと呼びたいので、混同を避けるために「マップチップ」と呼ぶことにします。マップ全体のサイズは96×24セルですが、マップを格納する配列の要素は48×12です。
ソースのSCROLL.cを見て、わかったことは、、、
・サンプルのマップチップは10種類。0~9番の番号が割り振られている。
・scroll関数でBGをスクロールさせる。scroll関数の第1引数がウインドウ番号。スクロールする画面をウインドウ0番、パネルをウインドウ1番に割り振ることで、1枚のBGを2枚に見せている。
・#inctileマクロでマップチップの画像のポインタを設定する。
・set_map_data関数を使ってマップのサイズとデータを設定する。
・set_tile_data関数でマップチップを設定する。この段階ではパターンはVRAMに転送されていない。
・load_tile関数を呼ぶと、パターンがVRAMに転送される。
・load_map関数を使ってBGを描画する。最初の一回だけは、表示画面全部を描く。
・16ピクセルぶんスクロールするたびに、load_map関数を使って、BGを部分的に描き足す。
、、、こんな感じです。マップ機能のために新しい関数がたくさん出てきます。
あと、ソースを見て気になったのが「0x600」という記述です。資料がなくて、これの意味がよくわかりませんでした。
VRAMのアドレスですよね。なぜ0x3FFより大きいのか?
ためしに「0x601」に変更したら、BATの設定が1セルぶんズレました。
なので、ウインドウ1のBATの格納開始位置は0x600番地なのかなと思います。間違っていたらすみません。
続いて、横スクロールを行うプログラムを新しく作ります。
マップチップの素材を描きます。
↓
初登場の#inctileマクロですが、前回の#incchrマクロとは違って、8x8ピクセルずつジグザグにデータ化します。
この仕様に対応するため、SPEDITにマップチップ用の変換機能を新しく追加しました。
https://sites.google.com/site/yugenkaisyanico/sprite-editor
変換すると、バイナリファイル「map_pattern.bin」「map_palette.bin」が生成されます。パターン用に10種類×64=640ワードのVRAMを消費します。パレットは0番にします。
パネルの素材を描きます。使える色は16色までです。
↓
BGデータに変換します。
パネルのタイル番号は512番以降に割り振ることにします。256番~295番まではマップチップに使っているためです。パレットは2番です。
そこで、SPEDITにカスタマイズ機能を追加してみました。
変換すると、バイナリファイル「bg_pattern.bin」「bg_palette.bin」「bg_bat.bin」が生成されます。この3つのファイルの役割は前回と同じです。
パターン用に32×4×16=2048ワードもVRAMを使ってしまいます。
あと、マップデータがソースにあると邪魔なので、バイナリ化してみました。これはちょっと手抜きです。本格的にゲームを作りたいという場合には、マップエディタが必要になると思います。
以上の素材がそろったので、あとはプログラムです。
/* scroll test by takuya matsubara*/ /* original program:scrolling demo(by David Michel)*/ #include "huc.h" #define MAP_VRAM 0x1000 #define PANEL_VRAM 0x2000 #define BAT2_VRAM 0x0600 #define MAP_PAL 0 #define PANEL_PAL 2 #incbin(panel_pattern, "bg_pattern.bin") #incbin(panel_pal, "bg_palette.bin") #incbin(panel_bat, "bg_bat.bin") #incbin(map_pattern, "map_pattern.bin") #incbin(map_pal, "map_palette.bin") #incbin(demo_map,"mapdata.bin") #define MAP_WIDTH 48 #define MAP_HEIGHT 12 #define NB_TILE 12 const char map_pal_ref[NB_TILE] = { MAP_PAL<<4, MAP_PAL<<4, MAP_PAL<<4, MAP_PAL<<4, MAP_PAL<<4, MAP_PAL<<4, MAP_PAL<<4, MAP_PAL<<4, MAP_PAL<<4, MAP_PAL<<4, MAP_PAL<<4, MAP_PAL<<4 }; int sx,map_x; int score; main() { disp_off(); cls(); set_map_data(demo_map, MAP_WIDTH, MAP_HEIGHT); set_tile_data(map_pattern, NB_TILE, map_pal_ref); load_tile(MAP_VRAM); load_palette(MAP_PAL, map_pal, 1); load_map(0, 0, 0, 0, 34/2, 24/2); set_font_pal(PANEL_PAL); load_vram(PANEL_VRAM, panel_pattern, 32*4*16); load_bat(BAT2_VRAM, panel_bat, 32, 4); load_palette(PANEL_PAL, panel_pal, 1); put_string("score: ", 1, 25); scroll(0, 0, 0, 0, (24*8)-1, 0xC0); scroll(1, 0, 24*8, 24*8, (28*8)-1, 0x80); disp_on(); sx = 0; map_x = 0; score = 0; while(1){ sx++; if((sx & 0xF) == 0) { map_x ++; if (map_x >= MAP_WIDTH){ map_x -= MAP_WIDTH; } load_map( (sx + 256) >> 4,0, /* sx,sy */ map_x + (32/2), 0, /* map x,y */ (2/2), (24/2)); /* w,h */ score += 1; } put_number(score, 5, 8, 25); scroll(0, sx, 0, 0, ((24*8)-1), 0xC0); vsync(); } }
サンプルのSCROLLから機能を削っただけのプログラムです。BGをスクロールさせたら、16ピクセルごとにload_mapを呼んでいます。
これをビルドしてROMイメージを作ります。
↓
PCエンジンエミュレータで実行すると、こうなります。無事にスクロールさせることができました。
ひたすら、右方向にスクロールします。マップチップが48個ぶん進んだら、最初に戻ります。