BASIC (ベーシック) であそぼう 3
〜 迷路プログラムをアニメーション風に改良 〜
2022-06-09 作成 福島
TOP > asob > decbasic-mazeanime
[ TIPS | TOYS | OTAKU | LINK | MOVIE | CGI | AvTitle | ConfuTerm | HIST | AnSt | Asob ]

迷路と自分を理想的な表示に

前々章 BASIC であそぼう 1 のプログラムは、基本説明を重視したため画面更新の箇所をおざなりにしていました。

ここでは、迷路の表示プログラムをアニメーションの仕組みを使って作り変えます。
こうして記述の分かりやすさを良くすることにより、プログラムの変更がしやすくなります。
また、バグ (プログラムの誤動作のこと) の発見が楽になります。

プログラムの構造変更なので、動作は何も変わりません。


0. 事前準備

0-1. この章では、十進 BASIC を使います。
インストールがまだなら、ここ (ラズパイ400)ここ (CentOS) の gtk2 版か、
ここ (Windows10) を参考にしてインストールしておいてください。
0-2. この章では、別のテキストエディタを使いません。
十進 BASIC には専用のエディタ画面があるので、これを使います。
0-3. 未経験者向けの情報を省いています。
プログラミング未経験の方は、予めこちら (BASIC であそぼう 1) を、
アニメーションの仕組みをまだ考えたことがない方は、こちら (BASIC であそぼう 2)
学習しておくことを推奨します。


1. 前々回 BASIC であそぼう 1 - 第 5 項 のおさらい

1-1. 部屋が迷路のプログラム
<テキスト5> では以下の様に記述していました。
改善点は 2 箇所あります。
 (1) 表示部とキー操作の判別部を一緒にしている。
 (2) 実行速度を保つための WAIT (待ち時間のこと) を固定値 (0.2) にしている。
です。

<テキスト5> ファイル名「program.BAS」
SET WINDOW 0,39,19,0

DIM heya$(7)
LET heya$(1) = "+---------------+"
LET heya$(2) = "|     #       # |"
LET heya$(3) = "| ### # # ### # |"
LET heya$(4) = "| # #   #   # # |"
LET heya$(5) = "| # ####### # # |"
LET heya$(6) = "|     #     #   |"
LET heya$(7) = "+---------------+"
SET COLOR 1
FOR tate = 1 TO 7
   LET gyou$ = heya$(tate)
   FOR yoko = 1 TO 17
      LET kabe$ = mid$(gyou$, yoko, 1)
      PLOT TEXT ,AT yoko,tate:kabe$
   NEXT yoko
NEXT tate

SET COLOR 1
PLOT TEXT ,AT 2,2:"A"

LET yoko = 2
LET tate = 2

DO
   IF GetKeyState(27) < 0 THEN EXIT DO
   
   SET COLOR 0
   PLOT TEXT ,AT yoko,tate:"A"  !-- 改善点 (1)
   IF GetKeyState(39) < 0 AND mid$(heya$(tate + 0), yoko + 1, 1) = " " THEN LET yoko = yoko + 1
   IF GetKeyState(37) < 0 AND mid$(heya$(tate + 0), yoko - 1, 1) = " " THEN LET yoko = yoko - 1
   IF GetKeyState(40) < 0 AND mid$(heya$(tate + 1), yoko + 0, 1) = " " THEN LET tate = tate + 1
   IF GetKeyState(38) < 0 AND mid$(heya$(tate - 1), yoko + 0, 1) = " " THEN LET tate = tate - 1
   SET COLOR 1
   PLOT TEXT ,AT yoko,tate:"A"  !-- 改善点 (1)
    
   WAIT DELAY 0.2       !-- 改善点 (2)
LOOP

END

2. 表示部とキー操作の判別部を別にする -- 改善点 (1)
2-1. 表示部を副プログラムにする。
<テキスト5> では、画面の変更点 (A の移動前と移動後) だけを描画していましたが、
今度は毎回部屋の全部を描画するようにしています。
また、描画に使う変数 yoko, tate の役割も分けて、自分 (A) の場所の横と縦をそれぞれ x, y と記述しています。

<テキスト6> ファイル名「program.BAS」
SET WINDOW 0,39,19,0

DIM heya$(7)
LET heya$(1) = "+---------------+"
LET heya$(2) = "|     #       # |"
LET heya$(3) = "| ### # # ### # |"
LET heya$(4) = "| # #   #   # # |"
LET heya$(5) = "| # ####### # # |"
LET heya$(6) = "|     #     #   |"
LET heya$(7) = "+---------------+"

DECLARE EXTERNAL SUB HeyaDisplay
CALL HeyaDisplay(heya$, 2, 2)

