2024年09月24日
Laboratoryテーマ18「回転する敵を作りたい」そのA
さて、今回はLaboratoryテーマ18「回転する敵を作りたい」そのAです。
当然ですが静止画だと、全く動きが判りませんね。
移動データを登録します。
前回同様、制御用コードとしてデータの始まりに「&H87」、データの終わりに「&H88」を付加します。
これで、全データで68バイトです。
⓪の時は上から下にデータを読んで、読んだデータをX座標に減算、Y座標に加算します。
データが「&H88」になったら⓪を@にして、今度は下から上にデータを読んでいきます。
読んだデータをX座標に減算、Y座標に減算します。
データが「&H87」になったら@をAにして、再び上から下にデータを読んでいきます。
読んだデータをX座標に加算、Y座標に減算します。
最後、データが「&H88」になったらAをBにして、下から上にデータを読んでいきます。
読んだデータをX座標に加算、Y座標に加算します。
今回もプログラムの効率化は図っていないので、遅く長いです。
このロジックを「水平ライン4枚(MSX2は8枚)を超えてSPRITEを表示させたい」と「BGM演奏ルーチン(通常版)」の組み込まれたプログラムに入れて実行させます。
結果は、動画でどうぞ。
基準線がないと、ちゃんと円描いて回ってるのか解り辛いので、円を描いてみました。
2024年09月23日
Laboratoryテーマ18「回転する敵を作りたい」その@
次は、Laboratoryテーマ18「回転する敵を作りたい」その@です。
回転する敵とは、画面内をぐるりと回転する敵です。
こんな感じの動作をします。
回転位置まで別の移動方法で移動してきて、任意位置でぐるりと回るなんてパターンをよく見かけますね。
円なので、三角関数の出番ですが、前回同様、Excelで移動量におけるY・X座標を求めておき、始点からの移動量をデータベース化します。
データベース化するのは、1回転分のデータです。
回転中に、任意位置で回転を止めて別の移動方法で逃走なんてのも、よく見かけますね。
今回も全部で252バイトもあるので、円を⓪〜Bに4分割します。
形を見てみれば、⓪を基準とすると、@は⓪の左右反転型。
Aは上下左右反転型。
Bは上下反転型となるので、やはりデータとしては⓪分の64バイト持っておいて、後は計算で求めるようにします。
2024年09月22日
Laboratoryテーマ16「波状攻撃してくる敵を作りたい」そのA
さて、今回はLaboratoryテーマ16「波状攻撃してくる敵を作りたい」そのAです。
当然ですが静止画だと、全く動きが判りませんね。
移動データを登録します。
制御用コードとして、データの始まりに「&H87」、データの終わりに「&H88」を付加します。
これで、全データで56バイトです。
⓪の時は上から下にデータを読んで、読んだデータをX座標に減算、Y座標に加算します。
データが「&H88」になったら⓪を@にして、今度は下から上にデータを読んでいきます。
読んだデータをX座標に減算、Y座標に加算します。
データが「&H87」になったら@をAにして、再び上から下にデータを読んでいきます。
読んだデータをX座標に加算、Y座標に加算します。
最後、データが「&H88」になったらAをBにして、下から上にデータを読んでいきます。
読んだデータをX座標に加算、Y座標に加算します。
プログラムの効率化は図っていないので、遅く長いです。
このロジックを「水平ライン4枚(MSX2は8枚)を超えてSPRITEを表示させたい」と「BGM演奏ルーチン(通常版)」の組み込まれたプログラムに入れて実行させます。
結果は、動画でどうぞ。
良い感じに波形移動しています。
因みにBGMは制作予定の「シューティングゲーム」の1面用のBGMです。
2024年09月21日
Laboratoryテーマ16「波状攻撃してくる敵を作りたい」その@
さて、長らく放置してしまったLaboratoryですが、「シューティングゲーム」を製作するにあたり、主に「シューティングゲーム」用の敵の移動系のテーマをやってしまおうと考えました。
多分4つとも使います。
まず、テーマ16「波状攻撃してくる敵を作りたい」その@です。
波状攻撃とは、いわゆる魔城伝説の序盤のコウモリです。
こんな感じの動作をします。
放物線を描いているので、三角関数の出番です。
…が、三角関数を用いて計算しながら移動させると、編隊飛行のように複数出現させるとなると処理が重いです。
ではどうするか?
何通りかの方法があると思いますが、今回は、もっとも単純な方法、最初にExcelで放物線上の任意の座標を求めておき、始点からの移動量をデータベース化します。
データベース化するのは、波形1回分のデータです。
後はそれを繰り返すだけです。
座標データ数により、敵の動作が速くなったり粗くなったりするので、そのあたりは最適な数を見付けて下さい。
このデータベースをそのまま利用してもいいのですが、全部で208バイトもある。
移動データ1つにそれだけのメモリはさすがに使えない…。
と、言う事で波形を⓪〜Bに4分割します。
形を見てみれば、⓪を基準とすると、@は⓪の上下左右反転型。
Aは左右反転型。
Bは上下反転型となるので、データとしては⓪分の52バイト持っておいて、後は計算で求めるようにします。
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)することで読込み出来ます。
出来てしまえば非常に単純で簡単でした。
次回、サンプル公開しますね。