codinggames

Carregando fases criadas pelo usuário no Tiled no Phaser JS - Skate Platformer Game Devlog #11

Escrito em 11 de novembro de 2020 - 🕒 3 min. de leitura

Fala pessoal, no devlog de hoje vou fazer uma parada muito legal - carregar dinamicamente arquivos externos de mapa do Tiled criado pelo usuário.

Primeiro, temos que entender como o Phaser funciona. O Phaser é executado dentro de um elemento de canvas do HTML que é anexado a qualquer ID de elemento HTML que você colocar na opção parent de configurações do Phaser, então, se eu quiser usar uma ação relacionada ao browser, como enviar um arquivo usando o elemento HTML de file input, eu tenho que cria-lo manualmente e para depois poder usa-lo quando necessário.

const fileInput = new HtmlFileInput({
    scene: this,
    spriteKey: 'file-input',
});

const callBackFunction = () => {
    // trigget the HTML file input click
    fileInput.fileInput.click();
}

Mas que diabos é esse HtmlFileInput? É basicamente uma classe que em seu construtor eu crio dinamicamente um elemento HTML de input a anexo ele ao DOM da página. A parte de estilo existe para garantir que o elemento não seja visível para o usuário.

class HtmlFileInput {
    constructor({
        scene,
        spriteKey,
    }) {
        // Phaser's parent HTML element
        const mainElement = scene.sys.game.canvas.parentElement;

        // create html input type
        const fileInput = document.createElement('input');
        fileInput.setAttribute('type', 'file');
        fileInput.setAttribute('accept', '.json');
        fileInput.setAttribute('id', spriteKey);

        // TODO this stylings
        fileInput.style.position = 'absolute';
        fileInput.style.top = 0;
        fileInput.style.display = 'block';
        fileInput.style.marginTop = '-400px';

        mainElement.appendChild(fileInput);
        this.setFileInput(fileInput);
        this.setScene(scene);
    }

    setFileInput = (fileInput) => {
        this.fileInput = fileInput;
    }

    setScene = (scene) => {
        this.scene = scene;
    }
}

export default HtmlFileInput;

Eu sei que parece uma gambiarra, mas esta é a maneira correta de fazer isso na Phaser 3, apenas não se esqueça de remover o elemento do DOM quando terminar de usá-lo, chamando fileInput.fileInput.remove().

Agora preciso fazer o parse do arquivo .json enviado pelo usuário e deixa-lo disponível no “gerenciador de arquivos em cache” do Phaser, e a melhor maneira de fazer isso é usando a função preload do Phaser. Primeiro, vamos dar uma olhada em como a função de callback realmente funciona.

const callBackFunction = (data) => {
    fileInput.textfield.onchange = (e) => {
        const reader = new FileReader();
        reader.addEventListener('load', (event) => {
            const result = JSON.parse(reader.result);
            this.scene.start('CustomStageLoadingScene', {
                stageKey: 'custom_stage',
                stageData: result,
                nextScene: 'GameScene',
            });
        });
        reader.readAsText(e.target.files[0]);
    };

    fileInput.textfield.click();
}

Como você pode ver, eu estou usando o FileReader para carregar o arquivo e passando ele como parâmetro para uma scene nova chamada CustomStageLoadingScene que só existe como uma game scene auxiliar para carregar dinamicamente a fase enviada pelo usuário.

class CustomStageLoadingScene extends Scene {
    constructor() {
        super('CustomStageLoadingScene');
    }

    init(data) {
        // data sent as a second parameter when calling the scene
        // will be available here
        const { stageKey, stageData, nextScene } = data;
        this.stageKey = stageKey;
        this.stageData = stageData;
        this.nextScene = nextScene;
    }

    preload() {
        const { stageKey, stageData } = this;
        // make the JSON data available to Phaser's internal cache
        this.load.tilemapTiledJSON(stageKey, stageData);
    }

    create() {
        const { stageKey, nextScene } = this;
        // start the next scene
        this.scene.start(nextScene, { stageKey, stageName: 'custom' });
    }
}

Agora que eu tenho os dados setados com o this.load.tilemapTiledJSON(), eu posso criar o novo estágio com scene.make.tilemap ({key: stageKey}). Show de bola!

E isso é tudo por hoje, por favor, não esqueça de curtir o vídeo e se inscrever no meu canal, e se esses devlogs forem de alguma utilidade para você, me avise nos comentários abaixo. Obrigado e até a próxima.

Tags:


Publicar um comentário

Comentários

Nenhum comentário.