Making「ActBarrier」その1

Home PC-6001mkII Program etc

Making「ActBarrier」 Top


2014/12/xx:はじめに
 「F-DOT2」以来、しばらくP6のセミグラで何も作ってないな。ここらで何か作りたいところだが…。

 そうだ、2012年にHSPやプチコンmkIIで作った「ActBarrier」なんかどうだろう。画面を埋め尽くす数十キャラクタの表示だと、結構インパクトがありそうだ。

 ドット単位の移動を行いたいこともあり、敵の表示位置によらず実際に表示する文字数を同じにしたい。P6のセミグラは1キャラクタあたり2x3ドットなので、その最小公倍数+1で7x7ドット(4x3文字)にするか。少々大きめではあるけれど。

 表示速度が問題なのは初めからわかっているので、できるだけ速い方法にしたい。ループ処理なんてもってのほかだ。という事で、4x3文字の表示ルーチンを書き始める。

 待てよ、画面外から出現する事を考えるともっと表示パターンがあるのか…。4x3文字、4x2文字や3x3文字等々。大きさ別の表示ルーチンを作り始めたが、なにか違う気がする。こんなこともあって、始めて間もなくお蔵入り状態となった。

2017/01/xx:発掘
 月日、というか年月が流れて2017年1月。2014年に少しだけ作りかけたプログラムを発掘した。これも一つの機会だし、どこまでできるか改めて考えてみるか。

 はじめは表示の大きさ別に専用の表示ルーチンを作った方が速いような気がしたが、表示ルーチンの分岐処理や表示開始アドレスの計算まで考えると、かえって遅くなるのではなかろうか?
 それならむしろ、4x3文字の表示ルーチンのみに固定して、画面外にはみ出した部分を何とかする方が速いような気がする。

 よし、この考え方でいくか。

2017/02/10:6パターン
 まずは表示だろう。という事で、最低限の表示を行うために必要なことを考える。

 まずは表示に使用するキャラクタデータだ。表示処理を極力シンプルにするために、あらかじめ以下のようにドット位置に応じた6パターンのキャラクタを作成する。
 元データの入力および変更の手間をを考えて、一番左のキャラクタを元に、右または下に1ドット移動させたキャラクタを順繰りに生成する処理を作成しよう。

画像

 本来ならば色も1ドット単位で移動させたいところだが、処理が面倒になりそうなので、今回は色は移動させないようにする。まあ、単色のキャラクタならば特に問題ないだろう。

 次に考えるのは座標系だ。画面外の上下左右から敵が画面内に入ってくる事を考えると、画面外の余白を最初から考えた方が良いだろう。まあ、32ドット分位余裕を持たせれば十分かな。

 画面右にスコア等を表示する事を考慮して、画面内の表示範囲は48x48ドットとする。という事で、表示範囲の座標は、X, Yともに20H〜4FHとなる。

画像

 まあ、こんなところかな。

2017/02/10:座標変換
 表示を行うにあたって、ドット単位の座標から文字単位のアドレスに変換する必要がある。

 1文字のドットの大きさは2x3なので、横方向は1/2、縦方向は1/3の計算をする。1/2はともかく、1/3は愚直に割り算の処理を行わないといけないので、マシン語では面倒な処理となる。また、割り算処理を作ったとしても、毎回計算すると遅くなるだろう。

 ということで、Y座標変換用テーブルを作成することにする。以下のように文字位置を上位5ビット、余りを下位2ビットに入れる。また、完全に画面外になる部分はFFHとする。
Y座標テーブル値Y座標テーブル値Y座標テーブル値
17HFFH18HFFH19HFFH
1AHF0H1BHF1H1CHF2H
1DHF8H1EHF9H1FHFAH
20H00H21H01H22H02H
23H08H24H09H25H0AH
(略)
20H70H21H71H22H72H
4DH78H4EH79H4FH7AH
50HFFH51HFFH52HFFH
 これで、ひとまず下準備が終わった。

2017/02/18〜19:キャラクタ表示
 いよいよキャラクタ表示だ。

 ひとまず、キャラクタが完全に画面内に入っている事を前提にした表示処理を作成し、表示座標を変えて、3つほどキャラクタを表示してみる。いざ実行!

画像

 表示位置については特に問題なさげだ。ということで、次はキャラクタの重ね合わせをする。表示するキャラクタと表示先の画面をOR演算して表示する。

 P6のセミグラでは、上位2ビットが色情報だが、これも構わずOR演算する。
 色が異なるキャラクタの場合は多少支障が出る(例えば黄色(01)と青色(10)が重なると赤色(11)になる)が、今回は基本単色表示にする予定なので、さほど問題は出ないだろう。

画像

 これで良し、と。

2017/02/26:画面外
 画面外の消去処理を考える。

 今回は、直接VRAMにキャラクタを書き込んでから、余白部分を消去する方法とする。余白付きの仮想画面に描画して、表示部分のみVRAMに転送する事も少し考えたが、処理速度的には前者が良いような気がする。

 黒枠(点線部分を含む)を表示画面とすると、7x7ドットキャラクタの表示範囲は赤枠の範囲となる。という事で、一通りキャラクタを表示した後、画面外にあたる赤の網掛け部分を消去すれば良い。

画像

 いや、少し正確でないところがある。
 まず、表示画面より左にある赤の網掛け部分は画面右と重なる位置にある。また、表示画面より上の部分はアトリビュートエリアのため、場所に応じたアトリビュート値を描かないといけない。という事で、実際には以下のようなイメージとなる。

画像

 黄部分はセミグラのアトリビュート値(60H)、青部分はテキストのアトリビュート値(20H)、赤部分はスコア等を上書き描画する。ちなみに下の灰色部分は消去しなくても特に表示に影響しないため、そのまま放っておく。

2017/02/26:表示テスト
 F-DOT2のマシン語ソースから、キー入力処理やウェイト処理など使えそうな部分をコピーし、自機を移動できるようにする。

 とりあえずの表示ができたところで、表示速度のテストをしてみる。

画像

 自機+敵32体+画面右表示で14〜15割り込み。25.6fpsに収めるには、1フレームにつき19割り込み以内に収める必要がある。今後、敵の移動や当たり判定など処理を作る事を考えると、かなり心許ない。

 画面外の消去処理で同じ処理を3回繰り返して、ループ回数をケチってみる。これで、およそ1割り込み分だけ減った。

2017/02/27:高速化その1
 キャラクタ表示ルーチンにて、描画元のアドレス移動にはINC HLを使っている。1キャラクタ当たり12バイトなので、キャラクタ番号によっては描画途中で描画元のアドレスが256バイトの境界を超えるため、16ビット演算にしている。

 これはこれで仕方ない...と思い込んではいけない。例えば、キャラクタデータのバイト数が256で割り切れれば、描画途中の描画元アドレス256バイト境界越えは起きないのではないか?

 若干メモリの無駄遣いになるが、ここは速度優先で考えて、1キャラクタ当たり12バイトで済むところをダミーの4バイトを加えて16バイトの構成にする。これで、INC HLがINC Lにでき、1回当たり2ステップの削減になる。
 計算上は、33キャラ表示だと2ステップ×0.5μ秒×11回×33キャラクタ=363μ秒ほど削減できるはず。

 さて結果は...1フレームで13〜14割り込み(13が若干多め)になった。微妙に早くなった感がある。


Making「ActBarrier」 その2