パソコン活用研究5番街(Visual Basic、Excel(VBA)、BASIC プログラミング研究)
BASICゲームのプログラムサンプル1
簡単なBASICゲーム作成のための説明。
のろのろ動くかめを安全に反対側まで移動させるゲーム
FM8Kame.basのプログラムの説明
ゲームの概要とプログラムのダウンロードはN88互換Basic カメの道路横断をご参照
もともとFM-7/8用に作成したゲームをN88互換BASIC for Win用に少し変更したバージョンです。
ここで説明用に使ったのはFM8Kame for N88互換Basic ver0.7.1a
オリジナルはプログラミングを始めたばかりの頃に作成したもので、そのコードをほぼそのまま引き継いで
いるので、変数の使い方や、キャラの移動処理などはあまりきれいなコードではないです。
1.プログラムの全体構成
プログラムの全体構成は以下の通り
黄色はサブルーチンにしている部分です。
10〜450行 初期設定
460〜570行 メインルーチン
メインルーチンの中で、以下の3つのサブルーチンを順番に呼び出し、最後570行から460行にgotoで
戻して、メインルーチンをぐるぐる回しています。
@自分のキャラであるカメ(@)の移動と当たり判定
A牛(U)の移動と当たり判定
B虎(T)の移動と当たり判定
メインルーチンの中で、ゲーム終了フラグ(over・・0 ゲーム継続中 1 ゲーム終了 2 面クリア)を
チェックし、over=1 の時はゲーム終了処理(1310行〜)にジャンプし、over=2 の時は、面クリア処理(1150〜1300行)
にジャンプします。
580〜760行 カメ(自分のキャラ)の移動と当たり判定のサブルーチン
770〜940行 牛の移動と当たり判定のサブルーチン
950〜1140行 虎の移動と当たり判定のサブルーチン
1150〜1300行 面クリアした時の処理
1310行〜 ゲーム終了処理
2. プログラム主要部の説明
以下、ゲーム作成でよく使うコードについていくつか説明します。
(1) 変数
50行でdefint a-zと全変数を整数型になるように宣言していますが、これは少しでも処理速度を
速くするためです。実数型より整数型のほうが処理速度が速いというのが通説 −>Basicの実行速度向上。
cx( ), cy( ) は牛の座標
tx( ), ty( ) は虎の座標
char( ) はその座標にあるキャラクタの識別用 0 何もいない 1 牛 2 虎
sc スコア hsc ハイスコア
max 牛の数 tmax 虎の数
over ゲームの状態 0 継続中 1 ゲームオーバー 2 面クリア
50 defint a-z 60 DIM cx(35),cy(35),char(40,20),tx(15),ty(15) 70〜140 省略 150 hsc=0 160 sc=0:max=15:tmax=2:over=0 sorede
@最初の画面の表示
最初の画面の表示部分です。char( )はその座標に移動できるかの判定処理などに使います。
Aキャラの初期配置
270〜280行 カメ(自キャラ)の配置
290〜300行 牛や虎のキャラの配置にあたり、乱数系列を初期化する
time$(時刻)から秒の部分を切り取って、乱数のシードにするのはゲームをやるたびに
違った乱数系列を得るための割と定番なやり方。
乱数の使い方についてはー>
・乱数 Basicの乱数の使い方
・乱数を使う準備 Cでの乱数の使い方ですが、コンピュータ内部でどうやって乱数を生成しているのかのお話
・乱数を使う1 こちらもCで乱数を使うときの話
ここではさらに起動時にユーザに入力させた値(q)も加えて、できるだけいろいろなシードを
与えられるように工夫しています(微々たる工夫ですが)
310〜380行 牛の配置
350行で、既にキャラの配置済みの場所は避けるようにしています。
forのループ文で制御用に使う変数は普通は,i,j,m,k などを使うのだが
ここはeを使っている。(あんまり美しくないね)
390〜440行 虎の配置
270 X=20:Y=13 280 LOCATE X,Y:PRINT"@"
290 time=val(right$(time$,2)) 300 randomize (time+q) 310 color 7 320 FOR e=1 TO max 330 cy(e)=INT(RND(1)*6)+6 340 cx(e)=INT(RND(1)*18)+11 350 if char(cx(e),cy(e))=1 then goto 330 '既にキャラがあれば、やりなおし 360 LOCATE cx(e),cy(e):PRINT"C" 370 char(cx(e),cy(e))=1 380 NEXT 390 color 2 400 FOR e=1 TO tmax 410 ty(e)=INT(RND(1)*6)+6:tx(e)=INT(RND(1)*18)+11 420 if char(tx(e),ty(e)) <>0 then goto 410 430 LOCATE tx(e),ty(e):PRINT"T": char(tx(e),ty(e))=2 440 NEXT
Bメインルーチン
460行 カメ(自キャラ)の移動と当たり判定のサブルーチンへ
490, 530行 虎の移動と当たり判定のサブルーチンへ。虎の移動速度をカメ(自キャラ)の倍にするため
メインルーチンの中で2回呼んでいる。
510行 牛の移動と当たり判定のサブルーチンへ
480, 500, 520行の3回 overの値を見て、ゲームオーバーの処理(と480行では面クリアの処理)への分岐
最近のハイスペックなPCでは処理が速すぎてゲームにならないので、waitを入れる工夫を
470, 550〜560行でしている。
N88互換BASICにはwaitに該当する命令がないので、メインルーチンで1秒は消費するようにしている。
460 GOSUB 580 470 time1=val(right$(time$,2)) 480 if over=1 then 1310 else if over=2 then 1150 490 GOSUB 950 500 if over=1 then 1310 510 GOSUB 770 520 if over=1 then 1310 530 GOSUB 950 540 if over=1 then 1310 550 time2=val(right$(time$,2)) 560 if time1=time2 then goto 550 '最近のPCでは速すぎるのでwaitを入れる 570 GOTO 460
C カメ(自キャラ)の移動と当たり判定
カメの移動方向はu$の値を読み取って決めていますが、少しキー入力のオートリピートによる
誤動作を防ぐ工夫を入れています。
キー入力のオートリピートが有効なハードウェア(PC)では、キーを押しっぱなしにしているとキーバッファ
に入力されたキーが蓄積され、思った通りにキャラを移動させられません。
このため、キーバッファを空にし、最後に押されたキーだけが有効になるような工夫を580〜600行では
行っています。完ぺきではありませんが、これである程度キーのオートリピートによるキャラの誤動作を
防止できています。
620行でカメをいったん消しています。
630〜660行で押されたキーにより、カメの次に移動する座標を決めています。
670〜700行では、カメの移動範囲を 10<= X <=30, 5<= Y <=13 の範囲に制限しています。
710行 カメがY=5まで移動した場合は、その面をクリアです。フラグとしてover=2を設定します。
720行 Iは面クリアにかかった時間(メインルーチンを回った回数)をカウントしています。
早くクリアすればそれだけ大きくスコアが加算されます。
730〜740行 当たり判定をしています。牛や虎のいる場所に移動した場合はゲームオーバーになります。
750行 620行で消したカメを新しい移動先の座標に表示します。
580 u$="" 590 ux$=inkey$ 600 if ux$="" then goto 610 else u$=ux$:goto 590 610 IF u$="5"THEN RETURN 620 LOCATE X,Y:PRINT" " 630 IF U$="4" THEN X=X-1 640 IF U$="6" THEN X=X+1 650 IF U$="8" THEN Y=Y-1 660 IF U$="2" THEN Y=Y+1 670 IF X<10 THEN X=10 680 IF X>30 THEN X=30 690 IF Y<5 THEN Y=5 700 IF Y>13 THEN Y=13 710 IF Y=5 THEN over=2 720 I=I+1 730 O=char(X,Y) 740 IF O=1 OR O=2 THEN over=1 'GAME OVER 750 LOCATE X,Y:color 4:PRINT"@" 760 RETURN
D牛の移動と当たり判定
770行 変数Aは、この牛の移動サブルーチンを繰り返すためのカウンタにしています。
790行 3回このサブルーチンを回ったら(=牛が3頭動いたら)、このサブルーチンからReturnします。
変数Pは牛のNo.です。
800行 maxにはその面で表示する牛の数が入っており、P>max になったらP=1に戻します。
810行 牛を消す処理
820〜900行 牛の次の移動先の決定と表示をします。牛は単純に1マスづつ左に移動します。
830〜840行 牛が左端を超えたら(X<10)、右端(X=30)に移動させます。
880行 決定した移動先に既にキャラが存在しているときは元の位置にとどまらせます。
r1,t1に元の座標を保持しています。(このあたりの変数の使い方がイマイチきれいでないです)
930行 当たり判定。カメ(自キャラ)に当たったときは、終了フラグover=1をたてます。
なお、790行のように IF文の終わりに、REM文(')を書くとN88互換BASICではエラーになるケースがるよう
です。
770 A=A+1 780 '3頭動いたらreturn returnの後ろのREM文はエラーになるようだ 790 IF A>3 THEN A=0:RETURN ELSE P=P+1 'Pは動かす牛のNo. 800 IF P>max THEN P=1 'maxを超えたら1に戻す 810 LOCATE cx(P),cy(P):PRINT" ":char(cx(p),cy(p))=0:r1=cx(p):t1=cy(p) 820 cx(P)=cx(P)-1 830 IF cx(P)<10 THEN GOTO 840 ELSE 870 840 cx(P)=30 850 LOCATE 10,cy(P):PRINT" ":char(10,cy(p))=0 860 cy(P)=INT(RND(1)*6)+6 870 oi=char(cx(p),cy(p)) 880 if oi<>0 then cx(p)=r1:cy(p)=t1 890 '移動先にキャラがある場合は元の位置にとどまる 900 LOCATE cx(P),cy(P):color 7:PRINT"C":char(cx(p),cy(p))=1 910 ' 920 '当たり判定 930 IF cx(P)=X AND cy(P)=Y THEN over=1 940 GOTO 770
E虎の移動と当たり判定
950行 tmaxがその面で表示する虎の数です。
970〜1110行 虎の次の移動先座標の決定と表示です。
虎の移動先の探索は下の図の@〜Cの順で移動できる場所を探します。
(この移動先決定のコードの書き方はイマイチですね。)
ここでも、移動先に既に別のキャラがいる場合は、元の位置にとどまるようにしています。
1120行で当たり判定をしています。
950 FOR G=1 TO tmax 960 LOCATE tx(G),ty(G):PRINT" ":char(tx(g),ty(g))=0:QT1=tx(G):QW1=ty(G) 970 tx(G)=tx(G)-1 980 OI=char(tx(G),ty(G)) 990 IF OI<>0 THEN ty(G)=ty(G)-1 ELSE 1060 1000 OI=char(tx(G),ty(G)) 1010 IF OI<>0 OR (ty(g)<=5 and ty(g)<12) THEN ty(G)=ty(G)+2 ELSE 1060 1020 OI=char(tx(G),ty(G)) 1030 IF OI<>0 THEN tx(G)=tx(G)+1 ELSE 1060 1040 OI=char(tx(G),ty(G)) 1050 IF OI<>0 THEN tx(G)=QT1: ty(G)=QW1 1060 IF tx(G)=<9 THEN 1070 ELSE 1110 1070 tx(G)=30:ty(G)=INT(RND(1)*6)+6 1080 IF ty(G)<6 THEN ty(G)=6 ELSE IF ty(G)>12 THEN ty(G)=12 1090 oi=char(tx(g),ty(g)) 1100 if oi<>0 then tx(g)=qt1:ty(g)=qw1 1110 LOCATE tx(G),ty(G):color 2:PRINT"T":char(tx(g),ty(g))=2 1120 IF tx(G)=X AND ty(G)=Y THEN over=1 '当たり判定 1130 NEXT 1140 RETURN
F面クリアの処理
1190〜1200行はスコアの加算です。変数iは時間(=メインルーチンを回った回数)です。
早く面クリアできればそれだけスコアの増加が大きくなります。最低加算点は1点になります。
1250〜1260行はキーのオートリピート等でキー入力バッファにたまった余計なキーを削除しています。
次の面の開始時にカメ(自キャラ)が不用意な動作をしないためです。
1270行 面をクリする毎に牛と虎の数を増やします。だんだん難しくしていく。虎が7頭を超えてくるとそれなりに
難しくなります。
1280〜1290行 ただし牛の最大数は30、虎の最大数は10に制限します。
Gゲームオーバー処理
1340〜1380行 過去のScoreのTop5の表示
1390〜1440行 スコアが過去のTop5にランクインしたかどうかの判定
Top5内に入った場合、1550行目からのサブルーチンでランクイン処理をする。
ランクイン処理が終了したら(ランクイン処理のフラグfin=1の場合)1420行目では
goto文でForループを飛び出している。
1450〜1490行目 過去Top5のファイルの更新
1500〜1540行 終了処理
1550〜1610行 ランクイン処理