85DATA HOMEへ
MYCAR情報掲示板BLOGプロフィール

HOME → ソフトウェア → X1でゼビウスを作る!

第1回 スクロールとキャラクタ描画について

スクロールとVRAMプレーン


Gプレーンだけをスクロールさせます。しかし、全画面をスクロールさせるのでは無く、上下が異なる箇所だけを描画させる方法としています。(差分描画)

ただし、Gプレーンは、キャラクタの描画としても共用している為、前ループにてキャラクタを描画させた箇所の背景を描画させて(前ループのキャラを消す)必要があります。
なお「どこの箇所が前ループにてキャラクタを描画させたのか(消す箇所なのか)」は8ドット単位(マップチップ単位)で記録しておきます。
その値によってマップチップを描画させます。(「キャラクタの描画」の項にて詳細を書きました)

スクロールの多色化について

上図の通り背景箇所のBプレーンとRプレーンでは以下のパターンです。

スクロールは、Gプレーンのみですが、B・Rのタイリングパターンとの組み合わせにより以下の4色が表現出来ます。
つまり、1プレーンだけのスクロールでも(場所は制限されるが)4色がスクロールして「見える」のです。

【スクロール色の組合せ】

よって、表現出来るタイリングパターンは以下の通り

実際の(概ねの)大きさにしてみると、次の様に見えます。
(もちろん、ご覧になられているディスプレイの大きさや解像度により異なりますが、雰囲気として掴んでもらえれば幸いです)

残念なのは、赤/黒のタイリングパターンが実現出来ない事です。
したがって、本移植作では「空港箇所」の「赤茶色」が再現出来ていません。

スクロールマップの作成

本家のマップ全体画像を62.5%に縮小させ、さらに7色(7パターン化させるため)に減色させます。
本家のマップチップは8×8ドットであり、本移植作においても同様の8×8ドットにします。
単純にリサイズ(縮小)した画像データをマップチップ化すると2000個を超えてしまいました。
(それは、当然ですよね。全体をリサイズしたのならばマップチップも同様にリサイズしなければパターン数が増加するのは当たり前です)

マップチップが8×8ドットに対応するマップ画像に修正します。
なるべくマップチップが重複するようにしてマップチップ数の削減を図りました。

     
@7色へ減色           A1プレーン化(G)                    BB・Rプレーンと合成するとこうなる。

また、スクロール手法は(前述した通り)1プレーンの差分描画方式です。
つまり、上下のマップチップが同一であるほど、描画する箇所が軽減され速度を稼げる事になります。
したがって、処理速度を稼ぐ為に極力上下が同一になるように「森」は全て同一パターンとし「海(湖)や川の点々」は省略「地上絵」は簡略化しています。「所々にある木」も省略しました。

現時点でマップチップ数は225個 (225×8 = 1800Byte)となり、マップチップが縦方向に同一であるか否かの情報もテーブルとして記録してあります。

なお、画像ファイルからのマップチップ化の手法は、以前作ったツールを使用しました。
詳細は「ゼビウスを作る! その1 マップデータ&マップチップの整備」をご参照下さい。

マップデータは、全体マップだけを非圧縮でメモリに格納しています。サイズとしては(1マップチップ=1Byteなので) 横80×縦160 = 12800Byteにもおよびます。

エリア毎に、スクロールさせる横位置を設定しており、その箇所のデータだけを読み込ませ描画させる仕組みです。
電波新聞社ゼビウスではエリア毎にマップデータを読み込む仕様だったのですが、本移植作ではオンメモリとなりました。

 

キャラクタの描画 (ソフトウェアスプライト)

【表現可能な色】

RプレーンとGプレーンをキャラクタの描画として扱います。

蛇足(と云うかX1では常套手段であると思っています)  
VRAMはI/Oポートの入出力により書込・読込を行います。  
  
RプレーンのVRAMは$8000〜  
GプレーンのVRAMは$C000〜
  
  
VRAMへの書込・読込はBCレジスタを使用し、プレーンの移動は加算や減算をせずBレジスタの6ビットをセット、リセットするだけで可能です。  
  
$80 (16進数)= 10000000B (2進数)
$C
0 (16進数)= 11000000B (2進数)

Rプレーン=0にした時に、上述の「スクロール色の組合せ」に加え次の組合せが可能となります。

よって(パレット機能による変更後の)表現可能な色は以下の通りです。
※カッコ()内はカラーコード

