PCエンジンのプログラミング(その5)マップ表示

nicotakuya.hatenablog.com
前回に続いて、「HuC」を使ったPCエンジンのプログラミング方法について紹介します。
前回はBGの表示に成功しましたが、今度はBGをスクロールさせます。単にスクロールするだけではなく、表示画面より大きなマップ内を動いているように見せたいと思います。これを「マップ機能」と呼ぶことにします。

f:id:nicotakuya:20201202101044p:plain
画面スクロールのサンプル「SCROLL」

マップ機能についてはサンプルの「SCROLL」が参考になります。
このプログラムではBGが横方向にスクロールします。表示サイズは32×24セルですが、96×24セルのマップを移動しているように表現しています。
画面下にある32×4セルのBGはスクロールさせません。この固定した画面を「パネル」と呼んでいます。

f:id:nicotakuya:20201202101525p:plain
load_map関数

マップ機能では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を部分的に描き足す。
、、、こんな感じです。マップ機能のために新しい関数がたくさん出てきます。

f:id:nicotakuya:20201202104622p:plain
0x600番地とは一体?

あと、ソースを見て気になったのが「0x600」という記述です。資料がなくて、これの意味がよくわかりませんでした。
VRAMのアドレスですよね。なぜ0x3FFより大きいのか?

f:id:nicotakuya:20201202104706p:plain
0x601番地に変更した場合

ためしに「0x601」に変更したら、BATの設定が1セルぶんズレました。
なので、ウインドウ1のBATの格納開始位置は0x600番地なのかなと思います。間違っていたらすみません。
続いて、横スクロールを行うプログラムを新しく作ります。
マップチップの素材を描きます。

f:id:nicotakuya:20201202105208p:plain
マップの素材

BMPPNGで保存します。色は16色までに限定します。

f:id:nicotakuya:20201202104527p:plain
#inctileの格納方法

初登場の#inctileマクロですが、前回の#incchrマクロとは違って、8x8ピクセルずつジグザグにデータ化します。

f:id:nicotakuya:20201202104755p:plain
マップチップ用の変換モードを追加

この仕様に対応するため、SPEDITにマップチップ用の変換機能を新しく追加しました。
https://sites.google.com/site/yugenkaisyanico/sprite-editor
変換すると、バイナリファイル「map_pattern.bin」「map_palette.bin」が生成されます。パターン用に10種類×64=640ワードのVRAMを消費します。パレットは0番にします。
パネルの素材を描きます。使える色は16色までです。

f:id:nicotakuya:20201202105233p:plain
パネルの素材

BMPPNGで保存します。

f:id:nicotakuya:20201202104848p:plain
BATをカスタマイズできるように

BGデータに変換します。
パネルのタイル番号は512番以降に割り振ることにします。256番~295番まではマップチップに使っているためです。パレットは2番です。
そこで、SPEDITにカスタマイズ機能を追加してみました。
変換すると、バイナリファイル「bg_pattern.bin」「bg_palette.bin」「bg_bat.bin」が生成されます。この3つのファイルの役割は前回と同じです。
パターン用に32×4×16=2048ワードもVRAMを使ってしまいます。

f:id:nicotakuya:20201202104937p:plain
マップデータのバイナリ化

あと、マップデータがソースにあると邪魔なので、バイナリ化してみました。これはちょっと手抜きです。本格的にゲームを作りたいという場合には、マップエディタが必要になると思います。
以上の素材がそろったので、あとはプログラムです。

/* 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イメージを作ります。

f:id:nicotakuya:20201202105011p:plain
実行結果。マップがスクロールする

PCエンジンエミュレータで実行すると、こうなります。無事にスクロールさせることができました。
ひたすら、右方向にスクロールします。マップチップが48個ぶん進んだら、最初に戻ります。