2019年04月15日

プチコンゲームプログラミング講座~第六回「潜水艦ゲームを作ろう」

文 プチ太郎 氏
=-=-=-=-=-=-=-=-=-=-
 冒頭から少しお詫び?です。今回は三次元視点シューティングゲームの予定でしたが、プログラムのメイン部分がうまく実装出来ず、頭を抱えていました(実は「スターウォーズ」「スペースハリアー」みたいなゲームを作った事がなかったw)今回もサンプルゲーム無しの講座にしようか、落とそうとかといろいろ考えていた所、たまたま今回のゲームを思い出したので、今回は(も?)急ごしらえですがこれにしました。キャラが多い割に、行数も150行強と短めです。
教材プログラム 6 「潜水艦ゲーム」(ファイル名「KOZA06」)

koz06_s1.jpg

★ ゲームの内容と説明 ★
 「ディプスチャージ」(英語で爆雷の意味)が元祖だが、79年にセガがアレンジして出した「ディープスキャン」で有名になりました。スピードに頼らず独特の味わいがあるので、その後も多くの類似作が作られています。
 初心者にとっては「第四回のシューティングゲーム『クセヴィオウス』(以下、第四回と略す)と全然違うな」と思った方もいると思います。実は第四回と自分・自弾・敵・敵弾の発生位置と動く方向が違うだけで、処理内容は似ており、今回も第四回からあちこちの処理をコピペして持ってきています。また第四回より一世代古いゲームなので、動きの処理ももっと単純です。今回もスプライトに関する命令が沢山出てきますが、それは次回でもまとめて解説するので、今回だけで判らない場合は、次回までお待ちください。

★ プログラムの説明1:初期設定とメインループ ★
 まず初めに、まとめて説明しておくべき「爆風とSPANIMの処理」から書きます。今回もゲーム中のキャラや爆発した時の爆風を、第四回同様にSPANIMで連続して見せています。今回やっているキャラは爆雷(これだけずっとそのままなので、9行目で定義)・潜水艦爆発・機雷上昇・機雷爆発の4種類です。SPANIMで使っている変数は全てAが表示間隔・変数Bがキャラです。どれも記述が長くなり、GOSUBかDEFでもっとコンパクトに出来ないか考えたが、それぞれ微妙に設定が違うので出来ませんでした。何かいい方法は無いでしょうか…。
 また水中という事で、スプライト表示を透明または半透明にしている部分があります。SPANIMに「"C"」「マイナス符号つきのfps時間」「0(カラー数値で言う透明)」を使っている所は大体これです。ただし使用後にSPCOLOR #WHITEをしないと、キャラが見えずに動くという、判りにくいバグが出るので注意!
 またS番号でSB[S]を新設しています。これは通常(SS[S]=O)と違う動作をしている間、どれだけ待つかというインターバルのBです(正しくはIntervalですがw)。爆破処理でSS[S]=1とした後(今回使っているのはこの爆破だけですが)、SB[S]に待たせたいカウントを代入し(今回は58行や113行で使用)、SS[S]が1ならSB[S]から1ずつ減算、0になるまで余計な事はしないという処理です。この処理がいい加減だと、やられた演出を表示中のキャラに何か命中した時、さらにやられた演出が繰り返されるなどのバグが出ます。第四回の爆破処理ではSS[S]に、-1より小さい数字で入れて使っていましたが、処理が複雑になったら、そうした変数共用は出来るだけ避け、今回の様に特定の変数を作る方が、バグが出にくくなります。

koz06_p1.jpg

@INIT1前の初期設定
 4~9行のS番号初期設定は、第四回を少し書き換えただけです。8~12行は、プログラム起動時に一度やっておけば変更が無いスプライトの設定です。背景は第三回「アドベンチャーゲーム」ではBGを使ったが、今回は13行目でBACKCOLOR命令を使いました。3号ではレイヤーが奥の1024から手前-256まであるが、これは一番奥に色をつける命令です。逆に一番手前はFADE(フェードインのフェード)が使えるが、単語と位置以外は同じ働きです。fps指定でSPANIMのようにジワジワ変える事も出来ます。
 14~16行はBG0番に海水のアニメーションを描いており、第四回の地面と似ているが、もっと簡単です。またこれも以前解説した事ですが、沢山のキャラを出すとどれが上や下になるか調整が大変です。今回は簡単な処理だからか、奥行き処理を一切しなくてほぼ大丈夫でした。強いて言うとゲームオーバー時のBG文字が、スプライトより後に出る程度です。
@INIT1 リプレイ時の初期設定
@INIT2 ミスした後の初期設定
 26行目のSPCOLORとSPROTは、配列変数S*[0]と共に、自機が沈んだ状態を元に戻しています(@MISS参照)。BKZは@JIKITAMA、DKZは@TEKITAMAを参照。
