O que veremos aqui?
Neste post, mostrarei como criar o mapa do jogo. Ele é a continuação do terceiro post desta série onde adicionamos o inimgo no jogo.
Como construir o mapa?
O mapa do jogo nada mais é que definições de quais blocos visuais serão colocados em determinados lugares. Eventualmente podemos trabalhar com multicamadas e blocos específicos de objetos e imagens.
Neste post veremos o básico, ou seja, como criar um mapa de uma única camada e fazer o phaser interpretá-lo para que nosso personagem possa interagir com este mapa.
Para construção do mapa usaremos uma ferramenta muito usada e compatível com a maioria dos frameworks de jogos: Tiled.
O que é o Tiled Map Editor?
Tiled Map Editor é uma ferramenta open source usada para criar mapas em jogos 2d. Ele é fácil de usar como veremos neste tutorial. Baixe-o no site oficial e instale-o.
Observação: Se ao instalar o Tilled, você receber o erro que está faltando a dll msvcp100.dll, basta instalar o Windows Visual C++ runtime 2010 ou superior, aqui o link para windows 64 bits.

Tileset básico para começar
Um Tileset é uma imagem, normalmente formada por várias outras imagens, que contém blocos os quais serão usados para montar todo o cenário.
Baixe este titleset para fazermos este exemplo:

Como percebe-se, este tileset tem uma resolução baixa. Ele é constituído de blocos de 32px de altura por 32px de largura (32×32).
Você pode baixar centenas de outros tilesets no google procurando por “Tileset game 2d”, ou mesmo montar o seu próprio. Basta observar que os blocos devem ser do mesmo tamanho sempre, ok?
Iniciando o mapa
Com o Tiled Map Editor aberto, clique em File -> New. Crie um mapa seguindo os detalhes abaixo.
32 x 32 é a largura de cada bloco do nosso tileset. Width de 100 tiles significa que a largura do mapa terá 100 blocos, e 20 de altura, como visto. O cálculo em pixels do nosso mapa, será então, 3200 de largura por 640 de altura.
Caso queira um mapa maior, poderá mudar os valores de width e height. Isso também poderá ser feito depois de criar o mapa. A única coisa que não pode ser alterada depois é o tamanho de cada Tile (lajota).
Feito isso, você verá o seguinte mapa, com fundo cinza por padrão:

Adicionando Tileset
Após criar o mapa, agora vamos adicionar as imagens que usaremos para criar o visual do jogo, ou seja, os tilesets.
Para isso, clique no menu Map -> New Tileset. Selecione a imagem que deseja adicionar (neste caso tileset.png) e defina a largura e altura de cada bloco (por padrão é a mesma do cenário 32×32):

Veja agora, que no canto direito inferior, existe o tileset que adicionamos. Ele está pronto para ser usado:

