エレ玩 Konyaの開発記録

アクセスカウンタ

zoom RSS PIC24Fでゼビウスもどきがつくれるか?(背景スクロール&キャラ重ね合わせ編)

<<   作成日時 : 2008/11/01 01:55   >>

驚いた ブログ気持玉 10 / トラックバック 0 / コメント 9

 もどきシリーズ第4弾はゼビウスです。
しかし、タイトルのように「つくれるか?」と疑問系...  弱気です...

ゼビウスはご存知のとおり、美麗な背景がスクロールし、多数の敵キャラが地上・空中を動き回る名作シューティングゲームです。

 実行速度、容量的にPIC24Fで可能か?
 私の技量や根気でつくれるのか?

と言うわけで、疑問系なわけで、弱気なわけです。


ゼビウスは昔の8ビットパソコン(マイコン)達の限界に挑戦するお題目として有名でした。
PC-6001のタイニーゼビウス、PC-8801のアルフォス、X1の見た目最高ゼビウス等々、当時はその移植度が話題になっていました。

上記8ビットパソコンに対してPIC24Fは16ビットで32MHz動作(命令実行サイクルは16MHz)と抜群の速度を誇っています。
問題はRAM容量が少ないことで、8KByteではカラー液晶用のバッファには容量不足です。
バッファが無いとスムーズな背景スクロールや、チラツキの無い背景とキャラの重ね合わせが難しくなります。

この辺の解決方法がスクロールゲーム作成のキモとなります。
では「背景スクロール&キャラ重ね合わせ編」行ってみましょう!!

画像


イキナリ結果です。まずは動画をご覧ください。(汚い画像ですがお許しを...)

PIGC3_XEV_00.wmv

2ドット単位ですが、まぁまぁスムーズにスクロールし、背景とキャラの重ね合わせも上手く行っているように見えます。
しかし、これがMAXスピードです。
過去のもどきゲーム達はメインループ内にウェイト処理を入れ、速過ぎる動作を調整していました。
しかし、今回はノーウェイトのMAXスピードです。
敵キャラ表示や当たり判定等を盛り込むと、とてもゲームになるとは思えません。

まだまだ、改良が必要ですが、とりあえず今回の背景スクロール、キャラ重ね合わせ処理のアルゴリズムを解説します。





方式1:背景画像全データをPICに格納、PIC内LCD用バッファなし

 下図で示すように、背景の全画像データをPICのプログラム領域に格納しておき、そのデータを直接LCDへ転送します。
表示Yの値を変更することで背景スクロールさせます。

多分、一番プログラムが簡単で高速な方式ですが、背景画像全データを格納するのは容量的に不可能です。

LCDは132x162dotですが、切り良く128x160dotで使うとして、

 1画面分の画像データ = 128 x 160 x 1.5Byte(赤4bit+緑4bit+青4bit=12bit)
               = 30720Byte
                約30KByte


PIC24F64のプログラム領域は64Kbyteなので2画面分を格納するのがやっとです。

画像


方式2:背景MAPテーブルで背景画像を復元、PIC内LCD用バッファなし

 背景画像データを16x16dotのMAPチップとして共通化。
背景MAPテーブルにチップ番号を記録しておき、背景MAP展開ルーチンで復元しLCDへ転送します。
(MAPチップが16x16dotの場合、LCD画面128x160は8x10ブロックに分割され、背景MAPテーブルも1画面分で8x10データ必要ですが、下図は分かり易くするため、1画面分で4x6データに簡略化しています。)


本家ゼビウスは8x8dotのMAPチップを使っているようですが、今回は速度重視のため16x16dotとしています。
LCDへのデータ転送はできるだけ纏めて実行した方がLCD座標指定等の手順が省け高速化できます。


画像


これで背景データの容量問題は解決しました。(多分)
しかし、復元した背景データを直接LCDへ転送しているため、キャラとの重ね合わせもLCDモジュール内のバッファで実行しなければなりません。
キャラデータを普通に転送すると、上図のように枠も書き込むため、リードモディファイライトが必要となります。

 @キャラ書込み予定の背景データをリード
 A書込み不要のドットはリードした背景データを書き戻す。(書き込み必要なドットは普通に書き込み)


