プログラム講座 中級編28

- もぐら叩きゲーム -

 中級編28です。今回は「もぐら叩きゲーム」について説明します。細長いもぐらのため、ほとんど「にょろにょろ叩きゲーム」です(^^;;




はじめに
 ゲームのプログラムの説明は結構面倒です。きちんと説明すると長くなってしまいますので、あらかじめ「今日からマックプログラマー Future BASICでGO!」の10章〜12章をざっと読んでから以下の文章を読んで下さい。本では説明されていない部分についてのみ説明していますm(_ _)m



ゲームの構成
 8匹のもぐら(にょろにょろじゃありません^^b)がウィンドウ下から出現するので、マウスボタンを押して叩いて下さい。一定数のもぐらが出現するとゲームは終了し得点が表示されます。
 マウスボタンを押したままで連射できてしまうオチがありますが、勉強用と言うことで目をつむっています(^^b 連射できた方がなぜか気分がいいという話もありますが・・・



得点加算について
   スコアはもぐらが下にいる時、つまり出現時に叩くと高得点になるようにしています。この処理は以下のようになっています。

score = score + ABS(50 - y(i))

 もぐらが一番上に来たときはY座標は64になります。一番下の場合は120(ウィンドウの縦幅)になります。つまり上記計算式で加算される得点は以下のようになります。

Y座標加算される得点
6414
12070



スコアなどの表示について
 スコアなどを表示する場合、少し注意が必要です。Future BASICの初期状態ではウィンドウに描画される文字は「論理輪」モード、つまり「重ね書き」されるようになっています。重ね書きなので、スコアが加算された場合、すでに表示された得点の上に重ね書きされ真っ黒になってしまいます。これを防ぐには「上書き」する描画モードにする必要があります。上書きさせるモードは「_srcCopy」をTEXT命令で指定します。これは以下のようになります。

TEXT _courier,12,,_srcCopy

 スコアなどの表示位置を指定する場合PRINT命令には便利な機能が備わっています。最初に%(x,y)のように%を付加する事によって「グラフィック座標を直接指定」できるのです。これは

CALL MOVETO(x,y)
PRINT "SCORE :"

 と同等の処理です。グラフィック座標でなく「文字座標」を指定する場合は、先頭に@マークを付加します。



初期設定部分について
 ゲーム開始後の初期設定部分はわかりにくいと思いますので説明します。もぐらの状態を以下のように初期化しています。

FOR i=0 TO 7
x(i) = i*36: ' "もぐらのX座標を設定"
y(i) = 999: ' "もぐらのY座標を設定"
NEXT

 Y座標を999にしているのはどうしてだろう?と疑問に思う人がいるはずです。これは「手抜き処理」です。普通は正しく移動速度、出現Y座標を指定する必要があります。下のループ内でY座標がウィンドウの縦幅(120ピクセル)以上だった場合、もぐらを再度出現させる処理を行っていますので、Y座標をわざと大きくしてメインループ内で処理させています。これは手抜きですので(笑)、ちゃんと初期化する方が良いでしょう。



アラートダイアログの位置指定
 アラートダイアログを作成すると標準では指定した座標に表示されます。指定座標ではなく、画面の中央に表示したい場合があります。このような場合は、以下のようにすると画面中央に表示されます。

(1)センタリングするアラートリソースを開く
(2)ALRTメニューからAuto Position...を選択する


(3)ポップアップメニューからCenterを選択する




終わりに
 もぐらの移動方向反転処理はFB本のブロック崩しのボールの移動方向反転と同じですので、そちらを参考にして下さい。判定処理も同じです。
 もぐらのグラフィックが今一(笑)なので、適当に書き直して下さい。なお、ウィンドウ上にゴミを残さないようにするため上に一定数の白ピクセル部分があります。8ビットマイコンの時代の技です(^^; これもFB本の11章に説明がありますので参考にしてください。

 次回の講座を作る前にページ構成を変更したい所です(-.-b こんなに大量に講座が増えるとは思っていなかったので、かなりごちゃごちゃになってしまいました。




今回のプログラムリスト
'------------------------------------------------------------ ' "もぐら叩き Future BASIC II-J" ' "1998 Presented By KaZuhiro FuRuhata" '------------------------------------------------------------ RESOURCES "mogura.res" _OK = 128: ' "もぐらのPICTリソース番号" _NG = 129: ' "もぐらのやられた時のPICTリソース番号" _title = 130: ' "タイトル画面のPICTリソース番号" _about = 128: ' "アバウト画面のリソース番号" _MoguraCount = 100: ' "もぐらの発生数" _GameOver = 130: ' "ゲームオーバーのダイアログのリソース番号" _windowLY = 120: ' "ウィンドウの最下限" ' "■■■■■■■■■■ タイトル表示 ■■■■■■■■■■" LOCAL FN title PICTURE FIELD #32,%_title,(0,0)-(320,_windowLY),_noFramedNoCR END FN ' "■■■■■■■■■■ ゲーム開始  ■■■■■■■■■■" LOCAL FN start DIM x(7): ' "X座標" DIM y(7): ' "Y座標" DIM pat(7): ' "もぐらの状態(叩かれた=_NG、健全=_OK)" DIM dy(7): ' "もぐらの上下方向の移動量" EDIT FIELD CLOSE #32: ' "タイトル画面を消す" FOR i=0 TO 7 x(i) = i*36: ' "もぐらのX座標を設定" y(i) = 999: ' "もぐらのY座標を設定" NEXT speed! = 3: ' "出現速度を設定(次第に速くなる)" mogura = _MoguraCount: ' "出現するもぐらの最大数設定" score = 0: ' "スコアを0にする" msFlag = _false ' "------------------------ ここからメインループ--------------------------" WHILE mogura > 0 startTime& = FN TICKCOUNT: ' "1/60タイマーを読み出す" endTime& = startTime& + 1: ' "1/60を1サイクルにする" ' "◆◇◆◇◆◇◆◇◆◇ もぐらの数(一度に10)だけ処理する ◆◇◆◇◆◇◆◇◆◇" FOR i=0 TO 7 PICTURE FIELD i,%pat(i),(x(i),y(i))-(x(i)+32,y(i)+64),_noFramedNoCR y(i) = y(i) + dy(i): ' "移動させる" IF (y(i) < (120-65)) THEN dy(i) = -dy(i): ' "もぐらが一番上になった時に降下させる" ' "◆◇◆◇◆◇◆◇◆◇ もぐら出現処理 ◆◇◆◇◆◇◆◇◆◇ LONG IF (y(i) > _windowLY) AND (dy(i) > 0):' "もぐらが画面外にでてしばらくしたら再登場させる" y(i) = RND(40) + _windowLY + 100 dy(i) = (RND(speed!)+1)/2 * -1 speed! = speed! + 0.4: ' "出現速度を上げる" IF speed! > 8 THEN speed! = 8 mogura = mogura - 1: ' "もぐらの残り数を減らす" pat(i) = _OK: ' "叩かれていない状態に戻す" END IF ' "◆◇◆◇◆◇◆◇◆◇ 判定処理を行う ◆◇◆◇◆◇◆◇◆◇ LONG IF (pat(i) = _OK) AND (FN BUTTON = _true) dummy = MOUSE(0): ' "マウス座標を読み込むための初期化" x = MOUSE(_horz): ' "マウスのX座標を読み出す" y = MOUSE(_vert): ' "マウスのY座標を読み出す" ' "◆◇◆◇◆◇◆◇◆◇ マウスの座標ともぐらの座標を調べる ◆◇◆◇◆◇◆◇◆◇ LONG IF (x >= x(i)) AND (y >= y(i)) AND (x <= x(i)+32) AND (y <= y(i)+64) AND (y < _windowLY) score = score + ABS(50 - y(i)): ' "高さに応じてスコアを加算する" dy(i) = 7: ' "ひっこむ時の速度" pat(i) = _NG: ' "叩かれていない状態に戻す" IF SOUND% THEN SOUND END: ' "音がすでに鳴っている場合はサウンド終了" SOUND "ite": ' "叩かれたときのサウンドを鳴らす" END IF END IF NEXT ' "◆◇◆◇◆◇◆◇◆◇ スコアなどの表示処理 ◆◇◆◇◆◇◆◇◆◇" PRINT %(0,10),"SCORE : ";score: ' "スコアを表示する" PRINT %(0,20),"LAST : ";mogura: ' "残りのもぐら数を表示する" WHILE FN TICKCOUNT < endTime&:WEND: ' "ウェイトタイマー" WEND ' "◆◇◆◇◆◇◆◇◆◇ ゲーム終了後の処理 ◆◇◆◇◆◇◆◇◆◇" sc$ = STR$(score): ' "スコアを文字列に変換" CALL PARAMTEXT(sc$,"","",""): ' "パラメーター文字を設定 err% = FN ALERT(_GameOver,0): ' "ゲームオーバーのダイアログ表示" ' "◆◇◆◇◆◇◆◇◆◇ ピクチャーフィールドを消去する ◆◇◆◇◆◇◆◇◆◇" FOR i=0 TO 9 EDIT FIELD CLOSE i NEXT FN title: ' "タイトルを表示してイベントループに戻る" END FN ' "■■■■■■■■■■ メニュー初期化  ■■■■■■■■■■" LOCAL FN initMenu APPLE MENU "もぐら叩きについて..." MENU 1,0,_enable,"ファイル" MENU 1,1,_enable,"/Sゲーム開始" MENU 1,2,_enable,"/Q終了" END FN ' "■■■■■■■■■■ メニュー分岐処理 ■■■■■■■■■■" LOCAL FN doMenu menuID = MENU(_menuID): ' "どのメニューバー項目を求める" itemID = MENU(_itemID): ' "選択項目を求める" IF ((menuID = 255) AND (itemID = 1)) THEN err% = FN ALERT(_about,0):' "アバウト画面を表示する" IF ((menuID = 1) AND (itemID = 1)) THEN FN start:' "もぐら叩きを始める" IF ((menuID = 1) AND (itemID = 2)) THEN END: ' "終了メニューが選択されたのでプログラムを終わる" MENU: ' "メニューのハイライトを元に戻します" END FN ' "■■■■■■■■■■ 各種初期化処理 ■■■■■■■■■■" ON MENU FN doMenu: ' "メニューイベントの処理先" FN initMenu: ' "メニューを初期化" WINDOW OFF: ' "デフォルト表示されるウィンドウを消す" WINDOW #1,"Mogura",(0,0)-(320,120),_dialogMovable:' "ウィンドウを表示する" TEXT _courier,12,,_srcCopy: ' "フォントとサイズ、表示モードを設定" FN title: ' "タイトルを表示する" ' "■■■■■■■■■■ イベントループ処理 ■■■■■■■■■■" DO HANDLEEVENTS UNTIL _false