Colisão em Grupo

Colisão em Grupo – Como Criar Jogos com PhaserJS

Estou aqui procurando palavras pra fazer uma introdução de impacto e que te deixe impressionado com o que eu fiz, mas a verdade é que eu não consegui concluir o que eu havia me proposto, pelo menos em parte. Como eu havia dito no começo desta série, estes artigos não são bem um tutorial, mas sim os passos que eu tomei no aprendizado do PhaserJS. Ao menos eu consegui ativar a Colisão em Grupo do meu jogo 😛

Proposta

Primeiramente eu havia me proposto a criar um grupo com vários inimigos, e também, uma lógica que permitisse que o jogador identificasse a posição do inimigo e atacasse ele, independente da sua posição. Bom, o grupo de inimigos eu consegui criar, mas não rolou a parte de identificar a posição do inimigo em relação ao jogador. Tem alguma coisa no meu script que não está permitindo que o meu Sprite apresente em qual face ele está batendo (Esquerda, direita, cima, baixo). No fim das contas, eu fiz uma porção de modificações e melhorias no código que eu ja tinha, mas fique à vontade para dar dicas se você souber qual a solução.

Preload de Assets

Quando eu criei o grupo de inimigos eu percebi que da forma como eu havia implementado meu código, cada vez que eu criava um inimigo eu baixava os arquivos json novamente, foi então que eu vi a necessidade de criar uma classe somente para carregar os meus assets antes de utilizá-los.

    /**
    * @description Carrega os sprites e imagens do jogo.
    * @param {*} context contexto
    * @param { string } item nome do item
    * @param {*} game variável global do Jogo.
    */
    function preload(context, item, game)
    {
        fetch(`public/assets/sprites/${item}.json`).then(response =>
        {
            response.json().then(spritesheet =>
            {
                game.cache.custom[item] = spritesheet;

                context.load.spritesheet(item, `public/assets/img/${item}.png`, { frameWidth: spritesheet.width, frameHeight: spritesheet.height });
            });

        }).catch(err =>
        {
            alert("Erro ao carregar armadura do jogador.");
        });
    }

A ideia é que eu passe um array de strings e carregue todos os meus Assets dentro do método preload() do jogo.

import { Preload } from './preload.js';

var preloadAssets = [
    'clotharmor',
    'sword1',
    'bat'
];

function preload() {
    preloadAssets.forEach(item =>
    {
        Preload().preload(this, item, game);
    });
}

Ainda tem algumas coisas que precisam ser trabalhadas, mas com isso eu já garanto um ganho de performance tremendo. Obviamente que eu removi as demais referências que tinham de criação de assets das minhas classes de Player e Enemy.

Eu fiz a mesma coisa com as animações e música.

    /**
     * @description Cria a animação dos elementos carregados.
     * @param {*} context contexto this
     * @param { string } item nome do item
     * @param {*} game variável global do Jogo.
     */
    function createAnimation(context, item, game, speed)
    {
        let ar = game.cache.custom[item];
        for (let armadura in ar.animations) {

            let length = ar.animations[armadura].length - 1;
            let start = ar.animations[armadura].row * 5;
            context.anims.create({
                key: armadura + item,
                frameWidth: ar.width,
                frameHeight: ar.height,
                frames: context.anims.generateFrameNumbers(item, { start: start, end: start + length }),
                repeat: -1,
                frameRate: frameRate ? frameRate : speed
            });
        }
    }

    /**
     * @description Carregaa música do jogo
     * @param {*} context contexto this
     */
    function loadMusic(context)
    {
        var music = context.sound.add('zoltan-town-music', {
            mute: false,
            volume: 1,
            rate: 1,
            detune: 0,
            seek: 0,
            loop: true,
            delay: 0
        });

        music.play();
    }

Criando o grupo de inimigos

Criar um grupo de inimigos é muito simples (Colisão em Grupo). Em teoria, basta criar o grupo e adicionar inimigos à ele. Mas e como ficou essa história no meu código? Bom… Foi bem mais fácil do que eu imaginava.

