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

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

趣味のプログラミング(3)~ゲームバランス篇

先日の記事:

nyagbon.hatenablog.com

で公開したゲームのソースコードを、2/19 にリハビリ中さんニコニコ生放送で実機の MSX に一生懸命入力して、プレイしてくださいました! ありがとうございます!

live2.nicovideo.jp

ニコニコのプレミアム会員の方なら、配信を放送終了後から7日間は見られるはずなので、是非とも御覧になってください。お早めに!

ゲームバランス

さて、先日の記事でMSXのゲームプログラミングは一旦終了したはずでした。ところが、自分で何度かプレイしてみたところ、

 

    敵の動きがゆるくて、コツさえつかめば永遠に死なない、つーか死ねないw

 

ということが発覚したのでした…! しかもリハビリ中さんも、さすがゲーマーだけあって、放送中にすぐにコツを掴んでしまったのです!

 

    これはマズいぞ…。ゲームとして成り立たないじゃないか! (; ・`д・´)

 

ゲームプログラマー(?)としての闘争心がめらめらと燃えてきたのでありました… 。

…いやいや、こうやってプレイしつつゲームバランスを整えていくのがゲームプログラミングの醍醐味の一つなのですよ、ネ。(*´ω`*)

ゲームバランスの調整

さて、どうしよう? 敵に弾を打たせる? 敵の動くアルゴリズムを変える?  でも、BASIC だからこれ以上処理を増やすと重くなるし、それに、コードをまたイチから入力するのは大変だよなぁ。

コードの変更が少なく、動作も重くならないようにしたいので、以下の方法をとることにしました。

  • 敵もライフ制にする。3発当てるとやっつけられる
  • 敵のライフが減るたびに、自分に近づく速度を速くする
  • 敵を倒した後に新しい敵が出てくる場所をランダムにする
  • 自分のミサイルの速度を少し遅くする

そして、これはキツくする方向じゃないですが、放送中にリスナーの方が出されたアイデア:

も実装することにしました。5000点ごとにしてみました。

これで、よりゲームらしくなり、以前よりも攻防が楽しめるようになったのではないかと思います。(*^^)v

では、コードの変更点を説明していきます。

敵をライフ制に

まず、ライフに応じて色を変えるようにします。緑→黄→赤と信号の様に変わり、赤の状態で打つと敵をやっつけられるようにします。このために、配列 EC を DIM で宣言し、EC(0)~EC(2) にライフに応じた色番号を代入しています。(60行目)

敵のスプライトの表示色は 630 行目で EL に応じて決まるようにしています。 

次に、敵のライフを表す変数 EL を新しく導入します。初期値を3として、弾が当たるごとに1減らし、0になったら見事やっつけたことになるようにします。(220, 742~744行目)

なお、敵のライフを減らした時、敵が弾に打たれてバウンドして動くような感じにしました。(742行目のEHの値)

また、このタイミングで20点入るようにしました。(746行目)

そして、敵のライフが減るたびに速く動くようにするため、EL が減ると敵の速度 EH と EV が大きな値に振れやすくなるようにしました。(520~530行目)

敵をやっつけた

まず、やっつけたパターンの表示とBEEP音の出し方を少しだけ変えました。(750行目)

そして、やっつけたときには60点入るようにしました。ライフを2つ減らしたときに 2×20=40点入るから、合わせて一匹ごとに100点入ることになります。(760行目)

やっつけた後、新しい敵の出現位置をランダムな場所にしますが、あまりに自分に近いとすぐやられてしまうので、ある程度離れた場所になるまでランダムな値を計算し続けるようにしました。(770~780行目)

その他の修正

自分のミサイルの移動速度を 12 ドットずつから 10 ドットずつにしました。(430行目)

エクステンドの処理は、30行目と 901~902行目です。変数 XT がエクステンドになる点数、XS がエクステンドになった時に、XT に加えて次のエクステンドを決める点数です。点数 SC が XT 以上になったら、変数 RIHA を増やして、自機スプライトを BEEP を鳴らしつつ光らせて、残機表示を更新します。(902~905行目)

さらに細かい修正

いままでの背景は MSX が立ち上がった時の水色と青のままでしたが、真っ黒に変更しました。そして、ゲームオーバーになったら元の色に戻るようにしました。(10行目、1010行目)

自機の色を、白から薄い黄色に変更しました。(610行目)

ちなみに

MSX BASICの変数名は、2文字までしか認識しないらしく、RIHA という変数と RI という変数は同一とみなされることが分かりました。RIBBON でも RIRIRI でも同じものを指します。勉強不足でした。

また、前のコードからの変更を最小にするために、新しく追加したコードの行番号が細かい刻みになっています。ご了承ください。

実行!

ソースコードを打ち込んで run コマンドで実行します。

あるいは、WebMSX のサイトに飛び、Alt+B で Input Text のウィンドウを出してソースコードをコピペして OK を押します。MSX の画面に全部ソースコードが入力されたら、run コマンドで実行しましょう。

画面イメージ

こんな感じです。黒背景になりました。また、敵が黄色なのは、敵のライフが1減ったからですね。

f:id:nyagbon:20190221172101p:plain

ゲームバランスはどうなったか?

自分でやってみたところ、前よりは難しくなりました! 特に赤く怒った敵との攻防が難しくなりましたね! でも慣れるとやっぱりカンタンかな? もっと追求したい方は、いろいろとコード内の数値をいじって試してみてください。

また、このブログやツイッターなどで感想やアイデアをコメントいただければなお一層嬉しいです! (*´ω`*)

ソースコード

赤い部分が前回のコードから変更、追加した部分です。既にコードを入力されている方は、赤い部分だけ入力し直していただければ新しいバージョンになります。

それでは、お楽しみください! ではまた~。

 

10 SCREEN 1,2,0:KEY OFF:COLOR 15,1,1
20 ' INITIALIZE
30 SC=0:RIHA=3:XT=5000:XS=5000
40 GOSUB 980
50 ' :ENEMY COLORS
60 DIM EC(2):EC(0)=6:EC(1)=10:EC(2)=3
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:EL=3 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-10 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)*(9-EL*2)+1) 530 EV=EV+SGN(Y-EY)*INT(RND(1)*(9-EL*2)+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),11,1 620 IF BB=1 THEN PUTSPRITE 2,(BX,BY),8,2 ELSE PUTSPRITE 2,,,0 630 PUTSPRITE 3,(EX,EY),EC(EL-1),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),15,3:BEEP 742 EH=-10:EL=EL-1 744 IF EL=0 THEN 750 746 SC=SC+20:GOSUB 980 748 BB=0:GOTO 800 750 PUTSPRITE 3,(EX,EY),5,4:BEEP:PUTSPRITE 3,,,4:BEEP 760 SC=SC+60:BB=0:EH=0:EV=0:EL=3 770 EX=INT(RND(1)*240):EY=INT(RND(1)*180) 780 IF X-48<=EX+64 AND EX-48<=X+64 AND Y-48<=EY+64 AND EY-48<=Y+64 THEN 770 790 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
901 IF SC<XT THEN 910
902 XT=XT+XS:RIHA=RIHA+1:GOSUB 980
903 FOR I=0 TO 2
904 PUTSPRITE 1,(X,Y),15,1:BEEP:PUTSPRITE 1,(X,Y),4,1:BEEP
905 NEXT
909 ' END THIS GAME?
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 SCREEN 1,1,1:KEY ON:COLOR 15,4,7 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