Criando um primeiro jogo com Phaser

Enquanto estudava desenvolvimento de jogos em HTML5 com Phaser acabei criando um jogo muito simples e muito bom para ser usado como introdução ao desenvolvimento com a engine.

Porque a Phaser?

Apesar de existirem muitas outras engines para o desenvolvimento de jogos multiplataforma, como a Unity, a ferramenta Phaser continua sendo a melhor opção para o desenvolvimento de um jogo que será executado em diversos dispositivos. A justificativa esta no fato da Phaser não necessita de nenhum complemento adicional, além de funcionar sem problemas em navegadores mobile.

Caso queira saber mais veja nesta outra postagem: Engine Phaser

O jogo que vamos usar será um lago onde peixes famintos tentam se alimentar de insetos que caem na água, lembrando que é apenas para estudo da engine, não esperam grandes efeitos ;D. O jogo que vamos criar pode ser acessado clicando aqui.


Preparando o ambiente.

A primeira coisa que vamos fazer é preparar o ambiente.

  • estrutura-pastas-phaserPasta Lago: É  o diretório principal do jogo
  • Pasta assets: Nesta pasta vamos armazenas as imagens e efeitos do jogo
  • Pasta css: Onde vamos armazenar os CSS “Só pra não ter duvidas!”
  • Pasta js: Onde iremos armazenar a engine e os scripts do jogo
  • Phaser.js ou phaser.min.js: É a engine responsável pelo controle das ações e fisica do jogo
  • Game.js: Aqui estarão os códigos que darão vida ao jogo
  • Game.html: Página onde o jogo será executado.

 

Agora que temos toda a estrutura de pastas montadas e os arquivos criados vamos começas o desenvolvimento.

Game.html:

A página onde o jogo será executado não precisa de muita implementação, basta usar um html bem simples.
No código abaixo a div <div id=”game” class=”div-game”> será onde o jogo realmente vai ser executado.

<html>
<head>
	<meta charset="UTF-8">
	<title>Lago</title>
	<script src="js/phaser.min.js"></script>
	<script src="js/game.js"></script>
	<style type="text/css">
		body, html{
			margin: 0;
			border: 0;
		}

		div-game {
			background-color:black;
			width:100%;
			height: 100%;
			min-height: 90%;
			display: -webkit-flex;
			display: flex;
			-webkit-align-items: center;
			align-items: center;
			-webkit-justify-content: center;
			justify-content: center;	
		}
	</style>
</head>
<body style="overflow: hidden;">
    <div id="game" class="div-game"></div>
  <div id="orientation"></div>
</body>
</html>

 

Assets:

Antes de entrar em mais detalhes quanto ao script game.js vamos a pasta assets, nela vão estar todos os arquivos de imagens que vamos usar no jogo.

  • Imagem de fundo: um bom exemplo disso é a imagem de fundo, para manter uma agonização ela está armazenada na pasta assets/maps.
  • Sprites: A segunda pasta dentro de assets é a pasta sprite, nela vamos armazenar as imagens dos personagens, tanto herói quanto vilão ou NPC, dando uma pesquisada rápida no Google imagens podemos achar uma infinidade de sprites prontos.

Sprites:

Com o phase criar a animação de um personagem é muito simples, primeiro carregamos a imagem com a sequencia de sprites que desejamos:

butterfly

Criamos um objeto spritesheet que é uma sequencia de sprites informando a altura e largura de cada sprit dentro da imagem e a quantidade de sprites que vamos carregar: game.load.spritesheet(“inseto”, “assets/sprites/butterfly.png”, 70, 70, 14);  os parâmetros 70, 70 representam a altura e largura de cada borboleta.

Depois adicionamos os sprites ao nosso personagem: var inseto = game.add.sprite(100, 150, “inseto”);  os parâmetros 100 e 150 informam a posição em x, y que vai ser criado na tela.

Para dar movimento ao personagem criamos uma animação informando a sequencia dos sprites e tempo a serem executados e para finalizar executamos a animação.

// criamos uma animação com a cadeia de sprite 
inseto.animations.add('fly', [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], 20, true);
inseto.play('fly');

Para o peixe carreguei uma imagens com vários sprites diferente e no hora da animação selecionei apenas os sprit que desejava:

animales2

// além do arquivo passamos como parametro a largura, altura e quantidade de sprites dentro da imagem. game.load.spritesheet(“peixe”, “assets/sprites/animales2.png”, 32, 33, 24); peixe[i] = game.add.sprite(randomPoint.x, randomPoint.y, “peixe”) // Como queremos apenas o peixe azul vamos usar apenas o 12,13 e 14 na animação peixe[i].animations.add(‘flyx’, [ 12, 13, 14], 20, true); peixe[i].play(‘flyx’);

Dessa forma podemos usar uma unica imagem para ter quantos sprites desejar.

 

game.js

