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:

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:

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:

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:

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:

Agora tente pular em cima do terceiro degrau para ver o que acontece:
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!



Ótimo tutorial, boa didática e organização.
Parabéns.
Obrigado pelo retorno Felipe!
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!!!
Legal Tiago, obrigado pelo retorno e bons estudos!
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.
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!
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’
Obrigado Danilo, falha ao copiar para o blog.
Já corrigi :)
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?
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!