Unityへの組み込み言語として、Miniscriptの紹介。
0.はじめに
Unity#3アドベントカレンダー・6日目の記事です。
はじめまして、MachiaWorksと申します。
仕事の傍ら、趣味でゲーム・曲・グラフィック・シンセサイザーの製作等
とりあえず興味のあるものに対して色々と手を出しています。
今回は、Unityへスクリプトを組み込む際の選択肢として、
「Miniscript」という言語を紹介します。
1. Unityにスクリプトを組み込むシチュエーション・メリット
実際に導入するシチュエーションの提示
Unityでスクリプトを導入したいというケースは割とあると思うんですよね。
例えば、バランス調整を行うのにスクリプトを使わない形だと、
Editor上のScriptableObjectを弄ったり
C#のコードを書き直したりする形になるかと思います。
(こっちが一般的かと)
Editor弄ってるとアプリ自体が落ちたら入力しなおしなのと、
ScriptableObjectの項目がだんだんと多くなってきて、Editorの動作自体が
怪しくなってきて・・・というケースが割とありますし、
できるならEditor上の数値入力は最小限にしたいところです。
また、C#で修正するのも、修正のたびにビルドや再構成が走るので、
ファイル数が多くなるたびに時間がかかっていくので、
割とすぐ修正する、というわけには行かないかと思います。
こういうときにスクリプトを導入するというのはひとつかと思います。
パッと思いつくのが、敵のバランス調整のためにスクリプトを書くパターン。
敵の出現タイミングや弾を吐くタイミング等、細かいバランスを
調整するときに割と頻繁に書き換えを行います。
アセットの数が増えることはあるでしょうけど、書き換えが行われても
それほどの時間はかかりません。むしろC#の再構成よりかは早い形かと。
(テクスチャを指定形式に変換する等もなく、単にテキストを読み込んで
くる形なので)
以下、簡単にスクリプト導入のメリデメをまとめました。
スクリプト導入時のメリット
- 修正のたびにUnity上でビルド・再構成を行わなくて済む(アセット扱い)
- (ScriptableObject弄るときと比べて)別ツールで修正するので、
UnityEditor落ちたときも復帰しやすい - 調整・メンテナンスをするときに、ロジックを直接触らずに済む
スクリプト導入時のデメリット
- スクリプトによるコントロールの仕組み作るのに時間がかかる
- 新たに言語を覚える必要がある
- 処理速度についてC#より遅い傾向がある
2. Miniscriptの紹介・特徴
場所・Github
Webページ:
https://miniscript.org/
Github:
https://github.com/JoeStrout/miniscript
Miniscriptの特徴
- 言語のシンプルさ
これは新たに覚える言語がすぐ使えるか、という部分ですが、
言語の文法がシンプルなので、割とすぐに使えるかと思います。
下記リンクに文法がまとまってますが、1ページにすべて収まっております。
超コンパクトです。参考:
https://miniscript.org/files/MiniScript-QuickRef.pdf - 組み込みの楽さ(C#想定)
元々Unityへの組み込みを想定されて作られたおかげか、
Unityへの組み込みについては簡単に行えます。
他言語への組み込みもそれほど難しくないんじゃないかと。下記にも方法の案内が記載されてますが、基本的には
マニュアルに沿った形で出来てしまうので便利です。 - 半分JIT形式
一度コンパイルしてバイトコードを保管、バイトコードを読み込んで
処理する形式なのでstring型を毎回使う等がありません。半分と書いたのは、あくまでコンパイルはC#側で明示的に行って、
以後実行のためのバイトコードは利用インスタンス内に保管されるからです。よって、各オブジェクトの読み込み時に一気にソースコードをコンパイル、
あとはバイトコードを実行し続けるという形であれば、
CPU使用率の削減にもつながるかと思います。 - おまけ:C#で書かれてる
C#が動く環境であれば動くかと思うので、他環境に移植する際も
ソースコードを読み込ませてエラーがでなければ問題ないです。
(いざとなったら自分で修正できますし。あとMITライセンスなので利用について制約も少ないかなと)ちなみにUnityの組み込みを最初に想定していると記載しましたが、実際のところ他の環境でも動くので、
他プログラムへの組み込みも想定してOKになってます。
実際、公式でMiniscript組み込んだコマンドラインツールを公開しております。
(C++で記載されており、これを組み込んだ形)
デメリットとの比較
> ・スクリプトによるコントロールの仕組み作るのに時間がかかる
前述の通り、「アプリケーションへの組み込みが楽」なので、
少なくとも1本スクリプトを処理する機能を実装するには、
それほど時間がかからないものと考えます。
(公式で組み込みガイドなんてものもあるので)
ちなみにyield機能もあるので、テキストADVみたいな読み込みも可能です。
> ・新たに言語を覚える必要がある
前述の通り、文法はすごいシンプルにまとめられていて、
まず他の言語を使ったことがある人であれば問題なく使えます。
また、プログラム初心者についても後述する「組み込み関数」を
中心に使ってもらえば、使う文法もシンプルに抑えることができます。
> ・処理速度についてC#より遅い傾向がある
正直、これはC#で言語を処理する関係上仕方ないものと考えます。
ただ、前述の通り半分JIT形式のため、バイトコードを処理する
形になるため、それほどの性能劣化はないものと考えます。
むしろ言語組み込みとのトレードオフで考える方がよろしいかと。
3. 実際の使い方
基本的には、公式ページの「Unity Integration Guide」をお読みいただくほうが
簡単に、かつ要点を抑えてまとめられてます。
まずはここのコードを見るのがいいかと思います。
あとは、AssetStoreにあるアセットに組み込みのサンプルがアップされてるので、
それで見てしまうのもアリかと。(有料ですが)
https://miniscript.org/files/MiniScript-Integration-Guide.pdf
利用シチュエーション
- 単体で利用する場合
Unity Integration Guideの
「1. Overview」に記載があります。
これだけで出来てしまうのは楽です。計算結果についてもコンソールへの出力が可能なので、
単に計算させるだけであればあっという間にできます。また、エラー取得についてはtry~catchを仕込んでおけば問題ないです。 - オブジェクトと協調する場合
Unity上のオブジェクトと協調する(変数更新・行動分岐等)Unity Integration Guideの「2. Bridging the Divide」に
Unityと協調させる内容が記載されてます。
これを使えば基本的には問題ないです。例えば特定の方向にキャラクターを動かす等だと
・グローバル変数をもたせる
・組み込み関数を使う(後述)
という方法があります。ただ、Miniscript上で指定したグローバル変数を
UnityのUpdate関数等で別途アクセスする場合、
どうもMiniscript上で計算されない模様。自分はゲームへの組み込みで大量の同じクラスのオブジェクトが
出てくるので、グローバル変数を使うことは困難かなーと考え、
後者の「組み込み関数を使う」ことにしてます。
組み込み関数で特定命令を実行するときに、delegate命令で
特定クラスの内部処理を行ってもらい、変数等の更新を行うことにしました。これで違和感なくオブジェクトの値更新も可能になっております。
組み込み関数の利用
Unity Integration Guideの「2. Bridging the Divide」に記載あり。
組み込み関数は、「Intrinsic」という単語で記載されております。
実装にはdelegateを利用します。
これによって、利用するクラスごとに必要な組み込み関数を定義、ということも
可能になっております。
ただ、関数登録についてはグローバル変数で登録してあるみたいなので、
登録自体は1回行えば問題ありません。
自分の場合だと、オブジェクトに対し初期化を行う際、グローバル変数で
登録処理を行ったことを確認するためのフラグを持っておいて、
1回だけ起動できるように仕込んでおきました。
4.終わりに
簡素にまとめましたが、
まず、Unity上でスクリプトを実行するという選択肢は、
バランス調整という観点から、候補にあげてもいいのではないかと思います。
そこで言語を自作する等もアリと思いますが、このMiniscriptを選ぶという
選択肢は組み込み方法・言語の簡易さから使いこなす負荷が軽減されているため
自作アプリ・ゲームにとっても有効な選択肢と考えます。
みなさんもスクリプトを組み込んでみて、
ゲームのバランス調整に集中できる環境を作ってみてはいかがでしょうか。
あ、あと一番最後になりましたが、
Miniscriptを組み込んでゲーム開発中です。
Project Actress – MachiaWorks (machiaworx.net)
開発日記は下記のWebサービス使ってます。
ちょうど下記のページにてMiniscriptでザコとボスの行動パターンを制御できるようにしてます。
実際の組み込み関数使ったソースコードのサンプルも書いてますので、よかったら見てみてくださいな。