2019年08月19日

プチコンゲームプログラミング講座~第10回「サイモンゲームを作ろう」

文 プチ太郎 氏
=-=-=-=-=-=-=-=-=-=-
 今回は訳あって(理由は文章の最後で!)アクションゲームでも思考ゲームでも自由に作れたのですが、第六回のように、以前と同じジャンルを再度作りたくないという考えがありました。で色々作りかけて、あれはプログラムが長い、これは締切まで完成できるか…と考えた結果、このゲームを思いついて、予想通り短時間で完成できました。

教材プログラム 10 「サイモン」(ファイル名「KOZA10」)
koz10_s1.jpg

★ ゲームの内容と説明 ★
 何かボタンを押すとゲーム開始で、4つの色のボタンが(以下「四色」と略す)、順番(以下「現回数」)に音を出してポーズをとります。左下に表示されている回数(以下「最大回数」)を全部終えると「今の順番を繰り返せ!」とメッセージが出るので、左の十字ボタンでも右の丸ボタンでも、さっきの順番と同じボタンを押してください。間違えず押せたらクリアです。最大回数は当初1回ですが、クリアするたび増えて、覚えるのがどんどん大変になります。一度でも間違えたらゲームオーバー。

Simon_game.jpg

 「サイモン」は、1978年にラルフ・ベアという発明家が作った携帯ゲームで(光線銃ゲームや家庭用ゲームも発明しています!)、いわゆるミニゲームですが、結構奥が深い上にプログラムが簡素にまとまる特徴があります(毎回文章の容量を規定内に削るのに苦労していましたが、今回は全文書いても少なめでした!)この連載では第二回で4方向移動ゲームをやりましたが、今回は四色の要素を配列変数に入れて、コンパクトにするなどの技術を勉強しましょう。

★ プログラムの事前説明 ★
 第五回で説明したテキスト以外の色コードについて、また短くする工夫を使っています。白を出すにはRGB関数か#WHITEだが、今回は3号のあるユーザが発見した「-1を指定すると#WHITEと同じ」を使っています。プチコンでは-1の二進数は、第五回の説明通り「10000000000000000000000000000001」となります。色指定の場合はこの左端1ビットをマイナス符号でなく、非常に大きな数と捉えるので、RGB(255,255,255)より大きいつまり#WHITEと認識します。前回の「!」同様、プログラム中で目立ちやすく、かつ短くて便利です。

koz10_p1.jpg

★ 初期設定 ★
 2行目のDIM OTO[99]は最大回数です。これも第五回で書いた通り、コンピュータと配列はゼロから始める(異世界生活ではないw)事が多いですが、人間からの見やすさを考え、1から始める(つまり[0]はダミーで使わない)事もあるので、今回はそうしています。[99]という事は最大添字が98なので、最大回数が98を超えるとエラーでゲームが止まりますが、そこまで行く超人は稀にしかいないと思い、あえてそのままです。なお配列の最大数を増やすにはPUSH、減らすにはPOPを使うので、興味ある方は調べてみて下さい。
 添字が[4]のDIMは全て、四色・四方向の定義です。オリジナルはアブストラクト(単なる記号)ですが、ここでは前回に続き、RPG向けの赤勇者・青魔女・緑僧侶・黄盗賊を使ってみました。サイモンでは画面を動くキャラこそ無いものの、4方向に配置したボタンがゲームの基本です。4方向の順番はプチコンの各要素でバラバラで、例えば十字ボタン=上下左右、丸ボタン=右下左上、文字キャラの人や車・スプライトの112~444=上右下左、464~1119=右下左上などとなっています(スプライトは一部違うものもあり)そこでここではFORとREADを使い、[0]~[3]に時計回りで上右下左の順番を入れています。これで四方向に関わる処理は、これら配列変数の添字を[0]~[3]で指定すれば、容易に使えます。順番が元々上右下左であるデータは、配列を使わずに掛け算で出しています。
 その後13~16行のGIで、左上のタイトルと中央のボタン操作を表示しています。

★ メイン処理 ★
@INIT リプレイ時の初期設定
 19行のGIは、リプレイ時の回数表示を消しています(@KAISUを参照)。20行目のDEF TENMETUは、四色全部を基本形のキャラに戻していますが、これは四色ともゲームオーバー時に通常と違う姿にしているためです(@OVER参照)21~22行はいつものスタートボタン待ちです。23行からはその後のスタート処理で、24行のDEF GI2でスタートメッセージの表示。21~22行で四色を同時に1秒だけ、ボタンを押した姿にしています(この処理については、DEF TENMETUも参照して下さい)

