🎮

Unity WebGL で WebSocket を使う

2023/12/14に公開

この記事は Unity Advent Calendar 2023 シリーズ 2 14日目の記事です。

はじめに

ちょっとした小ネタです。

Unity では、ご存じの通り Web ブラウザ向けにアプリケーションをビルドすることが可能ですが、実際に開発するとなると色々と気を付けなければいけないことが出てきます。

今回はその中でも WebSocket を使う場合どうすれば良いか紹介します。

何が問題か

通常、 Web ブラウザ上では、生のソケットの API を直接利用することはできません。
つまり、ブラウザが提供している API から利用可能な通信プロトコルのみ使用することができます。

Unity の WebGL ビルドでは、 Emscripten を使用して WebAssembly の実行ファイルを生成します。
このとき、 Unity でサポートされている通信ライブラリは UnityWebRequest のみです。

System.Net 名前空間のクラスを使用しても Unity はビルド時に ブラウザの API を使用するように変換してくれません。

つまり、 System.Net.WebSockets は利用できません。

解決策

ではどうするかというと、大まかに解決策は 2 つです。

  1. 既存の WebGL 対応の WebSocket 通信ライブラリを利用する
  2. 通信ライブラリを自作する

1 は当然 2 の方法をやっていますが、 Unity では、 C# から JavaScript の関数を呼び出すためのプラグインの仕組みがあり、この方法で通信ライブラリを自作することが可能です。

JavaScript で WebSocket で通信を行う部分の処理を記述したプラグインを用意し、それを C# 側から呼び出すことで実現できます。

jslib を実装する

C# 側から呼び出す関数を JavaScript で記述します。
ただし、 Emscripten の都合かもしれませんがモダンな書き方は出来ません。

今回は JavaScript 側で WebSocket クライアントのインスタンスを持っておき、そのインスタンスのメソッドを呼び出したりメッセージ受信時などのコールバックを C# で登録する想定の例を紹介します。

例えば jslib 側でこのように WebSocket クライアントのインスタンスを持っておいて、初期化時に C# 側からコールバックを登録するようにします。

https://github.com/yoshd/UnityWebSocket/blob/79dbb52a6c949cf400686127dd2ef90b232fa937/Assets/Plugins/WebSocket.jslib#L1-L8

上記で登録したコールバックは、接続時にこのように呼ばれるような記述を jslib 側でしてあげます。

https://github.com/yoshd/UnityWebSocket/blob/79dbb52a6c949cf400686127dd2ef90b232fa937/Assets/Plugins/WebSocket.jslib#L13-L16

この dynCall という関数を使うことで、 C# 側の関数に引数を渡してあげたりすることが出来ます。

詳細に興味があれば ドキュメント を参照してください。

そして autoAddDeps で jslib 側で定義しておきたい関数などを追加し、 mergeInto で C# 側から呼べるようにします。

https://github.com/yoshd/UnityWebSocket/blob/main/Assets/Plugins/WebSocket.jslib#L76-L77

C# 側から jslib で定義した関数を呼び出す

C# からは、 jslib で実装した関数を DllImport して利用します。
例えばこのような感じになります。

https://github.com/yoshd/UnityWebSocket/blob/79dbb52a6c949cf400686127dd2ef90b232fa937/Assets/Runtime/Internal/WebSocketClientWebGL.cs#L191-L205

jslib 側に渡して上げるコールバックメソッドには、 MonoPInvokeCallback アトリビュートを付けてネイティブコード側から関数ポインタを参照できるようにする必要があります。

https://github.com/yoshd/UnityWebSocket/blob/79dbb52a6c949cf400686127dd2ef90b232fa937/Assets/Runtime/Internal/WebSocketClientWebGL.cs#L157-L161

後は使いやすいようにライブラリ化したり実装するだけです!

まとめ

ということで、 Unity WebGL で WebSocket を利用するためには JavaScript でプラグインを書いて、それを C# から呼び出すようにする必要がるという話でした。
この例の実装だけだと、 WebGL でしか動作せず、エディタでの動作確認すらできなくてさすがに不便なので、 WebGL 以外でも動作するようにラップする層を挟んでおくと良いでしょう。
ちなみに Photon も WebGL 向けには通信プロトコルに WebSocket を利用しており(機能によっては WebRTC かも)、 jslib のプラグインを実装していたりするので興味があれば見てみると面白いかもしれません。

今回の例で使用したのは自分が以前雑に実装したライブラリです。
(コントリビュートなど大歓迎です。)

https://github.com/yoshd/UnityWebSocket

GitHubで編集を提案

Discussion