見出し画像

ティラノスクリプトと私③東西南北移動型マップを2次元配列で管理する

※ノベルゲーム特化型ゲームエンジン「ティラノスクリプト」でそこそこ本格的なゲームを作るため、Javascriptなどの面倒くさいことを(嫌々)試行錯誤するおっさんの備忘録です。(※ティラノスクリプトVer 507bで動作確認)

以前、ティラノスクリプトorティラノビルダー製フリーゲーム投稿サイトノベルゲームコレクションさんに『王家の棺』というゲームを投稿しました。

1980年代PC用アドベンチャーゲームのシステムを再現…というレトロゲームオマージュもの。サイト内での注目度は高くないです。遊べば面白いんですけどね!

現在制作中の『レトロゲームエイリアンズ』は、この『王家の棺』を含むいくつかのレトロゲームオマージュタイトルを丸ごと内包したノベルゲームです。古くさい様式やゲームシステムも見せ方次第では新鮮に思えるんじゃないか…という発想を形にする壮大?なプロジェクトなのですが、現在公開中の『王家の棺』のシナリオデータ(.ksファイル)をそのまま使うわけにはいきません。

ティラノビルダーで作ったため、ティラノスクリプトに組み込むには余計なマクロがいっぱいくっついていることと、そもそも「とりあえず動けばいい」という作りだったため書式がシステマティックではなく、どこにどんな不具合が潜んでいるかわかったものではないからです。

フリーゲーム版『王家の棺』はこんな感じ

『王家の棺』は、各場面を東西南北方向の移動で行き来することで物語を進め・謎を解きます。下画像はシーンのつながりのイメージ。1980年代PCゲーム雑誌のゲーム攻略記事で見慣れた感じです!(伝わらない)

名称未設定 1

このような場面移動の仕組みをティラノビルダー版でどのように実現していたかというと…

画像3

こんな風に各場面のシナリオファイルに選択肢(glinkタグ)を並べて、

画像2

そのコマンド実行結果を同一シナリオファイル内につらつらと書きました。スクリプトの半分は、ティラノビルダーのコンポーネント配置で自動的に生成されたもの。作業がラクな反面スクリプトが長々としやすく、場面のつながりの管理が完全アナログ(ノートやExelに書いたシナリオファイル名を確認しながら記述)というのが不安の種です。

場面の位置関係を2次元配列で表現

そこで2次元配列の出番です。
たとえばこんなつながりの全体マップを考えたとして…

画像4

まずは、これがスッポリはまる方形状のマス目と、2次元配列の変数f.mapのパラメータ格納位置のイメージを重ねます。

画像9

重ねました。
f.mapの最初の[ ]内の数値をY(タテ)座標に、2番目の[ ]内の数値をX(ヨコ)座標に割り当ててマッピング。そして、プレイヤーが現在いる場面(マス目)のY座標をf.py、X座標をf.pxに持たせてその数値を増減させれば、各シナリオファイルへの移動処理がスマートになるはずです。これが前回の記事で書いた「(ファイル名の一部として使用する変数の中身を)数値型にしておくと、シーンの移動やら配列変数やらを数式で管理・制御できたりと何かと応用がききます」の真骨頂?です。

ゲーム中での場面移動の処理

下準備として、各マス目に対応した場面のシナリオファイル名(文字列)を、2次元配列にあらかじめ格納しておきます。
  @iscript
  f.map = [
  [’map_00.ks',’map_01.ks',’map_02.ks',’map_03.ks'],
  [’map_10.ks',’map_11.ks',’map_12.ks',’map_13.ks'],
  [’map_20.ks',’map_21.ks',’map_22.ks',’map_23.ks'],
  [’map_30.ks',’map_31.ks',’map_32.ks',’map_33.ks']
  ]
  @endscript
