本エントリは Unity Advent Calnedar 5 日目の記事です。昨日は @tagia0212 さんによる uGUI で透明じゃないところだけに反応するボタンを作った (Unity) - Qiita でした。
はじめに
サマーレッスンの VR コンソールの話を見て、Unreal Engine にはコマンドを実行できるコンソールがあるのに Unity にはない!何故だ!というモチベーションから uREPL(ゆーれぷる) というアセットを作ってみました。2015/12/5 現在リリースしている v0.2.1 では以下の様な機能をサポートしています。
- (Unity で動く)任意の C# のコードを実行
- コードや GameObject の名前・パスなどの補完
- Attribute をつけるだけで作成可能なコマンド
- Emacs ライクなキーバインド
- 履歴の呼び出し
- GameObject や Component の簡易インスペクタ
- ログ出力
REPL とは Read Eval Print Loop のことで、コードを入力し、それを評価、結果を出力するインタラクティブシェルです。uREPL は Unity の実行時に直接コードを打ち込んでゲームを制御できたり、というものになっています。
デモ
コード実行や補完
Component のインスペクタ
GameObject のインスペクタ
環境
- Mac / Win
- Unity 5
インストール
上記 GitHub の Release ページよりダウンロードして下さい。
メニューの「Asset > Create > uREPL」を選択するか、Project ビューで「uREPL > Resources > uREPL > Prefabs > uREPL」を Hierarchy ビューへドラッグするかで設定は完了です。シーンに EventSystem
がない場合は UI の操作ができないので、「Hierarchy ビュー > Create > UI > EventSystem」から作成して下さい。
想定ユースケース
キーバインド
通常時
Key | Description |
---|---|
ctrl + a |
先頭へ移動 |
ctrl + e |
行末へ移動 |
ctrl + f , right arrow |
1文字進む |
ctrl + b , left arrow |
1文字戻る |
ctrl + h , backspace |
カーソル手前の1文字を消す |
ctrl + d |
カーソル後の1文字を消す |
ctrl + k |
カーソル位置から行末までを消す |
ctrl + l |
ログをクリア |
ctrl + n , up arrow |
1つ後の履歴を表示 |
ctrl + p , down arrow |
1つ前の履歴を表示 |
ctrl + tab |
補完 |
enter |
実行 |
補完時
Key | Description |
---|---|
ctrl + n , up arrow |
下の補完候補を選択 |
ctrl + p , down arrow |
上の補完候補を選択 |
tab , enter |
選択している補完を入力 |
esc |
補完ウィンドウを閉じる |
コマンド
コマンドの作成
コマンドは、command args1 args2 ...
という形式で入力できる構文で、以下の様に static public なメソッドに uREPL.Command
アトリビュートを付与することによって作成できます。
public class CommandTest { // 例として GameObject の情報を扱う static public GameObject gameObject; // アトリビュートをつけるとクラス名、括弧を省略したメソッド名でコマンドを呼び出せる // $ ShowCurrentSelectedObject ⏎ [uREPL.Command] static public string ShowCurrentSelectedObject() { return gameObject.name; } // name を指定するとメソッド名の代わりにそれを利用できる // $ selected ⏎ [uREPL.Command(name = "selected")] static public string ShowCurrentSelectedObject2() { return gameObject.name; } // description を指定すると補完時にそのコメントが表示される [uREPL.Command(name = "selected2", description = "show the selected gameobject name.")] static public void ShowCurrentSelectedObject3() { Debug.Log(gameObject.name); } }
引数付きコマンド
引数付きコマンドは引数は () で括ってあげたり、変数を渡したり出来ます。
public class CommandTest { // 同じくアトリビュートをつけるだけ [uREPL.Command(name = "print")] static public string Print(object obj) { return obj.ToString(); } // オーバーロードも可 [uREPL.Command(name = "print")] static public string Print(string value1, int value2, float value3) { return string.Format("string: {0}, int: {1}, float: {2}", value1, value2, value3); } }
ビルトインコマンド
以下の様なコマンドが用意されています。
help
- キーボードショートカットなど
commands
- 全てのコマンドを確認(ユーザ定義含む)
close
- uREPL のウィンドウを閉じる
inspect
GameObject
またはComponent
を渡すとインスペクタを表示
その他のコマンドについては、commands
コマンドから一覧を確認してください。
インスペクタ
inspect
コマンドで GameObject か Component を渡すか、拡張メソッドの GameObject.Inspect()
または Component.Inspect()
を利用すると、public メンバのみを同期して表示する簡易インスペクタをゲーム内で利用できます。詳細は冒頭のデモムービーを御覧ください。
GameObject
Component
ログ
現在は 3 レベルのログが使用できます。
static public class LogTest { [Command(name = "show logs")] static public void ShowLogs() { uREPL.Log.Output("this is normal log."); uREPL.Log.Warn("this is warning log."); uREPL.Log.Error("this is error log."); } }
他にもテクスチャの確認のための画像表示やパフォーマンス表示用にグラフの描画など色々なログを追加したいです。
補完プラグインの追加
uREPL ではデフォルトで、コード補完、GameObject の名前・パスの補完、コマンドの補完をサポートしていますが、ユーザ側で CompletionPlugin
を継承したクラスを作成し、どこかのオブジェクトにアタッチすれば別の補完手法を追加することも出来ます。
using UnityEngine; using System.Linq; using uREPL; // CompletionPlugin は MonoBehaviour の派生 public class SampleCompletion : CompletionPlugin { string[] gameObjectNames_; public void Update() { gameObjectNames_ = GameObject.FindObjectsOfType<GameObject>() .Select(go => go.name) .ToArray(); } // メインスレッド以外から呼び出されるため GameObject に関する情報などは // 別途収集しておく必要がある public override CompletionInfo[] GetCompletions(string input) { var partialName = input.Substring(input.LastIndexOf("\"") + 1); return gameObjectNames_ .Where(name => name.IndexOf(partialName) == 0) .Select(name => new CompletionInfo(partialName, name, "G", Color.red)) .ToArray(); } }
その他
複数 GUI 対応
対応していたのですが、どこからかバグってしまったので修正します。。
ワールドスペース対応
一部まだバグが有るのですがワールドスペースにも対応していて、VR 内などでも使えると思います。
ビルド
一部制限がありますがビルドしても動きます。
仕組み
Mono.CSharp
を利用しています。
Mono.CSharp.Evaluator.Evaluate()
を利用すると C# で eval することが可能になります。
また、同様に補完候補についても Mono.CSharp.Evaluator.GetCompletions()
に部分的なコードを渡すと返してくれますので、これを利用しています。
両者ともに string
の結果しかもらえないため、型情報も含めた結果の出力やリッチな補間は出来ないのですが、簡易的なものなら作成することが出来ます(出来る方法があったら教えて下さい)。
eval する際に、どのアセンブリ(DLL)の情報を使うか予め Mono.CSharp.Evaluator.ReferenceAssembly()
で登録しておかないと行けないのですが、これは以下のフォーラムの回答を参考にしています。
- Mono.CSharp.Evaluator - Unity Forum
- https://github.com/hecomi/uREPL/blob/master/Assets/uREPL/Scripts/Core/Core.cs#L69-L81
eval すること自体は簡単だったのですが、GUI を作るのが大変でした...。
先行事例
同様に Mono.CSharp
を利用して REPL を行うアセットは結構あります。特に Editor 上での利用に関しては先行事例がたくさんあります。
- 【Unity】エディタ上でREPLできるEditorRepl【エディタ拡張】 – ケットシーウェア
- Editor 上で REPL するアセットです。
- REPL - Unify Community Wiki
- こちらも Editor 用 REPL アセット(2010 年製)。現在は動作しません。
- GitHub - MrJoy/UnityREPL: C# REPL tool for Unity3D built on Miguel's tool.
- 同じく Editor 上
- 現在もアップデートが続けられているようですが残念ながら手元では動きませんでした...
- 動作例が Wiki に載っています
- GitHub - arcadia-unity/Arcadia: Clojure in Unity
- Clojure で Unity を制御するアセット
- Arcadia 0.1 Setup - YouTube
- GitHub - Wenzil/UnityConsole: Easy-to-use developer console for Unity 5
- 実行時に利用
RegisterCommand()
で static public な関数を登録して実行- (uREPL では
uREPL.Command
アトリビュートで同等の機能を実現)
おわりに
個人的には VR の中で自由自在にコンソールから世界を構築する!みたいなイメージではなく、パラメタ調整やコマンド実行といった堅実なデバッグが出来るところを目標にしていますが、色々な要望が貰えればと思っています。他にも色々と使い道があったら是非教えて下さい。個人的にはネットワーク越しにお互いにコマンド送り合ってカチャカチャやって戦うみたいなのを考えたのですが、そのままではセキュリティ駄目そうですね。。
まだまだおもちゃ程度で本当に開発が便利になるところまでは出来てないので、色んな機能や他アセットとの連携等を随時追加していこうと思います。欲しい機能などございましたら GitHub の issues に書いて頂けると嬉しいです(英語が嫌な方は Twitter でも構いません)。
明日の Unity Advent Calendar は @p_chin さんによる「UnityProject内でのコードレビューとComponent設計をする時に気をつけてる事」になります。