@LOOP 最大回数を一回増やしてプレイの繰り返し
 こうした処理は前回書いた通り、本当はGOTOを使わない構造化プログラミングが一番よいのですが、今回のゲームで構造化を使うと、むしろフラグ変数などを使って複雑になってしまうので、スパゲッティにならない程度のGOTOを使い、簡素にまとめてみました。
 変数K_ALLは最大回数で、19行でゼロにした後、@LOOPで32行を通るたびにINCで1ずつ増えていき、新たなOTO[K_ALL]に0~3の乱数を入れていきます。なおこの乱数が妙に偏ることが結構ありますが、これはプチコンやこのプログラムのバグでなく、プチコンの疑似乱数が0~3だと、たまたま偏りが出やすくなる様です。
 変数の再設定が出来たら繰り返しの開始です。33行のGI2で「じゅんばんを おぼえろ!」とメッセージを出し、34行のFOR…TO K_ALLで、最大回数K_ALL分だけTENNMETUを呼び出し、プレイヤーはこれを覚えます。36行はプレイヤーの繰り返し入力用の準備で、現回数を格納しておくK_NOWを1にします。

@LOOP2 ポタンが押されるまで待つループ
 39行で@KAISUを呼び出して、現回数と最大回数を表示します。実はこの位置に書くと、ボタンが押されるまで小刻みに@KAISUを実行するので、わずかながら無駄な負荷をかける非効率処理なのですが、文字表示のチラつきや処理落ちは起きず、これも処理が簡単という事で、そのままにりしてあります。
 40行のBL(BUTTON・LEFT)は左のボタンの1(上)+2(下)+4(左)+8(右)=15で、BR(BUTTON・RIGHT)は右のボタンの16(A)+32(B)+64(X)+128(Y)=240で、BUTTON関数とANDをとっています(こう書いている処理の理由も、第五回を読み返して解読してみて下さい)それを元に、左と右どちらかで四方向の一方向だけボタンを押したかが41~43行で該当すれば、-1だった変数V(40行で代入)に0~3の値を入れます。この処理は[0]から[3]まで4行並べてもいいのですが、今回は参考例として、FORループで3行にまとめた記述としました。
 Vが-1でない場合はOTO[K_NOW]と比較し、同じつまり正解なら44行で@ICCHIに、違うつまりミスなら45行で@OVERに飛びます。
 Vが-1のままならボタンを押さなかった事。WAITを60分の1秒だけ待って、Wにカウントを1加えます。47行で60で割った余りがゼロ、つまりWAIT 60こと一秒たったなら、プレイヤーに時間経過を知らせるため、早押しクイズのように一秒ごとに、BEEP 31で「タッ」と音を出して急かします。48行でWが600を超えたなら10秒オーバーなので、GIでタイムアウトを表示し、やはり@OVERに飛びます。それにも該当しなければ、49行で@LOOP2に戻って、入力待ちとカウントを繰り返します。

★ 定義済み処理 ★
@ICCHI 正しいボタンを押した時の処理
 TENMETUで正しい四色だけ白にします。この後WHILEとBUTTONでループをとっていますが、これは正解の後もボタンを押し続けた時、次の現回数が違う四方向だと、自動的にミスとしてゲームオーバーになってしまうので、指をボタンから離すまでわざと待つためです。また押したときのキャラの姿が、当初は中央のボタンを指差していましたが、つられて反対方向のボタンを押してしまうのでw外側に向けました。このキャラ番号も向きの関係で不連続になったので、計算でなく配列変数SS[i]に入れて、使うキャラ番号を求めています。
 53行で現回数と最大回数を比較し、最大回数が多かったらまだ残りがあるので、現回数を1増やしてWAIT 10で少し待ち、@LOOP2に飛ばして次の入力待ちです。

koz10_s3.jpg

 でなければ最大回数まで行ったのでノルマクリア。54行で「よくやった!」のメッセージを出し、55行でBGMPLAYによりファンファーレ。56~60行は四方向全部を躍らせるためです。第七回でやったSPANIMの記号の区別は覚えていますか? Cが色、XYが座標、Iがキャラ番号ですね。55行のA=96は四方向が踊っている時間で(つまり約1秒半)、Aから変数D・B・Cを求め、それをSPANIMで使っています。どの変数がどのSPANIMでどう使われているのか、一つ一つ計算してみましょう。61行のBEEP 71で「やったね!」の声を出して、また@LOOPに飛んでで最大回数1からやり直しです。
