Zpět

Vue.js & PlayCanvas

Ukázka #1 - Data-binding do 3D scény

  • // Předpoklad: Vytvořená základní scéna s kamerou a světelným zdrojem 
    function (scene) {
    
        var data = {};
    
        // načtení fontu
        var font = new pc.Asset('Arial.json', "font", { url: "../../../libs/playcanvas/Arial.json" });  
        scene.assets.on('load', function () {
    
            // text ve 3D scéně
            var text = new pc.Entity("text", scene);
            text.addComponent("element", {
                type: "text",
                anchor: [0, 0, 0, 0],
                pivot: [0.5, 0.5],
                fontSize: 16,
                fontAsset: font,
                opacity: 1,
                color: [0, 0, 1],
                shadowColor: [0, 0, 1],
                shadowOffset: [0.2, -0.2],
                text: "Hello World!"
            });
            text.setLocalScale(1 / 32, 1 / 32, 1 / 32);
            scene.root.addChild(text);
    
            // propojení textu a datového modelu aplikace pomocí mapy
            new MW.TwoWayMap({
                end1: data,
                map1: MAP.TEXT.to3DModel,
                end2: text,
                map2: MAP.TEXT.toDataModel,
                data1: {
                    text: 'Hello world!',
                    diffuseColor: '#dd3300',
                    outlineColor: '#ee9966'
                }
            });
    
            // Vue aplikace
            var app1 = new Vue({
                el: '#app1',
                data: data
            });
        });
    
        scene.assets.add(font);
        scene.assets.load(font);
        
    }
  • 
    <form>
    	<div>
    		<label>Text</label>
    		<input type="text" v-model="text" />
    	</div>
    	<div class="grid">
    		<div>
    			<label>Základní barva</label>
    			<div>
    				<input type="color" v-model="diffuseColor" />
    				<span :style="'color: ' + diffuseColor"> {{ diffuseColor }} </span>
    			</div>
    		</div>
    		<div>
    			<label>Barva lesku</label>
    			<div>
    				<input type="color" v-model="specularColor" />
    				<span :style="'color: ' + specularColor"> {{ specularColor }} </span>
    			</div>
    		</div>
    	</div>
    </form>
    
{{ diffuseColor }}
{{ outlineColor }}

Ukázka #2 - Práce s polem

  • // Předpoklad: Vytvořená základní scéna s kamerou a světelným zdrojem 
    function (scene) {
        
        var group = new pc.Entity("group", scene);
        group.setLocalScale(0.2, 0.2, 0.2);
        scene.root.addChild(group);
    
        // funcke pro vytvoření 3D kostky
        function createCube(index) {
            var data = {};
            var cube = new pc.Entity("box" + index, scene);
            cube.addComponent("model", { type: "box" });
            var material = new pc.StandardMaterial();
            material.update();
            cube.model.material = material;
            group.addChild(cube);
    
            // propojení kostky s datovým modelem
            new MW.TwoWayMap({
                end1: data,
                map1: MAP.CUBE.to3DModel,
                end2: cube,
                map2: MAP.CUBE.toDataModel,
                data1: {
                    color: getRandomColor(),
                    element: cube,
                    index: index
                }
            });
    
            group.setLocalPosition(-index * 0.2, 0, 0);
            cube.setLocalPosition(index * 2, 0, 0);
            return data;
        }
    
        // Vue aplikace
        var app2 = new Vue({
            el: '#app2',
            data: {
                items: [
                    createCube(0),
                    createCube(1)
                ],
            },
            methods: {
                // metoda pro přidání kostky
                add: function () {
                    this.items.push(createCube(this.items.length));
                },
                // metoda pro smazání kostky
                remove: function (index) {
                    var mesh = this.items[index].element;
                    group.removeChild(mesh);
                    mesh.destroy();
                    this.items.splice(index, 1);
                    for (var i = index; i < this.items.length; i++) {
                        this.items[i].index = i;
                        var original = this.items[i].element.getLocalPosition();
                        original.x = original.x - 2;
                        this.items[i].element.setLocalPosition(original);
                    }
                    group.setLocalPosition(- (this.items.length - 1) * 0.2, 0, 0);
                }
            }
        });
    }
  • 
    <form>
        <ul>
            <li v-for="(item, index) in items">
                <div class="grid">
                    <div>
                        <label>Objekt #{{index + 1}}</label>
                        <div>
                            <input type="color" v-model="item.color" />
                            <span :style="'color: ' + item.color"> {{ item.color }} </span>
                        </div>
                    </div>
                    <div>
                        <label>Šířka {{ Math.floor(item.size.x * 100) }}%</label>
                        <input type="range" v-model="item.size.x" min="0.1" max="2" step="0.1" />
                    </div>
                    <div>
                        <label>Výška {{ Math.floor(item.size.y * 100) }}%</label>
                        <input type="range" v-model="item.size.y" min="0.1" max="2" step="0.1" />
                    </div>
                    <div>
                        <label>Délka {{ Math.floor(item.size.z * 100) }}%</label>
                        <input type="range" v-model="item.size.z" min="0.1" max="2" step="0.1" />
                    </div>
                    <div>
                        <label>X {{ item.position.x || 0 }}</label>
                        <input type="range" v-model="item.position.x" min="-1" max="1" step="0.1" />
                    </div>
                    <div>
                        <label>Y {{ item.position.y || 0 }}</label>
                        <input type="range" v-model="item.position.y" min="-1" max="1" step="0.1" />
                    </div>
                    <div>
                        <label>Z {{ item.position.z || 0 }}</label>
                        <input type="range" v-model="item.position.z" min="-1" max="1" step="0.1" />
                    </div>
                    <div>
                        <a v-on:click="remove(index)">Smazat</a>
                    </div>
                </div>
            </li>
        </ul>
        <a v-on:click="add()" > Přidat nový objekt</a>
    </form>
    
  • #8c675a
  • #898472
