Parte 3 – adicionando inimigo ao jogo

O que veremos aqui?

Neste post, mostrarei como criar um inimigo no jogo. Ele é a continuação do segundo post desta série onde adicionamos o personagem ao jogo.

Adicionando um inimigo ao jogo

Após criar o cenário básico, e adicionar nosso jogador, o próximo passo será adicionar um inimigo, afinal o jogo deve ter dificuldades e emoções!

Neste post vou adicionar um inimigo de uma maneira bastante simples: como uma imagem comum, ou seja, nosso inimigo não terá animações por enquanto.

Escolha um inimigo no google (em png), eu escolhi este:

Inimigo
Inimigo

E o adicione-o na função carregaAssets:


function carregaAssets() {
    game.load.image('fundo', 'assets/fundo.jpg');
    game.load.image('chao', 'assets/chao.jpg');
    game.load.spritesheet('dude', 'assets/dude.png', 32, 48);
    game.load.image('inimigo', 'assets/inimigo.png');
}

A única mudança em relação ao jogador é que o inimigo é adicionado como imagem mesmo (image), já o jogador foi adicionado como spritesheet (uma folha de imagem animada).

Após carregar  a imagem do inimigo no jogo, o próximo passo é criar a função que cria o inimigo:

/**
 * Função que cria o inimigo
 */
function criaInimigo(){
    //  Cria inimigo dentro do grupo inimigos
    var inimigo = inimigos.create(500, 400, 'inimigo');

    //  Define gravidade do inimigo
    inimigo.body.gravity.y = 1500;

    // Faz inimigos não fugirem do mundo
    inimigo.body.collideWorldBounds = true;
}

Veja que usamos uma chamada a inimigos.create(300, 400, ‘inimigo’). Esta função create cria um objeto dentro de inimigos. Porém ainda não criamos o grupo inimigos, então adicione estas duas linhas na função criaCenario:

function criaCenario() {
    // O grupo inimigos será usado para gerenciar todos os inimigos
    inimigos = game.add.group();
    // Definimos aqui que qualquer inimigo terá um corpo,
    // ou seja, nosso personagem pode bater nele
    inimigos.enableBody = true;

    //... código que já tinha aqui
}

Agora que já criamos o grupo de inimigos, e a função que cria o primeiro inimigo, basta chamá-la para que ele apareça no jogo!

Edite novamente a função criaCenario e adicione a chamada da função que cria o inimigo:

function criaCenario() {
    // Chama função que cria inimigo
    criaInimigo();

    //... código que já tinha aqui
}

Agora precisamos garantir que o inimigo respeite os limites das plataformas, ou seja, do nosso chão. Como esta verificação precisa ocorrer a cada instante, insira este código na função autalizaJogo:

function atualizaJogo() {
    // Faz com que inimigos respeitem o chão
    game.physics.arcade.collide(inimigos, plataformas);

    // ... outros códigos que tinham aqui
}

E o resultado será o temível inimigo no jogo:

Inimigo criado no jogo
Inimigo criado no jogo

Fazendo o inimigo seguir o personagem

De nada adianta termos um inimigo temível e perigoso se ele ficar parado não é? Agora vamos fazer ele seguir o nosso jogodor.

Seguir o jogador nada mais é que fazer o inimigo andar para o lado que o jogador se encontra. Ou seja, se o jogador está mais para à esquerda do inimigo, então ele deve ir para esquerda, se estiver mais à direita, então deve ir para direita, simples assim!

Vamos então criar uma função que irá se encarregar de fazer esta verificação e definir para qual lado o bichinho vai andar:


/**
 *  Função que faz inimigo se aproximar do jogador
 */
function aproximaInimigo(){
    // Pega o primeiro elemento do grupo inimigos
    var inimigo = inimigos.children[0];

    // Faz com que ele fique parado
    inimigo.body.velocity.x = 0;

    // Se o inimigo está mais para esquerda do jogador
    if (inimigo.position.x < jogador.body.position.x){
        // faz ele ir para direita
        inimigo.body.velocity.x += 100;
    }else{
        // Senão, faz ele ir para esquerda
        inimigo.body.velocity.x -= 100;
    }
}

O resultado será um monstro indo em direção ao nosso jogador:
Inimigo seguindo parte1

Inimigo seguindo parte2

Inimigo seguindo parte3

Repare que o monstro não vira de lado, ele está sempre na mesma direção, apenas deslizando em direçaõ ao nosso jogador. Fazê-lo se mover na direção correta será um post futuro, aguarde!

Fazendo o monstro matar nosso jogador

De nada adianta um monstro correr atrás de nós se ele não fizer nada que nos faça perder pontuação ou mesmo o jogo, não é mesmo?

Futuramente veremos como diminuir a pontuação, ou como no super mário, reduzir o tamanho do personagem conforme ele vai morrendo.

Vamos ver agora como matar o personagem quando o monstro encostar nele.

Detectando sobreposição de personagem com inimigos

Sobreposição, ou overlap em inglês, é a situação onde dois corpos estão ocupando o mesmo espaço ao mesmo tempo, sim em games isso é possível!

