2024年03月21日
【ツール制作】MMLコンパイラ(通常版) 第1回
MMLコンパイラ(通常版) 第1回です。
「ゲーム制作」カテゴリで、2作品作成してきましたが、意外と時間かかっているのが「BGM」の作曲。
電子ピアノで作曲し、MMLに起こし「簡易MMLコンパイラ Ver.2.0」に登録してコンパイルしているのですが、
・3チャンネル纏めてコンパイルできない。(チャンネル毎に登録してコンパイルしなければいけない。)
・BGMの確認がリアルタイムにできない。(コンパイルしたデータをゲームに登録しないと演奏できないため、ちゃんとコンパイルできたかの確認に手間がかかる。)
など、かなり不便です。
このツールを使って3〜4曲も作曲するとなると、そりゃ時間かかるわ…。
…と、言う事で、「MMLコンパイラ(通常版) Ver.1.0」を制作します。
簡易版に比べ強化される機能は、
・3チャンネル纏めてコンパイル可能。
・テンポ「T」の指定が可能。
・コンパイルし終わると、演奏が開始。
・付点「.」が最大2つから最大4つに増加。
・ボリューム「V」の指定が可能。(併せて「)」、「(」でボリューム増減。)
・エンベロープ波形「S」、周期「M」の指定が可能。
・ノイズ周波数「Z」の指定が可能。
など、大幅な機能アップです。
「通常版」なので、せめてMSX標準MMLくらいはサポートしなきゃと言う事で、この機能に決めました。(「N」コマンドは過去に使ったことがないので不要と考え不採用。)
ただ、やはりコンパイラ部がBASICなので遅いと思われます。
「高機能版」を制作することがあるなら、「MuSICA」のようにエディタ部を用意し、コンパイラもマシン語で制作し、コンパイルから演奏まで高速処理できるようにしたいですね。
では、制作に取り掛かっていきます。
2024年03月20日
次回作選考
さて、そろそろ次回作について考えたいと思います。
「ロールプレイングゲーム」、「アドベンチャーゲーム」と、比較的腰据えてやるタイプのゲームが続きました。
一度、「暇つぶしにちょっとやってみようか」と思えるゲームを作りたいなと思いました。
と、なると「面クリア型のアクションゲーム」が一番近いのかな?
まぁ、簡単な「パズルゲーム」でもいいけど、「パズルゲーム」を手軽にプレイするっていう感覚が私にはない。
さて、「面クリア型のアクションゲーム」や「パズルゲーム」の制作をする時に一番悩むもの。
それは、「ゲームシステム」です。
「ロールプレイングゲーム」や「アドベンチャーゲーム」はプログラミングレベルとしては高いのですが、ゲームシステムとしては過去に「ほぼ完成形」となる作品がでており、ほぼ確立したものが存在します。
ストーリーに重きが置かれ、ゲームシステムがほぼ同じでも、別のゲームと認識されています。
私も「ゲームシステム」は既存のものを踏襲したので一切悩まずに、ストーリーやプログラミングに集中出来ました。
しかし、「面クリア型のアクションゲーム」や「パズルゲーム」は、「ゲームシステム」がそのゲームそのものであり、唯一無二のシステムとなります。
言い換えれば、ゲームシステムに重きが置かれ、キャラクタやストーリーを変えても、そのゲームシステムを使うと、「xxxの真似じゃん」となります。
「パックマン」や「マッピー」、「ディグダグ」などのアクションゲーム、「倉庫番」、「ロードランナー」などのパズルゲームを見れば分かりますが、そのゲーム独自のシステムで、逆にシステムを見ればゲームタイトルが思い出されます。
しかしいかんせん、既に無数の「面クリア型のアクションゲーム」や「パズルゲーム」が制作公開されており、今から全く新しいゲームシステムを作り出せと言うのは困難です。
と、なるとやはり既存のシステムをどうしても真似る形となるのは仕方ないのかな…。
最近「面クリア型のアクションゲーム」が出なくなったのも、こういったことが背景にあるのかも。(著作権など。)
まぁ、もうちょっと考えてみます。
2024年03月19日
過去製作ゲーム公開について
さて、私の過去製作作品の公開について「MuSICA」を利用している事で難しくなりました。(2024年03月02日記事参照「「MuSICA」の著作権」)
まさしく、次作の「TETRIS-SPECIAL」から「MuSICA」を利用しています。
公開を止めようかとも思いましたが、公開予定の作品がまだ9作品も残っている…。(2024年01月26日記事参照「公開状況」)
問題は「MuSICA」だけなので、BGMさえ何とかすれば解決します。
そこで、取れる対策としては、
@ BGMなし版を公開する
A 「MuSICA」に代わるツールと差し替える
B 自作「BGM演奏ルーチン」と差し替える
以上の3点くらいでしょうか…。
@は、論外。
Aは、良いツールが揃っていますが、やはりハンドアセンブルな私としては、ゲームプログラムのアドレスに影響のある選択はしたくない。(と、言うか「.BIN」のソースがないので、改変は不可能。)
それにやはり高機能すぎて容量が大きい。(これは「MuSICA」も同じでしたが…。)
となると、残るはBになります。
まぁ、今ちょうど「ゲーム制作」一息ついているところなので、いいタイミングではあります。
それに、ゲームに利用したBGMの元MMLは、「MuSICA」ディスクに残っているので、FM音源複数音の中から2音選択する形で流用できます。
…と、言う訳で自作の「BGM演奏ルーチン」に差し替える事にします。
ただ、現状の「簡易MMLコンパイラ」と「BGM演奏ルーチン」では、生産性が非常に悪い…。
せめて、MSX標準MMLは全て使えるようにしたいのと、コンパイルを1チャンネル毎ではなく全チャンネル纏めてコンパイルでき、そのBGMをすぐに確認できるようにしたいですね。
そこで「簡易MMLコンパイラ」と「BGM演奏ルーチン」のバージョンアップに取り掛かります。
これで「簡易版」から「通常版」となります。
この制作は、「ゲーム制作」カテゴリの一つとして扱う事にします。(ツールとして扱うので、新作連番は無し。)
因みに高機能版は、「MuSICA」のようにエディタ画面付きで「@」コマンドで各チャンネル毎にエンベロープ周期が設定でき音色の制作ができました。
ただ、この高機能版、制作した記憶と実際使って作ったBGMは残っているのですが、プログラム本体(フロッピーディスク1枚だった…。)が見付かりませんでした。(2023年03月24日記事参照「ディスクの中が見れた…」)
こちらもいずれ再制作したいですね。
2024年03月18日
Laboratoryテーマ8「32枚を超えてSPRITEを表示させたい(非走査線割込)」
Laboratoryテーマ8「32枚を超えてSPRITEを表示させたい(非走査線割込)」です。
MSX1のSPRITEは非常に便利ですが、32枚までしか使えません。
ゲームによっては32枚じゃ足らない事もしばしば…。
そこで32枚を超えて表示させる方法を検討します。
実は技術的には走査線割込みを使って表示させることは可能です。
HRAさんが公開されてますので、ご覧ください。
私の方法は走査線割込みは使いません。(結果的には使いますが…。)
横スクロール系のゲームを作るなら必須となる前回のテーマ、Laboratoryテーマ7「水平ライン4枚(MSX2は8枚)を超えてSPRITEを表示させたい」。
その拡張で可能です。
組み込む必要のあるロジックを、少しの拡張するだけで32枚を超えて表示させる機能が追加できるので、メモリ的なメリットも大きいと思います。
要は簡単。
仮想スプライトアトリビュートテーブルを64キャラクタ分用意します。(&HC900~&HC9FF)
シャッフルする際は前回同様、32/64キャラクタ分シャッフルし表示します。
あとは素数を加算し、32以上になったら32引いていたところを、64以上になったら64引くに変更するだけです。
そう、この表示される32キャラクタは64キャラクタの中から素数入替法によって選ばれますので、何回かの表示の間に必ず64キャラクタ全て表示されます。
結果はこちら。
点滅していて見辛いですが、64キャラクタ表示されています。(横16キャラクタ×縦4キャラ=64キャラクタ)
キャラクタ表示数をカウントし、32キャラを超えたらこちらのロジックに切り替えるだけで済みます。
(切り替えないと32キャラクタ以下でも点滅してしまいます。)
走査線割込みが技術的に難しいと言う方はどうぞ。
サンプルプログラムです。
「OVER32.BAS」【ダウンロード】
BASIC部です。
2024年03月17日
Laboratoryテーマ7「水平ライン4枚(MSX2は8枚)を超えてSPRITEを表示させたい」そのB
Laboratoryテーマ7「水平ライン4枚(MSX2は8枚)を超えてSPRITEを表示させたい」そのBです。
前回、実際に点滅する仕組みを作りましたが、ゴミが表示されるため、その解消法を検討します。
これも例えば、表スプライトアトリビュートテーブル(&H1B00)表示中に、裏スプライトアトリビュートテーブル(&H1C00)を書き換え、裏の書換えが終わったところで、表裏のスプライトアトリビュートテーブルのアドレスを書き換える(ページングと呼ばれる手法。)など、いくつかの方法があります。
しかし、シャッフルしながらVRAMへ転送をかけていると、タイミング取りの「NOP」の余り時間が無駄になり積み重なるとそれなりの無駄時間になります。
そこで、私のやり方は仮想スプライトアトリビュートテーブル(&HC900)とは別に、シャッフル用の仮想スプライトアトリビュートテーブル(&HC980)をもう一個用意します。
仮想スプライトアトリビュートテーブルからシャッフル用仮想スプライトアトリビュートテーブルに、メモリ上でシャッフル処理を行い、シャッフルした結果をニーモニックでいうところの「OTIR」命令(連続転送)でVRAM上のスプライトアトリビュートテーブルに一括転送します。
VRAMを扱うのはこの一括転送時のみ、シャッフル処理もメモリ間で行うため、早いです。
ただ、128バイト余分にメモリを消費します。
メモリに余裕があるゲームを作るならこちらがお奨めです。
メモリがない時は、上記ページングでやるしかないかな?
これで綺麗に表示されるようになりました。
このロジックを走査線割込みの中に組み込めば、普通にゲームを作るだけでSPRITEが水平方向に5枚以上並べば勝手に点滅してくれます。
1/60毎に毎回128バイトVRAMへ転送しているとは思えない速度ですよね。
走査線割り込みを使用したサンプルプログラムです。
「SPRITE.BAS」【ダウンロード】
戦闘機を動かす部分、スペースバーで全機止まります。
BASIC部です。
これで、横スクロールアクションも作れるようになりました。
2024年03月16日
Laboratoryテーマ7「水平ライン4枚(MSX2は8枚)を超えてSPRITEを表示させたい」そのA
Laboratoryテーマ7「水平ライン4枚(MSX2は8枚)を超えてSPRITEを表示させたい」そのAです。
前回、素数入替法の説明をしましたので、具体的にプログラムを組んでいきます。
このSPRITE面の入替は常時行っています。
よって、処理が早くないとゲーム全体の速度に影響します。
そこで、処理の遅い「BIOS」は使いません。
ニーモニックでいうところの「OUT」命令などを使います。
HRAさんのページに「スプライトが5枚以上並んだときに点滅表示で擬似的に5枚以上見えるようにする方法」の具体的なロジックの説明がありましたので(流石です。)、それを基に組んでみました。
まず、メモリ上に仮想スプライトアトリビュートテーブルを用意します。
この仮想スプライトアトリビュートテーブルから素数入替法に則り、VRAM上のスプライトアトリビュートテーブルへ1面につき4バイトずつシャッフルしながら32面分転送していきます。
こちらがその結果。
点滅はしていますが、それ以外のところにもなんだかゴミみたいなものが表示されてる…。
これはVDPの表示期間中にVRAM上のスプライトアトリビュートテーブルを書き換えると、意図しない中途半端な状態で表示が実行されてしまうためです。
では、次回は解消方法を検討します。
2024年03月15日
Laboratoryテーマ7「水平ライン4枚(MSX2は8枚)を超えてSPRITEを表示させたい」その@
「3Dダンジョンロールプレイングゲーム」完成後に、Laboratoryテーマ7「水平ライン4枚(MSX2は8枚)を超えてSPRITEを表示させたい」をする予定だったのですが、余りにも時間空け過ぎてすっかり忘れてました。
Laboratoryテーマ7「水平ライン4枚(MSX2は8枚)を超えてSPRITEを表示させたい」です。
MSX1で横スクロールのシューティングゲームやアクションゲームを作る際には、必須の機能です。
MSX1のSPRITE機能は非常に便利ですが、1枚につき1色であったり、水平方向に4枚までしか表示できないなど、制約が多いです。
特に問題なのは、後者「水平方向に4枚までしか表示できない」の方で、シューティングゲームの敵の弾とか見えなくなってはゲームになりません。
SPRITEはFONTを表示するテキスト面の前に、32枚分の表示面があり前から0面〜31面となります。
水平方向に5枚以上並んだ時は、面番号が小さい面が優先し表示されます。
(SPRITE面11、2、4、14、25、8と6枚並んだ時は、11、2、4、8が表示される。)
そこで、水平方向に5枚以上並んだ時に点滅させて疑似的に5枚以上表示させる方法がよく見られます。
全く見えなくなるよりは、点滅して見難くても見えた方が良いですよね。
やり方はルールに則って、SPRITEの表示面を入替えるだけです。
その方法で有名なのが「素数入替法」。
あるキャラクタを表示する時、どの表示面に表示するかの決定に、素数を利用する方法です。
0面から開始して、例えば17を足して32以上になったら32引くようにしていくと、32面目で元の数字に戻ります。(下表の「表示素数」)
面白いですね。
これを利用すると、例えば自機を表示する時、初回は0面に表示、次は17面、次は2面...となり、優先順位が高くなったり低くなったりで点滅すると言う訳です。
(キャラクタ側の面は+1でも良いのですが、こちらも別の素数でやるとバラけていい感じに点滅します。)
この方法の良いところは、何と言っても加算だけで表示面を決められること。
ただでさえメモリ→VRAM間の転送は遅いのに、その転送準備に時間をかけると、処理速度がどんどん遅くなってしまいます。
シャッフルするのに乱数や乗除算を使うと、毎回32回ループすることを考えるとマシン語とは言え負荷が大きいです。
因みに、この方法は1例です。
拙作「PAC-MAN」はこれとは別の方法で点滅させています。(確か4面単位で後ろにシフトする方法だったと思います。(記憶が薄い。))
自分の好きな方法を使うといいです。
では、次回は具体的に組んでみます。
2024年03月14日
Laboratoryテーマ28「マシン語でフロッピーディスクを制御したい」そのA
今回は、Laboratoryテーマ28「マシン語でフロッピーディスクを制御したい」そのAです。
マシン語で、フロッピーディスクからメモリへの読込と、メモリからフロッピーディスクへの書出を行うサンプルプログラムです。
「DISK.BAS」【ダウンロード】
読み込み時は、前回説明した「FCB」にドライブ番号と、ファイル名、拡張子をセットし「&H0F」でシステムコール(&HF37D)。
フロッピーディスク内にあるファイルから「FCB」にファイル情報が読み込まれます。
ファイルの読み込み先アドレスをセットし、「&H1A」でシステムコール。
「FCB」に読み込みに必要な情報をセットし、「&H27」でシステムコール。
書き出し時は、「FCB」にドライブ番号と、ファイル名、拡張子をセットし「&H16」でシステムコール。
フロッピーディスクに新たなファイルが作成されます。(強制上書)
メモリの書き出し元アドレスをセットし、「&H1A」でシステムコール。
「FCB」に書き出しに必要な情報をセットし、「&H26」でシステムコール。
書き出し時は、最後に「&H10」でシステムコールし、ファイルを閉じます。
簡単です。
BASIC部です。
2024年03月13日
Laboratoryテーマ28「マシン語でフロッピーディスクを制御したい」その@
今回は、Laboratoryテーマ28「マシン語でフロッピーディスクを制御したい」その@です。
以前にも書きましたが、私は過去作品でマシン語からフロッピーディスクを制御したことがありません。
完成品、未完成品含めすべてです。
フロッピーディスクからデータを読む必要がある時は、「3Dダンジョンロールプレイングゲーム」でやっていた通り、一旦BASICに戻っていました。
特にそれで不便を感じませんでしたし、不都合もありませんでした。
でも、やはりマシン語からBASICへ戻るには、コール内からは直接戻れないし、スタックポインタも全てクリアしないといけないなど制約が多いのも確か。
そこで、Laboratoryのテーマにあげました。
しかし、私自身知識が全くないので、あちこちのサイトやブログを探し回りましたが、フロッピーディスク制御に関して詳しく書かれたところは見つかりませんでした。
やむなく、「MSX2 TEchnical Hand Book」とにらめっこ。
今まで聞いたことのない専門用語が多く、本の解説も上級者向けの為、なかなか理解できませんでした。
それこそ「トライ&エラー」の連続でした。
そして何十回目かのトライで、これまでの努力が実り、やっと成功しました。
泣きそう…。
このロジックが「3Dダンジョンロールプレイングゲーム」や「無人島脱出アドベンチャーゲーム」で使えていれば、「BE」や「SC」、「SV」スクリプト命令がもっと簡単に組めていたかと思います。
今回はDISK-BASICから「FCB」(ファイルコントロールブロック)を利用して、ファイル名で読み書きできる方法を採用しました。
「FCB」は37バイトで、構成は下表の通り。
0 | ドライブ番号 |
1〜8 | ファイル名 |
9〜11 | 拡張子 |
12〜13 | カレントブロック |
14〜15 | レコードサイズ(1〜65535) |
16〜19 | ファイルサイズ(1〜4294967296) |
20〜21 | 日付 |
22〜23 | 時刻 |
24 | デバイスID |
25 | ディレクトリロケーション |
26〜27 | ファイルの開始クラスタ番号 |
28〜29 | 最後にアクセスしたクラスタ番号 |
30〜31 | ファイルの先頭クラスタからの相対位置 |
32 | カレントレコード |
33〜36 | ランダムレコード |
システムコールはファンクション番号をCレジスタに設定し、下表アドレスをコール
DISK-BASIC | &HF37D |
MSX-DOS | &H0005 |
ファンクション番号は下表の通り。
&H00 | システムリセット |
&H01 | コンソールから 1 文字入力 (入力待ちあり、エコーバックあり、コントロールコードチェックあり) |
&H02 | コンソールへ 1 文字出力 |
&H03 | 補助入力装置から 1 文字入力 |
&H04 | 補助出力装置へ 1 文字出力 |
&H05 | プリンタへ 1 文字出力 |
&H06 | コンソールから 1 文字入力 (入力待ちなし、エコーバックなし、コントロールコードチェックなし) / 1 文字出力 |
&H07 | コンソールから 1 文字入力 (入力待ちあり、エコーバックなし、コントロールコードチェックあり) |
&H08 | コンソールから 1 文字入力 (入力待ちあり、エコーバックなし、コントロールコードチェックあり) |
&H09 | 文字列出力 |
&H0A | 文字列入力 |
&H0B | コンソールからの入力チェック |
&H0C | バージョン番号の獲得 |
&H0D | ディスクリセット |
&H0E | デフォルト・ドライブの選択 |
&H0F | ファイルのオープン |
&H10 | ファイルのクローズ |
&H11 | ワイルドカードに一致する最初のファイルの検索 |
&H12 | ワイルドカードに一致する 2 番目以降のファイルの検索 |
&H13 | ファイルの抹消 |
&H14 | シーケンシャルなファイルの読み出し |
&H15 | シーケンシャルなファイルの書き込み |
&H16 | ファイルの作成 |
&H17 | ファイル名の変更 |
&H18 | ログイン・ベクトルの獲得 |
&H19 | デフォルト・ドライブ名の獲得 |
&H1A | DMA アドレスの設定 |
&H1B | ディスク情報の獲得 |
&H1C〜&H20 | 無効 |
&H21 | ランダムなファイルの読み出し |
&H22 | ランダムなファイルの書き込み |
&H23 | ファイルサイズの獲得 |
&H24 | ランダムレコード・フィールドの設定 |
&H25 | 無効 |
&H26 | ランダムブロック書き込み |
&H27 | ランダムブロック読みだし |
&H28 | ランダムなファイルの書き込み (不要部を 00H で埋める) |
&H29 | 無効 |
&H2A | コンソールから 1 文字入力 (入力待ちあり、エコーバックあり、コントロールコードチェックあり) |
&H01 | 日付の獲得 |
&H2B | 日付の設定 |
&H2C | 時刻の獲得 |
&H2D | 時刻の設定 |
&H2E | ベリファイ・フラグの設定 |
&H2F | 論理セクタの読み出し |
&H30 | 論理セクタの書き込み |
例えば、ファイル読込は一旦ファイル名を設定しシステムコール(&H0F)し、読込先アドレスを設定し再度システムコール(&H1A)、必要な設定を追加して三度システムコール(&H27)することで読込み出来ます。
出来てしまえば非常に単純で簡単でした。
次回、サンプル公開しますね。
2024年03月12日
細かく修正S
「ダウンロード」の「新作」に、新規公開した「無人島からの脱出」記事へのリンク追加。
先日、「ゲーム制作」のタイトルメニューを製作したので、トップページのグローバルメニューの飛び先をそちらに変更しました。
同じく「Laboratory」の飛び先も、テーマメニューページに変更しました。
(カテゴリ全記事は右サイドバーにある「カテゴリーアーカイブ」から参照できます。)
「Laboratory」のテーマメニューに新しく1テーマを追加。
「ゲーム制作」の「無人島脱出アドベンチャーゲーム」の前後回へのリンク切れがあったので修正。
それ以外は、画像の貼り直しや、記事の誤記の修正程度です。