Salvando o Trabalho
Antes de continuarmos o processo de construção é importante que salvemos o trabalho. Faça isso também durante toda a edição.
Aqui temos uma parte muito importante, que é o formato do nosso mapa. Todo o nosso mapa será construído num formato chamado JSON, muito usado em comunicações na internet para representação e troca de dados em javascript com outras linguagens.
Para salvar o mapa, siga estas regras:
- Salve o mapa em formato .JSON
- Ele deve ser salvo na mesma pasta que o tileset (assets)
- Salve o mapa com um nome que não possua espaço ou caracteres especiais (acentos e outros)
Para salvar, basta clicar no botão Save, bem grande na tela e salvar como mapacaverna.json:
Construindo o mapa
Basta agora clicar no bloco do tileset desejado, e clicar na área do mapa que deseja inserí-lo. Veja que defini aqui o nome da camada que estamos construindo. Teremos, por hora, somente uma camada, chamada cenario (sem acento):
Códifo fonte do jogo com Mapa completo
Uma vez que várias partes do jogo foram alteradas do tutorial anterior para este, segue o código fonte completo onde fazemos o personagem andar no cenário que criamos:
window.onload = function() {
// Cria o cenário com 1220 x 600 px
game = new Phaser.Game(1000, 640, Phaser.AUTO, '', {
preload: carregaAssets,
create: criaCenario,
update: atualizaJogo
});
};
/**
* Carrega imagens, sons etc, para usar no jogo
*/
function carregaAssets() {
game.load.image('inimigo', 'assets/inimigo.png');
game.load.spritesheet('dude', 'assets/dude.png', 32, 48);
// Carrega imagem do novo mapa,
// origem: http://www.ironstarmedia.co.uk/2010/10/free-game-assets-13-prototype-mine-tileset/
game.load.image('tilesCenario', 'assets/tileset.png');
// Carrega mapa em formato JSON
game.load.tilemap('mapa', 'assets/mapacaverna.json', null, Phaser.Tilemap.TILED_JSON);
}
/**
* Cria cenário do jogo
*/
function criaCenario() {
// Define que vai usar a física ARCADE - fácil no jogo
game.physics.startSystem(Phaser.Physics.ARCADE);
// Adiciona mapa
map = game.add.tilemap('mapa');
// Insere tileset
map.addTilesetImage('tileset', 'tilesCenario');
// Define quais blocos do tileset serão de colisão
//map.setCollision(1);
map.setCollisionBetween(1,5);
map.setCollisionBetween(8,12);
layer = map.createLayer('cenario');
layer.resizeWorld();
// 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;
// Cria o jogador
criaJogador();
// Chamaf unção que cria inimigo
criaInimigo();
// Define os cursores do teclado para poder controlar o jogador
cursors = game.input.keyboard.createCursorKeys();
}
/**
* Atualiza jogo. Esta função roda em torno de 60 vezes em 1 segundo, ou seja,
* 60 FPS (FPS = Frames Por Segundo)
*/
function atualizaJogo() {
aproximaInimigo();
game.physics.arcade.collide(jogador, layer);
game.physics.arcade.collide(inimigos, layer);
movimentaJogador();
verificaSeEncostouInimigo();
}
function verificaSeEncostouInimigo(){
// Verifica colisão entre jogador e inimigos
game.physics.arcade.overlap(jogador, inimigos, encostouInimigo);
}
function movimentaJogador(){
// Pára o movimento do jogador
jogador.body.velocity.x = 0;
if (cursors.left.isDown)
{
// Move to the left
jogador.body.velocity.x = -250;
jogador.animations.play('left');
}
else if (cursors.right.isDown)
{
// Move to the right
jogador.body.velocity.x = 250;
jogador.animations.play('right');
}
else
{
// Stand still
jogador.animations.stop();
jogador.frame = 4;
}
// Permite jogador pular somente se está tocando algum chão
if (cursors.up.isDown)
{
if (jogador.body.onFloor())
{
jogador.body.velocity.y = -650;
}
}
// Truque para jogador voar ao pressionar tecla T
if(game.input.keyboard.isDown(Phaser.Keyboard.T) && cursors.up.isDown)
{
jogador.body.velocity.y = -150;
}
}
/**
* Função que cria o jogador
*/
function criaJogador(){
// Cria o player e o adiciona no jogo (x,y)
jogador = game.add.sprite(50, game.world.height - 250, 'dude');
// É necessário adicionar a física no jogador
game.physics.enable(jogador);
// Propriedades da física do jogador. Dá a ele, um salto "normal".
jogador.body.bounce.y = 0.2;
jogador.body.gravity.y = 1600;
jogador.body.linearDamping = 1;
// Nâo deixa jogador "fugir" do mundo
jogador.body.collideWorldBounds = true;
// Define duas animações (esquerda e direita) para caminhar
// 'nome', posições no quadro, quantas atualizações por segundo
jogador.animations.add('left', [0, 1, 2, 3], 10, true);
jogador.animations.add('right', [5, 6, 7, 8], 10, true);
game.camera.follow(jogador);
}
/**
* 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;
}
}
/**
* Função que cria o jogador
*/
function criaInimigo(){
// Cria inimigo dentro do grupo inimigos
var inimigo = inimigos.create(700, 20, 'inimigo');
// Define gravidade do inimigo
inimigo.body.gravity.y = 400;
// Faz inimigos não fugirem do mundo
inimigo.body.collideWorldBounds = true;
}
/**
* 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 posicaoJogador = jogador.body.position.x;
var textoJogo = game.add.text(posicaoJogador - 150, game.camera.height / 2, "Você morreu", {
font: "48px Arial",
fill: "#ff0044",
align: "center"
});
}
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 adicionar moedas ao jogo com este novo cenário criado usando o Tiled Map Editor!



Opa, tudo bom?
Estou com uma dificuldade aqui… na linha 45 do teu código:
layer.resizeWorld();
Está dando problemas com meu código. Podemos trocar e-mails?
Muito obrigado pela atenção.
Abraços.
Olá Heitor, podemos sim, me envia seu código por email que assim que possível lhe ajudarei.
Antecipando, você pode baixar o exemplo completo desse post abaixo e comparar com seu código para ver o que saiu errado.
Bons estudos!
No meu código diz que não pode encontrar a função resizeWorld()
Oi Danilo, verifique se a layer cenario realmente existe.
Paulo, excelente tutorial, meu de vdd, parabéns!
Eu tive também problema com a layer, recebia a mensagem:
Tilemap.createLayer: Invalid layer ID given: null
Isso ocorreu porque a função ta procurando uma layer chamada “cenario” dentro do arquivo json gerado pelo tiled, essa layer não existia no meu mapa porque esqueci de renomeá-la, então voltei no tiled e renomei a minha layer para “cenario”, funcionou perfeitamente.
Abraços!
Obrigado pelo retorno Wilkier!