@LOOP メインループ
 キャラを細かく動かす場合、WAIT命令は1fpsずつ動かすのが基本です。しかし今回それをやったら、元のゲームがゲームなので微妙に速くなってしまったため、オリジナルと似た雰囲気の「WAIT 2」としました。このため前述のSB[S]などに、いつもなら待ちたいfpsと同じ数(一秒なら60)を代入すればいいが、今回は2fps待つのでその半分(一秒なら30)となるので、解析する方は注意して下さい。
★ プログラムの説明2:定義済み処理(メインキャラ) ★
@JIKI 自機(駆逐艦)
 近代戦風の軍艦キャラが無いので、10行目でSPDEF番号365番「帆船」を仮使用しました。小さいのでSPSCALEで横に拡大した所、イージス艦みたいにも見えたので(え?)見苦しくないかとそのままにしてあります。もしこれで不満だと思う方は、前回のミニプログラム「K05T16」とSPDEFを使って、灰色の軍艦を自作してみて下さい。
 マイキャラの移動は左右だけなので、第一回と同じくらい簡単です。BUTTON関数は、@JIKITAMAの爆雷ボタンと同時に押す必要があるので、前回と前々回説明した「ANDを使って、そのボタンのビットが立っているか」の判定で動かしています。
 さて以下の3処理の前に、書いておくべき特徴です。海中は自弾・敵機・敵弾の三種類が入り乱れて複雑そうですが、実際に影響するキャラ同士は非常に少なく「海中で自弾から敵機に」「海上で敵弾から自機に」の二つだけです(アーケード「ザ・ディープ」では撃ち消し合う)第四回で解説した二種類の当たり判定処理については、今回座標判定式だけです。当たり判定の数や場所が限られる事も理由ですが、もう一つの理由は、拡大・縮小して使っているスプライトが多く、これにSPCOLを使うと、上下左右にドット単位で当たり判定の誤差が出るためです(割り算で割り切れない余りが出るためではと思われます。スプライトやBGの表示も、砂粒のように乱れが出ますが、プチコンBIGでは表示の乱れは出ません)
@JIKITAMA 自弾(爆雷)
 こちらのBUTTON関数は、48行目で#Aと#BつまりAボタンとBボタンだけ取得し、49~50行でどっちかだけ押されたかにより、左右の投下位置を決めて「GOSUB @JT_NEW」で処理しています。変数BKZ(KZ=数)は第四回のS_Tと同じで、連射防止用のカウントです。
 爆雷が画面に出ていたら、108行目でグラフィック縦座標SY[S]を調べ、66行目で240に来ていたら底に着いたので、@S_LOSTで戻しています。ここから潜水艦との当たり判定です。ドット単位で動かしているので「縦と横どちらも一定の範囲に入ったか」でも考えたのですが、潜水艦は一段に一隻しか出ないので、縦座標(毎回SY[S]と書くのが面倒なため、53行目で一時的に変数Yに代入)は54行目で、前回説明したMODを使った「Y MOD 24==0」、つまり24ドット毎に当たりの可能性ありとし、55行目で当たった可能性のあるS番号をYから相対計算して変数SH(=Sprite Hit)に代入、56行目でSX[S]とSX[SH]の横の差が-8~32なら当たりと判定しています。得点は深い方が大きいので、これも63行目でよく似た処理により、スコアに代入しています。
 当たったら爆雷はすぐ@S_LOSTで消し、S番号がSHに入っている潜水艦の爆発処理に移ります。57行目のBEEP 108は3号ですぐに覚える音色「大爆発」ですが、ここで新パラメータ「BEEP 音色番号,周波数」を使っています。これは周波数の値に応じて音の高さを変えるものです。本来のパラメータは±32768だが、プチコンBIGでは±4000を過ぎると音が変わらなくなるので、±4000以内にした方がいいでしょう。58行目のSB[SH]は前述した通り。最後に69行目で上記のどちらの処理にも該当しなかったら、1ドット上に進めて表示し直しています。
@TEKI 敵(潜水艦)
 先に今回使う潜水艦のSPDEF情報の話をします。今回も3号のプリセットを使っていますが。潜水艦は上下左右4方向設定されていると思いきや、1419番と1420番のSPDEF定義が、どっちも右向きになっていました。これはSPCHRで表示する時にもアトリビュート設定(前回説明したビット単位でのパラメータ)で修正できるんですが、今回は19~20行においてSPDEF OUTで一度1419番のSPDEF情報を取得し、隣の1420番に、定数リテラル#SPREVH(Sprite Reverce Horizontal=スプライト横逆転)を使って再定義しています。SPDEFは次回詳しく解説します。
 肝心の処理ですが、「出す」「動かす」「自身が爆沈中に待つ」の三つしか無いので、ここも記述は少なめです。まず80行目で出現していなければ64分の1の確率で出現させています。RND関数で変数Aに0か1を入れ、これで左から出して右に動かすか、右から出して左に動かすかの変数を計算しています。83~84行目は、爆風の時にもスプライト表示情報を変えているので、それを戻すため。オリジナルの潜水艦キャラも高さが大きくて不づり合いなので、SPSCALEも実行しています。 87~88行は画面の反対側まで行ったら消滅し、でなければ90行目で移動。3号では文字以外は画面外にも表示する事が可能だが、そうすると機雷発生の処理が少し面倒なので、画面端にしました。93行目はSB[S]処理。

