【PlayCanvas】無理やりWebWorkerを使ってマルチスレッド化する


不完全ですがPlayCanvas上でWebWorker使ってマルチスレッド化を実現してみます

やり方

postmessage側とonmessage側のスクリプトをそれぞれ作ります。
postmessage側はPlayCanvasのスクリプトで作成し、適当なエンティティにアタッチしてinitializeに記述します
onmessage側はPlayCanvasスクリプトである必要はありません。

postmessage側

以下スクリプト作成し適当なエンティティにアタッチします

web-worker-test.js
var Webworkertest = pc.createScript('webWorkerTest');

Webworkertest.prototype.initialize = function() {

    if(window.Worker) {
        var workerfile;
        workerfile = this.app.assets.find("recive.js");

        this.worker = new Worker(workerfile.getFileUrl());

        this.worker.onmessage = function(e) {
            var result = e.data;
            console.log("from worker: " + result);
        };
        this.worker.onerror = function(e) {
            console.log(e);
        };
        var data = {
            name: "hello",
            age: 19
        };

        this.worker.postMessage(data);
    }
};

Webworkertest.prototype.update = function(dt) {

};

PlayCanvasのpc.Assets.find()メソッドで呼び出して、Worker()にgetFileUrl()メソッドで渡してあげるところがミソです。

onmessage側

recive.js
onmessage = function(e) {
    console.log(e.data);
};

シンプルにコンソール出力のみです。
こちらはアタッチする必要はありません。

実行

実行すると正しくrecive.jsのonmessageが動いていることが確認できます。

問題

現状Web Workerは"スクリプトファイル単位"で"同一ドメイン"が前提なため、ここから先動かすためにはちょっと問題があります。

ファイル圧縮すると動かない

ビルド時にConcatenate Scriptsにチェックを入れてビルドすると、内部のスクリプトファイルがすべて圧縮され__game-script.jsという名前に変更されてしまうため、正しく参照されなくなってしまいます

playcanv.asだとアセットファイルはCDNにあるため動かない

PlayCanvas上でデプロイするとindex.htmlはplaycanv.as上、アセットファイルはAmazon S3のEUリージョンにデプロイされます。

この状態ではクロスドメインなので当然Workerで呼び出すことはできません。

self hostでクロスドメインにならないような構成に変えてあげれば正しく動作します。