ふおー、めんどくさい。駆け足で行きます。 今日はマリオカートを再現してみます。 モード7という言葉を聞いたことがあるでしょうか。スーパーFC(Sファミコン とも言う)の画面モードのことで、拡大縮小回転をサポートしています。 で、そのモードで使われるパラメータがドドン。まぁアフィン変換ですね。画像に描かれてるパラメータの説明は多分嘘ですが気 にしないで下さい。 んで、こういう画像を用意しました。
嫌な予感がしますね。 ラスタ割り込みで、画面下方に行くにつれて縦横比を引き伸ばしてやると、こう なりました。
もうスペハリ地面が半分完成。早いですね。 ラスタ毎の横スクロールを全く調整してないので、なんか傾いてますが。 あとは、行列テーブルに三角関数を代入してやれば完成かしら。
結局スペハリかよ!という感じですが、一応動くデータも用意しました。 スタートボタンでマップが切り替わります。 raster_test_mode7.zip モード7の 3D 表現は一応インチキ無しの 3D ではありますが、原理上、平面し か表現出来ないので、絵ヅラは似たり寄ったりになりますな。 さて、次のネタを考えないと……。
ちょっと自己フォロー。 ここで紹介したコードはラスタスクロール用のテーブルを平気で書き換えてまし たけど、処理落ちが発生したときや、書き換え中に割り込みが発生したときなど に困ることになるので、ダブルバッファにするとか書き換え中に割り込みを止め るとかの措置を取らんと駄目ですね。スペハリ再現の方ではやってるんですけど、 アップしたコードが断片なのでそこらへん出てませんでした。
スト2を久しぶりにプレイしてみたら昇竜拳すら出せない体になってて笑った。 そういうわけで今日はスペハリを再現してみる。 まずはこういう画像を用意した。(画像1) 実は、この画像を作るのが一番大変だったらしい……。 今回も上辺と底辺からスクロール比率を計算しておく。それと、今回は縦方向に 圧縮するので、縦スクロール比をブレゼンハムか何かで計算してテーブル化して おく。ちなみに、求める値は画面上のY軸と置き換えたいY軸の差分となる。
(画像2) スペハリの地面は無限平面ということになっているので、横スクロール値を一定 の間隔でリセットする処理を組み込んで、ひとまず第一段階の完成。 ここまでの分をアーカイブしておいた。 raster_test_harrier1.zip -- 次に市松模様の再現だ。これまではテキトーに計算してきたけど、Z値は真面目 に計算してみる。これもテーブル化しておく。 画像1の縦線は二つのパレットだけで使って描かれているので、Z値テーブルに 合わせて割り込みでパレットを書き換えてあげれば市松模様になるというわけだ。 割り込み関数はこんな感じになった。
void HBlankFunc(void) { u16 line = REG_VCOUNT; if (line >= 160) return; REG_BG0_Y = vertical_offset[myplayer_y][line]; line += vertical_offset[myplayer_y][line]; REG_BG0_X = raster_scroll[line] / RASTER_TICK; switch (raster_palette[line] / PALETTE_TICK) { case 0: { background_pal[ODD_LINE] = PAL_BRIGHT; background_pal[EVEN_LINE] = PAL_DARK; break; } case 1: { background_pal[ODD_LINE] = PAL_DARK; background_pal[EVEN_LINE] = PAL_BRIGHT; break; } } return; }というわけで動くデータも用意した。Rボタンで逆スクロール。 raster_test_harrier2.zip 同じ手法でアウトランなんかも再現できるかと思います。 また続きますが、たぶん次で最終回です!
あんまり書かないのもアレなんで、現代ではもう廃れてしまった技術の解説でも ちょろっとやってみようかしら。 えーと、最初に軽く前提を。 まず、題名にある HBI とは Horizontal Blank Interrupt のことで、日本語だと 「水平帰線期間割り込み」とか言うらしい。略すときは HBI の他に H-INT とか HBL と記述されたりもする。 昔のゲーム機はグラフィックコントローラに搭載された VRAM が少なかったりし て、画面描画用のレンダリングバッファが1ライン分しか無かったりする。それ を逆手に取って、1ラインを描き終えたグラフィックコントローラが次のライン を描画し始める前に画面データを書き換えてやることで、様々な効果を生み出す ことが出来るようになる。 (特にスクロール値の書き換えで行われるエフェクトは、俗にラスタスクロール と呼ばれていて、ドラクエの旅の扉・スト2の地面・スペースハリアーの地面・ マリオカートのコースなどはラスタスクロールで実現されている。そんなこと知っ てるって? そうだと思ったよ!) そして冒頭で出てきた HBI を使うと、グラフィックコントローラが1ライン描き 終わったタイミングで割り込みが発生して、特定の関数が呼び出されるというわ けだ。 前提終わり。 -- とりあえず今日はスト2の、パースが付いた地面を再現してみる。 まずはこういう画像を用意した。ちなみに、実際に画面に表示されるのはこの範囲になる。
それぞれのラインの横幅からスクロール比率を計算しておき、スクロールテーブ ルに足してやるだけ。あとは HBI で呼び出された関数からライン毎のスクロー ル値を順次流しこめば、手前ほど速く横スクロールするようになる。 簡単だし要らないと思うけど、一応コードも書いてみる。
/* 1024で1ドット相当の固定小数点数 */ const int scroll_delta[] = { 1036,1049,1063,1077,1091,1105,1118,1132,1146,1160,1174,1188,1201,1215,1229,1243, 1257,1271,1284,1298,1312,1326,1340,1354,1367,1381,1395,1409,1423,1437,1450,1464, 1478,1492,1506,1520,1533,1547,1561,1575,1589,1602,1616,1630,1644,1658,1672,1685, 1699,1713,1727,1741,1755,1768,1782,1796,1810,1824,1838,1851,1865,1879,1893,1907, 1921,1934,1948,1962,1976,2004, }; static int raster_table[256] = { 0 }; static int next_line = 0; void HBlankFunc(void) { REG_BG0_X = raster_table[next_line] / 1024; next_line++; return; } int main() { BG_init(); IRQ_RegistFunc(INT_HBLANK, HBlankFunc); for (;;) { VBLANK_Wait(); KeyCheck(); if (key & KEY_RIGHT) { for (int i = 0; i < 96; i++) raster_table[i] += 1024; for (int i = 96; i < 160; i++) raster_table[i] += scroll_delta[i - 96]; } else if (key & KEY_LEFT) { for (int i = 0; i < 96; i++) raster_table[i] -= 1024; for (int i = 96; i < 160; i++) raster_table[i] -= scroll_delta[i-96]; } REG_BG0_X = raster_table[0] / 1024; next_line = 1; } }GBA エミュレータで動くデータも用意してみた。 raster_test_sf2.zip 同じ手法でダライアスが遺伝のコロニー背景とかも再現できるかと思う。手間の 割りに見栄えがするので、みんなも 20 年前にタイムスリップして使いまくりま しょう! 多分続く。
一人用は残機無制限でクリアタイムを競うモード(その場復活)と、普通に残機 が3機あるモード(戻り復活)の二通り。パターンを完全に忘れていてボロボロ なのに、残機無限なので自分から屈服しない限り陵辱され続けるという、世にも 恐ろしい体験を衆人環視の中でしてきたよ……。 画面モードの 2D / 3D 切り替えは本当に無意味だが素晴らしい。非常にスムーズ に切り替わるため、特に意味も無く何度も切り替えてはニヤニヤしてしまう。 IIの2面は、水の表現が完全に別なものへと変わり、出入水時に水際がネバーっ と上下に波打つようになる。が、その代わりに水しぶきが全く上がらなくなって しまったので、そこは残念かもしれない。
アトピーのことは。 自分の場合は部屋の汚れに対するアレルギー反応だということが分かりつつある ので、かゆくなりだしたら(それじゃもう遅いんだけど)掃除した方がいいみた いだ。特に布団が効くらしい。朝起きたら二度寝する前に布団を干しておき、昼 に目が覚めたら軽く叩いてから取り込んで、入念に掃除機がけをする。これだけ でも大分違う気がする。 休日に干しておいたおかげで今は布団がふかふかだ。これから寝るのが楽しみだ。 ただの生理的欲求としてだけでなく、楽しみになるという事実に自分で驚きだ。 普段どれだけ貧相な布団で寝てるんだよという話でもある。それではおやすみ。
ムフー。(;´ω`)