arcanum_jp’s blog

おっさんの日記

IchigoJamでゲームを作る

 こんにちは、arcanum_jpです。先日も書いたとおり、復活したベーマガに掲載されましたので記念に、このゲームの作っていたときの思考を再現して、IchigoJamでのゲームの作り方を解説してみたいと思います。IchigoJamでゲームを作ってみたい方に少しでも参考になればと思います。

表題の件です。2015年12月19日の発売なのに11月に入ってからゲームを投稿したので、今回は駄目かなぁとか思っていたのですが、アマゾンで買って今日配達されて、見てみたら掲載されていました。クリスマスイブの僕へのプレゼントです。

http://d.hatena.ne.jp/arcanum_jp/20151224/1450964790

IchigoJamの画面構成と、ゲーム画面全体を決める

 IchigoJamは画面がこのように、横32、縦24のボックスの集まりから出来ていて、一つ一つに文字が入ります。数字が0から始まっているのは、画面に文字を表示したいときに、x座標、y座標で指定しますが、その指定の仕方が0から始まるためです。

 今回のゲーム「爆炎チキンレース」は、某埠頭に集まる暴走族ですので、埠頭といえば、海が表現されている必要があります。なので、先の画面イメージにゲーム画面を書き込んで見ましょう。ここで画面を作るときに注意ですが、一番下の行は使えません。何故かというと、一番下の行に表示しようとすると、IchigoJamは、次の行が使えるように、画面を上にスクロールさせてしまいます。

 自分が作ったときに22までとしたのは単にIchigoJamの画面の範囲を調べずにやってしまったのが原因です。=͟͟͞͞( •̀д•́)))

 じゃぁ、これをIchigoJam BASICで作ってみます。コマンドはLOCATE,PRINTを使いますが、埠頭を上のほうから下まで繰り返し描画するのでFOR NEXTを使っているのに注意してください。

10 CLS:X=1:Y=22
20 FOR I=1 TO 21:LOCATE 0,I:PRINT"|":LOCATE 31,I:PRINT"|":NEXT
30 FOR I=1 TO 6:LOCATE 1,I:FOR J=1 TO 30:PRINT"~";:NEXT:NEXT
40 FOR I=1 TO 30:LOCATE I, 7:PRINT"=":NEXT
50 LOCATE X,Y:PRINT"@"
60 GOTO 60

 お、雰囲気出ていますねぇ・・

時機、爆炎の描画

 画面イメージを実際のIchigoJamに表示できると楽しいです。俄然作るぞ!と言う意識が出来てきます。ここからいろいろと試行錯誤していきます。

時機の描画

 次に実際に時機(以下爆炎)を動かしてみましょう。スコアとして変数「S」と、描画が早すぎるとゲームにならないので、ウエイトをしています。60行目が増えてますね。

10 CLS:X=1:Y=22:S=0
20 FOR I=1 TO 21:LOCATE 0,I:PRINT"|":LOCATE 31,I:PRINT"|":NEXT
30 FOR I=1 TO 6:LOCATE 1,I:FOR J=1 TO 30:PRINT"~";:NEXT:NEXT
40 FOR I=1 TO 30:LOCATE I, 7:PRINT"=":NEXT
50 LOCATE X,Y:PRINT"@"
60 Y=Y-1:S=S+1:WAIT 6
110 LOCATE 0,0:PRINT "SCORE:";S
120 GOTO 50

 おお!爆炎が海のほうに動いて行きます。だんだんゲームらしくなってきました。


ゲーム終了条件

 でもこの時点では海に落ちた処理を行っていないので、そのまま海を渡って永遠と行ってしまいます。そこでゲーム終了の条件だけ入れておきます。Y座標が海の境界だったらゲームオーバーにするのですね。

 70行目がその判定で、Y座標が6以下になったらゲームオーバーの行に飛ばしています。

10 CLS:X=1:Y=22:S=0
20 FOR I=1 TO 21:LOCATE 0,I:PRINT"|":LOCATE 31,I:PRINT"|":NEXT
30 FOR I=1 TO 6:LOCATE 1,I:FOR J=1 TO 30:PRINT"~";:NEXT:NEXT
40 FOR I=1 TO 30:LOCATE I, 7:PRINT"=":NEXT
50 LOCATE X,Y:PRINT"@"
60 Y=Y-1:S=S+1:WAIT 6
70 IF Y<=6 GOTO 130
110 LOCATE 0,0:PRINT "SCORE:";S
120 GOTO 50
130 LOCATE 0,21:PRINT"GAME OVER!!"


