パソコン活用研究5番街(Visual Basic、Excel(VBA)、BASIC プログラミング研究)

BASICゲームのプログラムサンプル2

(準備中)

簡単なBASICゲーム作成のための説明。

パソコン(FM-8)を買って始めて作成した記念すべきマイゲーム第1号をN88互換BASIC for Win用に
移植してみました。
パソコンを買ってその日のうちに、BASICの説明書と首っ引きで原型を作ったゲームなので、FM-8の
オリジナルプログラム(F-Basic)はかなりスパゲッティコードでした。なので移植にあたりそれなりにコードは
整理しなおしましたが、アルゴリズム等は基本的に作成当時のままです。

昔のBASICは構造化プログラミングには向かない(各機能をモジュール化出来ない)、大域変数しかない、
再帰ができない、構造体とかましてやクラスなどない・・のではありますが、それが却って小さいプログラム
(100行、100ステップ未満)を作ってみるには、とっつきやすいというメリットにもなります。
プログラミングの入門用としては昔のBASICはなかなかいいのではないかと思います。
おじさん(筆者)も自分でスクラッチで計算機を作ってみる時の、アルゴリズムの確認にはまず昔のBASICで
試してみました。ー>計算機を作ってみる(後置記法)などご参照

やはり、始めて作るプログラムということになると、こういう落下系のゲームになるよね、という見本のような
キャラクタ(文字)だけのゲームで、こんな原始的なゲームですが、そこそこの難易度なので、まあなつかしさ
とともに1時間くらいは楽しめるかと。

プログラムはN88互換BASICからダウンロードできます。

1.ゲームの概要
自分のキャラ(Y)を左右に動かして(1で左、3で右に動かす)、上から落下してくる敵キャラ(T, U, R)をよける
ゲームです。敵キャラの移動パターンがそれぞれに異なるので、そこそこの難易度になります。
基本的に使ったBASICの命令は、四則演算と LOCATE, PRINT, IF .. THEN, FOR .. NEXT, GOTO, GOSUB
INKEY$の7コの命令だけ。あとはCLSとDIMです。
他には移植の都合上、ゲームスピードの調整にVALとかRIGHT$, TIME$を使いましたがそれだけです。
基本的に、「BASIC超基本(10語でシューティングゲームを作る)」で書いた範囲内だけで作られています。
特別なアルゴリズムや工夫もないので、初めてつくるプログラムとして基本的な要素だけのプログラムに
なっています。

BASICは方言が多いプログラミング言語なので他の機種用のBASICに移植するときは、それぞれの方言の
違いをきちんと理解してアレンジする必要がありますが、ここに掲載したレベルのシンプルなものは、ほぼ
なんの修正もなしでどんな機種でも動くのではないかと思います。


1.プログラムの全体構成

プログラムの全体構成は以下の通り

5〜180 初期設定
5〜10 はプログラム起動時に1回だけ設定する部分
15〜180 は画面クリア毎に行う初期化部分

200〜320 メインルーチン
自キャラ(Y)、敵キャラ(T,U,R)の移動、当たり判定処理はそれぞれサブルーチン化しており
それぞれのサブルーチンへGOSUBで飛ばして処理しています。

280〜290 今どきのCPUでは処理が速すぎてN88互換BASICの表示が追いつかない+速すぎて
ゲームができないので、ウェイト処理を入れています。
昔のBASICゲームを今どきのPC上のN88互換BASICに移植するときには必須の処理になると
思います。

400〜480 自キャラ(Y)の処理

500〜620 敵キャラ(T)の処理
Tは基本的に自キャラを追いかけるように動きます。落ちてくる途中で1回だけ停止するときがあるので、
この停止中に自キャラが逃げる必要があります。

700〜800 敵クアラ(U)の処理
Uは中央付近だけを自クアラを追いかけるように動きます。自キャラが両端に行くと停止して中央付近に
戻ってくるのを待ちます。基本的に端のほうににげることによりUを避けるというのが基本的な回避行動に
なります。

900〜1020 敵キャラ(R)の処理
RはreverseのRです。落ち始めは自キャラから遠ざかる方向に動くという謎の動きをします。落下後半から
自キャラに近づく方向に動きます。基本的に前半でRからできるだけ遠ざかっておくというのが回避の基本行動
になります。

1500〜1540 これもウェイトです。
280〜290だけでは敵キャラの動きにウェイトをかけられないので表示が追いつかないことがあります。
このため敵キャラの動きにもウェイトを入れるためサブルーチン化して、敵キャラの処理の合間にここのウェイト
を呼んでいます。

1800〜1830 敵キャラが下のラインまで落ちてきたときの処理。サブルーチン化してあります。