! 自分の横位置、縦位置
LET x = 2
LET y = 2

DO
   IF GetKeyState(27) < 0 THEN EXIT DO
   
   IF GetKeyState(39) < 0 AND mid$(heya$(y + 0), x + 1, 1) = " " THEN LET x = x + 1
   IF GetKeyState(37) < 0 AND mid$(heya$(y + 0), x - 1, 1) = " " THEN LET x = x - 1
   IF GetKeyState(40) < 0 AND mid$(heya$(y + 1), x + 0, 1) = " " THEN LET y = y + 1
   IF GetKeyState(38) < 0 AND mid$(heya$(y - 1), x + 0, 1) = " " THEN LET y = y - 1
   
   CALL HeyaDisplay(heya$, x, y)
    
   WAIT DELAY 0.2
LOOP

END


! 部屋を表示する副プログラム EXTERNAL SUB HeyaDisplay(heya$(), x, y) SET DRAW MODE Hidden CLEAR SET COLOR 1 FOR tate = 1 TO 7 LET gyou$ = heya$(tate) FOR yoko = 1 TO 17 LET kabe$ = mid$(gyou$, yoko, 1) PLOT TEXT ,AT yoko,tate:kabe$ NEXT yoko NEXT tate SET COLOR 1 PLOT TEXT ,AT x,y:"A" SET DRAW MODE Explicit END SUB
2-2. 表示部を副プログラムにしたプログラムの説明。
<テキスト6> ファイル名「program.BAS」
SET WINDOW 0,39,19,0

DIM heya$(7)
LET heya$(1) = "+---------------+"
LET heya$(2) = "|     #       # |"
LET heya$(3) = "| ### # # ### # |"
LET heya$(4) = "| # #   #   # # |"
LET heya$(5) = "| # ####### # # |"
LET heya$(6) = "|     #     #   |"
LET heya$(7) = "+---------------+"

DECLARE EXTERNAL SUB HeyaDisplay  ! 副プログラムがあることの宣言。名前を HeyaDisplay としました。
CALL HeyaDisplay(heya$, 2, 2)     ! 部屋と自分を表示します。

! 自分の横位置、縦位置
LET x = 2    ! 自分の横位置の名前を x に変更。
LET y = 2    ! 自分の縦位置の名前を y に変更。

DO
   IF GetKeyState(27) < 0 THEN EXIT DO

   ! ↓ 自分の横位置、縦位置の名前を変更したことに従い、移動部分も変更します。
   IF GetKeyState(39) < 0 AND mid$(heya$(y + 0), x + 1, 1) = " " THEN LET x = x + 1
   IF GetKeyState(37) < 0 AND mid$(heya$(y + 0), x - 1, 1) = " " THEN LET x = x - 1
   IF GetKeyState(40) < 0 AND mid$(heya$(y + 1), x + 0, 1) = " " THEN LET y = y + 1
   IF GetKeyState(38) < 0 AND mid$(heya$(y - 1), x + 0, 1) = " " THEN LET y = y - 1
   
   CALL HeyaDisplay(heya$, x, y) ! 部屋と自分を表示します。
 
   WAIT DELAY 0.2
LOOP

END


! 部屋を表示する副プログラム EXTERNAL SUB HeyaDisplay(heya$(), x, y) SET DRAW MODE Hidden ! 描画中に画面更新しないモードにする。 CLEAR ! 画面を背景色で塗りつぶす。 SET COLOR 1 FOR tate = 1 TO 7 LET gyou$ = heya$(tate) FOR yoko = 1 TO 17 LET kabe$ = mid$(gyou$, yoko, 1) PLOT TEXT ,AT yoko,tate:kabe$ NEXT yoko NEXT tate SET COLOR 1 PLOT TEXT ,AT x,y:"A" ! 自分を描画する。 SET DRAW MODE Explicit ! 画面更新モードを元に戻す。 END SUB

3. 実行速度を保つための WAIT に固定値を使わない -- 改善点 (2)
3-1. 実行速度を保つ WAIT を可変値にする。
長さの異なる待ち時間を自動的に作る副プログラム BogusTick を利用し、
プログラムの実行タイミングを一定に保ちます。

<テキスト7> ファイル名「program.BAS」
SET WINDOW 0,39,19,0

DIM heya$(7)
LET heya$(1) = "+---------------+"
LET heya$(2) = "|     #       # |"
LET heya$(3) = "| ### # # ### # |"
LET heya$(4) = "| # #   #   # # |"
LET heya$(5) = "| # ####### # # |"
LET heya$(6) = "|     #     #   |"
LET heya$(7) = "+---------------+"

DECLARE EXTERNAL SUB HeyaDisplay
CALL HeyaDisplay(heya$, 2, 2)

