プログラミング講座(155) 手続きとデータの分離
前回のテキストアドベンチャーゲームをあの方式で拡張していくと、プログラムは If 文と Goto 文が延々と続くものになります。そこで、ゲームのシナリオをデータ化し、プログラムの手続きはそのデータを扱う共通のものにしてはどうかと考え、書き直してみました。その改訂版を FCD758-1 として発行しました。
メイン
メイン部はとてもシンプルになりました。
' Text Adventure 0.2
' Program ID FCD758-1
Init()
Game()
' end of program
シナリオデータの初期化
シナリオデータは前回のメイン部をそのままデータにしたようなものになりました。このデータは一種のスクリプト言語になっています。空白で始まる行はテキストとして表示され、":" (コロン)で終わる行は飛び先ラベルとして扱われ、"->" で始まる行は Goto のような制御文として処理され、それ以外の "," (カンマ)を含む行は選択肢としてユーザー(プレイヤー)の入力を促すようになっています。
本来シナリオは21行目で終了ですが、テストのために22行目を追加し、ゲームの先頭に戻るようにしてあります。
Sub Init
scenario[1] = "stage_0:"
scenario[2] = " You're at a fork in the road."
scenario[3] = " Which way do you go?"
scenario[4] = "LEFT,RIGHT,STAY"
scenario[5] = "-> stage_1_1,stage_1_2,stage_1_3,stage_0"
scenario[6] = "stage_1_1:"
scenario[7] = " Good choice, you find some money. :)"
scenario[8] = " Have a nice day."
scenario[9] = "-> end"
scenario[10] = "stage_1_2:"
scenario[11] = " You're at a stairs."
scenario[12] = " Which way do you go?"
scenario[13] = "UP,BACK"
scenario[14] = "-> stage_2,stage_0,stage_1_2"
scenario[15] = "stage_1_3:"
scenario[16] = " Nothing happend."
scenario[17] = " "
scenario[18] = "-> stage_0"
scenario[19] = "stage_2:"
scenario[20] = " Hard choice. But, good luck!"
scenario[21] = "end:"
scenario[22] = "-> stage_0"
nScenario = Array.GetItemCount(scenario)
pScenario = 1
EndSub
シナリオデータの解析と実行
サブルーチン Game では配列 scenario にあるシナリオを解析し実行します。
Sub Game
While pScenario <= nScenario
line = scenario[pScenario]
If Text.StartsWith(line, " ") Then
TextWindow.WriteLine(Text.GetSubTextToEnd(line, 2))
pScenario = pScenario + 1
ElseIf Text.EndsWith(line, ":") Then
pScenario = pScenario + 1
ElseIf Text.StartsWith(line, "->") Then
id = 1
Jump()
ElseIf Text.IsSubText(line, ",") Then
choices = line
Choose()
TextWindow.WriteLine("")
If id = 0 Then
id = n + 1
EndIf
pScenario = pScenario + 1
line = scenario[pScenario]
Jump()
Else
msg = "Unknown scenario: line " + pScenario
Error()
EndIf
EndWhile
EndSub
"->" 制御文の処理
"->" は単独の場合は Goto 文と同じ働きをしますが、直前に選択肢がある場合は、BASIC の ON GOTO 文のような働きをします。直前の n 番目の選択肢が入力されたときは n 番目のラベルに制御を移します。選択肢以外が入力されたときは、最後のラベルに制御を移します。
Sub Jump
' param id - choice
' param line
' work label - destination
len = Text.GetLength(line)
p = 3
While p <= len And Text.GetSubText(line, p, 1) = " "
p = p + 1
EndWhile
label = ""
For i = 1 To id
c = Text.GetIndexOf(Text.GetSubTextToEnd(line, p), ",")
If c = 0 Then
c = len - p + 2
EndIf
If i = id Then
label = Text.GetSubText(line, p, c - 1) + ":"
Else
p = p + c
If len < p Then
msg = "Label shortage: line " + pScenario
Error()
EndIf
EndIf
EndFor
For p = 1 To nScenario
If scenario[p] = label Then
pScenario = p
Goto break
EndIf
EndFor
msg = "Label " + label + " not found: line " + pScenario
Error()
break:
EndSub
エラー表示
シナリオが間違っているとプログラムが続行できないので、その場合はエラーを表示してプログラムを終了するようにしました。
Sub Error
TextWindow.ForegroundColor = "Red"
TextWindow.WriteLine(msg)
TextWindow.WriteLine("")
TextWindow.ForegroundColor = "Gray"
pScenario = nScenario + 1
EndSub
この他に選択肢を入力する Choice というサブルーチンがありますが、これは前回と同じものを使用しています。
今回の変更によりゲームのシナリオ自体は配列データとなり、プログラムをちょっと変更すればファイルから読み込むことも可能になりました。同じプログラムで複数のシナリオを実行するようにすることもできますね。ただ、プログラムで書かなくて済んだのですが、データのほうはある種のプログラムになってしまったので、データ側をテストして正しいものにする必要があります。シナリオデータの誤りを減らすために工夫をする必要もあるかもしれません。
テキストアドベンチャーゲームはまだまだ改善の余地がありそうですが、今回までとして、次回は TextWindow で動きのあるゲームについて紹介しようと思います。
(つづく)
| 固定リンク
「Small Basic」カテゴリの記事
- プログラミング講座 (202) 1次元セルオートマトン(2020.09.20)
- プログラミング講座 (201) パラメーター(2020.09.14)
- プログラミング講座 (200) 3次ベジエ曲線(2020.09.14)
- プログラミング講座 (199) スーパー三角関数?(2020.09.02)
- プログラミング講座 (198) スーパー楕円(2020.09.01)
「ゲームプログラミング」カテゴリの記事
- プログラミング講座(160) エアホッケー(2014.08.18)
- プログラミング講座(159) 射撃ゲーム(2014.08.03)
- プログラミング講座(158) 垂直スクロールゲーム(解説その2)(2014.07.31)
- プログラミング講座(157) 垂直スクロールゲーム(解説その1)(2014.07.30)
- プログラミング講座(155) 手続きとデータの分離(2014.07.16)
コメント