趣味のプログラミング(2)~MSXゲーム完成篇
前回の記事:
nyagbon.hatenablog.com
に引き続き、MSX でプログラミングを楽しみましょう! 前回は、自機を動かして、ミサイルが打てるところまで作りました。
今回はいよいよ敵が現れて、やっつけると点数が入り、やられると残機が減って、残機がなくなるとゲームオーバーになります。つまり、ちゃんとゲームとして遊べるシロモノにアップグレードです!
ソースコードは前回のものをベースとしていますが、いろいろな要素を追加しました。それぞれ説明していきます。
画面表示
まず、KEY OFF コマンドを使って、画面下のファンクションキー表示を消しました。これで画面がすっきりします。(10行目)
次に、スコア表示と残機表示を付けました。いろいろな場面で表示内容を変える必要があるので、サブルーチンにしました。また、PRINT USING コマンドを使って桁ずれが起きないようにしています。(980~990行目)
このサブルーチンは、スコアと残機を初期化した後の40行目、敵をやっつけてスコアが入った後の780行目、敵に体当たりされてやられた後の870行目、ゲームオーバーになった時の1020行目から GOSUB コマンドで呼び出しています。
また、SCREEN コマンドの引数で、キークリック音を消しています。(10行目)
スコアと残機とゲームオーバー
変数 SC がスコア、変数 RIHA が残機を表しています。30行目で初期化しています。
敵をやっつけたときにスコアを10点プラス(770行目)、自機に敵が体当たりした時に残機を1マイナス(860行目)しています。
上にも書きましたが、スコアか残機が変更されたら表示を更新するために980行目のサブルーチンを呼び出しています。
残機が 0 になったらゲームオーバーになります。その判定を880行目で行っています。1010行目からがゲームオーバーの処理で、画面をクリアしたあとにスコア表示をし、”GAME OVER!"と表示して END コマンドでプログラムを終了します。
敵
敵は、ゆらゆらと自分を襲って来るようにしました。
仕組みはよくある方法にランダム要素を加えたもので、敵の移動速度を自分に向かうように増加・減少させています。また、速くなり過ぎないようにもしています。(510〜570行目)
敵の初期位置は、画面左端、縦の座標はランダムにしています。(220行目)
敵のスプライトを新しく定義し(2410〜2560行目)、630行目で表示しています。ちなみにこのデザインはリハビリ中さんのツイッターのページから拝借しました。(カワイイw
当たり判定(ミサイルと敵)
さて、「当たり判定」という言葉が出てきました。キャラクタ同士が衝突したかどうかを判定することを、ゲームプログラミング用語で「当たり判定」と言います。
730行目がミサイルと敵の当たり判定をしています。なんでこんな長い IF 文になるのかの詳細は省きますが、気になる方は
などのページを見ると良いと思います。
ミサイルと敵が当たったら、敵をやっつけたスプライトを表示して、ビープ音を鳴らして、新たな敵を出現させて(=敵の場所を初期化して)、スコアを足して、スコア表示を更新することになります。ミサイル発射フラグも 0 にします。それが740~780行目です。
やっつけたスプライトパターンは、2610~2760行目で定義しています。自機がやられたときにも使いまわしています。
ちなみに、MSX だと ON SPRITE GOSUB コマンドで当たり判定を行えるらしいのですが、以下のページ
を読んで、キャラクタが多いときには思うように使えないと知り、自前で当たり判定を実装しました。
当たり判定(敵と自機)
敵と自機が衝突したら、やられないといけません。これも上と同じように当たり判定をしています。(810行目)
自機がやられたら、ちょっとだけ派手な演出をすることにしました。やっつけられたパターンを赤で表示して、ビープ音を鳴らして、パターンを消して、ビープ音を鳴らして、という処理を6回繰り返すことにしました。つまり、音が鳴りながらやられたパターンが点滅するわけです。(830~850行目)
そして残機数 RIHA を1マイナスし、もし残機数が 0 ならば、ゲームオーバーの処理に向かいます。そうでなければ、自機や敵やミサイルを初期化して再スタートします。(210行目に飛ぶ)
くりかえし
さて、ここまでで敵が動いて、当たり判定がなされて、やっつけたりやっつけられたりすることができるようになりました!
また、おまけで ”Q" キーを押したら好きなときにゲームオーバーで終了するようにしました。飽きてきたときとか改造したい時にどうぞ。(910~920行目)
ここまでの処理が一連の流れになるので、これを繰り返すとゲームになります。というわけで、930行目で300行目に戻り、ループします。
画面イメージ
こんな感じです。画面に自機、敵、ミサイル、スコア、残機が表示されています。
というわけで
2回に渡ってお届けした「MSXでゲームプログラミングをやってやろうぜ!(リハビリ中篇)」は今回で終了となります。
久々に BASIC を触って、なかなかいい言語じゃん! もっと書きやすい言語あるけどな! とツンデレな自分に会えました。
また、初めての MSX プログラミングでしたが、特にスプライト機能はお手軽で、さすがゲームがあれだけ出たプラットフォームだなぁ、と感心しましたよ。
またネタを思いついたらプログラミング記事も書いていければと思います。それでは以下のコードでお楽しみください。ではまた~。
ソースコード
10 SCREEN 1,2,0:KEY OFF 20 ' INITIALIZE 30 SC=0:RIHA=3 40 GOSUB 980 100 ' READ SPRITE 110 FOR S=1 TO 4:L$="":R$="" 120 FOR I=1 TO 16:READ I$ 130 L$=L$+CHR$(VAL("&B"+LEFT$(I$,8))) 140 R$=R$+CHR$(VAL("&B"+RIGHT$(I$,8))) 150 NEXT 160 SPRITE$(S)=L$+R$ 170 NEXT 200 ' INITIALIZE POSITIONS 210 X=180:Y=80:BB=0 220 EX=0:EY=INT(RND(1)*180):EH=0:EV=0 300 ' MOVE BY CURSOR KEY OR JOY STICK 310 ST=STICK(0) OR STICK(1) 320 SG=STRIG(0) OR STRIG(1) 330 IF ST=0 THEN 400 340 IF ST>=1 AND ST<=2 AND Y>0 THEN Y=Y-8 350 IF ST>=3 AND ST<=4 AND X<240 THEN X=X+8 360 IF ST>=5 AND ST<=6 AND Y<180 THEN Y=Y+8 370 IF ST>=7 AND ST<=8 AND X>0 THEN X=X-8 400 ' BULLET 410 IF BB=1 THEN 430 420 IF SG<>0 THEN BB=1:BX=X:BY=Y 430 BX=BX-12 440 IF BX<0 THEN BB=0 500 ' ENEMY 510 EX=EX+EH:EY=EY+EV 520 EH=EH+SGN(X-EX)*INT(RND(1)*3+1) 530 EV=EV+SGN(Y-EY)*INT(RND(1)*3+1) 540 IF EH>10 THEN EH=10 550 IF EH<-10 THEN EH=-10 560 IF EV>10 THEN EV=10 570 IF EV<-10 THEN EV=-10 600 ' PUT SPRITES 610 PUTSPRITE 1,(X,Y),15,1 620 IF BB=1 THEN PUTSPRITE 2,(BX,BY),8,2 ELSE PUTSPRITE 2,,,0 630 PUTSPRITE 3,(EX,EY),3,3 700 ' COLLISION CHECK 710 ' :BULLET VS EMENY 720 IF BB=0 THEN 800 730 IF NOT(BX+2<=EX+13 AND EX+2<=BX+13 AND BY+2<=EY+13 AND EY+2<=BY+13) THEN 800 740 PUTSPRITE 3,(EX,EY),5,4 750 BEEP 760 BB=0:EX=0:EY=INT(RND(1)*180):EH=0:EV=0 770 SC=SC+10 780 GOSUB 980 800 ' :ENEMY AND ME 810 IF NOT(X+2<=EX+13 AND EX+2<=X+13 AND Y+2<=EY+13 AND EY+2<=Y+13) THEN 900 820 ' :DEAD! 830 FOR I=0 TO 5 840 PUTSPRITE 1,(X,Y),8,4:BEEP:PUTSPRITE 1,,,0:BEEP 850 NEXT 860 RIHA=RIHA-1 870 GOSUB 980 880 IF RIHA=0 THEN 1010 890 GOTO 210 900 ' FINISHED A CYCLE 910 K$=INKEY$ 920 IF K$="q" THEN 1010 930 GOTO 300 970 ' SUBROUTINE TO SHOW SCORE AND LEFT RIHA 980 LOCATE 0,0:PRINT USING "SCORE:##### RIHA: #";SC;RIHA 990 RETURN 1000 ' GAME OVER 1010 SCREEN1,1,1:KEY ON 1020 GOSUB 980 1030 PRINT "GAME OVER!" 1040 END 2000 ' MINI RIHABILLY 2010 DATA 0000000000000000 2020 DATA 0000000110000000 2030 DATA 0000001111000000 2040 DATA 0000011111100000 2050 DATA 0000011001100000 2060 DATA 0000111111100000 2070 DATA 0000111111100000 2080 DATA 0011000000000000 2090 DATA 0111111011100000 2100 DATA 0001011101100000 2110 DATA 0000011111100000 2120 DATA 0000010011100000 2130 DATA 0000001111000000 2140 DATA 0000010000100000 2150 DATA 0000100000010000 2160 DATA 0000000000000000 2200 ' BULLET 2210 DATA 0000000000000000 2220 DATA 0000000000000000 2230 DATA 0000000000000000 2240 DATA 0000000000000000 2250 DATA 0000000000000000 2260 DATA 0000000000000000 2270 DATA 0000011111100000 2280 DATA 0001110000111000 2290 DATA 0000011111100000 2300 DATA 0000000000000000 2310 DATA 0000000000000000 2320 DATA 0000000000000000 2330 DATA 0000000000000000 2340 DATA 0000000000000000 2350 DATA 0000000000000000 2360 DATA 0000000000000000 2400 ' ENEMY 2410 DATA 0000000000000000 2420 DATA 0000000000000000 2430 DATA 0011000001100000 2440 DATA 0100100010010000 2450 DATA 0000011100000000 2460 DATA 0000011110000000 2470 DATA 0000111111000000 2480 DATA 0000111111100000 2490 DATA 0000110101100000 2500 DATA 0000110101110000 2510 DATA 0000111111110000 2520 DATA 0001111111110000 2530 DATA 0001111111111000 2540 DATA 0011111111111100 2550 DATA 0000000000000000 2560 DATA 0000000000000000 2600 ' KILLED 2610 DATA 0000000000000000 2620 DATA 0000000100000000 2630 DATA 0010000100001000 2640 DATA 0001000100010000 2650 DATA 0000100000100000 2660 DATA 0000000000000000 2670 DATA 0000000000000000 2680 DATA 0111000000011100 2690 DATA 0000000000000000 2700 DATA 0000000000000000 2710 DATA 0000100000100000 2720 DATA 0001000100010000 2730 DATA 0010000100001000 2740 DATA 0000000100000000 2750 DATA 0000000000000000 2760 DATA 0000000000000000