2000〜2080 敵キャラが当たった時の処理。サブルーチン化してあります。

3000〜3070 1画面終了時の処理


ゲームとしてはこんな感じ



2. プログラム主要部の説明

以下、ゲーム作成でよく使うコードについていくつか説明します。

(1) 変数

X 自キャラのx座標
TX( ), TY( ) は落ちてくる敵キャラの座標
M( , ) その座標に何がいるかの判定用  0 何もいない  1 自キャラ  2 敵キャラ
TIM 経過時間 50を超えると終了
MIS 敵キャラと当たった回数
max 牛の数  tmax 虎の数
over ゲームの状態 0 継続中  1 ゲームオーバー  2 面クリア

(2) 初期設定

5〜10行はプログラム起動時に1回だけ行う初期設定

15〜180行 画面クリア毎に行う初期設定
20〜60行のFORループでM( , )の初期化をしています。
敵キャラのX座標、Y座標を表すのに、TX(),TY()と配列にして、89〜90行で敵キャラの初期座標を
初期化しています。
敵キャラを配列にしたことにより、敵キャラが着地したときの処理(1800行から)、敵キャラと自キャラが
ぶつかった時の処理(2000行)をサブルーチンにして統一的に処理できるようにしています。



5 LMIS=50
10 DIM M(30,30)
15 CLS
20 FOR I=5 TO 20
30 FOR J=5 TO 16
40 M(I,J)=0
50 NEXT J
60 NEXT I
65 TIM=0: MIS=0
70 X=13: M(X,16)=1
80 TX(0)=13: TY(0)=9: M(TX(0),TY(0))=2:STOPF=0
90 TX(1)=13: TY(1)=7: M(TX(1),TY(1))=2
100 TX(2)=13: TY(2)=5: M(TX(2),TY(2))=2
110 FOR I=5 TO 15
120 LOCATE 4,I: PRINT"|": LOCATE 21, I:PRINT"|"
130 NEXT I
140 FOR I=5 TO 20
150 LOCATE I,16: PRINT"-"
160 NEXT I
170 LOCATE 5,18:PRINT" Key 1 <-- --> 3"
180 LOCATE 8,1:PRINT"FALLING"

(3) メインルーチン

@メインルーチン
経過時間(TIM)が50を超えるまでは200〜320行をぐるぐる回ります。
自キャラ、敵キャラの処理はサブルーチンに飛ばしています。

今どきのCPUでは処理が速すぎるので、
200 TIME1=VAL(RIGHT$(TIME$,2))
280 TIME2=VAL(RIGHT$(TIME$,2)) 290 IF TIME1 = TIME2 THEN GOTO 280
で全体で1ターンの処理に1秒かかるように調整しています。

225 GOSUB 1500
235 GOSUB 1500
の敵キャラの処理に少しウェイトを入れる処理(1500行)に飛ばしています。

200 TIME1=VAL(RIGHT$(TIME$,2))
210 GOSUB 400
220 GOSUB 500
225 GOSUB 1500
230 GOSUB 700
235 GOSUB 1500
240 GOSUB 900
280 TIME2=VAL(RIGHT$(TIME$,2))
290 IF TIME1 = TIME2 THEN GOTO 280
300 TIM=TIM+1: LOCATE 25,1:PRINT"TIME";TIM
310 LOCATE 25,2:PRINT"MIS ";MIS
320 IF TIM>50 THEN GOTO 3000 ELSE GOTO 200

A自キャラの処理
450〜460行 キーボードのオートリピート対策
オートリピートでキーバッファにたまったキーを捨てている。こうしないとキーバッファにたまったキーが
呼び出されて意図しない動きになる。

400 A$=INKEY$: M(X,16)=0
410 IF A$="1" THEN X=X-1
420 IF A$="3" THEN X=X+1
430 IF X<5 THEN X=5
440 IF X>20 THEN X=20
449 REM キーのオートリピート対策
450 A$=INKEY$
460 IF A$="" THEN GOTO 470 ELSE GOTO 450
470 LOCATE X-1,16:PRINT"-Y-": M(X,16)=1
480 RETURN

B 敵キャラTの処理
自キャラのいる方に近づくように動きます。
ただし510行でワンターンだけ停止するようにしています。

