PlayCanvasでサンディちゃんを歩かせるゲームを作るぞ☆（第5回）〜CSSとHTMLでUI部品作成〜

# こんなん作ってます。
https://playcanv.as/b/iAPwWXqY/
※本解説よりも開発が進んでいることもございますのでご了承ください。

# そういえばUIのことを考えていなかった・・・
ゲームのメイン部分を作っててメッセージとかステータスを表示するUI部分を忘れてた・・・てこと、よくありますよね。
私もよく後になってテキトーなものを作ることが多々あります。

PlayCanvasはJavaScriptベース・・・ということは、HTMLがそのまんま使えるんじゃね？

・・・

チュートリアルにありました。（説明はない）
https://developer.playcanvas.com/ja/tutorials/htmlcss-ui/

今回はほぼチュートリアルに沿う形で、かつ僕が使いやすいテンプレートになるように、HTMLでダイアログを作ってメッセージを表示するところまでやります。
（とりあえずUI部品を画面全体に置いてみて）


# 表示したいHTMLを作成する
Assetsでuiディレクトリを作成し、その直下に「css」「message」を用意します。
![スクリーンショット 2020-02-23 15.12.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110583/1dae1cf6-b6eb-c2d5-db72-d9dcf99c54f6.png)

「css」はそのままの意味です。（わかんない人は置いていく主義・・・）

```css
.container {
    height: 16vh;
    width: 25vw;
    
    background-color: #444;
    padding: 8px;
    
    color: #fff;
    font-size: 18px;
    font-weight: 100;
    border-radius: 12px;
    box-shadow: 0 0 16px rgba(0, 0, 0, .3);
}

.container > .button {
    float: right;
    display: inline-block;
    background-color: #07f;
    padding: 0 16px;
    font-size: 18px;
    line-height: 32px;
    border-radius: 4px;
    cursor: pointer;
    
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.container > .caption {
    background-color: #E85700;
    width :100%;
    //padding: 0 16px;
    font-size: 20px;
    line-height: 32px;
    border-radius: 0px;
}

.container > .message {
    //margin-top: 52px;
    padding: 0 16px;
    font-size: 18px;
    line-height: 32px;
    border-radius: 0px;
}

.pos_top_left {
    position: absolute;
    top: 0;
    left: 0;
    margin: auto;
}


.pos_top_center {
    position: absolute;
    left: 0;
    right: 0;
    margin: auto;
}

.pos_top_right {
    position: absolute;
    top: 0;
    right: 0;
    margin: auto;
}

.pos_center_left {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    margin: auto;
}

.pos_center_center {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}

.pos_center_right {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}


.pos_bottom_left {
    position: absolute;
    left: 0;
    bottom: 0;
    margin: auto;
}

.pos_bottom_center {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}

.pos_bottom_right {
    position: absolute;
    right: 0;
    bottom: 0;
    margin: auto;
}

```

containerクラスはゲームからのメッセージを載せるダイアログの形状、pos_~のクラスは表示する位置（左上・中央上・右上・左中央・画面真ん中・右中央・左下・中央下・右下）を示します。

「message」は表示するHTMLを書きます。ヘッダ部などは今回は要りません。

```html
<div class="container pos_center_center">
    <div class="caption">center</div>
    <div class="message">center</div>
    <div class="button">Close</div>
</div>

<div class="container pos_top_left">
    <div class="caption">top</div>
    <div class="message">left</div>
    <div class="button">Close</div>
</div>


<div class="container pos_top_center">
    <div class="caption">top</div>
    <div class="message">center</div>
    <div class="button">Close</div>
</div>

<div class="container pos_top_right">
    <div class="caption">top</div>
    <div class="message">right</div>
    <div class="button">Close</div>
</div>

<div class="container pos_center_left">
    <div class="caption">center</div>
    <div class="message">left</div>
    <div class="button">Close</div>
</div>

<div class="container pos_center_right">
    <div class="caption">center</div>
    <div class="message">right</div>
    <div class="button">Close</div>
</div>


<div class="container pos_bottom_left">
    <div class="caption">bottom</div>
    <div class="message">left</div>
    <div class="button">Close</div>
</div>

<div class="container pos_bottom_center">
    <div class="caption">bottom</div>
    <div class="message">center</div>
    <div class="button">Close</div>
</div>

<div class="container pos_bottom_right">
    <div class="caption">bottom</div>
    <div class="message">right</div>
    <div class="button">Close</div>
</div>


```

９つのダイアログを表示します。


# スクリプトからHTMLを読み込んで表示
まずスクリプトを作成。
Assetsでsrcディレクトリ直下に「ui.js」を作成。
スクリプト属性で「css」「html」を作成。
（後ほどエディタ上から、cssにはAssets/ui上のcssを、htmlには同じくmessageを渡すようにします）

```ui.js
var Ui = pc.createScript('ui');

Ui.attributes.add('css', {type: 'asset', assetType:'css', title: 'CSS Asset'});
Ui.attributes.add('html', {type: 'asset', assetType:'html', title: 'HTML Asset'});


// initialize code called once per entity
Ui.prototype.initialize = function() {
    // CSSを適用する
    var style = document.createElement('style');
    document.head.appendChild(style);
    style.innerHTML = this.css.resource || '';
    
    // DIVタグを作成し、messageファイルの中身を書き込む
    this.div = document.createElement('div');
    this.div.innerHTML = this.html.resource || '';
    
    // 画面に作成したDIVタグを載せる
    document.body.appendChild(this.div);
    
};

```

次にRoot直下に「ui」という名前で空のEntityを作成し、ADD COMPONENTでSCRIPTを追加し、ui.jsを使うように割り当てます。
そしてスクリプト属性「css」にアセットの「css」を、「html」にアセットの「html」を充てます。

Launchすると・・・

![スクリーンショット 2020-02-23 15.55.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110583/08f2765a-fa89-71f3-3c38-b0da5b0ddf81.png)

はい、鬱陶しいほどダイアログが並んで出てきました！！


# Closeボタンで閉じる
```ui.js

// initialize code called once per entity
Ui.prototype.initialize = function() {
    ・・・
    //最後に追加
    this.bindEvents();
}

Ui.prototype.bindEvents = function() {
    var self = this;

    // get button element by class
    var button_list = this.div.querySelectorAll('.button');
    var container_list = document.querySelectorAll('.container');

    button_list.forEach(function(button) {
        // add event listener on `click`
        button.addEventListener('click', function() {
            container_list.forEach(function(value) {

                value.style.display = 'none';

            });
        }, false);
    });
};
```

DOM要素にイベントをバインドする関数を用意して、Initialize関数で呼び出しています。
「どれか一つでもCloseボタンを押したら全てが非表示になる」という仕様にしていますが、もちろん個別で消せるようにもできます。
今回はわかりやすく大雑把にやらせてもらいました。

・・・ただこのやり方よりも、vue.js使う方がよりスマートに作れそうな気がしてます。