【MSX】シューティングゲーム制作⑤
また前回から間を置いてしまった。
年度末・年度初めでしばらく開発をすることができなかったのだが、その間に腰が重くなってしまった、というのが理由だ。
しかし、連休で時間もできたので、そろそろ再開することにした。
久しぶりにソースを開いたところ、処理が入り組んでおり、自分でもどこで何をしているのかわからなくなっていた。
関数呼出しのオーバーヘッドを軽減するため、1つの関数内でプレイヤーや敵、敵弾などの処理を処理分岐で書いていたわけなのだが、逆に開発効率が落ちると感じた。
そこで、各処理を関数に切り出し、ついでにソースを分割した。
結果、見通しが良くなり、機能追加や修正がしやすくなった。
もっと早くこうしていれば良かった。
コンパイルして実行したところ、元の状態と比べても処理速度には影響が無さそうで、一安心である。
ソースを分割する際につまづいたのは、ヘッダファイルの定義内容だ。
今まで曖昧にしていたのだが、この機会に調べ直し、基本的には以下のものを定義すると理解した。
- 関数のプロトタイプ宣言
- 構造体、列挙型、定数の定義
- 他ファイルに公開する変数・配列
なお、処理速度の問題はあるが、処理構造が理解しやすく効率も良いため、開発はこのままC言語で進めようと思う。
速度が必要なところは適宜アセンブラで書いていく方針とする。
さて、ソース分割して手を加えやすくなったので、前回追加したバリアの発生中に敵弾が当たると、敵弾を反射する処理を追加してみた。
プログラム的には、敵弾接触判定時にプレイヤーの状態を見て、バリア発生中なら接触した敵弾の属性と方向を変える、というものだ。
反射した弾(リフレクト弾)は敵にダメージを与えることができるよう、プレイヤーのショットと同様の処理を実装している。
スプライトのチラツキで見にくいかもしれないが、うまく行った。
バリア発生時間など、微調整は必要だが、基本的なシステムとしてはこれで行くことにする。
【MSX】シューティングゲーム制作④
さて、前回の更新から少し間が空いてしまったが、引き続き制作を続けていく。
今回は、自機周りについて、新しい操作を追加しようと思う。
とは言え、非力なZ80で、しかも主にC言語で書いている以上、あまり複雑で派手なものは追加できないので、簡単でゲームプレイにも効果的なものを考えた。
短いフレーム内で左右方向を交互に入力することで、一定時間自機が回転し、バリアを張る、というものだ。
適当に操作していても発生することがあるので、シューティングゲームに不慣れな初心者の救済措置という意味でも有効ではないか、と思っている。
以下、MSXPenで書いたBASICでのサンプルプログラムである。
プログラム的には、なるべく処理を簡単にするため、左右の入力状態をビット値で持たせて判定している。
簡単に説明すると、右=&B01、左=&B10として入力時にOR計算し、左右を入力すると&B11となって回転が発動する、というものだ。
斜め方向の入力でも有効になるように、配列変数Cで左右入力時の値を定義した。
入力後に次の入力までの有効時間を変数CTで持ち、カウンタがゼロになったり、上下など無効な入力があったら、左右の入力状態をリセットしている。
この有効時間は、サンプルでは初期値を2としているが、減らすと発動が難しくなり、増やすと発動しやすくなる。
ゲームのシステムとしては、バリア発生中は移動や攻撃はできず、守りに徹することにする。
この間、敵との接触や通常の敵弾は無効(敵弾は跳ね返しても面白い)だが、敵のレーザーは被弾するとして、リスクもある状態としたい。
また、連発できたり、あまり長い時間バリアが発生していると、それだけで進めることができてしまうので、実際には一定時間経過が必要など、何かしら制約は必要かもしれない。
この辺りは、実際にゲームに組み込んで、現物合わせで調整していこうと思う。
これをCで実装して、通り動作を確認したものが、以下の動画となる。
Cでいきなり作り始めるとデバッグが難しいが、BASICで作る時からCの実装を意識すると、比較的容易に動作するロジックを落とし込めるので、自分はこのような手法で開発を進めている。
チラつきが酷いが、現状はあえてチラつく量のキャラクターを出しているためで、最終的には調整していく。
ちなみに、今回一番時間がかかったのは、自機が回転しているように見せるパターンの追加だった。
表示上は16x16ドットサイズだが、倍角スプライトのため8x8ドットで表現しなければならず、なかなかうまく描くことができなかったのだ。
一先ずはそれっぽく見えるし、左右移動時も傾けることができるようになったので、これで良しとする。
【MSX】シューティングゲーム制作③
ここ1週間ほど、風邪をひいて体調を崩していたため、目立った進捗は無いわけだが、それでも少しづつ進めている。
今回は、自機の弾で敵を倒せるようにした。
敵も自機の弾も、画面上の数が常に変動するが、なかなか効率の良い処理が思いつかなかったので、愚直に敵の処理の中でループを組み、プレイヤー弾に対して当たり判定を行った。
敵がプレイヤー弾と接触したと判定された場合、敵のオブジェクトをそのまま爆風の属性に変更して、残りの生存時間とスプライトパターン番号を設定する。
爆風の処理の中では、生存時間がゼロになったらキャラクターを消去し、ゼロでなかったらスプライトパターン番号を切り替えてアニメーションさせるようにしている。
また、ゲームのメインシーン以外ではスクロール処理をしないようにし、タイトル画面などを表示できるようにもした。
ちなみに、キャラクターが2~3個出てくるとスクロールのスピードが少し落ちるのが分かると思う。
これは明らかに処理落ちで、高速化が必要になってきているのだが、これがなかなか悩ましい。
キャラクターの属性は構造体で定義しており、恐らくこの構造体へのアクセスに結構なコストがかかっていると考えているが、実際のアセンブリコードの検証まではできていない。
また、ではどのようなデータ構造なら性能が上がるのか?の答えに辿り着いていないので、最悪は主要部分をアセンブリで書くことになるかもしれない。
【MSX】シューティングゲーム制作②
今回は、敵周りの処理を追加した。
敵の出現方法には、ランダムとパターンの2種類あるが、今回はパターンを定義して出現させるようにしてみた。
そのパターンデータは、上記の動画では以下のように定義している。
// ステージシーケンステーブル uint8_t stageSeqTbl[] = {'n', 20, 'e', 1, 'n', 20, 'e', 1, 'e', 1, 'n', 20, 'e', 1, 'e', 1, 'n', 20, 'e', 1, 'e', 1, 'e', 1, 'n', 20, 'e', 1, 'e', 1, 'e', 1, 'n', 20, 'e', 1, 'e', 1, 'n', 40, 0xff};
'n'はなにもしない(ブランク)コマンドで、続く数字はブランクを継続するフレーム数となる。
'e'は敵発生のコマンドで、続く数字は敵の種類を意味する。
0xffは終了マークで、テーブルの先頭に戻すようにしている。
こうすることで常に一定のパターンで敵が出現し、他のコマンドを追加することで、何らかのイベント(例えばボス前のワーニング表示など)を発生させることもできる。
また、複数のテーブルを用意することで、ランクによる切替も容易だろう(データを用意するのが大変だが)。
出現位置や移動スピードなどは、敵の種類を判断してロジックで制御する方針とした(今回はすべて出現X座標はランダム、移動速度は固定)。
ちなみに、画面に表示するオブジェクトは、要素数32のオブジェクトテーブルで管理している。
このテーブルにはどういうキャラクターなのかを判断するためのラベルが定義されており、未登録の時は「登録なし」のラベルを付けている。
ゲームのメイン処理ではこのテーブル全体に対してループし、このラベルにより処理を振り分けるようにした。
新しくキャラクターを出現させる場合、例えばプレイヤーが弾を撃つ場合は、プレイヤー処理の中でトリガボタンONの時に「弾発生フラグ」をtrueにする。
その後、「登録なし」のテーブルの処理で「弾発生フラグ」を判定し、trueなら弾を生成して登録する。
次のループからは、オブジェクトテーブルに登録されているプレイヤーの弾の処理によって移動していく、という形だ。
こうすることで、オブジェクト生成時にわざわざオブジェクトテーブルを走査することなく登録でき、最大数を超えないようにも制御できるのだ。
ただ、ここで問題になるのは当たり判定で、敵や敵弾とプレイヤーであれば、n:1の判定なので問題ないのだが、敵とプレイヤーの弾の場合はn:nの判定となり、その時にオブジェクトテーブルのどれが敵でどれがプレイヤーの弾なのか、インデックスが不定のため全量走査しないとならなくなるが、それではあまりにも非効率だ。
まだ具体的な案が浮かばないでいるのだが、良い案が浮かんだら、当たり判定を実装してみようと思う。
【MSX】シューティングゲーム制作①
タイトルに①と付けているが、果たして完成まで続くのか・・・はさておき。
一先ず、ベースとしてのプログラムを作成した。
今回入れた要素は以下。
- タイルパターンとスプライトキャラクターの定義(仮デザイン)
- サウンドドライバ組み込み
- 画面スクロール
- プレイヤーキャラクターの移動、ショット発射
また、今は未使用だが、以下の処理も入っている。
- 16方向移動テーブル
- 2オブジェクト間の角度検出
- BCD値加算・表示処理
なお、今回は1/60で全ての処理を行うのは厳しいため、H.TIMI割り込みの処理はスクロールの処理と他の処理を交互に行っている。(サウンドドライバは毎フレーム実行)
メインルーチンは1/30で回すようにしたので、処理に多少余裕ができたと思う。
また、スプライトは16x16ドットの倍角表示モードを採用した。
通常のキャラクターは8x8ドットでデザインし、ボスは16x16ドットでデザインすることで、大型のキャラクターの表現も低負荷でできるようにしている。
ちなみに、z88dkのライブラリにはスプライトの倍角モードに変更するための関数が見当たらなかったため、自分でVDPを操作して設定した。
; スプライトモード設定 ld a, (MSX_IO_OUT) ; I/O out address (port #0) inc a ld c, a ; set port #1 ; write data ld hl, MSX_RG1SAV ld a, (hl) or 0b00000001 ; MAG=1(double size) out (c), a nop nop ; write register number ld a, 0b10000001 ; mode register(=control register) #1 out (c), a
次は敵キャラクターを登場させ、当たり判定を行う予定。
敵の出現パターンデータをどう持つか、はまだ未検討である。
【MSX】シューティングゲーム制作開始
ボチボチ再開しますと言っておいて、またしばらく放置してしまった。
ここ最近は、MSXでシューティングゲームを作り始めた。
技術検証として進めていた
- 16方向の移動データ
- 2オブジェクト間の角度算出
- 低負荷逆スクロール処理
- スプライトローテーションによるチラツキ表示
- マップパターンの組み合わせによる長いマップの表示
に目途が立ち、なんとなく形になりそうになってきたので、思い切って1つ作ってみることにしたのである。
今更シューティングゲームというのは自分の中でもあって、MSXでも市販・同人含めて素晴らしいものが多く、これまで意識的に避けていた。
しかし、昔、子供の頃にMZ-80K2を使っていたときに、BASICしか使えずに満足いくシューティングゲームが出来なかったのが悔いとして残っていて、今回はそのリベンジの意味も込めている。
タイトルは、MZで作っていたものと同じものに決めている。
ターゲットはMSX1でz88dkのC言語を使うので、現代のシューティングゲームにある高速スクロールや弾幕、巨大なボスといった要素は期待できない。 速度に満足行かない場合はアセンブリに移行する可能性もあるが、どれくらいものができるか、挑戦してみるつもりだ。
Vivliostyleはじめました
特に今すぐ何か書いて出す、というわけでは無いのだが、以前から電子書籍を自分で作ってみたい、という願望はあった。
以前からJoplinを使用しており、断片的なメモなどはここに全て集めているのだが、単一のノートからPDFファイルの生成はできても、表紙やレイアウトなど本としての体裁までは整えられなかった。
Joplinではマークダウン形式で書いているので、マークダウンから手軽に本としてのPDF(可能ならEPUBも)を作成できないものか、と探していたところ、Vivliostyleというものを見つけた。
オープンソースでnode.jsが動けばどのOSでも使用でき、HTMLで書いた原稿から電子出版・Web出版を可能にするもので、原稿はマークダウン形式のファイルもサポートしている。
組版はCSSで行うため、Webページと同じ感覚で紙面の編集ができる、というものだ。
早速試してみようと、まずはWSL2上でnode.jsのインストールを行い、Vivliostylleをインストールしてみたが、いかんせん公式パッケージで入れたnode.jsがバージョンが古く、失敗してしまった。
node.jsのインストール方法はこれといった標準は無さそうだったが、今後の利用も考慮してnvmをインストールした上でLatest版のnode.jsとnpmを入れ、ようやくVivliostyleが動作するようになった。
node.jsのインストールについては、以下にまとめたのでそちらを参照。 https://aburi6800.github.io/documents/linux/2025-11-01-linux-install-nodejs.html
動作後に公式サイトのチュートリアルを進めていたが、少し古いバージョンを対象に書かれたものなのか、ファイル構成が若干異なっており、そのままでは思うように進められなかった点があった。
それでも断片的な情報を集めつつ手探りで色々と試し、ようやくローカルフォントの指定や体裁の変更ができるようになってきたところである。
こうなってくると、なかなか面白い。

とりあえず、マイコンBASICマガジンの特選プログラムコーナーのようなレイアウトで、自作ゲームのドキュメント作成をゴールに、当面は色々と試してみたいと思う。