2020年6月4日木曜日

ゲームボーイの画面にアニメーションを表示する

おもしろ半分でParty Parrotをゲームボーイで動かしたら、結構な数の皆さんに回覧いただきました。せっかくなので、仕組みをまとめておきます。

実装までの流れ

次のフローで組み立てていきます。

  1. 絵を用意する
  2. ゲームボーイの表示データに変換する
  3. 順番に表示する

絵を用意する

Party ParrotはWikipediaのものを使いました。gifアニメを各コマに分解し、4階調に変換します。これはimagemagickを使いました。

この白黒画像を、ゲームボーイの画面表示に合わせたビット列に変換していきます。

ゲームボーイの表示データに変換する

任意の絵をゲームボーイにする方法が例示されているので、それに従います。リンク先の解説でいくつか挙げられている注意点がさらに厳しくなるので気をつけてください。

  • 8x8サイズのパーツが255種類に収まるように絵を描きます→127種類に収めてください
  • Pic2Tilesで生成されたC言語のファイルからconstを外すよう記載がありますが、一部を除き外してはいけません。

パーツを127種類に収める点について。1枚絵の表示であれば255種類すべて使えるのですが、アニメにする関係で半分に制限されます。1枚表示している間にもう一方の絵を用意し、整ったところで一気に表示を切り替える方法をとっているため、このもう一方を用意するために半分ずつしか使えないということになります。

constを外してはいけない点について。現時点のGBDKではコンパイルエラーが出なくて問題がないことと、constなしでは起動時にRAMに展開されるために今回のように10コマ使用すると、5コマ以上でRAMがオーバーフローするためゲームボーイが落ちます。画像のデータそのものは動的に変化する必要がないので、基本的にconstのままROMにとどめておくようにしてください。例外はmap.Cのうち偶数枚目のコマのものです。変換時に生成されるCファイルには「タイル内のデータ」と「どの位置にどのタイルを並べるかを定義したデータ」が含まれています。後者のデータは常にタイル内データが専用の領域の先頭から並んでいる前提で生成されるので、偶数コマのデータは128個分のオフセットが必要になります。あらかじめ数字を書き換えておくか、constを外してゲームの起動時に初期化の一環として一気に書き換える必要があります。今回のParty Parrotでは面倒だったので起動時に書き換えましたが、コマが多かったり他の用途でRAMを使っていたりで容量が逼迫しているとconstのまま書き換えておいたほうがよいです。

順番に表示する

GBDKに用意されているタイル表示用の関数を使います。基本的に下記のコードを繰り返すだけです。

set_bkg_data(0,100,TileData_pp0); set_bkg_tiles(0,0,20,18,MapData_pp0); delay(50); set_bkg_data(100,100,TileData_pp1); set_bkg_tiles(0,0,20,18,MapData_pp1); delay(50);

set_bkg_dataでタイル内のデータを専用領域にコピーします。第1引数の数字がコピー位置のオフセットです。Party Parrotの場合はどのコマもタイル数が100以下だったので100としています。set_bkg_tilesは、指定した範囲をマップデータに従って書き換えるものです。

次のコマのタイルデータを書き込む際、多少時間を空けないと表示が崩れることがあったのでdelayを入れています。

さいごに

ポケットカメラの撮影時プレビューを見ると、明らかにタイルデータでは間に合わなさそうなドット画像の動画が表示されているので、まだ改善の余地はあるのかもしれません。この記事のやりかたでも、タイルとマップデータをカートリッジに入りきるだけ用意すれば、それなりの時間のアニメーションを表示させることもできるなど、可能性は残しています。