PlayCanvasでDOMを扱う手引き [ZIPダウンロード編]

[前回はCSSのstyleの話をしました](https://qiita.com/sutobu000/items/3f5f0dae4e17a5f2374e)

前回のstyleの話も、まだまだ色んなstyleや使い方があるから色々試してみて欲しいと思っていたり。

---

# おさらい
さて、PlayCanvasでDOMを扱う方法を書いてきました。

基本はJSでDOMを追加して、style当てることになるかなと。

JavaScriptはVanilla JSで説明していましたが、Vue.jsとかを使っても良いでDOM操作はもっと簡単になるかもしれませんね。

- [DOMを追加する方法はこちら](https://qiita.com/sutobu000/items/79aa414a1352474386e5)
- [CSSのstyleについてはこちら](https://qiita.com/sutobu000/items/017bc70f556e835e57a2)
- [もっとCSSのstyleについて知るのはこちら](https://qiita.com/sutobu000/items/3f5f0dae4e17a5f2374e)


ただ、このJSからDOMを追加するやり方は、**PUBLISH TO PLAYCANVAS**で使う手法かなと思ってます。

というのも、DOMはJSから追加するのはSEO的にもあまり好ましくないと思いますし、個人的にもちょっとめんどくさいです。
とは言っても、PlayCanvasのエディターからではDOM要素を扱うにはJSから追加せざる得ない感じです。

なので、PlayCanvasのエディターからDOMを追加するのではなく、
**PlayCanvasのPublishしたデータをダウンロードしてPlayCanvasをローカル環境に落とし込む**。
このやり方がやっぱ一番良いと思います。


# PlayCanvasのPublishしたデータをダウンロード?
PlayCanvasで作ったコンテンツはダウンロードができます。

**PUBLISH**の画面から**DOWNLOAD .ZIP**という項目があります。
ここからPublishするデータをダウンロードすることができます ~~が、これは**Freeプランでは機能制限で使えません**。
**PersonalプランかOrganizationプランでないと使用できない**のご注意を。~~
**→ 全プランでZIPをダウンロードすることができるようになりました (2020/07/10)**
![スクリーンショット 2019-12-25 13.06.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109168/6f0207b8-bc95-322d-030d-bbfb62ddd1e5.png)


このDOWNLOAD .ZIPをすると以下のようなデータが取得できます。
![スクリーンショット 2019-12-25 13.40.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109168/fabbceb4-4fce-d68b-929c-a89096e1e403.png)
このデータ一式、PUBLISH TO PLAYCANVASのデータとほぼほぼ一緒です。
PUBLISH TO PLAYCANVASした際に生成されるURLリンクの先にこれがあって、index.htmlが読み込まれると思ってもらえると良いかと。

このデータを使ってローカル環境からWebページを作ってみます。

# ダウンロードしたデータについて

## `playcanvas-stable.min.js`
PlayCanvasエンジンのJSですね。
これがないとPlayCanvasは動かないです。

## `__start__.js`
PlayCanvasをスタートするJSです。名前の通りですね。
中身はPlayCanvasのコンテンツを表示するためのcanvas要素を作ったりCSSを指定したりします。

ちなみに、ここで**canvas要素を作ってPlayCanvasコンテンツを表示**していますが、
ここの記述を、**あらかじめcanvas要素を用意**しておき、**そのcanvas要素を参照し、PlayCanvasコンテンツを表示**するということもできます。

この辺りの記述は読みやすいと思うので、自分なりに変更してみると良いでしょう。

## `__game-scripts__.js`
PlayCanvas内で作成し使用するScriptをここにまとめています。
これを読んで書き直すこともできなくもないですが、大体はminifyしてしまっていると思うので、書き換えるならPlayCanvasエディターからのが良いでしょう。

## `__modules__.js`
これもPlayCanvas内で使用しているモジュール類をまとめているやつです。
例えば、PlayCanvasはammo.jsという物理演算ライブラリを使っていますが、これはレガシーのものです。
最新のammo.jsを使いたい場合に、別途Importする必要があります。
[これらについてはこちらを参照]https://developer.playcanvas.com/en/user-manual/physics/physics-migration/
このインポートした最新のammo.jsはモジュールとして扱われ、`__modules__.js`で使用されるようになります。

## `__loading__.js`
PlayCanvasコンテンツを読み込み完了するまでのプログレスバーなどを表示させます。
デフォルトのままだと、PlayCanvasのロゴとプログレスバーが読み込んでいるものが表示されます。


このローディング画面ですが、**変更することができるのはOrganizationプラン**のみです。
かつ、**編集する際もPlayCanvasエディターから編集しなくてはならない**のでご注意ください。
https://developer.playcanvas.com/en/user-manual/designer/loading-screen/
   
**このローディング画面の変更は全プランで変更することができるようになりました。**


## config.jsonと12345678.json
config.jsonはPlayCanvasの設定を保持しているものです。
コンテンツのFillModeだとかresolutionなんかもここで管理されています。

後者の数字のjsonはプロジェクトのシーンIDの数字のことで、シーンの設定データを保持しています。
Entityなんかもここなんじゃないかと思います。

## index.html

もう説明するべきファイルはないと思います。
あとはindex.htmlの中身でしょうか。以下がそのindex.htmlです。

```html
<!doctype html>
<html>
<head>
    <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no' />
    <meta charset='utf-8'>
    <link rel="stylesheet" type="text/css" href="styles.css">
    <link rel="manifest" href="manifest.json">
    <style></style>
    <title>DOMを追加する</title>
    <script src="playcanvas-stable.min.js"></script>
    <script>
        ASSET_PREFIX = "";
        SCRIPT_PREFIX = "";
        SCENE_PATH = "848220.json";
        CONTEXT_OPTIONS = {
            'antialias': true,
            'alpha': false,
            'preserveDrawingBuffer': false,
            'preferWebGl2': true
        };
        SCRIPTS = [ 26178113, 26178100, 26178104, 26178109, 26178168 ];
        CONFIG_FILENAME = "config.json";
        INPUT_SETTINGS = {
            useKeyboard: true,
            useMouse: true,
            useGamepads: false,
            useTouch: true
        };
        pc.script.legacy = false;
        PRELOAD_MODULES = [
        ];
    </script>
</head>
<body>
    <script src="__start__.js"></script>
    <script src="__loading__.js"></script>
</body>
</html>
```

SCRIPT_PREFIXとか書いていますが、ここでメタ情報的なものを設定しています。
ただ、index.htmlにインラインで記述しているのはちょっと気が引けますね。

---

簡単に説明しましたが、使用するのは大体`__start__.js`とか`__loading__.js`とかじゃないかなと。

そんなこんなで実際にPlayCanvasのコンテンツを落とし込んでみたのがこちらのページ
https://sutobu000.com/pc/

クリックするとPlayCanvasのロゴが生成され、右上の四角をクリックするとDOMが表示されます。
DOMに書いていますが、生成したロゴを削除できるボタンも用意。

ここで記載しているDOM要素はPlayCanvasで追加しておらず、別で用意してPlayCanvasのコンテンツを配置しています。


## PlayCanvasコンテンツとDOM間のやりとり
この中で、生成したロゴを削除しているボタンについて説明したいと思います。
PlayCanvasで生成されたロゴ、これは`__game-scripts.js`の中で記述されたScriptsによって実行されています。

これ、DOM側ではそのScriptを参照するのですが、
グローバル変数を作って、PlayCanvasのコンテンツのスクリプトにDOM側からリアクションできるようにしました。

PlayCanvas側でグローバル変数を作成します。
ここではオブジェクトとして作りましたが、これは管理しやすそうってのでオブジェクトにしてます。
`pcpo.delete`を作って消すか消さないかを参照します。
これをupdate関数で監視しています。

```js
pcpo = {};

Script.prototype.update = function (dt) {
    if(pcpo.delete) {
        pcpo.delete = false;
        this.deleteBox();
    }
};
```

`this.deleteBox()`は以下のような感じ。
タグを参照してそいつらを消している感じですね

```js
Script.prototype.deleteBox = function (point) {
    var t_children = this.setEntity[0].parent.children;
    for(var i=0; i < t_children.length; i++) {
        if(t_children[i].findByTag("spawnBox")){
            t_children[i].enabled = false;
        }
    }
};
```


では、上記のScriptからDOM側でリアクションしてみます。

ボタンをクリックしたら、グローバル変数の`pcpo.delete`を変えてあげているだけですね。
これだけでOK!

```js
let $clearBtn = document.querySelector(".section__btn");
$clearBtn.addEventListener("click", (e) => {
    pcpo.delete = true;
});
```

これでデモページのようにDOM側からコンテンツに対して、ボタンを押すアクションからロゴを消すまでのリアクションを起こすことができました。


こんな感じでPlayCanvasではコンテンツ側とDOM側でイベントなどを管理していくと良いのではないかと思っています。
もっとこういう風にしたほうが良い！というやり方があれば、是非ご教授お願いします！


---

大体わかってきたでしょうか？
正直、私自身もやりながら勉強しているのでまだまだ未開な部分もあります。
PlayCanvasを使って、もっと色んな可能性を見出せていけたら良いなと思います。


これで、PlayCanvasでDOMを扱う手引きは終わりです。

他にもDOMを扱うためにVue.jsなどのライブラリを使って見るのもいいですね。

色んなところでWeb3Dなサイトが増えると良いなと思います。

おつかれさまでしたー