🚪

unityroomでJavaScriptライブラリを使う

2021/12/16に公開

この記事はUnity Advent Calendar 2021の16日目の記事です。

成果物

表題の通りunityroomでJavaScriptライブラリを使ってみました。実際に動作するデモとコードを公開しています。

https://unityroom.com/games/javascript_library_sample
https://github.com/tarakoKutibiru/AdventCalendar2021_Unity

はじめに

Unityは大変便利ですが、何か少し凝ったことをやろうと思うと、とたんに面倒くさいことになります。対象プラットフォームごとに場合分けしてネイティブプラグインを書いたり、Unityでも動作する.NET向けのライブラリを組み込んだりする作業が必要になります。

WebGLの場合は、直接ブラウザのAPIを叩きたいときがあります。その場合は.jslib拡張子のファイルを用意して、これを経由してブラウザ側のAPIを叩くのが正攻法です。簡単な機能であれば.jslibを少し書けばすみますが、複雑な機能をUnityの独自形式である.jslibで全て実装するのは大変面倒です。この問題を回避する方法のひとつに、すでに公開されているJavaScriptのライブラリを使う方法があります。

具体的にどうすればよいかと言うと、使いたい.jsファイルをUnityのWebGLプレイヤーが埋め込まれたhtmlページに、Scriptタグで読み込ませれば良いです。これにはいくつかの方法がありますが、unityroomで使いたい場合は実装方法はかなり限られます。

例えば、WebGLゲームを自分のサーバや、Firebase Hostingを使って公開している場合は、htmlを直接書き換えることができるはずです。UnityのWebGLプレイヤーを読み込んでいるhtmlページの適当な箇所に直接

<script src="hoge.js"></script>

と書いたり、WebGLTemplateを編集してScriptを埋め込んだりすれば良いです。しかしunityroomの場合はWebGLゲームのデータをアップロードするだけで、htmlを編集することはできないので、この方法は使えません。

動的にScriptタグを仕込む

この問題はhtmlを動的に編集してScriptタグを仕込むことで回避できます。具体的には以下のような.jslibファイルを用意してゲームが起動したときに、1度Unity側から呼び出すようにします。

Sample.jslib
mergeInto(LibraryManager.library,
    {
        InjectionJs: function (url) {
            url = Pointer_stringify(url);
            var s = document.createElement("script");
            s.setAttribute('src', url);
            document.head.appendChild(s);
        },

        InjectionCSS: function (url) {
            url = Pointer_stringify(url);
            var s = document.createElement("link");
            s.setAttribute('href', url);
            s.setAttribute('rel', 'stylesheet');
            document.head.appendChild(s);
        },

        SwalFireBase: function (body) {
            body = Pointer_stringify(body);
            Swal.fire(body);
        }
    });
Sample.cs
using System.Runtime.InteropServices;

public class Sample : MonoBehaviour
{
    [DllImport("__Internal")]
    public static extern void InjectionJs(string url);

    [DllImport("__Internal")]
    public static extern void InjectionCSS(string url);

    [DllImport("__Internal")]
    private static extern void SwalFireBase(string body);

    void Awake()
    {
        #if !UNITY_EDITOR && UNITY_WEBGL
        {
            var url = "https://cdn.jsdelivr.net/npm/sweetalert2@11";
            InjectionJs(url);
        }
        #endif
    }

    public void ShowMessage(string body)
    {
        SwalFireBase(body);
    }
}

.jsファイルの場所について

多くの場合、JavaScriptライブラリはCDNで公開されているので、それをURLで読み込んで使います。(例えばThree.jsとか。https://unpkg.com/three@0.131.3/build/three.min.js)
そうでない場合は、Firebase Hostingなどのホスティングサービスを使ってホストして読みこむようにしましょう。
.jsファイルをUnityはサポートしていないので、Unityプロジェクトに含めることはできません。自分のサーバや、Firebase Hostingを使ってWebGLゲームを公開している場合は、多くの場合StreamingAssetsフォルダを使えるはずなので、.jsファイルをStreamingAssetsフォルダに置いて読み込むようにしても良いです。しかしunityroomの場合はStreamingAssetsフォルダは使えません。なので前述した方法で対応しましょう。

サンプルについて

記事の冒頭でも言及しましたが、デモとコードを公開しています。

https://unityroom.com/games/javascript_library_sample
https://github.com/tarakoKutibiru/AdventCalendar2021_Unity

適当に面白そうなJavaScriptライブラリを試してみました。自分はWeb畑の人間ではないので、それぞれのライブラリについての理解は非常に浅いことをご留意下さい。

1.SweetAlert2

https://sweetalert2.github.io/

手軽にリッチなモーダルウィンドウを実装できるライブラリのようです。特に特別な権限とかは不要なので、unityroomでも十全に使えると思います。今回試したライブラリの中では一番便利そうです。
GoogleMapやYouTubeをiframeで組み込んだモーダルウィンドウを表示できるのは強いと思います。GoogleMapのサンプルではブラウザのGeometry APIを叩いて現在地の緯度経度を取得してマップに表示する、という実装を試してみたんですが、これはunityroomでは動作しませんでした。WebGLプレイヤーがiframeでサンドボックス化されているのが原因です。なんでもかんでも実行されてしまうと問題があるので、セキュリティ的に当然だと思います。

2.Uppy

https://uppy.io/

ファイルアップローダーです。指定したエンドポイントにファイルをアップロードできます。オプションでモーダルウィンドウで表示できるので、iframeで組み込まれたunityroomからでも使いやすい気がします。ドラッグ&ドロップにも対応しています。

3.Pushbar

https://github.com/oncebot/pushbar.js

unityroomで使う機会はおそらくないです。画面の上下左右からメニューをスライドして表示できます。スライドさせるメニューは動的にDOMを操作して作成する必要があるので、このまま使うのは大変面倒な気がします。別途DOM操作を楽にするライブラリとかなんかを導入するか、事前に用意しておいたhtmlファイルを動的に読み込ませるみたいなことがもしもできれば実用的になるかもしれません。

4.Push.js

https://pushjs.org/

手軽にプッシュ通知を使えるようにするライブラリです。紹介しておいてなんですが、これはunityroomでは動作しません。Gifはunityroomではなくローカルサーバで試してみたものです。uniryroomで使えない理由は前述したGeometry APIと同じです。iframeではユーザーの許可が必要な操作は基本的にできないようです。今回紹介したライブラリの中でもプッシュ通知は、放置ゲームに組み込んだり色々できそうだったので、期待していたんですが使えないのは少し残念です。

あとがき

今回の記事は、もともとWebRTCのDataChannelをWebGLで使うためにアレコレ調べたり検証した内容をまとめたものでした。そっちのほうも公開しているので、よかったらどうぞ。

https://publicfilehost.web.app/AyameDataChannelSample/
https://github.com/tarakoKutibiru/UnityAyameWebGLSample

参考文献

https://tech.griphone.co.jp/2018/11/05/js-on-unity-webgl/
https://qiita.com/void_vtuber/items/2aad097eac69771826fd
https://question.unityroom.com/?qa=225/unityroomではstreaming-assetsは使えないのでしょうか?

Discussion