Existe uma função no framework phaser que faz o trabalho difícil de detecção para nós. Ela consegue verificar se o jogador colidiu com alguma coisa no jogo. Podemos configurar para ser com um bloco, outro jogador, ou mesmo inimigos.

Como é uma função que precisa ser chamada o tempo todo (pois a verificação de choque deve ser imediata), vamos colocá-la dentro da função atualizaJogo:


function atualizaJogo() {
    // ... outros códigos que já estavam aqui

    // Verifica colisão entre jogador e inimigos
    game.physics.arcade.overlap(jogador, inimigos, encostouInimigo);
}

Função que mata o jogador

A função game.physics.arcade.overlap verifica a sobreposição entre jogador e inimigos. Caso eles se choquem em algum momento, esta função irá chamar a funão encostouInimigo, que então irá fazer alguma coisa.

Precisamos agora criar esta função encostouInimigo e fazer ela mostrar que o nosso jogador morreu:

/**
 *  Função que mata o jogador e informa que ele morreu
 */
function encostouInimigo (jogador, inimigo) {
    // Remove jogador do jogo
    jogador.kill();

    // Mostra texto informando morte do jogador
    var textoJogo = game.add.text(game.camera.width / 2 - 150, game.camera.height / 2, "Você morreu", {
        font: "48px Arial",
        fill: "#ff0044",
        align: "center"
    });
}

Agora sim, veja que quando o monstro encostar em nosso jogador, ele morre:

Inimigo matou jogador
Inimigo matou jogador

Melhorando um pouco o cenário para nosso personagem conseguir escapar

Que tal ajudarmos um pouco nosso jogador inserindo alguns degraus para ele poder ficar em cima e não ser pego pelo monstro?

Crie esta função para adicionar os degraus:

/**
 *  Função que cria 3 degraus no jogo
 *  2 fixos e 1 móvel
 */
function criaDegraus(){
    // Cria primeiro degrau
    var degrau1 = plataformas.create(0, 440, 'chao');
    // Define que seu corpo não é movível
    degrau1.body.immovable = true;

    // Cria o segundo degrau também imovível
    var degrau2 = plataformas.create(550, 350, 'chao');
    degrau2.body.immovable = true;

    // Cria terceiro degrau movível
    var degrau3 = plataformas.create(750, 270, 'chao');
    degrau3.body.immovable = false;
}

E agora chame esta função na função criaCenario, afinal ela é quem define o funcionamento do cenário:


function criaCenario(){
    // ... demais código que já havia aqui

    // Cria os degraus do jogo para jogador fugir dos inimigos
    criaDegraus();
}

Veja que o jogador nasce em cima do primeiro degrau:
degraus no jogo

Agora tente pular em cima do terceiro degrau para ver o que acontece:

degrau móvel caindo

Isso mesmo, o degrau cai, ou vai para o lado ou para cima, tudo depende de como o jogador bater nele. Ele é um degrau móvel, muito útil para aquelas situações do jogo onde você só quer permitir que o jogador pule uma vez em algo e depois tenha que pular em outro lugar.

Legal né?

Jogo em ação

Aqui você pode ver o código que implementamos funcionando.

Neste link você pode baixar esta versão do jogo:

O que vem por aí?

No próximo post veremos como criar um cenário maior para o jogo!

11 Comments

  1. Seu tutorial é incrível, muito obrigado por compartilhar!!! Consegui entender grande parte do funcionamento da engine até aqui graças a essa dinâmica…

    Abraços… Boa sorte!!!

  2. Bom tutorial cara, porém acho que tem um bug no seu jogo: Pela física, o jogador deveria cair em cima do primeiro degrau e ficar parado em cima dele no momento em que o jogo é iniciado, certo? Porém, ao atualizar a página, em algumas vezes, o jogador ignora o primeiro degrau e cai em cima do chão e é morto pelo inimigo porque está encurralado pelo mesmo. Achei que fosse algum erro de codificação que eu fiz, porém no seu exemplo acontece o mesmo problema.

    1. Oi Breno,
      isso é um problema relacionado à construção do jogo. Até o penúltimo tutorial, eu usei a física ARCADE e a construção do jogo foi feita de maneira que exige muito processamento para que tudo funcione. Em alguns computadores, então, ocorre essa falha, pois o FPS baixa muito e o phaser não consegue mais processar a colisão de objetos corretamente.

      Dica: remova o fundo, deixe em branco e veja o tutorial parte 11, lá explico um pouco na nova física (P2) usada no jogo, ela traz mudanças importantes e o modo de desenvolver fica bem mais divertido e flexível.

      Bons estudos!

  3. Só tem uma correção a fazer, quando você declara na função carregaAssets(), o nome da instância não pode estar repetida, trocar ‘chao’ por ‘inimigo’

  4. Ola professor faz um tempo que acompanho seu site e aprendi muitas coisas aqui. E este curso é mais um que estou fazendo por aqui e esta bem legal. Mas já estou com uma dúvida.

    Na função aproximaInimigo na primeira linha o comentário diz que é para pegar o primeiro elemento do grupo inimigos. O que seria esse elemento?

  5. Paulo, seus tutoriais são incríveis, facilitando minha vida, obs, no tuto só faltou informar para chamar a função aproximaInimigo() dentro da função atualizaJogo().
    Abração!

Leave a Reply