FuzeBasicでヘビのゲームを作ろう!
FuzeのサイトにあるWorksheetsの最終回として、ヘビのゲームを作りたいと思います。
こんな感じのゲームです。(意外とハマるかも?)
ヘビのゲームを作る
ヘビを表示する
DEFCHARコマンドでヘビのパーツの絵を設定しています。
キーボードの矢印キーで、ヘビを移動することができます。
関数が初めて登場しています。
DEF PROC 関数の名前
~
ENDPROC
関数は、やりたいことをまとめたものになります。
DEF PROC と ENDPROCの間にやりたいことを書いておきます。
そして、PROCコマンドで呼ぶだけで、関数の中に書かれていることを実行します。
PROC 関数の名前
いろいろなところで行いたい処理をまとめて関数にしておくと便利です。
snake_1.fuzeを見てみると、ゲームとしての処理は、最初の部分だけになります。
setup関数で初期化した後は、LOOP内でヘビを動かしているだけです。
このように、ゲームは「初期化処理」を行った後に、「更新処理」をループで回す作り方が一般的になっています。
PROC setup LOOP IF newlevel = TRUE THEN PROC newlevel IF SCANKEYBOARD(SCANUP) AND dir <> 3 THEN dir = 1 IF SCANKEYBOARD(SCANRIGHT) AND dir <> 4 THEN dir = 2 IF SCANKEYBOARD(SCANDOWN) AND dir <> 1 THEN dir = 3 IF SCANKEYBOARD(SCANLEFT) AND dir <> 2 THEN dir = 4 IF TIME - timer > speed THEN PROC snake UPDATE REPEAT END
snake_1.fuze(クリックすると開きます)
PROC setup LOOP IF newlevel = TRUE THEN PROC newlevel IF SCANKEYBOARD(SCANUP) AND dir <> 3 THEN dir = 1 IF SCANKEYBOARD(SCANRIGHT) AND dir <> 4 THEN dir = 2 IF SCANKEYBOARD(SCANDOWN) AND dir <> 1 THEN dir = 3 IF SCANKEYBOARD(SCANLEFT) AND dir <> 2 THEN dir = 4 IF TIME - timer > speed THEN PROC snake UPDATE REPEAT END DEF PROC resetgame CLS snakelength = 2 speed = 200 newlevel = TRUE ENDPROC DEF PROC newlevel FONTSIZE(zoom) screenheight = THEIGHT - 2 screenwidth = TWIDTH - 1 DIM screen(screenwidth, screenheight) FOR segment = 0 TO snakelength LOOP snakex(segment) = INT(TWIDTH / 2) snakey(segment) = INT(THEIGHT / 2) REPEAT dir = 1 newlevel = FALSE ENDPROC DEF PROC setup FULLSCREEN = 1 UPDATEMODE = 0 zoom = 6 timer = TIME FONTSIZE(zoom) DIM snakex(200) DIM snakey(200) DEFCHAR(1, 60, 126, 219, 255, 255, 255, 153, 199, 126, 60) DEFCHAR(2, 0, 60, 126, 255, 255, 255, 255, 126, 60, 0) DEFCHAR(3, 0, 0, 60, 126, 126, 126, 126, 60, 0, 0) DEFCHAR(4, 170, 85, 170, 85, 170, 85, 170, 85, 170, 85) DEFCHAR(5, 28, 126, 123, 255, 255, 255, 255, 126, 126, 24) PROC resetgame ENDPROC DEF PROC snake INK = LIGHTGREEN FOR segment = snakelength + 2 TO 1 STEP -1 LOOP snakex(segment) = snakex(segment - 1) snakey(segment) = snakey(segment - 1) REPEAT IF dir = 1 THEN snakey(0) = snakey(0) - 1 IF dir = 2 THEN snakex(0) = snakex(0) + 1 IF dir = 3 THEN snakey(0) = snakey(0) + 1 IF dir = 4 THEN snakex(0) = snakex(0) - 1 PRINTAT(snakex(0),snakey(0));CHR$(1); screen(snakex(0),snakey(0)) = 1 FOR segment = 1 TO snakelength LOOP PRINTAT(snakex(segment), snakey(segment));CHR$(2); screen(snakex(0),snakey(0)) = 2 REPEAT PRINTAT(snakex(segment),snakey(segment));CHR$(3); screen(snakex(segment),snakey(segment)) = 3 PRINTAT(snakex(segment+1),snakey(segment+1));" "; screen(snakex(segment+1),snakey(segment+1)) = 0 timer = TIME ENDPROC
カベを作る
screen変数で、画面上に何があるかを管理しています。
何もなければ0、ヘビの頭が1、ヘビの胴体が2、ヘビのしっぽが3、そして、カベが4になります。
snake_2.fuze(クリックすると開きます)
DEF PROC newlevel .... DIM screen(screenwidth, screenheight) FOR column = 0 TO screenwidth LOOP screen(column,1) = 4 screen(column,screenheight) = 4 REPEAT FOR row = 2 TO screenheight - 1 LOOP screen(0,row) = 4 screen(screenwidth,row) = 4 REPEAT CLS FOR column = 0 TO screenwidth LOOP FOR row = 0 TO screenheight LOOP content = screen(column,row) IF content = 4 THEN INK = BLUE IF content <> 0 THEN PRINTAT(column,row);CHR$(content); REPEAT REPEAT FOR segment = 0 TO snakelength LOOP .... ENDPROC
ゲームオーバーを作る
ヘビの頭が何かにぶつかったらゲームオーバーにします。
ぶつかったかどうかは、ヘビの頭のある場所にscreen変数で何かあるかどうかを調べて判定しています。
ゲームオーバーになったときに、PLAYMUSICコマンドで音を鳴らしています。
音は %userprofile%\Documents\Fuze\extras\sounds フォルダに入っています。
ゲームオーバーの文字を表示するときに、TWIDTHとTHEIGHTを使っています。
これは、フォント単位の画面の幅と高さになります。
以前、GWIDTHとGHEIGHTを使いましたが、こちらはグラフィック描画で使う単位での画面の幅と高さになります。
文字を書くときは、TWIDTHとTHEIGHTを使うと覚えておいていいと思います。
TはTextを表しています。
snake_3.fuze(クリックすると開きます)
DEF PROC setup .... DIM snakex(200) DIM snakey(200) tune1 = LOADMUSIC("snaketune1.wav") tune2 = LOADMUSIC("snaketune4.wav") tune3 = LOADMUSIC("snaketune3.wav") tune4 = LOADMUSIC("snakeintro.mp3") gulp = LOADSAMPLE("gulp.wav") DEFCHAR(1, 60, 126, 219, 255, 255, 255, 153, 199, 126, 60) .... ENDPROC DEF PROC snake .... IF dir = 3 THEN snakey(0) = snakey(0) + 1 IF dir = 4 THEN snakex(0) = snakex(0) - 1 IF screen(snakex(0),snakey(0)) <> 0 THEN PROC gameend PRINTAT(snakex(0),snakey(0));CHR$(1); .... ENDPROC DEF PROC gameend PLAYMUSIC(tune2,0) text1$ = "Ouch!" text2$ = "That's Game Over" starttime = TIME WHILE TIME - starttime < 4000 LOOP FOR segment = 1 TO snakelength LOOP INK = RND(3) + 7 PRINTAT(snakex(segment),snakey(segment));CHR$(3); PRINTAT(snakex(0),snakey(0));CHR$(1); PRINTAT(snakex(segment+1),snakey(segment+1));" "; REPEAT INK = RND(30) PRINTAT(TWIDTH/2-LEN(text1$)/2,THEIGHT/2);text1$ PRINTAT(TWIDTH/2-LEN(text2$)/2,THEIGHT/2+2);text2$ UPDATE REPEAT PROC resetgame ENDPROC
エサを置く
エサを画面上にランダムに置いていきます。
screen変数を調べて、その場所に何もないことを確認しています。
snake_4.fuze(クリックすると開きます)
DEF PROC resetgame .... newlevel = TRUE maxfood = 4 foodcounter = maxfood score = 0 level = 0 ENDPROC DEF PROC newlevel .... screen(screenwidth,row) = 4 REPEAT FOR counter = 0 TO maxfood LOOP empty = TRUE WHILE empty = TRUE LOOP foodx = RND(screenwidth - 2) + 1 foody = RND(screenheight - 2) + 2 IF screen(foodx,foody) = 0 THEN screen(foodx,foody) = 5 empty = FALSE ENDIF REPEAT REPEAT CLS FOR column = 0 TO screenwidth LOOP FOR row = 0 TO screenheight LOOP content = screen(column,row) IF content = 4 THEN INK = BLUE IF content = 5 THEN INK = ORANGE TONE(1,50,100,.1) UPDATE WAIT(0.1) ENDIF IF content <> 0 THEN PRINTAT(column,row);CHR$(content); REPEAT REPEAT FOR segment = 0 TO snakelength LOOP snakex(segment) = INT(TWIDTH / 2) snakey(segment) = INT(THEIGHT / 2) REPEAT dir = 1 newlevel = FALSE maxfood = maxfood + 1 foodcounter = maxfood ENDPROC
エサを食べる
ヘビの頭が、エサのある場所に到達したら、エサを食べます。
エサを食べると、ヘビの胴体が伸びます。
これがゲームを面白くしていますね!
その分、ゲームが難しくなるけど。
snake_5.fuze(クリックすると開きます)
DEF PROC snake .... IF dir = 4 THEN snakex(0) = snakex(0) - 1 IF screen(snakex(0),snakey(0)) = 5 THEN PROC checkfood IF screen(snakex(0),snakey(0)) <> 0 THEN PROC gameend .... ENDPROC DEF PROC checkfood PROC updatescore(100) PLAYSAMPLE(0,gulp,0) snakelength = snakelength + 1 screen(snakex(0),snakey(0)) = 0 foodcounter = foodcounter - 1 IF foodcounter <= 0 THEN PLAYMUSIC(tune3,0) text$ = "Yummy!" starttime = TIME WHILE TIME - starttime < 3000 LOOP FOR segment = 1 TO snakelength LOOP INK = RND(3) + 13 PRINTAT(snakex(segment),snakey(segment));CHR$(3); PRINTAT(snakex(0),snakey(0));CHR$(1); REPEAT INK = RND(30) PRINTAT(TWIDTH/2-LEN(text$)/2,THEIGHT/2);text$ UPDATE REPEAT newlevel = TRUE ENDIF ENDPROC DEF PROC updatescore(value) score = score + value INK = YELLOW PRINTAT(0,0);"Score ";score; PRINTAT(TWIDTH/2-4,0);"Level ";level; UPDATE ENDPROC DEF PROC newlevel PLAYMUSIC(tune1,0) .... foodcounter = maxfood level = level + 1 PROC updatescore(0) speed = speed - 10 IF speed <= 50 THEN speed = 50 ENDPROC
タイトル画面を作る
ゲームを起動したら、最初に表示されるタイトル画面を作ります。
ゲームオーバーした後も、タイトル画面に戻ります。
snake_6.fuze(クリックすると開きます)
DEF PROC resetgame CLS text$ = "Play Snake" text1$ = "Press SPACE to play" text2$ = "Cursor keys control Snake" PLAYMUSIC(tune4,0) WHILE SCANKEYBOARD(SCANSPACE) = FALSE LOOP INK = RND(3) + 13 FONTSIZE(5) PRINTAT(TWIDTH/2-LEN(text$)/2,(THEIGHT/2)-1);text$ IF TWIDTH < 35 THEN FONTSIZE(3) INK = RND(30) PRINTAT(TWIDTH/2-LEN(text1$)/2,THEIGHT/2+2);text1$ PRINTAT(TWIDTH/2-LEN(text2$)/2,THEIGHT/2+3);text2$ UPDATE REPEAT PLAYMUSIC(tune1,0) snakelength = 2 .... ENDPROC
まとめ
ヘビのゲームで遊んでみると、意外と面白いですね。
何が面白いのか考えてみましょう。
そして、もっと面白くなるように改良してみましょう!
GitHubにソースをアップしました。
参考にしてください。
ヘビのゲームのソースコード