黒(0)・赤(2)・水色(5)は、どの箇所でも描画可能
白(7)は、$55AAの箇所だけの描画可能
緑(4)は、$AA55の箇所だけの描画可能

2プレーン描画の場合、普通に考えれば3色しか表現できません(透明色は別として)
しかし、本移植作では(描画箇所の制限が2色ありますが) 2プレーン描画で5色の表現が可能となっています。

【2ドット単位の描画】

このソフトウェアスプライト・ルーチンでは、2ドット単位の描画を可能としています。
2ドット単位の描画だと、動作が速いキャラクタに関しては不自然では無いのですが、動作が遅いキャラクタ(敵弾・トーロイド・ドモグラム)だと、カクカクとした動きになってしまいます。

上述のスクロールの仕組みにより1ドット単位の移動は(色が変化してしまう為)出来ませんので、動きの遅い(敵弾・トーロイド・ドモグラム)は描画データを横に1ドットずらしたパターンを用意し1ドット単位での描画を可能としています。

描画データは、Gプレーンデータ、Rプレーンデータ、マスクデータです。
X座標(必ず2の倍数となっている)により、それぞれのデータを適宜ビットシフトさせます。
詳細は以前書いた「レトロプログラミング  疑似スプライトルーチンの作成」記事を参照下さい。

データの読み込みは「POP」を使用しており Gデータ、Rデータ、マスクデータの順に格納されています。

POP BC
POP DE
POP HL

この様に1ラインのデータを一気にレジスタに読み込ませ、同ループ内にて3つのデータをビットシフトさせています。

※ガルバーラ・ガルデロータ・ソルの大きなキャラクタは20ドット(1ラインで3Byte)である為、POPによるデータ読込はさせていません。また、ビットシフトもさせておらず、配置は8ドット単位にしています。

本移植作では、Gプレーンが背景とキャラクター描画の共用である為に、必ず「重ね合わせ処理」を実行しなければなりません。
速度的にはデメリットも大きいのですが、キャラクタの一部が欠ける事はありません。

【描画したキャラクタを消去する】

描画したキャラクタは、次のループで消さなければなりません。消すと言うよりもスクロール背景を、その箇所に上書きさせるという表現が適切だと思います。
(Gプレーンについては背景描画を行いますが、同じ座標のRプレーンは$FFを書き込みます)

蛇足
本移殖作は、320×200ドット 2画面を使用しています。
表示されていない画面に描画を行い、全ての描画が完了したら表示させるようにしています。以下の様な流れです。

@画面1を表示画面とする
A画面2に描画(画面2は非表示状態)
B画面2を表示画面とする。
C画面1に描画(画面1は非表示状態)
D@に戻る。

この方法により(描画中が見えない為)画面がチラつく事はありません。

したがって、この項で言う「前ループ」とは正確には「2ループ前」を指しているのです
(が、話がややこしくなるので読み飛ばして下さい)

前項で「どこの箇所が前ループにてキャラクタを描画させたのか(消す箇所なのか)は8ドット単位(マップチップ単位)で記録」と書きました。
しかし、キャラクタ描画は2ドット単位なので、マップチップ全て(8ドット)を背景で上書きしてしまうと無駄(消さなくても良い箇所まで描画する事)が発生してしまいます。
さらに、移動しない地上物に関しては全部を消す必要はなく、上部4ドットだけを消せばよいのです。(その区別をしています)

ソフトウェアスプライト・ルーチンをコールした時に、以下の(消す箇所の)記録を8ドット単位で行います。
(仮想テキストRAMを準備しておいて、そこに値を記録する・・と言った方が分かり易い・・・いや分かりづらいかな?)

・マップチップ上部4ドットを描画の場合、値1でORする
・マップチップ下部4ドットを描画の場合、値2でORする
・マップチップ全部8ドットを描画の場合、値3でORする

そして、描画するキュラクタの数だけ、ソフトウェアスプライト・ルーチンをコールします。
その消す情報(値)を基に、スクロール・ルーチンにて背景を描画します。それにより前ループで描かれたキャラクタが消去される事になるのです。

スクロール・ルーチンでは「マップチップ自体が縦方向に同一では無い」or 「マップデータが上下が異なる」or 「前ループでキャラクタが描画された」箇所をマップチップ描画します。

ただし、アンドアジェネシス登場時は例外です。