Primeiro eu criei uma variável para receber o grupo de inimigos e um array vazio de inimigos.

var enemiesGroup;
var enemies = [];

Após isso, eu defini os limites onde os inimigos seriam criados. No meu caso, usei os limites do meu “mundo”.

function create() {
        var spriteBounds = Phaser.Geom.Rectangle.Inflate(Phaser.Geom.Rectangle.Clone(this.physics.world.bounds), -100, -100);
    enemiesGroup = this.physics.add.group({
        collideWorldBounds: true
    });
}

Para criar os sprites já com a animação “idle_down” ativa, eu preciso criar os meus sprites após a criação das animações. Você vai perceber que eu verifico isso utilizando o index dos meus assets.

    // Carrega os Assets definidos na variável de configuração.
    preloadAssets.forEach((item, index) =>
    {
        Preload().createAnimation(this, item, game);
        if (index == preloadAssets.length - 1) {
            player.configPlayer(this, game);
            for (let i = 0; i < numeroInimigos; i++) {
                // Cria uma posição aleatória dentro do retângulo.
                var pos = Phaser.Geom.Rectangle.Random(spriteBounds);
                // Recebe uma referência do item criado.
                var inimigo = enemiesGroup.create(pos.x, pos.y, 'bat');
                // Cria um inimigo.
                var enemy = new Enemy('bat', pos.x, pos.y, 100);
                // Passa o Sprite Criado pelo Grupo de Inimigos.
                enemy.setSprite(inimigo);
                // Inicia a animação.
                enemy.playAnimation('idle_down');
                // Coloca o Inimigo no Objeto criado pelo Crupo para ter acesso ao HP.
                inimigo.enemy = enemy;
                enemies.push(inimigo);
            }
        }
    });

Por fim, ao invés de verificar colisões com um sprite apenas, eu adiciono o grupo que eu criei enemiesGroup, eu também posso usar a minha variável enemies que o resultado será o mesmo. Pra falar a verdade eu tinha criado a variável enemies com um outro propósito, quem sabe no próximo artigo eu a utilize. Perceba que agora eu acesso e.enemy, pois eu adicionei a referência do inimigo criado ao meu Sprite propriamente dito.

    // Adiciona um Listener de colisões entre a espada e o inimigo.
    this.physics.add.collider(player.getSprite().list[1], enemiesGroup,
        function (p, e)
        {
            console.log(e);

            // Muda o status de colisão para falso para colidir apenas 1 vez
            player.setColliderStatus(false);
            // Verifica se o HP do inimigo chegou a 0
            if (e.enemy.getHp() - player.getStrength() > 0) {
                e.enemy.playAnimation('idle_down');
                e.enemy.setHp(e.enemy.getHp() - player.getStrength());
            } else {
                // Zera o HP.
                e.enemy.setHp(0);
                // Se o HP do Inimigo Zerar ele destroi o inimigo.
                e.destroy();
            }

        },
        function ()
        {
            // Se retornar falso não realiza colisão, isso previne que a função acima seja chamada multiplas vezes seguidas.
            return player.getColliderStatus();
        }, this);

Ahh!! Já ia me esquecendo… Eu movi toda a lógica do script de PathFinding para o meu Script do Player.

Conclusão

No fim das contas eu só fiz a metade das coisas que eu havia me proposto (Colisão em Grupo), porém eu aprendi muita coisa no meio do caminho. Confesso que fiquei meio frustrado com isso, mas eu sei que os erros são os melhores amigos dos programadores. Me inspirei a fazer um jogo para o FB Instant Games, devo trazer mais novidades no futuro. Eu sie muito bem que o objetivo aqui não é criar um RPG totalmente funcional, mas aprender os conceitos por trás do PhaserJS. Sinto que todo o conhecimento adquirido nesta séria vai ser muito útil pra mim no futuro. Mas é isso ai, por hoje ficamos pro aqui.

Aquele Abraço!!

BAIXAR CÓDIGO

Referências

Colisões de Grupo
Custom Debug Colors

Leave a comment

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Copyright © – Jonatan Pietroski