HOME → ソフトウェア → X1でゼビウスを作る!
第2回 時間測定による自機(ソルバルウ)の動作とスクロール速度
時間測定
X1は時間測定やタイマ割込みの機能が貧弱な機種のようですが、一定の速度でゲームを進行させる事は重要です。 X1の場合、垂直帰線期間
(以降「Vブランク」と書きます) は I/Oポート 1A01Hのbit7
により確認する事が可能です。そこで、この情報を利用し時間測定を行う事にしました。
LD
BC,1A01H IN
A,(C)
;BIT7=0 の時、Vブランク
上記の例では、AレジスタのBIT7を調べれば、Vブランクであるか否かの判断ができます。
@ 前回調査したレジスタ値(のBIT7)と、現在のレジスタ値(のBIT7)
が異なる時 A 現在のレジスタ値がVブランクである時
よって、@とAの条件が満たされた場合が、Vブランクに切り替わったタイミングであると判断出来ます。
しかし、常にこれを監視していては処理が止まってしまいますので、この”Vブランク検出・ルーチン”を ゲームのループ内に複数回コールする仕組みとします。つまりポーリングです。
Vブランクのサイクルは、約1/62秒 (以降
「1/62秒」と書きます※文末の補足を参照下さい。私は、1/60秒であると勘違いしていました) =
0.016145秒です。 したがって、”検出ルーチン”を、は0.016145秒以内に1回以上はコールしなければなりません。 (でないとVブランクの検出を取りこぼしてしまいます)
本移植作では、処理コストの掛かる描画ルーチン (”ソフトウェア・スプライトルーチン”、”スクロール・ルーチン”、”アンドアジェネシス描画ルーチン”) をコールする度に”Vブランク検出・ルーチン”もコールするようにしています。
さらに、この”Vブランク検出・ルーチン”にて、Vブランクに切り替わったタイミングで、自機の移動ルーチンやサウンド再生ルーチンをコールするようにしています。 よって、1/62秒※単位で、自機の移動
(やサウンド再生)が可能となります。 つまり、”1/62秒毎※にソフトウェア割り込み”を行っているようなものです。
さらに、Vブランク回数をカウントしており、ループ最後の”ウェイト処理”にてVブランク回数が6回になるまで待ちます。(1ループは0.09687秒 (1/62秒※×6回)
になります)
これにより、一定の速度でゲームが進行出来るようになります。 (自機の移動ルーチンやサウンド再生ルーチンは、1ループ内で6回コールされる事になります)
【処理の概要】
この手法は、X1でゲームを作る時は、常套手段かもしれませんね。 (改めて書くほどの内容では無いのですが、まぁ備忘録として記録しておきます)
ゲームの画面サイズやキャラクタの大きさ
本家ゼビウスのゲーム画面は、縦288ドット。(横228ドット) X1の画面で表示可能なのは縦200ドットです。
よって、小さいドット構成にしなければ画面に収まりません。 約69.4%の縮尺率
(200/288= 約69.4%)
で作れば良いのですが、キリが悪いので62.5%の縮尺率で作ります。
縦ドット数 = 176ドット =
Int(本家288ドット×62.5%/8ドット)×8ドット 横ドット数 = 136ドット =
Int(本家224ドット×62.5%/8ドット)×8ドット
62.5%にする理由は、処理の軽減(高速化)とPCGの節約です。 キャラクタサイズは本家16×16ドットを本移植では10×10ドットにします。これが62.5%の縮尺率なのです。
前章に書いた「キャラクタ描画 (ソフトウェア・スプライトルーチン)」の処理軽減がねらいです。 10ドットにした場合2Byte
(16ビット=16ドット)で収束できます。2Byte内で6回のビットシフトが可能であり、描画速度に貢献できるはずです。(下図参照)
16ビットのシフトイメージ
(黄色部が、グラフィックデータ)
10ドットを超えたキャラクタサイズの場合、3Byteによるビットシフトが必要となります。2Byteと3Byteでは速度面で大きな違いとなります。
後述のソルバルウ(や照準、ザッパー)においては、PCGを使用します。同様にキャラクタサイズが10ドットであれば、ずれたパターンを定義するのも縦横2×2のキャラクタ数で収束可能です。
ただし、(前章でも書きましたが)ガルバーラ・ガルデロータ・ソルの大きなキャラクタは20ドット(1ラインで3Byte)になります。 この場合は、ビットシフトをさせず、キャラクタの配置は8ドット単位に割り切りました。
自機(ソルバルウ)の動作
1/62秒※単位で、自機の移動ルーチンがコールされますが、このルーチンに多くの処理コストを掛ける訳にはいきません。
そこで、X1の特徴でもあるPCGを利用する事にしました。
蛇足 PCGとはテキスト文字(8×8ドット)をドット単位で8色の定義が可能。もちろん表示は文字として扱えるので高速で描画が可能です。 グラフィックの場合
8Byte×3プレーン(RGB)=24ByteのデータをVRAMへ転送する事が必要ですが、PCGの場合であれば、1Byteで済みます。 グラフィック描画と比較すれば24倍も速いという事です。
PCGは8×8ドット単位での定義ですが、以下の様にドットをずらしたパターンを用意する事により、2ドット単位で動かせるようにします。
蛇足 PCGデータ(画像データ)は下図の左上だけを、ピットシフトをしながらPCG定義を行います。また、PCG定義が終了したら、その画像データのメモリ領域は別の用途しとして使用します。
自機(ソルバルウ)自体のドット構成は10×10ドットなので、ひとつのパターンで4個のPCG定義が必要となります。
横方向に4パターン、縦方向に4パターンの合計16パターンが必要となります。 (PCGの定義数で言えば、4倍の64個必要となる) なんと、贅沢(無駄な?)PCGの使い方でしょう。
自機を動かすという事は、同時に照準も動かす事になりますので自機と同様に16パターンを定義します。
なんだか、野暮ったい照準ですね。ちょっと太すぎる感がありますが、スクロール背景がタイリングパターンなので、この位にしておかないと、照準が滲んでしまうのです。
照準が地上物と重なった場合のパターンは準備していません。(本家は照準の一部が赤点滅となる) 残念ながら、PCGの定義数が足りないのです。
点滅はテキストVRAMのアトリビュートのBIT2を変化させる事で、実現させました。
通常時は$27 (00100111B)とし、点滅時には、$23 (00100011B)とさせる。
赤を点滅させたかったのですが、マゼンダ(赤紫)の点滅になってしまいました。
さらに、弾(ザッパー)も16パターン用意し、1/62秒毎※に動かせるようにしました。 弾(ザッパー)の移動単位は8ドットにしていますが、1/62秒毎※に動かしているので滑らかに見えます。
この3つのキャラクタだけで、PCG定義数は160個にもおよんでしまいました。 (自機64個+照準64個+弾32個)
普通ならば、こんな事はしないのですが (前記事「スクロールとキャラクタ描画について」で書いた通り)
他のキャラクタや背景は全てがグラフィックなので、この手法も有効ではないかと思った訳です。
スクロール速度について
上述の通り、0.09687秒※※毎(1ループ毎)にスクロールさせますので、スクロール速度は以下の表の通りになります。 本家(オリジナル)とも比較してみましょう。 (X1版と記載してあるのは、本移植作を示しています。電波新聞社製ではありません)
X1版の方が本家に比べ僅かに速いのですが、Vブランク回数を7回待つようにすると遅くなってしまいますし、グラフィック描画のキャラクタの動き(速度)と自機の動き(速度)のバランスが悪くなってしまいます。
今回は、これで妥協しました。・・・といっても、それほど違和感がある程では無いと思っています。
補足
※1/62秒
エミュレータ上で動作させると1/60秒がVブランクの周期でした。 しかし、実機では少し異なるという事をX1
CENTERの管理人さんに教えていただいきました。 本記事内に1/62秒と記載しておりますが、正確には1/61.938417秒
(0.016145秒) のようです。
※※0.09687秒
エミュレータ上で動作させると0.1秒でした。 つまり、X1のVブランクのタイミングは、0.016145秒毎なので6フレームの場合0.09687秒となるそうです。
以下はX1
CENTERの管理さんからいただいたコメントの抜粋です
X1の標準設定におけるフレーム周期は 14.31818MHz /
(8dot x 112(R0+1) ) / (8x 32(R4+1) + 2(R5) ) =
61.938417Hz
CRTCレジスタのR0,R4,R5を、上手くいじれば本家と同じ速度でゲームが進行出来るようになる・・・・のかもしれません。
|