« プログラミング講座(154) テキストアドベンチャーゲーム | トップページ | プログラミング講座(156) すごろくゲーム »

2014/07/16

プログラミング講座(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 で動きのあるゲームについて紹介しようと思います。

(つづく)

|

« プログラミング講座(154) テキストアドベンチャーゲーム | トップページ | プログラミング講座(156) すごろくゲーム »

Small Basic」カテゴリの記事

ゲームプログラミング」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: プログラミング講座(155) 手続きとデータの分離:

« プログラミング講座(154) テキストアドベンチャーゲーム | トップページ | プログラミング講座(156) すごろくゲーム »