500 M(TX(0),TY(0))=0: LOCATE TX(0),TY(0): PRINT" ":OLDTX=TX(0):OLDTY=TY(0)
510 IF TY(0)=13 AND STOPF=0 THEN STOPF=1: GOTO 580
520 IF STOPF=1 THEN STOPF=0
530 IF TX(0)<X THEN TX(0)=TX(0)+1
540 IF TX(0)>X THEN TX(0)=TX(0)-1
550 IF TX(0)<5 THEN TX(0)=5
560 IF TX(0)>20 THEN TX(0)=20
570 TY(0)=TY(0)+1
580 IF M(TX(0),TY(0))=2 THEN TX(0)=OLDTX: TY(0)=OLDTY:goto 610
590 IF M(TX(0),TY(0))=1 THEN K=0:GOSUB 2000: GOTO 610
600 IF TY(0)=16 THEN K=0: GOSUB 1800
610 LOCATE TX(0),TY(0):PRINT"T":M(TX(0),TY(0))=2
620 RETURN

C敵キャラUの処理
700行 自キャラが両端にいる時はそのままの位置で停止します。
710〜740行 中央付近のみの範囲で自キャラに近づく方向に動きます

700 IF X<8 OR X>17 THEN goto 790
705 M(TX(1),TY(1))=0: LOCATE TX(1),TY(1):PRINT" ": OLDTX=TX(1):OLDTY=TY(1)
710 IF TX(1)>X THEN TX(1)=TX(1)-1
720 IF TX(1)<X THEN TX(1)=TX(1)+1
730 IF TX(1) <10 THEN TX(1)=10
740 IF TX(1) >15 THEN TX(1)=15
750 TY(1)=TY(1)+1 
760 IF M(TX(1),TY(1))=2 THEN TX(1)=OLDTX: TY(1)=OLDTY:goto 790
770 IF M(TX(1),TY(1))=1 THEN K=1:GOSUB 2000: GOTO 790
780 IF TY(1)=16 THEN K=1: GOSUB 1800
790 LOCATE TX(1),TY(1):PRINT"U":M(TX(1),TY(1))=2:
800 RETURN

D敵キャラRの処理
落下中の前半は自キャラから遠ざかる動きをし、途中から自キャラに近づいていくという動きをします。

900 LOCATE TX(2),TY(2):PRINT" ":M(TX(2),TY(2))=0:OLDTX=TX(2):OLDTY=TY(2)
910 IF TY(2)<12 and X>TX(2) THEN TX(2)=TX(2)-1
920 IF TY(2)<12 and X<TX(2) THEN TX(2)=TX(2)+1
930 IF TY(2)>11 and X>TX(2) THEN TX(2)=TX(2)+1
940 IF TY(2)>11 and X<TX(2) THEN TX(2)=TX(2)-1
950 IF TX(2)<5 THEN TX(2)=5
960 IF TX(2)>20 THEN TX(2)=20 
970 TY(2)=TY(2)+1
980 IF M(TX(2),TY(2))=2 THEN TX(2)=OLDTX:TY(2)=OLDTY:GOTO 1010
990 IF M(TX(2),TY(2))=1 THEN K=2: GOSUB 2000:GOTO 1010
1000 IF TY(2)=16 THEN K=2: GOSUB 1800
1010 LOCATE TX(2),TY(2): PRINT"R": M(TX(2),TY(2))=2
1020 RETURN

Eウェイトの処理
ゲームスピードの調整のためにFORループでウェイトを入れています。


1500 FOR II=0 TO 100
1510 FOR KK=0 TO 30
1520 NEXT KK
1530 NEXT II
1540 RETURN

F敵キャラが着地したときの処理
敵キャラが着地したとき、つまりTY()=16のときは、TY()=5 として上に戻します。


1800 LOCATE TX(K),TY(K):PRINT"+"
1820 TY(K)=5
1830 RETURN

G 敵キャラにあたった時の処理
爆発したイメージとして***の表示
MISをひとつ加算

2000 LOCATE TX(K)-1, TY(K):PRINT"***":BEEP
2010 MIS=MIS+1
2020 TIME3=VAL(RIGHT$(TIME$,2))
2040 TIME4=VAL(RIGHT$(TIME$,2))
2050 IF TIME3=TIME4 THEN GOTO 2040
2060 LOCATE TX(K)-1, TY(K): PRINT"---"
2070 TY(K)=5
2080 RETURN

H 1画面終了時の処理
3000行 ミスの回数がこれまでの最小回数より少なければLMISを更新

3000 IF LMIS > MIS THEN LMIS=MIS
3005 LOCATE 25,3:PRINT"Least Miss:";LMIS
3010 LOCATE 5,20:PRINT"もう一度やる(Y/N)"
3020 A$=INKEY$
3050 IF A$="Y" OR A$="y" THEN GOTO 15
3060 IF A$="N" OR A$="n" THEN END
3070 GOTO 3020


ウウェイトを入れないと今どきのCPUでは処理が速すぎてまったく画面表示がおいついてこない





TOP PAGE >Basic活用研究目次