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!