DECLARE EXTERNAL SUB BogusTick
BogusTick_before = -1

! 自分の横位置、縦位置
LET x = 2
LET y = 2

DO
   CALL BogusTick(BogusTick_before, 10)

   IF GetKeyState(27) < 0 THEN EXIT DO
   
   IF GetKeyState(39) < 0 AND mid$(heya$(y + 0), x + 1, 1) = " " THEN LET x = x + 1
   IF GetKeyState(37) < 0 AND mid$(heya$(y + 0), x - 1, 1) = " " THEN LET x = x - 1
   IF GetKeyState(40) < 0 AND mid$(heya$(y + 1), x + 0, 1) = " " THEN LET y = y + 1
   IF GetKeyState(38) < 0 AND mid$(heya$(y - 1), x + 0, 1) = " " THEN LET y = y - 1
   
   CALL HeyaDisplay(heya$, x, y)
LOOP

END


! 部屋を表示する副プログラム EXTERNAL SUB HeyaDisplay(heya$(), x, y) SET DRAW MODE Hidden CLEAR SET COLOR 1 FOR tate = 1 TO 7 LET gyou$ = heya$(tate) FOR yoko = 1 TO 17 LET kabe$ = mid$(gyou$, yoko, 1) PLOT TEXT ,AT yoko,tate:kabe$ NEXT yoko NEXT tate SET COLOR 1 PLOT TEXT ,AT x,y:"A" SET DRAW MODE Explicit END SUB
! BogusTick version 1.0 written by fuku@rouge.gr.jp EXTERNAL SUB BogusTick(before, fps) IF before >= 0 AND fps > 0 THEN LET current = TIME IF before > current THEN LET before = before - 24 * 3600 LET this_wait = 1 / fps - (current - before) IF this_wait > 0 THEN WAIT DELAY this_wait END IF LET before = TIME END SUB
3-2. 実行速度を保つ WAIT を可変値にしたプログラムの説明。
<テキスト7> ファイル名「program.BAS」
SET WINDOW 0,39,19,0

DIM heya$(7)
LET heya$(1) = "+---------------+"
LET heya$(2) = "|     #       # |"
LET heya$(3) = "| ### # # ### # |"
LET heya$(4) = "| # #   #   # # |"
LET heya$(5) = "| # ####### # # |"
LET heya$(6) = "|     #     #   |"
LET heya$(7) = "+---------------+"

DECLARE EXTERNAL SUB HeyaDisplay
CALL HeyaDisplay(heya$, 2, 2)

DECLARE EXTERNAL SUB BogusTick   ! 副プログラム BogusTick があることの宣言。
BogusTick_before = -1             ! BogusTick で使用する変数を指定に従って -1 で初期化します。

! 自分の横位置、縦位置
LET x = 2
LET y = 2

DO
   CALL BogusTick(BogusTick_before, 10)  ! BogusTick を呼び出して実行速度を一定に保ちます。
                                              ! ここでは 10fps (1 秒間に 10 回実行) を指定しています。

   IF GetKeyState(27) < 0 THEN EXIT DO
   
   IF GetKeyState(39) < 0 AND mid$(heya$(y + 0), x + 1, 1) = " " THEN LET x = x + 1
   IF GetKeyState(37) < 0 AND mid$(heya$(y + 0), x - 1, 1) = " " THEN LET x = x - 1
   IF GetKeyState(40) < 0 AND mid$(heya$(y + 1), x + 0, 1) = " " THEN LET y = y + 1
   IF GetKeyState(38) < 0 AND mid$(heya$(y - 1), x + 0, 1) = " " THEN LET y = y - 1
   
   CALL HeyaDisplay(heya$, x, y)
LOOP

END


! 部屋を表示する副プログラム EXTERNAL SUB HeyaDisplay(heya$(), x, y) SET DRAW MODE Hidden CLEAR SET COLOR 1 FOR tate = 1 TO 7 LET gyou$ = heya$(tate) FOR yoko = 1 TO 17 LET kabe$ = mid$(gyou$, yoko, 1) PLOT TEXT ,AT yoko,tate:kabe$ NEXT yoko NEXT tate SET COLOR 1 PLOT TEXT ,AT x,y:"A" SET DRAW MODE Explicit END SUB
! ↓ BogusTick を以下に記述しています。詳細はこちらを参照してください。 ! BogusTick version 1.0 written by fuku@rouge.gr.jp EXTERNAL SUB BogusTick(before, fps) IF before >= 0 AND fps > 0 THEN LET current = TIME IF before > current THEN LET before = before - 24 * 3600 LET this_wait = 1 / fps - (current - before) IF this_wait > 0 THEN WAIT DELAY this_wait END IF LET before = TIME END SUB
この章は、ここで終了です。