PC-8001mk2版のXeGraderをリリースして10日が経過しました。リリース直後はバグ修正に追われましたが、現在は無事落ち着いたようで特にバグの報告もなく、元気に皆さんの環境で動作しているようです。皆様からの評価としてはだいたい2つで「面白い」「速い」となっていて、ゲーム制作者としては大変嬉しく思っています。

さて、この評価のうち「速い」に関しては、今回特に意識したプログラム部分を簡単に説明していきたいと思いました。XeGrader for PC-8001mk2 は現在も配布中ですが、残念な事に実機でしか動作しなくなっております。現在追加開発中の PC-6001mk2 版では、フリーのエミュ環境で動作させる予定ですので、実機の 80mk2を持っていない方は 60mk2版の完成をお待ちください。
では、高速化の解説始めます。実はやった事は単純かつ明快にして簡単なんです。それは、いつも結果が同じになる判定をしないという事だけなんです。こんなの当たり前でしょと思われるかもですが、案外皆さん同じ結果となる判定を何度も何度も行っていたりするのです。本物のプログラムだと説明しにくいので、例として簡素化したプログラムで説明します。
call SHOT.MoveNormal ; 通常弾の移動 ld a, (WRK.PL.Status) and FLAG.SHOT_PLUS ; 貫通弾を持っていれば call nz, SHOT.MovePlus ; 貫通弾の移動 ld a, (WRK.PL.Status) and FLAG.SHOT_DOUBLE ; ダブルを持っていれば call nz, SHOT.MoveDouble ; ダブルの移動 ld a, (WRK.PL.Status) and FLAG.SHOT_EXTEND ; 拡散弾を持っていれば call nz, SHOT.MoveExtend ; 拡散弾の移動 ld a, (WRK.PL.Status) and FLAG.SHOT_SIDE ; 側方弾を持っていれば call nz, SHOT.MoveSide ; 側方弾の移動 ret
自分の攻撃弾の移動処理の一部を概念的に記述してみました。ゲーム中、アイテムを拾う事でプレイヤーは様々なパワーアップをしていきます。そのショットを持っているかどうかはワークエリアに保持されていて、それぞれ 1bit のフラグで 1 なら所持しているとしています。一見すると普通の処理です。
ですが、待って欲しい。この攻撃タイプってそんなに頻繁に変わる事でしょうか。そりゃアイテム拾えば変わります。1 miss しても変わります。でも、ゲーム進行中は変わらないですよね。なので、通常は決め打ちしてしまうんです。こんな風に…
call SHOT.MoveNormal ; 通常弾の移動 call SHOT.MovePlus ; 貫通弾の移動 call SHOT.MoveDouble ; ダブルの移動 call SHOT.MoveExtend ; 拡散弾の移動 jp SHOT.MoveSide ; 側方弾の移動
BIALETTI(ビアレッティ)
※ コーヒーでほんのちょっとだけプチ贅沢してみませんか。インスタントコーヒーではなく粉末コーヒーから抽出した味わい深いコーヒーが、自宅で手軽の飲めるようになります。
※ コーヒーでほんのちょっとだけプチ贅沢してみませんか。インスタントコーヒーではなく粉末コーヒーから抽出した味わい深いコーヒーが、自宅で手軽の飲めるようになります。
いやいやいやいやちょっと待って、これじゃアイテムの所持とか関係なく呼び出してるやん…。そう、だってゲーム進行中は判定しないですからね。では、どうするかというと、ステージ開始直前とアイテムを拾った時だけ、プログラムの流れを書き換えてしまうのです。その前にちょっとだけ細工します。
patch0: call SHOT.MoveNormal ; 通常弾の移動 patch1: call SHOT.MovePlus ; 貫通弾の移動 patch2: call SHOT.MoveDouble ; ダブルの移動 patch3: call SHOT.MoveExtend ; 拡散弾の移動 patch4: jp SHOT.MoveSide ; 側方弾の移動
わはは、なんとなく見えてきましたかね😁 そして、ステージ開始直前やアイテム取得時に、以下のサブルーチンを呼び出します。
SetShot: ld a, (WRK.PL.Status) ld c, a call .chk ld (patch0), a call .chk ld (patch1), a call .chk ld (patch2), a call .chk ld (patch3), a rr c jr c, .@@F ld a, $C9 ; RET db $21 ; LD HL,nn 2byte jump .@@ ld a, $C3 ; JP xx ld (patch4), a ret .chk rr c ld a, $CD ; CALL xx ret c ld a, $21 ; LD HL,nn ret
そう、自己書き換えなんです。そのため、このテクニックはプログラムがRAMにある事が大前提です。そして、Z80 のように、先読みキャッシュとかがない CPU だけのワザです。最初にこのようにプログラムを改変することで、ゲーム内では極力条件判定を行わないようにしています。例えば貫通弾と拡散弾だけ持っているのであれば、実行中は
patch0: call SHOT.MoveNormal ; 通常弾の移動 patch1: call SHOT.MovePlus ; 貫通弾の移動 patch2: ld hl, SHOT.MoveDouble patch3: call SHOT.MoveExtend ; 拡散弾の移動 patch4: ret dw SHOT.MoveSide
こんな感じにプログラムが書き換わっている状態になります。今回、プログラム書き換えしている箇所は 100 を軽く超えています。それだけの数の条件判定式を消しているので速いのだと思います。なお、このワザ、ROM版でもやろうと思ったら出来ます。それは、RAMエリアにプログラムの呼び出しを構築して、メインからはRAMエリアを呼び出すようにするのです。現在制作中の 60mk2版は、戦士Ⅱカートリッジ供給予定ですが、ROM にあるプログラムを RAM にコピーしてから動作させてます。
以上、参考になれば幸いです。
※ふわっふわなミルクの泡を手軽に作るのならこれ。喫茶店とかでよく出るふわふわの泡が自宅で再現できます。


コメント