Help us understand the problem. What is going on with this article?

PlayCanvasでモデルがクリックされたときにHTMLの表示を切り替える方法

PlayCanvasとHTMLを組み合わせる

PlayCanvasとHTMLを組み合わせる方法について紹介をします。

PlayCanvasは特性上、エディターを使用した開発でHTMLを触ろうとすると少し癖があります。JavaScriptのフレームワークと組み合わせることで解消も可能だったりもします。

一例
playcanvas-next-test

PlayCanvas界隈では様々な方法が試されていると思いますがその中で自分が、メンテナンス性などのも考えて、使いやすかったものを紹介します。

今回はPlayCanvasの基本的な説明は省いています。

今回作るもの

このような3Dモデルが並んでいるページで、モデルがクリックされたらHTMLの表示を切り替えるものを作ります。

例: https://playcanv.as/p/9uV03p1Y/

モデルがクリックされたらモデルの情報をDOMを切り替えるものになります。
  
(モデルはサンディちゃんを使用しています。)

HTMLを組み込む

PlayCanvasのエディター上でHTML, CSSを組み込む

HTMLを組み込むためにそれぞれのスクリプトを追加します。
こちらは様々な方法があるかと思いますが、insertAdjacentHTMLを使用してHTMLを組み込みます。

1. ui.js index.html, style.cssを作成する

ui.js
const 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"
});

Ui.prototype.initialize = function() {
  const body = document.getElementsByTagName("body")[0];
  const head = document.getElementsByTagName("head")[0];
  const style = `<style>${this.css.resource}</style>`;
  body.insertAdjacentHTML("afterbegin", this.html.resource);
  head.insertAdjacentHTML("afterbegin", style);
};
index.html
<div class="container">
    <h2 class="title">タイトル</h2>
    <h2 class="url">URL</h2>
    <img class="image" />
</div>
style.css
.container{
    position: absolute;

    background-color: white;
    z-index:1;
}

.container img{
    object-fit: cover;
    width:300px;
    height:300px;
}

スクリプトにCSSHTMLを追加する

Rootのエンテティにui.jsを追加します。追加ができたら、style.cssindex.htmlを設定します。

スクリプト属性
スクリプトのアトリビュート機能は、スクリプト内で使用する変数をPlayCanvasエディタ内で編集することができるようにする便利な機能です。この機能を使うことで、一度コードを書いた後にエンティティごと作られるインスタンスにそれぞれ違うパラメータを設定する調整ができるようになります。これにより、アーティスト、デザイナーやその他のプログラマーではないチームメンバーがコードを書かずに値を変更できるにプロパティを露出させることができます。
https://developer.playcanvas.com/ja/user-manual/scripting/script-attributes/

情報を保持するためのスクリプトを追加

次に、各モデルに、クリックされた時の情報を追加します。

info.jsを作成

info.jsとしてスクリプトを作成します。
このスクリプトの役割は、プログラムを変更せずに変更できる値を保存しておくために存在しています。

info.js
/*jshint esversion: 6, asi: true, laxbreak: true*/
const Info = pc.createScript('info');
Info.attributes.add("title", {"type": "string", default: "example"})
Info.attributes.add("url", {"type": "string" , default: "https://example.com"})
Info.attributes.add("image", {"type": "asset"})

スクリプトを適用する

スクリプトを追加すると、それぞれtitleurlimageと値を設定できるようになります。クリックされたときにはエンテティのこの値を使用して表示を切り替えるようにします。

クリックされたときに値を切り替えるスクリプトを追加

最後にクリックされたときに情報を切り替えるためのスクリプトを追加します。
こちらはCAMERAコンポーネントを持っている持っているエンテティに追加します。

マウスが押されたときに、直接DOMの切り替えを行なっています。

picker-raycast.js
/*jshint esversion: 6, asi: true, laxbreak: true*/

const PickerRaycast = pc.createScript('pickerRaycast');

// initialize code called once per entity
PickerRaycast.prototype.initialize = function() {

    // マウスがクリックされたときに、onSelect関数を実行します
    this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onSelect, this);
};

PickerRaycast.prototype.onSelect = function (e) {
    const from = this.entity.camera.screenToWorld(e.x, e.y, this.entity.camera.nearClip);
    const to = this.entity.camera.screenToWorld(e.x, e.y, this.entity.camera.farClip);

    // クリックされた位置にエンティティがあれば result.entityにentityの情報が入ります
    const result = this.app.systems.rigidbody.raycastFirst(from, to);

    if (result) {
        const entity = result.entity;
        // entityにinfoというスクリプトが含まれているかを調べます。
        if(entity.script && entity.script.hasOwnProperty('info')){

        // title: string
        // スクリプト名 infoの属性 titleを参照します
        const title = entity.script.info.title

        // url: string
        // スクリプト名 infoの属性 url
        const url = entity.script.info.url

        // image: Asset
        // スクリプト名 infoの属性 imageを参照します
        // imageのtypeはAssetなので、getFileUrl()関数を使用してAssetのURLを参照します。
        const image = entity.script.info.image
        const imageUrl = image.getFileUrl()

        // ui.jsで追加したHTMLの要素を取得します
        const titleElement = document.getElementsByClassName("title")[0]
        const urlElement = document.getElementsByClassName("url")[0]
        const imgElement = document.getElementsByClassName("image")[0]

        // HTMLの要素を書き換えます
        titleElement.textContent = title
        urlElement.textContent = url
        imgElement.src = imageUrl
        }    
    }
};

感想

すべてのモデルで決まった値を表示したい場合にはこちらの方法を使うことで表示を切り替えることができます。
ただ、複雑に切り替わる場合などには向いていないためシンプルに実装したいときに使っております。

今回のプロジェクトで質問や意見がありましたら。@mxcn3まで連絡をお願いします。

yushimatenjin
インターネットに無限の可能性を感じています。
https://twitter.com/Mxcn3
playcanvas
"PlayCanvasは、ブラウザ向けに作られたWebGL/HTML5ゲームエンジンです。PlayCanvas運営事務局は日本国内でのPlayCanvasの普及を目的に活動しています"
https://playcanvas.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした