UnityアプリケーションをNamedPipe経由で制御する

以下のようなWindowsアプリケーションから、UnityアプリケーションをNamedPipeを介して制御する方法を紹介する。なおソースコード全体はGitHubのリポジトリに置いてある。

Windows側

Unity側にメッセージを送るときには、NamedPipeのクライアントであるIPCクラスを利用する。以下では、ViewにバインドされたプロパティでUnity側にメッセージを送っている。SendはUnity側からの応答を返す。

Unity側

まず第一に、NamedPipeをUnityで利用するには、Player SettingsでApi Compatibility Levelを.NET 4.xにする必要があることに注意してほしい。エディターのプレイモードなら.NET Standard 2.0でも動くが、standalone playerでエラーになってしまう。

Unity側ではこちらのIPCクラスを使用する。以下にNamedPipeの待ち受けを行うReceiveメソッドの定義を示す。

UniTaskを用いた非同期メソッドになっている。コルーチンよりもUniTaskのほうがずっと簡単に非同期操作を実装できる。ここでNamedPipeの非同期系(~Async)のメソッドを用いていないのは、Unityには非同期系のメソッドが実装されていないからだ。コンパイルは通るが実行時にエラーになるので注意してほしい。

以下は、Windowsからのメッセージを処理するControllerクラスである。すべてのシーンに空のGameObjectを配置して、Controllerオブジェクトをコンポーネントとして張り付ける。

AwakeでControllerをDontDestroyOnLoadを使用して、シーンが変わったときにControllerが破棄されないようにしている。そうしないとLoadSceneでシーンを切り替えた後にWindows側に応答を返せなくなる。Startではメッセージのハンドラーを与えてIPC.Runを実行する。

OnDisableでは以下に実装を示したIPC.Closeを呼んでいる。IPC.Closeは、シーンの切り替え中はパイプが接続中なので何もせずに終了する。

それ以外は自身のNamedPipeに接続して、IPC.Receiveの待ち受け状態を解除する。エディターのプレイモードで実行したときに、そうしないと待ち受けスレッドが残り、終了時とコードリロード時にエディターがフリーズする。

上で紹介した2つのIPCクラスは私が独自に実装したものだ。UnityでNamedPipeを使う記事はどれも実験レベルで、現実のアプリケーションで問題なく動くように作られていなかったので、自分で実装することにした次第である。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です