モラこじ! ブログモードでGo!

レトロゲーム界隈にずぶずぶハマりつつある40代おっさんの生き様です!

趣味のプログラミング(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行目に戻り、ループします。

画面イメージ

こんな感じです。画面に自機、敵、ミサイル、スコア、残機が表示されています。

f:id:nyagbon:20190215205545p:plain

というわけで

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