Válí se ti projekty v šuplíku? Dostaň je mezi lidi a získej cool tričko a body na profi IT kurzy v soutěži ITnetwork summer 2017!
Přidej si svou IT školu do profilu a najdi spolužáky zde na síti :)

4. díl - Zpět a Vpřed

JavaScript 3D webová hra Zpět a Vpřed

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulém díle jsem ukazoval, co to je stav aplikace a jak ho držet. V tomto díle ukáži, jaké výhody nám to přináší.

Logování

Ve chvíli, kdy držíme stav aplikace na jednom místě, můžeme všechny jeho změny velmi elegantně logovat a tím vidět, co se v aplikaci děje. Vytvoříme si funkci wrapReducer.

function wrapReducer(reducer){
    //Kontrola pro případ, že bych byl v prostředí node.js
    if('groupCollapsed' in console){
        return function (oldState,action) {
            console.groupCollapsed(`==[${action.type}]==>`);
            console.log(oldState);
            console.log('||');
            console.log('||');

            console.log(`[${action.type}]`, action);
            const newState = reducer(oldState, action);

            console.log('||');
            console.log('||');
            console.log('\\/');
            console.log(newState);

            console.groupEnd();
            return newState;
        }
    }else{

        return reducer;
    }
}

Potom vytváříme store tak, že reducer nejdříve "obalíme" touto logovací funkcí.

const store = Redux.createStore(wrapReducer(stateReducer), defaultState);

Nyní se po každé akci do konzole prohlížeče vypíše, co se stalo + stav předtím a potom.

URL

Ve webové aplikaci by bylo dobré, aby se každá změna stavu zaznamenávala do URL adresy v prohlížeči. Do URL však nemůžeme uložit příliš mnoho informací a tak můžeme stav ukládat do LocalStorage pod unikátním IDčkem a dané ID dávat do URL adresy.

function loadState(key){
    try {
        const serializedState = localStorage.getItem(key);
        if (serializedState === null) {
            return null;
        }
        return JSON.parse(serializedState);
    } catch (err) {
        return null;
    }
}
saveState(state){
    const key = uuid.v4();
    const serializedState = JSON.stringify(state);
    localStorage.setItem(key,serializedState);
    return key;
}
function createStateFromUri(uri){
    const key = uri.split('#',2)[1];
    const state = loadState(key);
    if(state){
        return state;
    }else{
        return defaultState;
    }
}
function createUriFromState(state){
    var key = saveState(state);
    return `#${key}`;
}

Nyní budeme poslouchat změny na store nejen kvůli vykreslování, ale i proto, abychom si nový stav uložili do LocalStorage a URL.

const store = Redux.createStore(stateReducer, createStateFromUri(document.location.toString()));

const canvas = document.getElementById("scene");
const engine = new BABYLON.Engine(canvas, true);
const scene = createScene(canvas, engine);

function render() {
    updateScene(scene, store.getState());
}

store.subscribe(render);
render();


store.subscribe(()=> {
    const state = store.getState();
    const uri = createUriFromState(state);
    const title = createTitleFromState(state);
    document.title = title;
    history.pushState({}, title, uri);
});

engine.runRenderLoop(function () {
    scene.render();
});


window.addEventListener("resize", function () {
    engine.resize();
});

Zpět a vpřed

Nyní ukládáme stav do URL adresy a při načtení hry ho z něj načítáme. Pokud chceme plně využít potenciál webové aplikace, musíme umožnit uživateli klikat na tlačítka zpět a vpřed v prohlížeči.

let store;
const canvas = document.getElementById("scene");
const engine = new BABYLON.Engine(canvas, true);
const scene = createScene(canvas, engine, ()=>store);

engine.runRenderLoop(function () {
    scene.render();
});

window.addEventListener("resize", function () {
    engine.resize();
});

function render() {
    updateScene(scene, store.getState());
}

//store vytvořím na začátku + vždy když uživatel klikne na zpět nebo vpřed vytvořím store nový a nahradím jím store původní.
function initializeStore() {
    store = Redux.createStore(wrapReducer(stateReducer), createStateFromUri(document.location.toString()));
    store.subscribe(()=> {
        const state = store.getState();
        const uri = createUriFromState(state);
        history.pushState({}, document.title, uri);
    });
    store.subscribe(render);
    render();

}
initializeStore();

//Zde posloucháme, zda uživatel kliknul na tlačítko zpět či vpřed.
window.onpopstate = initializeStore;

Titulek

Na to, aby naše hra naplno využívala historii prohlížeče, už stačí měnit titulek podle aktuálního stavu. Vytvoříme proto funkci, která vyrábí ze stavu titulek stránky.

const WEB_NAME = 'Simple web game';
const TITLE_SEPARATOR = ' | ';

function createTitleFromState(state) {
    let titleParts = [];

    if (state.blocks.length> 1) {
        titleParts.push(state.blocks.length + ' blocks world');
    }
    titleParts.push(WEB_NAME);

    return titleParts.join(TITLE_SEPARATOR);
}

A tuto funkci při každé změně stavu využijeme.

let store;
const canvas = document.getElementById("scene");
const engine = new BABYLON.Engine(canvas, true);
const scene = createScene(canvas, engine, ()=>store);

engine.runRenderLoop(function () {
    scene.render();
});

window.addEventListener("resize", function () {
    engine.resize();
});

function render() {
    updateScene(scene, store.getState());
}

function initializeStore() {
    const initialState = createStateFromUri(document.location.toString());
    document.title = createTitleFromState(initialState);
    store = Redux.createStore(wrapReducer(stateReducer), initialState);

    store.subscribe(()=> {
        const state = store.getState();
        const uri = createUriFromState(state);
        const title = createTitleFromState(state);
        document.title = title;
        history.pushState({}, title, uri);
    });
    store.subscribe(render);
    render();
}
initializeStore();

window.onpopstate = initializeStore;

Rozdělanou hru si můžeš stáhnout pod článkem, nebo jít do Git repozitáře kde najdeš nejnovější verzi. V dalším díle ukáži, jak jednotlivé Javascriptové soubory spojit pomocí nástroje WebPack.


 

Stáhnout

Staženo 6x (5.63 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

 

Článek pro vás napsal Pavol Hejný
Avatar
Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!
Autor se věnuje vývoji mnoha www aplikací - http://pavolhejny.cz/
Miniatura
Předchozí článek
Stav hry
Miniatura
Všechny články v sekci
Vytvoř si vlastní 3D webovou hru
Aktivity (2)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!