リードモディファイライトで実行速度は遅くなりますが重ね合わせは実現できます。
しかし、LCD内バッファでの重ね合わせは、重ね合わせる前(キャラを書き込む前)の状態が表示される可能性があり、チラツキの可能性があります。

 @全背景をLCD内バッファに書き込み(キャラ消去)
 AキャラをLCD内バッファに書き込み
 B表示Yをインクリメントし@へ


LCD内バッファをLCD画面に反映するタイミングは外部から制御できません。
BのタイミングでLCD画面に反映してくれれば問題ないのですが、各々のタイミングで反映されるとチラツキます。
@の途中で反映されるとスクロール前後の画像が混在し、背景が歪んで見えるはずです。

試しに背景スクロールなしで本方式を実行してみましたが、キャラがチラツキまくりました。




方式3:背景MAPテーブルで背景画像を復元、PIC内LCD用バッファあり(1画面分)

 PIC内のRAMをLCD用バッファに見立て、背景画像をPIC内バッファに展開、キャラを重ね合わせてからLCDへ一括転送する方式です。
LCDと同等のバッファを持つ場合は1dot=1.5Byte(12bit 4096色)となりますが、処理の容易化、容量削減のためバッファは1dot=1Byte(8bit 256色)とします。
よってLCDへの転送時に256→4096色変換処理が必要となります。(下図参照)

キャラの重ね合わせは簡単です。
PIC内バッファは1dot=1Byteなので書き込み不要のドットは書かずに次のアドレスに進めば良いだけです。
例えばキャラデータのドット値が0x00(黒色)なら書き込みをスキップ、それ以外なら書き込めば良い。


この方式ならキャラのチラツキもなく、1画面分を一括転送するため、高速な表示が可能なはずです。

しかし、冒頭でも書いたようにPIC内のRAMは8KByte、バッファに必要な容量は約20KByte(下図参照)、ぜんぜん足りません。

画像



方式4:背景MAPテーブルで背景画像を復元、PIC内LCD用バッファあり(1/10画面分)


 128x16dot(1/10画面)分のバッファで10回に分けてLCDへ転送する方式です。
これなら2KByteのRAM(下図参照)で実現可能です。

この方式はキャラを重ね合わせる時に、PIC内バッファに展開した背景Y座標とキャラのY座標を比較し書き込み有無の判定が必要なことと、バッファからはみ出した分を書き込まないようクリッピング処理が必要となります。
また、10回に分けてLCDへ転送するため速度的に方式3より不利になります。


あぁ、PIC24Fに32KBのRAMがあれば簡単なのに...

画像


マップチップは縦16dotのため、1dot単位のスクロールには、さらに工夫が必要です。
下図のように2列分のMAPテーブル使い、組み合わせてバッファ展開します。

あぁ、これも面倒だ...

画像


この方式4をインプリした結果が最初の動画です。
初期の頃はプログラムの無駄が多く実行速度が遅いため、ビロッ、ビロッと背景が歪んだスクロールをしていました。
プログラムの無駄をかなり見直し、ようやく動画の速度を実現しています。

128x160=20,480回のループがあるので、ループ内では1命令減らしただけでも効果があります。

 1命令時間=62.5ns(16MHz) 
 62.5ns x 20,480 = 1.28ms

30FPS出すためには1画面あたり33.3ms以内の処理が必要なので1.28msの削減はかなり効果があります。
実際に何FPS出てるかは知らないんですがね...


さて、今回はここまでです。
今後のゼビウスもどきの予定は未定です。
今までのゲームとは規模が違うため、かなりの長期戦になると思われます。
他の工作もやりながら、たまに結果報告みたいになるかもしれません。

ゼビウスは全部で16エリアありますが、最初の1エリアくらいは完成させたいと思っています。
1エリアだけでもかなり大変ですが...

テーマ

関連テーマ 一覧


月別リンク