アンドアジェネシスはかなり大きなキャラクタです。上述のスプライトルーチンは使用しておらず、専用の描画ルーチンを作りました。
描画の順序として「スクロール背景」→「アンドアジェネシス」→[キャラクタ(地上物・空中物・敵弾)」です。
アンドアジェネシスの下の背景を描画する必要はありません。また、アンドアジェネシスの上に描画されたキャラクタも消す必要はありません。
なぜなら、アンドアジェネシスで上書きされるからです。
アンドアジェネシス描画箇所の背景が透過されない箇所(かなり大きな面積)は、以下の値を記録します。

・マップチップ全部8ドットを描画しない場合とし、値4でORする ※下の赤線内

よって値4でORされた値 (4,5,6,7) 箇所はスクロールルーチンにより背景を描画させない事にするのです。

 

なぜ、PCGを活用しないのか?(まとめ・・のようなモノ)

PCGを有効活用しているスクロール手法と云えば、リボルティ2です。
「リボルティー2のスクロール技術」は、割と最近(と云っても、ここ1〜2年前くらい)知りました。
 
http://copin.sakura.ne.jp/fuga/tech/revolty/revolty.html
 
要約すれば
 
・PCGにカラーパターン(タイリング)をセットし、画面に敷き詰める。
・VRAM  1プレーンを、PCGのマスクとして(差分)スクロールさせる。
 
(※以降「リボルティ2手法」と書く)
 
素晴らしい手法であり、私が考えたスクロール手法 (以降「トモカズ手法」と書く)よりも優れていると思います。
 
X1 Centerの管理人さんからも「フルカラー高速スクロールならリボルティー2の解説も参考になる」という提案も頂きました。
 
それを、知ってからも、X1でゼビウスを作ろうとした時に、「リボルティ2手法」を使用せずに作ったのはなぜか???

【リボルティ2手法】
 
背景がフルカラー(といってもタイリングですが)が使える。
・背景とキャラ描画のVRAMが独立出来るので、重ね合わせ処理が軽減出来る。
・しかし、320×200では背景マスクの隙間が大きすぎる
  →この案は640×200で使うのが望ましい気がする。
・640×200ならば綺麗に出来るが、キャラの描画コストと容量が多くかかってしまう。
2プレーンがキャラ描画なので3色対応(透明色を除く)だが、ゼビウスだと白・黒・赤・透明色の選択が最善だと思う。
   →この色パターンだと、X1ゼビウスらしくない。(水色を含めたかった)
 
【トモカズ手法】
 
背景の色数が4色(しかも、その配置に制約がある)見た目はかなりショボイ画面となる。
・背景のタイリングは市松模様に出来る(リボルティ2手法だと隙間が大きい)
キャラ描画は5色対応 白(場所限定)水色・緑(場所限定)・赤・黒・透明でも描画が可能となる。
  →X1ゼビウスらしく出来る
重ね合わせ処理を必ずしなければならない

では、共に320×200で作成した場合に、どんなイメージになるのでしょう?
 
リボルティ2手法  → 3色(白・黒・赤)
トモカズ手法       → 4色(白・水色・赤・黒)
 

やはり、リボルティ2手法は、320×200では、厳しい気がします。
(もちろん、ドット絵を描くセンスにもよると思いますが・・・)
よって、(リボルティ2手法は640×200である事を前提として比較し)今回は背景の見た目を犠牲にしてでもスピード重視で作る方針にしてみました。
 
しかし、色々と書きましたが、一番の(手法決定の)決め手は・・・・

「リボルティ2手法は自分が考えたモノでは無い!」という事が一番の要因です。
(今後、リボルティースクロール案でも作ってみたい気がしますけどね)
 
トモカズ手法においては、キャラの描画の殆どが、グラフィック描画になってしまい、且つ、全てにおいて重ね合わせ処理をしなければなりません。
 
ゼビウスモドキのゲームを作るのであれば、スクロール背景と地上物はグラフィックにして、空中物はPCGにすると、(見た目も)処理速度においても有利だとは思います。
(30年前は、ゼビウスモドキのゲームを作ったので、それで作りました)
 
ゼビウスの場合は、PCGによる8ドット(キャラ)単位の動きでは、とても再現出来そうにないのです。

どこまで、描画ルーチンを最適化(高速化)出来るのかは分かりませんが、それにチャレンジするのも、面白いと思っています。
 
これは、私のプログラミング能力が低いが故(そしてZ80の事を忘れてしまっているが故)に、アレコレと試行錯誤するのも楽しみのひとつなのです。