O coração de tudo, no game.js vamos iniciar o jogo, carregar os sprites, criar as animações e eventos. Como o código do script está todo comentado não vou entrar em mais detalhes.

var game = new Phaser.Game(700, 680, Phaser.AUTO, 'game', { preload: preload, create: create, update: update });
/*
700, 680 - é a area do jogo
'game' - é a div onde o jogo vai ser executado

*/
var cardume = 15;
var peixe = [];
var inseto;

// Carrega os objetos a serem usados durante o jogo.
function preload(){
	// game.load.image - são objetos para imagens estáticas
    game.load.image('oceano', 'assets/maps/oceano-azul.jpeg');
	// game.load.spritesheet - são para objetos animados, 
	// além do arquivo passamos como parametro a largura, altura e quantidade de sprites dentro da imagem.
	game.load.spritesheet("peixe", "assets/sprites/animales2.png", 32, 33, 24);
    game.load.spritesheet("inseto", "assets/sprites/butterfly.png", 70, 70, 14);   
}

// cria os objetos do jogo e as instancias
function create(){
	// Aplicando a imagem de fundo do jogo
    bg = game.add.tileSprite(0, 0, 700, 680, 'oceano');

    // vamos criar o inseto no jogo
	// inserimos ele no centro do jogo pegando a largura e altura dividido por 2
	inseto = game.add.sprite(game.width / 2, game.height / 2, "inseto");
    inseto.anchor.set(0.5);
    // Ativamos o sprite
    inseto.inputEnabled = true;
    //  Permitimos arrastar com o mouse
    inseto.input.enableDrag();	
	// criamos uma animação com a cadeia de sprite 
    inseto.animations.add('fly', [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], 20, true);
    inseto.play('fly');


    for(var i = 0; i < cardume; i++){
		// randomPoint - usado para inserir o peixe em um ponto aleatório da tela
        var randomPoint = new Phaser.Point(game.rnd.between(0, game.width - 1), game.rnd.between(0, game.height - 1));
        peixe[i] = game.add.sprite(randomPoint.x, randomPoint.y, "peixe")
        peixe[i].anchor.set(0.5);
		// Velocidade do peixe
        peixe[i].speed = game.rnd.between(50, 150);
		// Força do peixe
        peixe[i].force = game.rnd.between(5, 25);
		// Aplica fisica ao peixe
        game.physics.enable(peixe[i], Phaser.Physics.ARCADE);
		// Não permite o peixe girar sobre o proprio eixo, o obriga a fazer a curva
        peixe[i].body.allowRotation = false;
		// Cria uma animação
        peixe[i].animations.add('flyx', [ 12, 13, 14], 20, true);
        peixe[i].play('flyx');
		// O sprit esta ao contrario, esta fazendo o peixe nada de ré, vamos inverter a imagem
        peixe[i].scale.x = -1;
		// corrige o angulo do peixe
        peixe[i].angle = 30;        
    }
}

// atualiza todo o jogo frame a frame
function update(){
    for(var i = 0; i < cardume; i++){
        // direção vector é a direção em linha reta do peixe ao alvo
        var direction = new Phaser.Point(inseto.x, inseto.y);
        // agora nós subtrair a posição peixe atual
        direction.subtract(peixe[i].x, peixe[i].y);
        // então nós normalizá-lo. Um vector normalizado tem o seu comprimento é 1, mas mantém a mesma direcção
        direction.normalize();
        // tempo para definir magnitude (comprimento) para evitar velocidade
        direction.setMagnitude(peixe[i].speed);
        // agora nós subtrair a velocidade peixe atual
        direction.subtract(peixe[i].body.velocity.x, peixe[i].body.velocity.y);
        // normalizar novamente
        direction.normalize();
        // finalmente, definir a magnitude de anular a força, que deve ser a maneira mais baixa do que a sua velocidade
        direction.setMagnitude(peixe[i].force); 
        // Agora vamos adicionar direção peixe a atual velocidade peixe
        peixe[i].body.velocity.add(direction.x, direction.y);
        // normalizar a velocidade
        peixe[i].body.velocity.normalize();
        // vamos definir a magnitude para construir a velocidade
        peixe[i].body.velocity.setMagnitude(peixe[i].speed);
        
		// Se estiver distante muda de direção
        if (peixe[i].position.distance(inseto.position) > 2){
            peixe[i].angle = 180 + Phaser.Math.radToDeg(Phaser.Point.angle(peixe[i].position, new Phaser.Point(peixe[i].x + peixe[i].body.velocity.x, peixe[i].y + peixe[i].body.velocity.y)));
        }
        
		// Se o peixe pegar o inseto o inseto recebe uma nova posição na tela, da a impressão de ser outro.
        if(peixe[i].position.distance(inseto.position) < 2){
            inseto.x = game.rnd.between(10, game.width - 10);
            inseto.y = game.rnd.between(10, game.height - 10);
        }
    }   
}

Clique aqui para ver o jogo rodando.

Deixe um comentário

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

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.