uGUIでノベルゲームのようなものを作る…の続きです。
今日はコマンド周りをやります。
uGUIでノベルゲームのようなものを作る。その1 - テラシュールブログ
シナリオをテキストファイルから読み込む
ノベルゲームのようなゲームの多くは、シナリオをテキストファイルで格納します。これは単純にシナリオライターが一番楽な方法がテキストエディタであるという事に依存します。
とりあえずテキストファイルをUnityから取得する方法を考えます。
- System.IO.FIle.ReadAllTextで取得する*1
- WWWクラスでWeb(もしくはローカルストレージ)から参照する
- Resources.Loadで取得する
- 直接参照する
今回はResources.Loadで取得する方法を選択肢します。
後は、テキスト制御のTextControllerとシナリオ制御のScenarioManagerに分割します。
改行でテキストを区切っても良いのですが、複数行の表現が難しくなるため改行タグ(@br)を使用しテキストを区切ることにします。
その際、改行のみの空行が出来てしまうので、それらの文字列は排除します。
ちなみに参照関係の構築が面倒くさいので、マネージャーは全部シングルトンにしてしまいます。
あとは作成したコンポーネントを適当なオブジェクトに配置し、以下の様なテキストファイルをResources/Scenarioフォルダに 配置すると、シーン起動時に読んでくれるようになります。
吾輩(わがはい)は猫である。
名前はまだ無い。
@br
// これは冒頭のセリフです。
どこで生れたかとんと見当(けんとう)がつかぬ。
@br
何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。 // と思っているのか?
コマンドの制御
コマンドの制御は、表示する行が特定の文字列を持っていた場合、その文字列を消してコマンドを実行する処理で行います。
本当はこの手の処理は事前にScriptableObject等に出力しておいて読むほうがCPUに優しいですが、ここでは面倒なので説明しません。今のモバイルやPCの性能だとココを頑張っても余り意味無いですし。
コマンドの実行方法ですが、EventとかSwitchとかSendMessageで一括コールとか色々とやり方がありますが、今回はCommandパターンで行きます。
コマンドの構文は最も簡単な(頭に@)の行ならコマンド処理にまわし、その後のテキストを正規表現で確認し一致するならコマンド実行…という感じの方法を使います。
正規表現を使うことで、コマンドの中身をかなり柔軟に読み込むことが出来ます。
例えば、(\\S+)=(\\S+)で正規表現判定を行えば、◯◯=△△のような文書を判定し、◯◯と△△の内容を取得することが出来ます。これで取得した値はDictionaryにでも入れておきます。
何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。 // と思っているのか?
@br// 名前がLayer1のレイヤーで画像「01_1」を表示する
@img name=Layer1 image=01_1
吾輩はここで始めて人間というものを見た。
後は各Commandオブジェクトに取得したコマンド情報を渡し、該当するコマンドに動いてもらいます。また表示時に呼ばれるCommandとは別にPreCommandを用意します。これは文字が表示完了したタイミングに呼び出す処理で、画像ロード等の重い処理を行います。*2
コマンドはm_commandListにインスタンス化しておきます。ここはComponenttとして配置するか迷いましたが、とりあえず普通のクラスとしてインスタンス化しました。実際はゲームのAPIを直接叩くケースが多い為、コンポーネントにしたほうが何かと使い勝手が良いかもしれません。
コマンドの中身ですが、Commandメソッドの引数にパラメータが入っているため、それを表示したりすればOKです。例えば画像の表示コマンドはこんな感じにしました。
CommandUpdateImageは@imgのコマンドの中身で、nameでオブジェクト名、imageで画像名を指定して呼び出します。
画像読込はちょっとだけ工夫してます。
具体的には、そのままの状態ではなく「拡張子bytes」等に変更し、テクスチャーではなくpngやjpegのようなフォーマットを維持することによって、アプリサイズを1/20から1/100にします。
ノベルゲームは特に画像サイズが大きく枚数も多いので、テクスチャーをそのまま維持したら50GB~100GBとか簡単に超えてしまうので、その対策