DEF TENMETU LS,LA 四色の1つの表示を切り替える
 まず「IF LA THEN」なら(この記述の意味は前回参照)、四色の中からLSだけ、-1で明るく表示して、@ICCHIで説明したSS[LS]で指差しポーズを出します。

koz10_s2.jpg

 ここで音を出しますが、BEEPよりBGMPLAYと文字列で自作メロディを出す、いわゆるMML(プチコンではmkIIから実装されています)の方が良い音になったので、そちらを採用しました。この講座ではMMLは扱ってきませんでしたが、実は現代式のMMLをよく知らないもので(^^;)、ここでは最低限の文法だけで作っています。「@+数字」はBEEP同様に音色番号で(これは国際規格です)、今回使っていませんが、演奏速度や音符の長さも指定できます。ドレミファのメロディは文字順でなく「CDEFGAB…」となるので、CHR$(67+LS)を使って四色の[0]を"C"/ド、[1]を"D"/レ、[2]を"E"/ミ、[3]を"G"/ファとしました。音が出終わるまで、WHILEとBGMCHKでループをかけて待っています。
 その後LAが1でも0でも67行を実行し、四色の暗さとキャラを元に戻しています。
DEF GI LX,LY,L$,LX2,LY2,LC1,LC2 GPUTCHRで背景に色が付いた文字を出す
 第九回と同じです。
DEF GI2 L$,LX2,LC1,LC2 LX=30・LY=26・LY2=2に固定してDEF GIを実行
 メッセージ表示のうち、右下はメインとして非常によく出すので、処理をまとめました。
DEF GI0 LX=30・LY=26・LY2=2に固定して文字を消す
 同じ場所で文字を消す処理です。GOSUBでもいいが、整合性を出すためDEFにしました。

@KAISU 左下に回数を表示
 DEF GIで現在に回数と最大回数を表示します。本来のサイモンには無いのですが、こうした表示は、数字がやや多めに出てくる処理ではよく見られるので、入れてみました。同時に「最大何回の繰り返しで何回目まで行ったか」というスコア表示の役目にもなっています。
 84行ではSTR$関数を使って、K_NOWとK_ALLを変数A$に入れており、これを86行のDEF GIで表示しています。ただし最大回数が増えると、現回数が小さい時に表示文字数の増減が大きくなり、以前表示したGIが右に残ってしまうので(こういうのをゴミと言います)、85行でそれより少し長い分スペースを表示して、必ず消す様にしています。

koz10_p2.jpg

@OVER ゲームオーバー処理
 90行で四色全部を驚いた顔にし、次の91行ではタイムオーバーでなければ、本来押す予定だった正しい色を、コケた姿にしています(前回のバトルゲームで倒れた時と同じ)92~92行でミスの表示をし、BEEP 122のサウンドが終わったら、ゲームオーバー表示以後はこれまでと同じです。

koz10_s4.jpg

★ お別れのご挨拶 ★
 さて、第0回も含めれば11回も続いたた当連載、実は今回で終了となります。
 同じ事をやっている松原拓也さんの「日経ソフトウェア」のプチコン講座を目指して頑張りましたが、同じゲームはやりにくいし、作ろうと思ってもなかなか上手く作れなかったり、こんな難しいゲームと解説でいいのか、もっと簡単にしようか…思い返すと、サンプルゲームのジャンルや内容があまりに偏り過ぎて、それはひどいものでした(三回やった予習・復習は「逃げ」でなく、必要なものとしてやりましたが…)三次元迷路とかトランプゲームとか、松原さんの連載とダブっても、私のプログラムでやるべきでしたね(^_^;)
 「プチコン4が出たら、連載形式で毎回仕様を実装していく、大きめのゲームが作れたらいいね」と、B-Magaさんと話していたのですが、私がプチコンを触れる時間が減ってしまったため、残念ながら終了させて頂く事にしました。決してB-Magaさんとの関係が悪化したのでなくwちゃんと円満終了です。
 皆さんに対してどれ程役立ったか判りませんが、今後ゲームを作る際、少しでも参考になれば幸いです。
 では、さようなら!

★今回の教材プログラムは、サーバにアップしてありますので、サーバからダウンロードしてご覧下さい。
公開キー  :7P33E334
プロジェクト:KOZA
ファイル名 :上の教材プログラムの見出しをご覧下さい。
=-=-=-=-=-=-=-=-=-=-
次の更新は、『URAURA! GAME REVIEW』の予定です。お楽しみに!