ちょっと…いやだいぶ間違えそうですが、こう正しく書くことでf.map[0][0]には’map_00.ks'f.map[1][0]には’map_10.ks'…といった具合にわかりやすく格納されます。
シナリオファイルを用意しなくていいマスにもシナリオファイル名を割り当てていますが、こう記述しておけば急な場面追加にも対応できます。

それでもって場面移動の際には、現在地座標を以下のように変化させます。
  @eval=exp"f.px=f.px+1"  ※東に移動
  @eval=exp"f.px=f.px-1"  ※西に移動
  @eval=exp"f.py=f.py+1"  ※南に移動
  @eval=exp"f.py=f.py-1"  ※北に移動

あとはシナリオの移動命令(jumpタグ)を以下のように書けば、当該シナリオファイルに勝手に飛んでくれるというわけです。素晴らすぃい。
  @jump storage = &f.map[f.py][f.px]

懸案①進行不可マスの処理

以上が2Dマップの移動を2次元配列で管理・制御する基本です。正直ティラノスクリプトに限定した話ではないし、今どきこんな構成のゲームを作ろうとする人もいないでしょうが、個人的な備忘録なので気にしません。

とはいえこの状態では不十分な点があります。それは「移動先ではない方向の処理」です。

「そっちにはすすめません」というテキストを表示するだけだったら、現在地の場面のシナリオファイル内で処理すればすむ話ですが、場所によってテキスト内容が変わったり、移動即ゲームオーバーになったりとリアクションの多様性を再現しようとすると、移動できないけどそっちに行こうとした場合の専用のシナリオファイルを別個に用意した方が、メンテナンス面にも好影響です。


先のサンプルマップに、進行不可リアクション用のシナリオファイルを追加した状態を視覚化すると、こんな感じ。

画像6


さらにこの構成で2次元配列化すると、こう。

画像9

シナリオファイルが無駄に増えた印象です。無駄じゃないですが。

さらに付け加えると同一の進行不可マスでも、移動元によって進めない理由が異なる=リアクションが変化するケースもあります。それを視覚化したのがこちら。

画像9

「こういうパズルゲームかな?」という見た目になってしまいましたが、進行不可マス内のグレーの三角形の数が、そのマスで必要なリアクションのパターン数です。このマップ構成では1マスにつき1~3パターンのリアクションが必要です。

これを判別するには移動元に関するデータ(東西南北の選択情報など)を照らし合わせて、シナリオファイル内のラベル基準で分岐…という処理が必要になってきますが、そのあたりは未来の私がうまいことやってくれるでしょう!

懸案②マップ拡大への対応

2次元配列で最初にマップ構造とシナリオファイル名を定義しておけば便利なのは間違いないことですが、もし途中でマップ全体の大きさを拡大しなければならなくなったとしたら…各シナリオファイル名の修正は避けられないでしょう。

そんな未来の手間を省く手段として2次元配列で用意する変数の数を必要最低限よりもやや多めに確保しておくのもアリなのかなと。例えば上記サンプルマップは6×6マス想定(f.map[0~5][0~5])で2次元配列を定義しましたが、あえて8x8マス想定(f.map[0~7][0~7])で定義することで、ある程度の外周方向への広がりに対応できます。ゆとりを作って非常時に備える…現代社会に足りない発想です。

参考サイト

2次元配列については私自身何となくわかっているので細かく書かなかったのですが、りまねさんのブログ記事のリンクを貼っておきます。すでに公開終了となったfor構文追加プラグインの使い方とともに、配列変数の基本がとてもわかりやすく解説されています!

※20210622追記

最初に記事をアップした時に掲載していた2次元配列の作り方が間違っていました。ついf.map[x][y]と表記したくなる誘惑に流されてしまいましたが、2次元配列の定義表記と2Dマップの見た目を合わせるのであればf.map[y][x]にしないとだめでしたね…。本文内容、使用画像ともに修正対応しました。これが「2次元配列完璧に理解した」クオリティです。


この記事が気に入ったらサポートをしてみませんか?