ブログ気持玉

クリックして気持ちを伝えよう!
ログインしてクリックすれば、自分のブログへのリンクが付きます。
→ログインへ
気持玉数 : 10
驚いた 驚いた 驚いた 驚いた 驚いた
なるほど(納得、参考になった、ヘー) なるほど(納得、参考になった、ヘー) なるほど(納得、参考になった、ヘー)
面白い
ナイス

トラックバック(0件)

タイトル (本文) ブログ名/日時

トラックバック用URL help


自分のブログにトラックバック記事作成(会員用) help

タイトル
本 文

コメント(9件)

内 容 ニックネーム/日時










すみませんが、前の書き込みは誤送信ですので削除してください。

さて、ゲーム頑張ってますねぇ。すごいですよ。

やはり、RAMは増やしたいですね。あとはDMAですかね。
キャラ・背景データ類はSDカードやmicroSDを利用してはどうでしょうか。
安くなっていますので直づけでも良いと思いますよ。


そら。
2008/11/01 08:48
SDカードなら安くて大容量のメモリが使えますよね。
問題は使い方を知らないことです。
勉強しようとは思っているのですが...

マイコンの内蔵ROM・RAMが大きいのが一番簡単なんですけどね。
Konya
2008/11/01 14:14
以下のMP3プレーヤのSDカードのアクセスが参考になるかもしれません。
C言語のソースを公開しています。
http://yuki-lab.jp/hw/mp3kit-bk1/index.html

ただ、このキットはFATアクセスでSDカードのアクセスはセクタ単位です。
接点直づけて組み込む場合などFATが不要の場合はセクタ単位アクセスで良いでしょう。

FAT不要の場合は外付けのI2C EEPROMの様にSDカードにアクセス出来ると楽なんですがセクタ単位以外のアクセス方法があるのかどうか、またその方法は私にも分かりません。(^_^;)

SDカード自体とはSPIで送受信出来ます。
そら。
2008/11/02 07:29
参考サイトのご紹介ありがとうございます。
地道に勉強していきます。
MP3にも挑戦したいと思ってました。
Konya
2008/11/02 08:58
Konyaさんお久しぶりです。
かなり進みましたね〜、私はあれからほとんど進んでいませんが…(やっぱり16bitsI/Oは厳しい…)。
だいぶ前にお話したCrystalFine(と思われる)液晶ですが、売り切れになってしまったようですね…(買っておけば良かったです)。
Konyaさんがお使いの液晶を買って再チャレンジしてみようと思います。
ずんや
2008/11/05 13:28
ずんやさん、ご無沙汰しております。

液晶市場は結構売り切れますよね。
私も172BA00を追加購入するか迷っています。
買えるうちに買っとけ!?
Konya
2008/11/05 22:21
AVRですが、こんなのを見つけました。

http://avga.prometheus4.com/index.php

上記のサイトでAtmega168などを使ったゲーム機を紹介しています。

Atmega168 1個で実現しています。

映像出力は抵抗を使って、DACにしているようです。
テレビにつなぐ場合はRGB->ビデオ信号変換が別途必要なようです。

回路図や基板パターン、プログラムもダウンロード出来るので作ってみても良いかもしれません。

映像信号はNTSCも出来るようですが、PALでの解説しか無いので微妙・・・

そら。
2008/11/18 02:25
マリオすげー!!

白黒ゲームの工作は良く見かけますが、カラー且つ、スムーズな動き。

VRAMとかどうしてるのでしょうか?
単純に考えて、192x144x0.5Byte(16色)=13,824Byte 必要。
Atmega168はRAMが1KByteですよね?

とにかく凄い!
Konya
2008/11/19 23:34
すごいですよね。

そのうち手持ちのATmega168で試そうと思います。


そら。
2008/11/21 09:35

コメントする help

ニックネーム
本 文
PIC24Fでゼビウスもどきがつくれるか?(背景スクロール&キャラ重ね合わせ編) エレ玩 Konyaの開発記録/BIGLOBEウェブリブログ
文字サイズ:       閉じる