Construindo um Jogo para a Web – Bomberman
Transcrição
Construindo um Jogo para a Web – Bomberman
Construindo um Jogo para a Web – Bomberman Programação para a Internet Prof. Vilson Heck Junior Tecnologias Necessárias • Tecnologias já Estudadas: – HTML; – CSS; – JavaScript; • Tecnologias Novas: – – – – – Computação Gráfica Básica; Noções de Geometria; Noções de Física; Reprodução de Sons; Enredo; Computação Gráfica • É um campo da Ciência da Computação que estuda métodos para sintetizar e manipular digitalmente conteúdo visual: – Geração de imagens 2D; – Geração de imagens 3D (renderização); – Com ou sem animação; Noções de Geometria • Gráficos 2D ou 3D são na verdade a composição de pequenas peças geométricas: • A relação espacial dada entre diferentes objetos existentes em uma cena deve ser respeitada: – Dois corpos não podem ocupar um mesmo lugar no espaço! Noções de Física • Objetos podem possuir algum tipo de movimento ou interação com outros objetos; • Para isto, geralmente respeitam alguma(s) regras físicas: – Próximas a real: Simulação; – Diferenciadas: Arcade; Reprodução de Sons • O som é o elemento responsável por estimular o sentido da audição; • Não tanto quanto os gráficos, mas os sons são responsáveis por completar uma boa sensação de imersão em jogos e entretenimento; • Geralmente os sons (músicas ou barulhos) serão escolhidos conforme um determinado contexto ou acontecimento. Enredo • O enredo irá explicar ao usuário o que deverá ser feito e deve ser o principal responsável por atrair a atenção do jogador: – História; – Diversão; – Desafios; – Passatempo; – ... Enredo • Bomberman: – Lançado em 1983; – Plataforma: PC doméstico; – Desenvolvido pela Husdson Soft. Nintendo -1989 Enredo • Bomberman: – Jogo árcade baseado em labirintos; – Inimigos não podem te alcançar; – Destruir paredes e inimigos com bombas. Nosso Conceito Bomberman LISTA DE RECURSOS INICIAIS Recursos Iniciais • Pasta: “Bomberman”: – index.html • Construiremos de um documento web, inserindo todos os demais elementos necessários; – estilo.css • Definiremos algumas configurações de cores, bordas e outros para nossa interface; – Bomba.js & bomberman.js & Mapa.js & mapaMascara.js • Faremos todo o processamento e configurações do jogo, ou seja, daremos ações aos acontecimentos e eventos do jogo. – Jogador.js & Inimigo.js • Implementaremos a parte de movimentação do jogador e dos inimigos; index.html • • • • • Crie o arquivo como doctype para html 5; Crie as tags para: – <html>, <head>, <body> e <title>; Estipule um <link> com arquivo de estilo; Adicione os arquivos de <script> dentro do <head>: – mapaMascara.js – Mapa.js – Jogador.js – Inimigo.js – Bomba.js Adicione o arquivo de <script> bomberman.js ao fim do <body>; – Importante: adicionar os outros arquivos js antes, pois o último precisa dos primeiros já executados. index.html • Adicione os seguintes Tags com seus atributos dentro do <body>: – <canvas>Navegador não suportado!</canvas> • id = “tela” width=200 height=200 – <button>Iniciar</button> • onclick=“pausar()” id=“btnIniciar” – <button>Novo Jogo</button> • onclick=“reiniciar()” id=“btnNovo” – <p id="tecla"></p> – <p>A,S,D,W -> Mover<br> Barra de Espaço -> Liberar bomba</p> estilo.css body { background-color: #224422; text-align: center; } #tela { background-color: black; border: 2px solid red; } button { background-color: #EE9999; color: white; border: 1px solid red; width: 100px; height: 30px; font-weight: bold; cursor: pointer; } button:hover { background-color: #EEBBBB; } button:disabled { background-color: #DDDDDD; cursor: not-allowed; } Bomberman DESENHANDO NO CANVAS <canvas> • Canvas é um termo inglês dado a alguns tipos de tela para pintura; • No nosso caso, será uma área dentro do documento HTML onde poderemos pintar o que precisarmos; • Nosso pincel e paleta de cores estão disponíveis através de código JavaScript. <canvas> • O Canvas é feito para oferecer suporte a rápido desenho de cenas bidimensionais ou tridimensionais: – Geralmente acelerado por Hardware; 0 X width 0 y height bomberman.js //Recuperando referência dos objetos no documento var canvas = document.getElementById("tela"); var ctx = canvas.getContext("2d"); //Um pequeno teste (remover depois de testar) ctx.fillStyle = "#FF0000"; //Usar cor vermelha ctx.fillRect(20, 30, 50, 100); //x=20, y=30, w=50 e h=100 Desenhando • Temos uma tela para desenho; • Conhecemos uma primeira ferramenta para pintar algo; • Temos que utilizar esta ferramenta de forma a construir o cenário inicial do nosso jogo; Relembrando Estrutura de Dados: matriz Posições da matriz Descrição Representação Gráfica Código (cor) Livre 0 - (preto) Parede 1 - (branco) Jogador 2 - (vermelho) Tijolo 3 - (verde) Inimigo 4 - (azul) Bomba 5 - (N/A) Mapa.js function Mapa() { //Sem elementos estáticos } //Compreensão do conteúdo do mapa Mapa.LIVRE = 0; Mapa.PAREDE = 1; Mapa.JOGADOR = 2; Mapa.TIJOLO = 3; Mapa.INIMIGO = 4; Mapa.BOMBA = 5; //Linhas e colunas existentes no mapa atual Mapa.colunas = 0; Mapa.linhas = 0; //Largura e altura de cada linha/coluna em pixels Mapa.largura = 40; mapaMascara.js Exemplo de cenário com 5 colunas e 6 linhas: var mapaMascara = [ [1, 1, 1, 1, 1], [1, 0, 2, 0, 1], [1, 3, 1, 0, 1], [1, 3, 1, 3, 1], [1, 3, 4, 0, 1], [1, 1, 1, 1, 1] ]; Dimensões • Cada elemento da matriz terá uma largura e altura, sendo elementos quadrados: largura = altura. Largura Dimensões • A largura, ou altura, geral do jogo, será definida pela largura de cada elemento x o número de elementos: AlturaTotal = Largura * nLinhas Mapa.js ... //Mantém e carrega o mapa atual Mapa.atual = null; Mapa.carregar = function (canvas) { Mapa.atual = new Array(); var y, x; for (y = 0; y < mapaMascara.length; y++) { Mapa.atual.push(mapaMascara[y].slice(0)); } Mapa.linhas = Mapa.atual.length; Mapa.colunas = Mapa.atual[0].length; canvas.width = Mapa.colunas * Mapa.largura; canvas.height = Mapa.linhas * Mapa.largura; }; Mapa.js //Carrega textura e desenha mapa Mapa.imgTijolo = new Image(); Mapa.imgTijolo.src = "tijolo.png"; Mapa.desenhar = function (ctx) { if (Mapa.atual != null) { var x, y; for (y = 0; y < Mapa.linhas; y++) { for (x = 0; x < Mapa.colunas; x++) { if (Mapa.atual[y][x] == Mapa.PAREDE) { ctx.fillStyle = "#BBBBBB"; ctx.fillRect(x * Mapa.largura, y * Mapa.largura, Mapa.largura, Mapa.largura); } else if (Mapa.atual[y][x] == Mapa.TIJOLO) { ctx.drawImage(Mapa.imgTijolo, x * Mapa.largura, y * Mapa.largura, Mapa.largura, Mapa.largura); } } } } }; bomberman.js var canvas = document.getElementById("tela"); var ctx = canvas.getContext("2d"); //Adicionar temporariamente. Remover depois. Mapa.carregar(canvas); Mapa.desenhar(ctx); Jogador.js //Classe para controle e movimentos do jogador function Jogador() { } Jogador.x = -1; Jogador.y = -1; Jogador.desenhar = function (ctx) { ctx.fillStyle = "#00BBBB"; ctx.fillRect(Jogador.x * Mapa.largura + 2, Jogador.y * Mapa.largura + 2, Mapa.largura - 4, Mapa.largura - 4); }; Mapa.js Mapa.carregar = function (canvas) { ... for (y = 0; y < mapaMascara.length; y++) { Mapa.atual.push(mapaMascara[y].slice(0)); for (x = 0; x < Mapa.atual[y].length; x++) { switch (Mapa.atual[y][x]) { case Mapa.JOGADOR: Jogador.x = x; Jogador.y = y; break; } } } ... }; bomberman.js var canvas = document.getElementById("tela"); var ctx = canvas.getContext("2d"); //Adicionar temporariamente. Remover depois. Mapa.carregar(canvas); Mapa.desenhar(ctx); Jogador.desenhar(ctx); Bomberman OS VILÕES! Os Vilões • No Bomberman, os vilões são “monstros” que andam pelo labirinto; • Cada mapa terá um número diferente de inimigos. • Em nossa implementação, cada inimigo será uma instância de uma classe chamada Inimigo; • Cada vez que encontramos Mapa.INIMIGO no mapa, instanciamos um novo objeto Inimigo. Inimigo.js //Classe para controle e movimentos dos inimigos function Inimigo(x, y, imagem) { this.x = x; this.y = y; Construtor this.imagem = imagem; this.desenhar = function (ctx) { ctx.drawImage(this.imagem, this.x * Mapa.largura, this.y * Mapa.largura, Mapa.largura, Mapa.largura); }; } Inimigo.js //Classe para controle e movimentos dos inimigos ... Inimigo.todos = new Array(); Inimigo.desenharTodos = function (ctx) { var i; for (i = 0; i < Inimigo.todos.length; i++) { Inimigo.todos[i].desenhar(ctx); } }; Mapa.js Mapa.carregar = function (canvas) { ... switch (Mapa.atual[y][x]) { case Mapa.JOGADOR: Jogador.x = x; Jogador.y = y; break; case Mapa.INIMIGO: var inimigoImg = new Image(); inimigoImg.src = "inimigo.png"; inimigoImg.onload = desenharTudo; Inimigo.todos.push(new Inimigo(x, y, inimigoImg)); break; } bomberman.js function reiniciar() { Mapa.carregar(canvas); desenharTudo(); document.getElementById("btnIniciar").disabled = false; document.getElementById("btnIniciar").innerHTML = "Iniciar"; } function desenharTudo() { ctx.clearRect(0, 0, canvas.width, canvas.height); Mapa.desenhar(ctx); Jogador.desenhar(ctx); Inimigo.desenharTodos(ctx); } reiniciar(); Testar! Bomberman GERAÇÃO DE MAPAS Geração de Mapas • Em “Arquivos para Atividades Práticas” – Na pasta “bomberman”; – Baixe BombermanMapGenerator.zip; – Isto é um projeto NetBeans! • Gerar um arquivo BMP no MS Paint! – Observar cores que irão definir objetos. • Converter com o software Java! Geração de Mapas • Em “Arquivos para Atividades Práticas” – Na pasta “bomberman”; – Baixe “cenario.png” para qualquer pasta – Converta o arquivo com o Gerador de Mapas baixado anteriormente; • salve o arquivo gerado com nome mapaMascara.js ; • Coloque o arquivo gerado dentro da pasta do seu projeto, substituindo o arquivo digitado anteriormente. Bomberman • Teste sua página! Bomberman COLOCANDO VIDA O que precisamos? • Fazer o Bomberman se movimentar ao pressionar de tecla? • Fazer os inimigos se movimentarem: – Com qual intervalo de tempo? – Para qual direção? • O que acontece se o usuário ordenar que o Bomberman se mova contra uma parede? • O que ocorre quando o Bomberman liberar uma boba? • O que ocorre quando o Bomberman encontrar um inimigo? – E se a bomba explodir perto de um inimigo? • E quando acabarem todos os inimigos do mapa? Movimentação do Bomberman • O Bomberman irá se movimentar conforme teclas que o usuário pressionar: – A, S, D, W; – Outras teclas configuradas; Bomberman INTERAGINDO COM O USUÁRIO Eventos! • A interação é dada por uma troca entre a máquina e o usuário; • A máquina fornece principalmente imagens que descrevem uma situação, onde pode ser necessária a intervenção do usuário; • O usuário irá intervir basicamente através de comandos! – Comandos são captados através de eventos. Eventos! • Nosso document possui propriedades de eventos que podem ser associadas à funções quaisquer; • Estas funções determinam algo a ser feito quando aquele evento ocorrer: – document.onkeydown • Ao descer uma tecla qualquer; – document.onkeyup • Ao soltar uma tecla qualquer; bomberman.js document.onkeydown = function (evt) { document.getElementById("tecla").innerHTML = evt.keyCode; } Teste! bomberman.js document.onkeydown = function (evt) { Jogador.tratarTecla(evt); } Apagar o <p id=“tecla”> do HTML Jogador.js //Configurações de teclas para o Jogador Jogador.cmdEsq = 65; //A Jogador.cmdDir = 68; //D Jogador.cmdCim = 87; //W Jogador.cmdBai = 83; //S Jogador.cmdBomba = 32; //Espaço //Variáveis para controle de movimentação Jogador.proximoMov = null; Jogador.plantarBomba = false; Jogador.js //Tratar tecla pressionado conforme comportamento do Jogador Jogador.tratarTecla = function (evt) { switch (evt.keyCode) { case Jogador.cmdEsq: case Jogador.cmdDir: case Jogador.cmdCim: case Jogador.cmdBai: Jogador.proximoMov = evt.keyCode; evt.preventDefault(); break; case Jogador.cmdBomba: Jogador.plantarBomba = true; evt.preventDefault(); break; } }; Jogador.js (1/3) //Com base no último movimento solicitado, executa movimento Jogador.mover = function () { var nx = -1; var ny = -1; switch (Jogador.proximoMov) { case Jogador.cmdEsq: nx = Jogador.x - 1; break; case Jogador.cmdDir: nx = Jogador.x + 1; break; case Jogador.cmdCim: ny = Jogador.y - 1; break; case Jogador.cmdBai: ny = Jogador.y + 1; break; } Jogador.js (2/3) if (Jogador.plantarBomba) { if (Bomba.todas.length < Bomba.maxBombas) { Bomba.todas.push(new Bomba(this.x, this.y)); } Jogador.plantarBomba = false; } if (nx >= 0 && nx < Mapa.colunas) { switch (Mapa.atual[Jogador.y][nx]) { case Mapa.PAREDE: case Mapa.TIJOLO: case Mapa.BOMBA: break; default: Jogador.x = nx; break; } } Jogador.js (3/3) if (ny >= 0 && ny < Mapa.linhas) { switch (Mapa.atual[ny][Jogador.x]) { case Mapa.PAREDE: case Mapa.TIJOLO: case Mapa.BOMBA: break; default: Jogador.y = ny; break; } } Jogador.proximoMov = null; }; Bomberman • Colocar temporariamente os comandos dentro, no fim da função Jogador.tratarTecla(evt): – Jogador.mover(); – desenharTudo(); • Teste sua página! Bomberman CONTROLE GLOBAL DO MOVIMENTO Movendo com Tempo • Todo tipo de movimento tem uma velocidade; • Como determinamos a velocidade de algum objeto? – Medida Espacial / Tempo! • KM/h • m/s • ... Controlando o Tempo • Como já definimos, a unidade de espaço de cada movimento dos inimigos e do jogador será por posição; • Agora precisamos determinar o intervalo de tempo que nosso jogo irá usar para fazer cada movimento dos elementos; • Como nosso jogo gira em torno do Bomberman e dos Inimigos (e cada um terá uma velocidade diferente), estes tempos serão como guias para todo o jogo. Controlando o Tempo • Função JavaScript: – relogio = setInterval(“NomeFuncao()”, intervalo); • relogio é uma referência ao timer/clock que foi criado; • NomeFuncao() é a função que será executada a cada intervalo; • intervalo é um número inteiro representando a quantidade em milissegundos de intervalo entre uma execução e outra da função NomeFuncao(). – clearInterval(relogio); • Para o relógio de repetição; bomberman.js • Crie a variável: – var intervaloJogador = 200; – var intervaloInimigos = 400; • A primeira variável irá definir a quantidade de milissegundos entre cada movimento do Jogador; • O intervalo entre os movimentos dos inimigos será um pouco maior, para deixá-los mais lentos. bomberman.js • Crie as variáveis: – var tempoJogador = null; – var tempoInimigos = null; • Elas serão responsaveis por armazenar a referência aos objetos que farão a temporização de movimento do Jogador e dos Inimigos. bomberman.js function reiniciar() { if (tempoJogador != null) { pausar(); } intervaloJogador = 200; intervaloInimigos = intervaloJogador * 2; Mapa.carregar(canvas); desenharTudo(); document.getElementById("btnIniciar").disabled = false; document.getElementById("btnIniciar").innerHTML = "Iniciar"; //Bomba.todas.length = 0; //Bomba.maxBombas = 1; } bomberman.js function pausar() { if (tempoJogador == null) { tempoJogador = setInterval("atualizaJogador()", intervaloJogador); tempoInimigos = setInterval("atualizaInimigos()", intervaloInimigos); document.getElementById("btnIniciar").innerHTML = "Pausar"; } else { clearInterval(tempoJogador); tempoJogador = null; clearInterval(tempoInimigos); tempoInimigos = null; document.getElementById("btnIniciar").innerHTML = "Continuar"; } } bomberman.js function atualizaJogador() { Jogador.mover(); desenharTudo(); } function atualizaInimigos() { desenharTudo(); } Bomberman • Se você ainda não retirou os seguintes comandos de dentro da função Jogador.tratarTecla(evt), retire: – Jogador.mover(); – desenharTudo(); • Teste sua página! Bomberman MOVIMENTAÇÃO DOS INIMIGOS Movimentação dos Inimigos • Para que os inimigos se movam, precisamos definir regras que de alguma forma demonstrem coerência no seu movimento; • Por exemplo: – – – – Não mudar de direção a todo o segundo; Ser capaz de eventualmente trocar de direção; Não atravessar as paredes; Entre outros. • Antes de mover, o inimigo precisa verificar as possibilidades para onde pode se mover. Inimigo.js function Inimigo(x, y, imagem) { ... this.direcoes = new Array(); this.direcaoAtual = 0;//Parado ... } Construtor Inimigo.js this.mover = function () { this.direcoes.length = 0; this.adicionaDirecao(this.direcaoAtual, 8); this.adicionaDirecao(Jogador.cmdCim, 4); this.adicionaDirecao(Jogador.cmdEsq, 4); this.adicionaDirecao(Jogador.cmdDir, 4); this.adicionaDirecao(Jogador.cmdBai, 4); this.adicionaDirecao(0, 1);//Ficar parado var aleat = Math.round(Math.random() * (this.direcoes.length -1)); this.direcaoAtual = this.direcoes[aleat]; switch (this.direcaoAtual) { case Jogador.cmdDir: case Jogador.cmdCim: this.x++; this.y--; break; break; case Jogador.cmdEsq: case Jogador.cmdBai: this.x--; this.y++; break; break; } }; Inimigo.js (1/2) this.adicionaDirecao = function (dir, vezes) { var nx = this.x; var ny = this.y; switch(dir) { case Jogador.cmdEsq: nx--; break; case Jogador.cmdDir: nx++; break; case Jogador.cmdCim: ny--; break; case Jogador.cmdBai: ny++; break; } //Fim do switch Inimigo.js (2/2) if (nx < 0 || ny < 0 || nx >= Mapa.colunas || ny >= Mapa.linhas) { return; } switch (Mapa.atual[ny][nx]) { case Mapa.PAREDE: case Mapa.TIJOLO: case Mapa.BOMBA: return; } var z; for (z = 0; z < vezes; z++) { this.direcoes.push(dir); } }; //Fim do adicionaDirecao() Inimigo.js //Mover todos os inimigos: método estático! Inimigo.moverTodos = function() { var i; for (i = 0; i < Inimigo.todos.length; i++) { Inimigo.todos[i].mover(); } }; bomberman.js function atualizaInimigos() { Inimigo.moverTodos(); desenharTudo(); } Testar! Alterações Restantes • O que falta alterar? – INSERIR A BOMBA! – E quando explode a bomba? • Se atingir o próprio bomberman? Se atingir um inimigo? Se atingir um tijolo? Se atingir uma parede? – Fim de jogo? – Sons? bomberman.js function atualizaJogador() { Jogador.mover(); desenharTudo(); if (Jogador.verificaMorte()) { gameOver(); } } function atualizaInimigos() { Inimigo.moverTodos(); desenharTudo(); if (Jogador.verificaMorte()) { gameOver(); } } Jogador.js //Verifica se o Jogador morre (contato com inimigo) Jogador.verificaMorte = function() { var i; for (i = 0; i < Inimigo.todos.length; i++) { if (Jogador.x == Inimigo.todos[i].x && Jogador.y == Inimigo.todos[i].y) { return true; } } return false; }; bomberman.js //Executa comandos para efetuar o gameover function gameOver() { if (tempoJogador != null) { pausar(); } document.getElementById("btnIniciar").disabled = true; } Testar! Bomberman A BOMBA! A Bomba • • • • • Depois de ser armada (criada), a bomba terá um tempo até a sua explosão; Ao explodir, ela irá alcançar um raio, apenas nas quatro direções básicas: cima, baixo, esquerda e direita; O raio da explosão pode ser limitado por qualquer objeto que haja no caminho; Caso a bomba atinja o Jogador ou algum Inimigo, este deverá morrer; Caso a bomba atinja outra bomba, a segunda também deverá explodir imediatamente. Bomba.js function Bomba(x, y) { this.x = x; this.y = y; this.ciclos = Bomba.nCiclosAtual; this.cicloAtual = 0; this.raio = Bomba.raioAtual; Mapa.atual[y][x] = Mapa.BOMBA; } Bomba.som = null; Bomba.todas = new Array(); Bomba.todas.length = 0; Bomba.maxBombas = 1; //Valor definido no "novo jogo" Bomba.nCiclosAtual = 15; Bomba.raioAtual = 2; Bomba.nCiclosPos = 2; Bomba.js (1/5) this.desenhar = function(ctx) { var raio = Mapa.largura / 2; var prop = 0.5 + ((0.5 * this.cicloAtual) / this.ciclos); if (prop > 1) { prop = 1; } ctx.fillStyle = "rgb(" + Math.round(prop * 255) +", " + Math.round(prop * 100) + ", 0)"; if (this.cicloAtual <= this.ciclos) { ctx.beginPath(); ctx.arc(this.x * Mapa.largura + raio, this.y * Mapa.largura + raio, raio, Math.PI * 2, false); ctx.closePath(); ctx.fill(); } else { //Pinta o ponto central da explosão ctx.fillRect(this.x * Mapa.largura, this.y * Mapa.largura, Mapa.largura, Mapa.largura); Bomba.js (2/5) } else { ... var nx, ny, r; //Para cima for (r = 1; r <= this.raio; r++) { ny = this.y - r; if (ny >= 0) { if (Mapa.atual[ny][this.x] == Mapa.PAREDE) { break; } else { ctx.fillRect(this.x * Mapa.largura, ny * Mapa.largura, Mapa.largura, Mapa.largura); } if (Mapa.atual[ny][this.x] == Mapa.TIJOLO) { break; } } //Fecha if (ny >= 0) } //Fecha for (r) Bomba.js (3/5) } else { ... //Para baixo for (r = 1; r <= this.raio; r++) { ny = this.y + r; if (ny < Mapa.linhas) { if (Mapa.atual[ny][this.x] == Mapa.PAREDE) { break; } else { ctx.fillRect(this.x * Mapa.largura, ny * Mapa.largura, Mapa.largura, Mapa.largura); } if (Mapa.atual[ny][this.x] == Mapa.TIJOLO) { break; } } //Fecha if (ny) } //Fecha for (r) Bomba.js (4/5) } else { ... //Para esquerda for (r = 1; r <= this.raio; r++) { nx = this.x - r; if (nx >= 0) { if (Mapa.atual[this.y][nx] == Mapa.PAREDE) { break; } else { ctx.fillRect(nx * Mapa.largura, this.y * Mapa.largura, Mapa.largura, Mapa.largura); } if (Mapa.atual[this.y][nx] == Mapa.TIJOLO) { break; } } //Fecha if (nx) } //Fecha for (r) Bomba.js (5/5) //Para direita for (r = 1; r <= this.raio; r++) { nx = this.x + r; if (nx < Mapa.colunas) { if (Mapa.atual[this.y][nx] == Mapa.PAREDE) { break; } else { ctx.fillRect(nx * Mapa.largura, this.y * Mapa.largura, Mapa.largura, Mapa.largura); } if (Mapa.atual[this.y][nx] == Mapa.TIJOLO) { break; } } //Fecha if (nx) } //Fecha for (r) } //Fecha o else }; //Fecha o método desenhar() Bomba.js Bomba.desenharTodas = function (ctx) { var i; for (i = 0; i < Bomba.todas.length; i++) { Bomba.todas[i].desenhar(ctx); } }; bomberman.js //REVISAR A FUNÇÃO function reiniciar() { if (tempoJogador != null) { pausar(); } Mapa.carregar(canvas); desenharTudo(); document.getElementById("btnIniciar").disabled = false; document.getElementById("btnIniciar").innerHTML = "Iniciar"; intervaloJogador = 200; intervaloInimigos = intervaloJogador * 2; Bomba.todas.length = 0; Bomba.maxBombas = 1; } bomberman.js //REVISAR A FUNÇÃO function desenharTudo() { ctx.clearRect(0, 0, canvas.width, canvas.height); Mapa.desenhar(ctx); Bomba.desenharTodas(ctx); Jogador.desenhar(ctx); Inimigo.desenharTodos(ctx); } Testar! Bomba.js Bomba.executarTodosCiclos = function () { var i; for (i = 0; i < Bomba.todas.length; i++) { Bomba.todas[i].executarCiclo(); } }; Bomba.js this.executarCiclo = function () { this.cicloAtual++; if (this.cicloAtual > this.ciclos) { if (this.cicloAtual == this.ciclos + 1 && Bomba.som != null) { //Bomba.som.currentTime = 0; //Bomba.som.play(); } //this.explodir(); } }; bomberman.js //REVISAR A FUNÇÃO function atualizaJogador() { Jogador.mover(); Bomba.executarTodosCiclos(); desenharTudo(); if (Jogador.verificaMorte()) { gameOver(); } } Testar! Bomba.js (1/5) this.explodir = function () { var nx, ny, r, continua; //Para cima continua = false; for (r = 1; r <= this.raio; r++) { ny = this.y - r; if (ny >= 0) { continua = this.verificaEstrago(this.x, ny); } if (!continua) { break; } } //Fim do for Bomba.js (2/5) //Para baixo continua = false; for (r = 1; r <= this.raio; r++) { ny = this.y + r; if (ny < Mapa.linhas) { continua = this.verificaEstrago(this.x, ny); } if (!continua) { break; } } Bomba.js (3/5) //Para esquerda continua = false; for (r = 1; r <= this.raio; r++) { nx = this.x - r; if (nx >= 0) { continua = this.verificaEstrago(nx, this.y); } if (!continua) { break; } } Bomba.js (4/5) //Para direita continua = false; for (r = 1; r <= this.raio; r++) { nx = this.x + r; if (nx < Mapa.colunas) { continua = this.verificaEstrago(nx, this.y); } if (!continua) { break; } } Bomba.js (5/5) //Garante o tempo da explosão ativa if (this.cicloAtual > this.ciclos + Bomba.nCiclosPos) { var posicao = Bomba.todas.indexOf(this); Bomba.todas.splice(posicao, 1); Mapa.atual[this.y][this.x] = Mapa.LIVRE; } }; //Fim do método explodir() Bomba.js (1/3) this.verificaEstrago = function (x, y) { //Se encontrar uma parede, para o avanço da explosão if (Mapa.atual[y][x] == Mapa.PAREDE) { return false; } //Se encontrar um tijolo, quebra e para if (Mapa.atual[y][x] == Mapa.TIJOLO) { if (this.cicloAtual > this.ciclos + Bomba.nCiclosPos) { Mapa.atual[y][x] = Mapa.LIVRE; } return false; } Bomba.js (2/3) //Se encontrar uma bomba, explode quando for necessário var i; for (i = 0; i < Bomba.todas.length; i++) { if (Bomba.todas[i].x == x && Bomba.todas[i].y == y && this != Bomba.todas[i] && Bomba.todas[i].cicloAtual < Bomba.todas[i].ciclos) { //Vai explodir Bomba.todas[i].cicloAtual = Bomba.todas[i].ciclos; } } //Se encontrar o jogador, fim de jogo if (Jogador.x == x && Jogador.y == y) { gameOver(); } Bomba.js (3/3) //Se encontrar um inimigo, mata-o i = 0; while (i < Inimigo.todos.length) { if (Inimigo.todos[i].x == x && Inimigo.todos[i].y == y) { Inimigo.todos.splice(i, 1); } else { i++; } } return true; };//Fim do método verificaEstrago() Bomba.js this.executarCiclo = function () { this.cicloAtual++; if (this.cicloAtual > this.ciclos) { if (this.cicloAtual == this.ciclos + 1 && Bomba.som != null) { //Bomba.som.currentTime = 0; //Bomba.som.play(); } this.explodir(); } }; Retirar o comentário Testar! Bomberman ESTÍMULOS SONOROS Estímulos Sonoros • Conforme comentado anteriormente, quanto mais estimularmos, de forma positiva, os sentidos dos jogadores, maior a probabilidade dele se sentir como parte do jogo; • Para isto, iremos adicionar alguns pequenos sons associados a eventos como colisões; • Baixe os arquivos e salve na subpasta snd: – bomba.mp_; – bomba.ogg; <audio> e <source> • HTML 5! • MIME Types: – MP3 – audio/mpeg – Ogg – audio/ogg – Wav – audio/wav • Suporte: – Ps.: Múltiplos <source> fornecem redundância! Browser MP3 Wav Ogg IE 9+ Sim Não Não Chrome 6+ Sim Sim Sim Firefox 3.6+ Não Sim Sim Safari 5+ Sim Sim Não Opera 10+ Não Sim Sim index.html ... <audio controls id=“sndBomba"> <source src="snd/bomba.mp_" type="audio/mpeg"> <source src="snd/bomba.ogg" type="audio/ogg"> </audio> <script src=“bomberman.js"></script> bomberman.js //Recuperando referência dos objetos no documento var canvas = document.getElementById("tela"); var ctx = canvas.getContext("2d"); Bomba.som = document.getElementById("sndBomba"); Bomba.js this.executarCiclo = function () { this.cicloAtual++; if (this.cicloAtual > this.ciclos) { if (this.cicloAtual == this.ciclos + 1 && Bomba.som != null) { Bomba.som.currentTime = 0; Bomba.som.play(); } this.explodir(); } }; Retirar os comentários Testar! Trabalho 1. 2. 3. 4. 50% 5. 50% 6. 7. 8. 9. 10. 11. Customize cores e outras configurações do arquivo de estilo; Customize cores, tamanhos e disposição dos objetos do jogo (dentro do Javascript). Utilize gradientes e/ou imagens; Complete o HTML informando o nome da disciplina, o nome do instituto e o seu nome, dispondo os elementos com layouts CSS; Existe um bug: quando o jogo não esta em execução, teclas pressionadas são processadas ao retomar o jogo. Corrija este bug. Bug: Ao pressionar o botão “Novo Jogo”, o jogo reinicia mas duplica os Inimigos existentes. Crie um placar com pontuação; Crie uma indicação visual dentro do Canvas de fim de jogo; Adicione novos sons a eventos diferentes no jogo; Adicione teclas de atalho para “Pausa” e para “Novo Jogo”; Ao evoluir no jogo, crie novos desafios para o jogador; – Adicione outros elementos a seu critério; Entregue os arquivos por e-mail ao Professor junto com uma descrição/resposta para cada item do trabalho.