Unity+MoonSharpで開発を進めている。
現在、次のようなLuaスクリプトが動かせるものが出来ている。
function main()
表示文です。
[名前タグ]はろーわーるど。
>english print text.
-- 下の二つは同じ意味
[tag]text
>[tag]text
log("普通のLuaの記述")
local x=0
for i=1,10 do
foo(i)
end
end
NScripter系と同じ仕様の表示文を
___p("名前タグ","はろーわーるど")
というように行を一対一対応で置換して実行する。いわゆる外部DSLというやつだが、こうすることでLuaの文法に最小限の拡張をしてゲームのシナリオを記述できるようになった。Luaのエラーメッセージも行番号にズレがないのでちゃんと正しい場所を返してくれる。
ここからしばらく、勘違いで必要のなかった作業についての記述なので折りたたんでおきます。ただ、ビルド前処理の練習にはなりました。
問題はこのファイルの拡張子を.luaのままにしておきたいということだ。.txtにしたり.bytesにしたりすると、テキストエディタのシンタックスハイライト機能が効かなくなるからだ。
しかしUnityは元々登録されている拡張子のリソース以外は読み込んでくれない。StreamingAssetsにしておけば生ファイルを扱えるが、スクリプトファイルがそのままコピーされてしまうため、さすがにゲームのコードをダブルクリックでそのまま読めてしまうのは具合が悪い。そこで次の方法でとりあえずの解決を見た。
- Assets外のフォルダにluaファイルを置いて、そこで編集し、「再生ボタンを押した時」もしくは「ビルド前」にAssets/Resourcesにテキストアセットの拡張子に変換したものをファイルコピーし、インポートさせる。コードからはこのテキストアセットのほうを読み込む。[PostProcessScene]を使って実装した。
(疑問点)再生ボタンを押すごとにluaスクリプトリソースがフル更新されるんだけどこういう設計でいいのか? また、このタイミングでリソース更新をかけた場合確実にリソースが更新されることは保証されているのか?
(考察)元々再生時にシーンまるごとメモリに読み込んでバックアップしてるようだし、これくらいはどうってことなさそうな気もする。リソースの更新についてはどうなんだろう。各アトリビュートのついた関数の実行タイミングが、リソースを追加していいタイミングなのかどうかってどこかで分かるんだろうか? とりあえず今のところ大丈夫のようだが。
ひとまず何か一本作ってみないと分からないかもしれない。この後簡単なギャルゲADV風のサンプルシステムを組んだら、何かゲームを一本作る。
(注釈)その後、たとえばAtomでは「Select Grammer」で、テキストファイルを開いたときでも文法をLuaで認識させることが出来るのが判明しました。これならもうテキストアセットでいいや……ただ、ビルド前やエディタ実行前に何かやる、という処理を書くのに役には立つのでいい経験になりました。
セーブロードの仕様について検討
セーブロードの機構をどうするかも悩み所。Luaの実行状態はセーブ出来ないからだ。ギャルゲADV以外では「シーンの冒頭まで巻き戻る」か、いっそ「宿屋やロビー画面でしかセーブ/ロードはさせない」で解決する(むしろそうしない場合、撤退できないイベントや場所で絶対に敵に勝てないレベルでセーブされると詰む、みたいな状況が頻発するので慎重な作業が必要になる。あと、特に3Dとかアクションゲームとかの場合、ゲームの実行状態を全部完全に保存するのが現実的でないこともしばしばあるので)。 ただ、ギャルゲ系の読み物ADVはどうしても、読んだところでちゃんとセーブして次はそこから始まって欲しいという需要がある。シーン単位だと、そのシーンが長大な時にかなり巻き戻ることになるからだ。これを実装するのは生のLuaスクリプトでは無理で、別のスクリプト言語が必要になると思われる。NScr2で言えばBASICだし、吉里吉里で言えばKAGだろう。この部分の文法をどうするか。うーん、やはりギャルゲADV界隈はどうしてもどこかで俺俺言語のくびきを逃れられないのだねえ。
今回のテーマは疎結合
正直NScr2のBASICはリッチすぎる。RPG風戦闘シーンとかミニパズルゲームまでこのBASICで組んじゃってるわけだが、そういうのは本来LuaやC++(Unityの場合ならC#)でやるべきだ。スプライトシステムがBASICの記述に最適化されているためBASICでやれることはBASICでやってるのが現状だが、今作ってるUnityのスクリプト環境のほうでは、「疎結合」をテーマにしたい(名前もLooseScriptにしようかなとか思ってる)。UnityはVisualC++でDirectXで組んでるときとは違い、アセットもコンポーネントもUIエディタも充実していて、こちらで組んだ方がLuaや自前言語で組むよりむしろ楽だし、JITの効くC#のほうが絶対に実行が速い。なので、そういう複雑なゲーム的な部分はUnity側で組んで、Luaやシナリオスクリプトはそれを大まかに制御するだけにしたいのだ。だから、シナリオ部分をスクリプト言語にするとしたら、出来るだけシンプルなタグ付けだけのものにしたい。その上で、演算したい場合はLuaコードをHTMLで言うscriptタグみたいな感じで呼べるようにするかな。
今回作ってるエンジンの方向性について。
一年以上グダグダ作っては作り直してますが、そろそろこれは形にする。相当ブラッシュアップされてきたので。
ひとまず、サンプルのADV環境は提供するけど、カスタマイズは生Unity環境でやるようなものになると思う。UnityのGUIエディタやC#スクリプトは使ってもらうし、ビルドプロセスはUnityのものになるので。「宴」ほどには統合環境的ではなく、あくまでプラグイン的な立ち位置。初心者には難しいかも知れない。その分生Unityに近く、疎結合で柔軟なため、SpineでもLive2Dでもなんでも、よそのコンポーネントは使い放題になると思う。
まあ、まだ出来てないようなものの青写真はともかくとして、うちの業界はクロスプラットフォーム開発環境への以降をぼちぼち考えはじめてる人も増えてるはずで、その流れに乗りたいです。
配布形態はオープンソースにして導入作業やサポートを引き受けた時にお金取るか、あるいはアセットとして売るか……お金は欲しい、のだが、今世の中見てると、もうエンジンそのものを売って商売するのは難しくなってきてる。だから組んで仕事出来る人が現れそうなら前者でいいかもしんない。名前も売りたいし求職活動にもなりそうならそのほうがいいかもね。シンプルな読み物ADV作る以外の用途では、プログラマはどうせ必要なんだから、そっちの実作業でお金取ればいい気もするのだ。