Přidat nový objekt

Ukázka #3 - Pokročilejší scéna

  • // Předpoklad: Vytvořená základní scéna s kamerou a světelným zdrojem 
    function (scene) {
    
        // "Vlákno" 3D scény
        window.sceneWorker = new MW.SyncWorker(function (worker) {
    
            // načtení fontu
            var font = new pc.Asset('Arial.json', "font", { url: "../../../libs/playcanvas/Arial.json" });
            scene.assets.on('load', function () {
    
                var leds = [], lights = [], number = 0;
    
                // základní deska
                var ledBoard = new pc.Entity("group", scene);
                ledBoard.setLocalScale(0.2, 0.2, 0.2);
                scene.root.addChild(ledBoard);
                ledBoard.rotateLocal(70, 0, 0);
                var board = new pc.Entity("board", scene);
                board.addComponent("model", { type: "box" });
                var material = new pc.StandardMaterial();
                material.diffuse = new pc.Color(0.05, 0.4, 0.05),
                material.update();
                board.model.material = material;
                board.setLocalScale(16, 0.1, 6);
                ledBoard.addChild(board);
    
                // Zlatý text
                function GoldText(text, size, z) {
                    var textMesh = new pc.Entity("text", scene);
                    textMesh.addComponent("element", {
                        type: "text",
                        anchor: [0, 0, 0, 0],
                        pivot: [0.5, 0.5],
                        fontSize: size,
                        fontAsset: font,
                        opacity: 1,
                        color: [0.8, 0.6, 0],
                        text: text
                    });
                    textMesh.setLocalPosition(0, 0.06, z);
                    textMesh.rotateLocal(-90, 0, 0);
                    this.mesh = textMesh ;
                }
                ledBoard.addChild((new GoldText("LED Diody (8 bitu)", 0.8, -1.5)).mesh);
    
                // materiály pro LED diodu
                var ledOffMaterial = new pc.StandardMaterial();
                ledOffMaterial.diffuse = new pc.Color(0.4, 0.4, 0.4);
                ledOffMaterial.emissive = new pc.Color(0.6, 0.6, 0.6);
                ledOffMaterial.opacity = 0.8;
                ledOffMaterial.blendType = pc.BLEND_NORMAL;
                ledOffMaterial.update();
                var ledOnMaterial = new pc.StandardMaterial();
                ledOnMaterial.opacity = 0.8;
                ledOnMaterial.blendType = pc.BLEND_NORMAL;
                var glowMaterial = new pc.StandardMaterial();
                glowMaterial.cull = pc.CULLFACE_FRONTANDBACK;
    
                // LED Dioda
                function Led(index) {
                    var led = new pc.Entity("led" + index, scene);
                    var sphere = new pc.Entity("sphere" + index, scene);
                    sphere.addComponent("light", { type: "point", range: 0.75 });
                    sphere.addComponent("model", { type: "sphere" });
                    sphere.setLocalScale(0.8, 0.8, 0.8);
                    sphere.setLocalPosition(0, 1, 0);
    
                    var cylinder = new pc.Entity("cylinder" + index, scene);
                    cylinder.addComponent("model", { type: "cylinder" });
                    cylinder.setLocalScale(0.8, 1, 0.8);
                    cylinder.setLocalPosition(0, 0.5, 0);
                    var bottom = new pc.Entity("bottom" + index, scene);
                    bottom.addComponent("model", { type: "cylinder" });
                    bottom.setLocalScale(0.9, 0.2, 0.9);
                    bottom.setLocalPosition(0, 0.1, 0);
                    led.addChild(sphere);
                    led.addChild(cylinder);
                    led.addChild(bottom);
                    lights.push(sphere.light);
    
                    this.switch = function (state) {
                        if (state) {
                            sphere.model.material = ledOnMaterial;
                            cylinder.model.material = ledOnMaterial;
                            bottom.model.material = ledOnMaterial;
                            sphere.light.intensity = 10;
                        } else {
                            sphere.model.material = ledOffMaterial;
                            cylinder.model.material = ledOffMaterial;
                            bottom.model.material = ledOffMaterial;
                            sphere.light.intensity = 0;
                        }
                    }
                    this.mesh = led;
                }
    
                // materiály pro tlačítko
                var buttonMaterial = new pc.StandardMaterial();
                buttonMaterial.diffuse = new pc.Color(0.5, 0.5, 0.8);
                buttonMaterial.update();
                var bottomMaterial = new pc.StandardMaterial();
                bottomMaterial.diffuse = new pc.Color(0.1, 0.1, 0.1);
                bottomMaterial.update();
    
                // Tlačítko
                function Button(index, switchableLed) {
                    var button = new pc.Entity("button" + index, scene);
                    var cylinder = new pc.Entity("cylinder" + index, scene);
                    cylinder.addComponent("model", { type: "cylinder" });
                    cylinder.setLocalScale(0.6, 0.8, 0.6);
                    cylinder.setLocalPosition(0, 0.51, 0);
                    cylinder.model.material = buttonMaterial;
                    var bottom = new pc.Entity("bottom" + index, scene);
                    bottom.addComponent("model", { type: "box" });
                    bottom.setLocalScale(0.8, 0.5, 0.8);
                    bottom.setLocalPosition(0, 0.26, 0);
                    bottom.model.material = bottomMaterial;
                    button.addChild(cylinder);
                    button.addChild(bottom);
                    button.setLocalPosition(0, 0, 2);
    
                    cylinder.onclick = function () {
                        switchableLed.switch(!switchableLed.state);
                        number = (number * 1) + (Math.pow(2, index) * (switchableLed.state ? 1 : -1));
                        worker.postMessage({ type: "number", value: number });
                    }
    
                    this.switch = function (state) {
                        if (state) {
                            cylinder.setLocalScale(0.6, 0.4, 0.6);
                        } else {
                            cylinder.setLocalScale(0.6, 0.8, 0.6);
                        }
                    }
                    this.mesh = button;
                }
    
                // LED Dioda s tlačítkem
                function SwitchableLed(index) {
                    var group = new pc.Entity("switchableLed" + index, scene);
                    var led = new Led(index);
                    var button = new Button(index, this);
                    var text = new GoldText((Math.pow(2, index)).toString(), 0.5, 1.2);
                    group.addChild(led.mesh);
                    group.addChild(button.mesh);
                    group.addChild(text.mesh);
    
                    group.setLocalPosition((((8 - index) - (8 / 2)) * 2) - 1, 0, 0);
                    ledBoard.addChild(group);
    
                    this.switch = function (state) {
                        led.switch(state);
                        button.switch(state);
                        this.state = state == true;
                    }
                    this.state = false;
                }
    
                // inicializace LED Diod s tlačítky
                for (var i = 0; i < 8; i++) {
                    leds.push(new SwitchableLed(i));
                }
    
                // funkce pro nastavení čísla
                function setNumber(value) {
                    number = value;
                    var bin = toBin(number);
                    for (var i = 0; i < leds.length; i++) {
                        leds[leds.length - i - 1].switch(bin[i] == "1");
                    }
                }
    
                // funkce pro nastavení barvy světla
                function setColor(value) {
                    ledOnMaterial.diffuse = (new pc.Color()).fromString(value);
                    ledOnMaterial.emissive = (new pc.Color()).fromString(value);
                    glowMaterial.emissive = (new pc.Color()).fromString(value);
                    for (var i = 0; i < lights.length; i++) {
                        lights[i].color = (new pc.Color()).fromString(value);
                    }
                }
    
                // zpracování přijatých zpráv
                worker.addEventListener("message", function (data) {
                    switch (data.type) {
                        case "init":
                            setColor(data.color);
                            setNumber(data.number * 1);
                            break;
                        case "number":
                            setNumber(data.value * 1);
                            break;
                        case "color":
                            setColor(data.value);
                            break;
                        default: break;
                    }
                });
                worker.postMessage({ type: "sceneReady" });
            });
    
            scene.assets.add(font);
            scene.assets.load(font);
    
        }, true);
    
    }
  • // VUE Aplikace v rámci SyncWorker
    function () {
    
        // "Vlákno" Vue aplikace
        window.appWorker = new MW.SyncWorker(function (worker) {
    
            // výchozí stav datového modelu
            var data = {
                int: 50,
                color: '#ff0000'
            }
    
            // zpracování přijatých zpráv
            worker.addEventListener("message", function (message) {
                switch (message.type) {
                    case "number":
                        data.int = message.value;
                        break;
                    case "sceneReady":
                        worker.postMessage({ type: "init", number: data.int, color: data.color });
                        break;
                    default: break;
                }
            });
    
            // Vue aplikace
            var app3 = new Vue({
                el: '#app3',
                data: data,
                // dopočítáváné vlastnosti pro hexadecimální a binární zápis
                computed: {
                    hex: {
                        get: function () { return toHex(this.int); },
                        set: function (v) { this.int = parseInt(v, 16); }
                    },
                    bin: {
                        get: function () { return toBin(this.int); },
                        set: function (v) { this.int = parseInt(v, 2); }
                    }
                },
                // sledování změn čísla a barvy
                watch: {
                    int: function (v) {
                        worker.postMessage({ type: "number", value: v });
                    },
                    color: function (v) {
                        worker.postMessage({ type: "color", value: v });
                    }
                }
            });
        }, true);
    
        // samotné propojení zasílání zpráv
        window.appWorker.addEventListener("message", window.sceneWorker.postMessage);
        window.sceneWorker.addEventListener("message", window.appWorker.postMessage);
    
    }
  • 
    <form>
    	<div>
    		<label>
    			<span class="left">0</span>
    			<span class="right">255</span>
    		</label>
    		<div>
    			<input type="range" v-model="int" min="0" max="255" step="1" />
    		</div>
    	</div>
    	<div>
    		<div class="grid">
    			<div>
    				<label>Číslo</label>
    				<input type="text" v-model="int" />
    			</div>
    			<div>
    				<label>Binární zápis</label>
    				<input type="text" v-model="bin" />
    			</div>
    			<div>
    				<label>Hexadecimální zápis</label>
    				<input type="text" v-model="hex" />
    			</div>
    			<div>
    				<label>Barva světla</label>
    				<input type="color" v-model="color" />
    				<span :style="'color: ' + color"> {{ color }} </span>
    			</div>
    		</div>
    	</div>
    </form>
    
#ff0000