時機の生き延びる条件

                  
 では海に落ちる前にスペースキーを押したら、次の列の爆炎がスタートするようにしていみます。ここは簡単で、INKEY()関数で32が帰ってきたら、X座標を右にずらし,Y座標を初期化します。80行目がそれにあたります。ほぼこれでゲームになってきました。

10 CLS:X=1:Y=22:S=0
20 FOR I=1 TO 21:LOCATE 0,I:PRINT"|":LOCATE 31,I:PRINT"|":NEXT
30 FOR I=1 TO 6:LOCATE 1,I:FOR J=1 TO 30:PRINT"~";:NEXT:NEXT
40 FOR I=1 TO 30:LOCATE I, 7:PRINT"=":NEXT
50 LOCATE X,Y:PRINT"@"
60 Y=Y-1:S=S+1:WAIT 6
70 IF Y<=6 GOTO 130
80 K=INKEY()
90 IF K=32 Y=22:X=X+1
110 LOCATE 0,0:PRINT "SCORE:";S
120 GOTO 50
130 LOCATE 0,21:PRINT"GAME OVER!!"


ゲームクリア処理

 
 さてゲームらしくなってきましたが、これだと右端に行ったらどうなるのでしょうか?ゲーム面クリアの処理が必要です。これは画面の右端に行ったらまた画面をクリアして、スタートさせてやります。暴走族たちの夜は長いのです。100行目でその条件を判断し、右端まで来ていたら各種変数を初期化して画面描画の20行目に飛ばしています。

10 CLS:X=1:Y=22:S=0
20 FOR I=1 TO 21:LOCATE 0,I:PRINT"|":LOCATE 31,I:PRINT"|":NEXT
30 FOR I=1 TO 6:LOCATE 1,I:FOR J=1 TO 30:PRINT"~";:NEXT:NEXT
40 FOR I=1 TO 30:LOCATE I, 7:PRINT"=":NEXT
50 LOCATE X,Y:PRINT"@"
60 Y=Y-1:S=S+1:WAIT 6
70 IF Y<=6 GOTO 130
80 K=INKEY()
90 IF K=32 Y=22:X=X+1
100 IF X>30 X=1:CLS:GOTO 20
110 LOCATE 0,0:PRINT "SCORE:";S
120 GOTO 50
130 LOCATE 0,21:PRINT"GAME OVER!!"

 さてこれで一応ゲームとしての体裁は整いました。あれ?なんか面白くない。なんだろこれ??(=゚ω゚)

ゲームバランス

 作ってみて、何か足りないと思いました。ゲームにつき物の緊張感です。このままでは、1面が間延びした感じですし、なにより難しくありませんし、その繰り返しです。改善策としてこんなことを考えました。

  • 画面の幅が広すぎる
    • もうちょっと狭くして1面を簡単にして次のステージにいきやすくなります。(飽きません)
  • 爆炎のスピードが遅い
    • だんだん、爆炎が速くなってくる。某像族たちはエキサイトしていくのです。
  • 海の距離が遠いので簡単
    • だんだん海までの距離を近くして難しくします。
画面の幅が広すぎる

 画面の幅が広すぎるので、狭くしてみます。改造する部分は、埠頭の描画処理、面クリアの条件部分と複数個所に渡るので、なるべく一箇所の変更で済むよう、変数「H」で制御してみます。

10 CLS:X=1:Y=22:S=0:H=20
20 FOR I=1 TO 21:LOCATE 0,I:PRINT"|":LOCATE H+1,I:PRINT"|":NEXT
30 FOR I=1 TO 6:LOCATE 1,I:FOR J=1 TO H:PRINT"~";:NEXT:NEXT
40 FOR I=1 TO H:LOCATE I, 7:PRINT"=":NEXT
50 LOCATE X,Y:PRINT"@"
60 Y=Y-1:S=S+1:WAIT 6
70 IF Y<=6 GOTO 130
80 K=INKEY()
90 IF K=32 Y=22:X=X+1
100 IF X>H X=1:CLS:GOTO 20
110 LOCATE 0,0:PRINT "SCORE:";S
120 GOTO 50
130 LOCATE 0,21:PRINT"GAME OVER!!"

 お、これで各面は簡単になるが、面を移動しやすいので、ゲーム中間延びした感覚が起きず、緊張感を持続させられます。

だんだん爆炎が速くなる

 だんだん爆炎を早くして難しくしていきます。速くするタイミングはどこがいいでしょうか?面クリアしたら次の面はちょっと爆炎が速くなるというのはどうでしょうか?夜もふけていき、暴走族どもはエキサイティン!です。

 ここでは、面クリアした後に画面を再度描画しますが、ここでウエイトの変数を小さくしています。(実は100行目でやればよいかと思ったのですが、IFの中にIFを書きたくなかったため、画面描画のときに処理を書いています、今思うともうちょっとましな場所に書けそうですがゲフンゲフン・・・)

10 CLS:X=1:Y=22:S=0:H=20:W=6
20 FOR I=1 TO 21:LOCATE 0,I:PRINT"|":LOCATE H+1,I:PRINT"|":NEXT
30 FOR I=1 TO 6:LOCATE 1,I:FOR J=1 TO H:PRINT"~";:NEXT:NEXT
40 FOR I=1 TO H:LOCATE I, 7:PRINT"=":NEXT:W=W-1:IF W<0 W=0
50 LOCATE X,Y:PRINT"@"
60 Y=Y-1:S=S+1:WAIT W
70 IF Y<=6 GOTO 130
80 K=INKEY()
90 IF K=32 Y=22:X=X+1
100 IF X>H X=1:CLS:GOTO 20
110 LOCATE 0,0:PRINT "SCORE:";S
120 GOTO 50
130 LOCATE 0,21:PRINT"GAME OVER!!"
だんだん、海の距離が近くなってくる

 だんだん暴走族は海までの距離を近くしていきます。海のY座標として、変数「R」で表現します。海の境界までを描画する、海に飛び込んでしまう条件あたりを変えればいいのかなと思います。あと何回か作っている最中にやってみて、この距離もあんまり長いと、プレイが長い時間になり興ざめするので、何回か試行錯誤し、最後は誌面にあるようにR=10で落ち着きました。

10 CLS:X=1:Y=22:S=0:H=20:W=6:R=6
20 FOR I=1 TO 21:LOCATE 0,I:PRINT"|":LOCATE H+1,I:PRINT"|":NEXT
30 FOR I=1 TO R-1:LOCATE 1,I:FOR J=1 TO H:PRINT"~";:NEXT:NEXT
40 FOR I=1 TO H:LOCATE I, R:PRINT"=":NEXT:W=W-1:IF W<0 W=0
50 LOCATE X,Y:PRINT"@"
60 Y=Y-1:S=S+1:WAIT W
70 IF Y<=R GOTO 130
80 K=INKEY()
90 IF K=32 Y=22:X=X+1
100 IF X>H R=R+2:X=1:CLS:GOTO 20
110 LOCATE 0,0:PRINT "SCORE:";S
120 GOTO 50
130 LOCATE 0,21:PRINT"GAME OVER!!"

出来た!

 どうでしょうか?ゲームを作るって以外と簡単ではないでしょうか?画面を紙に描いてみてそのとおりにIchigoJam上に表示して、それからひとつひとつ肉付けする形で作っていけばいいんです。方眼紙を用意して画面のイメージを作るなんてはお子さんにさせてもいいですし、そこからプログラムを起こすのはお父さんの役目、そして二人でいろいろ話し合いながら出来ると楽しそうです。

 そして出来上がったら、電子工作マガジン編集部に送ります。ベーマガに採用されたら規定の原稿料ももらえるそうなので、お子さんが自分で考えた物が出来上がり、お金に変わっていく感覚を得られ、貴重な体験を出来ると思いますし、なにより鼻が高いでしょう。お父さんも同僚に息子自慢ができます。

 今回のは実際には、初めは左右のフレームが無かったら画面が寂しいので付けたなど試行錯誤があったりしたのですが、いくつか省略して書いています。ゲームを作る際の助けに少しでもなればと思い書いてみました。