koz06_p2.jpg

@TEKITAMA 敵弾(機雷)
 「ディープスキャン」では難易度の表現として、潜水艦を沈めるたびにレベル表示が高くなっていき、機雷の発射頻度も増えます。これを再現するため、変数DKZをゲーム開始時には28行目で0とし、潜水艦が沈むたびに64行目で+1して行きます。100行目のFORループではD_SからD_Eでなく「D_S+DKZ」としているので、潜水艦が沈むたびに機雷が増えます。ただし注意点として、100行目ではこの時の値がD_Eを超えない様にしています。超えるとS番号が未定義なのでエラーが出てしまいます。
 第四回でも説明した「敵弾を敵キャラから出すかの判定は、敵キャラ内の処理で行うか、敵弾内の処理で行うか」ですが、今回は後者の101~107行で行っています。機雷は雪の結晶みたいなSPDEF1203~1204番を使いましたが、サイズが大きいのでSPSCALEで半分にしています。機雷が画面に出ていたら108行目で縦座標を判定し、海面上である28なら109~112行でスプライトを爆発に書き換え、@JIKITAMA同様に機雷と駆逐艦の横の差が-12~52ドット以内なら、SS[0]=-1で駆逐艦の死亡フラグを立てます。でなければ116行目で1ドット上に進めます。119行目はSB[S]処理。

★ プログラムの説明3:定義済み処理(その他) ★
@S_LOST 特定のスプライトを画面から消す
 第四回では消すS番号と他のS番号が干渉するため、この処理での変数をS2にして、Sと区別していましたが、今回は処理が単純なので、ここでもSのままです。
@ALLCLS ゲームに必要な画面を一端クリア
 今回は全スプライトと、文字表示用のBG3番を消すだけで、この時@SCRも実行しています。
@SCR スコアやハイスコアを表示
 以前と全く同じではつまらないので、「特定の点数で一機追加」を新規実装しました。これは@INIT1でフラグ変数EXを0にしておき、得点が入ってスコア表示のたび、「EXがまだ0 AND スコアが一機追加の基準(今回は2000点)」まで行ったら、ファンファーレのBEEP 113を鳴らして一機追加というものです。なおここでEXを1にしておかないと、その後は得点表示するたびに一機追加が続く…というバグになってしまいますwここをうまく工夫すると、さらに得点を積むと一機だけでなく二機目も追加とか、「ゼビウス」のようにウン万点取るたび(そう、ここもMODで計算すればいいですね)に毎回追加…という実装も可能です。
DEF JI LX,LY,L$ BGを使って文字列を表示
@MISS ミスおよびゲームオーバー
 34行目でSS[0]が-1になるとここに飛びます。145~146行は駆逐艦が傾いて轟沈する姿を、SPANIM命令で容易に表現しています。これは「ディープスキャン」のプチコン亜流のうち、葛城コニミルさんの「D.P.S.」を参考にしました。
 ところで「ディプスチャージ」では残機制でなく時間制で、自機は時間内に何度やられても復活します。時間制の部分は簡単に実装出来たんですが(本当は三次元シューティングで使う予定でした)、ゲームが進みながら自機がやられてまた出てくるのは、プログラムが複雑になるので見合わせました。またこの当時のゲームのBGMは、ミスしてやられる瞬間にBGMSTOPが多いが、今回は23行目からずっとBGMPLAY 34が続きます。これも時間制にしようとした名残ですが、雰囲気を考えてこのままとしました。

koz06_s2.jpg

★ このゲームの未実装・改良できる部分 ★
 3号の性能で「ディープスキャン」よりも綺麗な画面となりましたが、未実装もかなりあります。見やすくするプログラムとして入れられなかった理由が大きいのですが、ある程度件数があるので並べておきます。スキルのある方は実装に挑戦してみて下さい。
・未発射の爆雷のストックが、画面上部に表示されていない。
・潜水艦の速度が、オリジナルでは上にいるほど速い。
・潜水艦に沈めた時の点数が表示されていない。
・「ディープスキャン」では、高得点を狙える「X艦」が最深部を通る。
・潜水艦の接近を知らせるレーダーが無い。
(第七回につづく シューティングが二回続いてバランスが悪くなってしまいましたね。七回目はまたミニプログラムによる基本の復習、八回目は反射神経でない数値思考ゲームの予定です)
★今回の教材プログラムは、サーバにアップしてありますので、サーバからダウンロードしてご覧下さい。
公開キー  :5DBEVWKE(連載が進んで新しい教材プログラムが追加されると、公開キーも変わります。この公開キーでダウンロード出来ない場合は、連載の一番新しい回の公開キーをご利用下さい)
プロジェクト:KOZA
ファイル名 :上の教材プログラムの見出しをご覧下さい。
=-=-=-=-=-=-=-=-=-=-
次の更新は、『自爆して点を稼げ!PSPにもなったよ。EveryExtend』の予定です。お楽しみに!