52
Programando PONG com DHTML Jogador 1: Jogador 2: Diego A. Oliveira

Construção de Jogos PONG

Embed Size (px)

DESCRIPTION

Nesta apostila comento sobre programação de jogos e ensino alguns conceitos mais básicos sobre o Canvas. No final é feito a implementação do jogo PONG em JavaScript. O código completo também se encontra no final da apostila. Para visualizar este e mais exercícios de graça acesse: http://diegoalvez2015.blogspot.com.br/

Citation preview

Page 1: Construção de Jogos PONG

Programando

PONGcomDHTML

Jogador 1: Jogador 2:

Diego A. Oliveira

Page 2: Construção de Jogos PONG

Sumário

1 O Que é Esse DHTML? 3

2 E Qual a Desvantagem do DHTML? 32.1 Por Que O PONG? . . . . . . . . . . . . . . . . . . . . . . . . 42.2 O Canvas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.3 O Que Vamos Precisar? . . . . . . . . . . . . . . . . . . . . 72.4 Desenho no Canvas . . . . . . . . . . . . . . . . . . . . . . 82.5 Começando o Pong . . . . . . . . . . . . . . . . . . . . . . . 112.6 Final de Seção . . . . . . . . . . . . . . . . . . . . . . . . . . 13

3 OBJETOS COM JAVASCRIPT 153.1 Usando os Objetos Que Criamos . . . . . . . . . . . . . . 183.2 Melhorando o Código . . . . . . . . . . . . . . . . . . . . . 183.3 Final de Seção . . . . . . . . . . . . . . . . . . . . . . . . . . 24

4 DETECÇÃO DE TECLA 264.1 Final de Seção . . . . . . . . . . . . . . . . . . . . . . . . . . 31

5 MOVIMENTO [Parte Um] 325.1 Explicando o Que Aconteceu . . . . . . . . . . . . . . . . . 335.2 SetTimeout E SetInterval . . . . . . . . . . . . . . . . . . . 345.3 Final de Seção . . . . . . . . . . . . . . . . . . . . . . . . . . 36

6 MOVIMENTO DA BOLA E COLISÃO 376.1 Velocidade da Bola . . . . . . . . . . . . . . . . . . . . . . . 416.2 Fim de Seção . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

7 Placar 457.1 Final de Seção . . . . . . . . . . . . . . . . . . . . . . . . . . 46

8 MELHORANDO A PERFORMASSE [Opcional] 50

9 LIVROS INDICADOS 52

Page 3: Construção de Jogos PONG

1 O Que é Esse DHTML?

O DHTML (Dinamic Hiper Text Markup Language) é a junção detrês outras linguagens o JavaScript, o Css e o HTML. Mas, jogosem DHTML na verdade levam muito pouco de HTML e Css a maiorparte do trabalho fica mesmo com o JavaScript.

A vantagem do JavaScript em relação as demais linguagens éque ela é interpretada pelo browser. O que significa que desdeque você tenha um OS com um browser moderno instalado serácapaz de testar seu trabalho. Outra vantagem é que você não pre-cisa instalar nada em sua máquina, pois você necessitará apenasde um editor simples de texto. Por fim o JavaScript tem uma ex-celente curva de aprendizado. São tantos recursos que em poucotempo você já será capaz de fazer coisas impressionantes.

Se você já fez disciplinas como algoritmo, lógica de progra-mação ou mesmo cálculo numérico então você já deu o primeiropasso para o mundo da programação, isso mesmo o primeiropasso. Isso porque estas disciplinas trabalham apenas o básicoe estão bem longe do que se deseja para formar um programadorde nível mediano. Se no entanto, você nunca teve nenhum con-tato com nenhuma linguagem pare a leitura desta apostila e pro-cure em uma biblioteca, ou mesmo na internet aulas sobre lógicade programação. Todos os livros ou tutoriais sobre jogos, por maisbásico que sejam e venha com frases como: "aprenda passo apasso", "a partir do básico", "for dummies" e etc., requerem umconhecimento razoável pelo menos em lógica de programação. Ese você não o têm, não conseguirá entender completamente oseu conteúdo. E esta apostila não é diferente.

2 E Qual a Desvantagem do DHTML?

A resposta para a pergunta acima é sim. Existem várias lingua-gens de programação e apesar do que muita gente acredita, eujá vi até professores universitários afirmarem isso, elas não sãotodas iguais. Cada linguagem possui uma característica própriaque facilita uma ou outra tarefa. Temos que nos lembrar que oJavaScript foi criado para dar interação a páginas Web e não paracriação de jogos. Assim, temos de lidar com algumas limitações.Por exemplo:

3

Page 4: Construção de Jogos PONG

� O JavaScript não trabalha bem com ambientação 3D;

� Como roda no browser possui suas limitações gráficas;

� O debug é difícil;

� É necessário testar seus códigos em vários navegadores.

A linguagem mais indicada para criação de jogos, segundo al-guns profissionais, é a linguagem C. Esta linguagem é normal-mente usada para programação de sistemas que envolvam pro-cessamento pesado. Outra linguagem que você pode usar é alinguagem Python, mas ao contrário do C ela não é indicada parajogos muito engenhosos e que exigem muito do computador. Nor-malmente ela é usada para produção de jogos mais simples quenão exigem muito da máquina (assim como o JavaScript).

2.1 Por Que O PONG?

Ninguém começa programando jogos complexos, como Devilmy Cry ou o Super Smash Bros. Na verdade, estes jogos são feitospor uma equipe de profissionais, muito bem treinados, que traba-lham em conjunto. Assim o ponto de partida de quase todo pro-gramador é o mundo 2D com jogos bem simples.

O PONG é um jogo relativamente simples de programar, porisso muitos livros de programação o apresentam em suas páginasfinais. Sendo simples é um excelente ponto de partida para quemestá começando.

2.2 O Canvas

O Canvas é uma tecnologia presente nas especificações doHTML5 e já está implementada em todos os navegadores inclu-sive no IE9. Essa tecnologia surgiu com a proposta de adicionarmais interatividade a páginas web, querendo inclusive substituiro Flash como recurso multimídia.

A forma mais simples de se pensar no Canvas é como umafolha de papel em branco. Nesta folha é que "desenhamos" oucolocamos os elementos do jogo.

4

Page 5: Construção de Jogos PONG

Agora veja como podemos criar um Canvas em uma páginaHTML. Para isso vamos partir da estrutura básica de um arquivoHTML. Digite o código seguinte em seu editor de texto e se pos-sível tente decora-lo.

1 <!DOCTYPE html>2 <html lang = "pt-br">3 <head>4 <title>Pong com HTML5 e JavaScript</title>5 </head>6 <body>7 </body>8 </html>

Para criar o Canvas utilizamos a tag <canvas>. Os atributoswidth e height informam a largura e a altura, respectivamente,da área de desenho. É importante também informar um id parapodermos trabalhar com ele no código JavaScript:

1 <body>2 <canvas id="myCanvas" width="600" height="480"></canvas>3 </body>

Entre as tags de abertura e fechamento, podemos colocar al-guma mensagem indicando que o browser não suporta essa tec-nologia. Caso o browser a suporte, esse conteúdo é ignorado:

1 <body>2 <canvas id="myCanvas" width="600" height="480"> Seu

navegador nao suporta o Canvas do HTML5.<br/>3 Procure atualiza-lo. </canvas>4 </body>

Os atributos width e height da tag <canvas> são obrigatórios,pois são os valores usados na geração da imagem. O Canvas podereceber dimensões diferentes via Css, no entanto, seu processa-mento sempre será feito usando as dimensões informadas na tag.

5

Page 6: Construção de Jogos PONG

1 <!DOCTYPE html>2 <html lang = "pt-br">3 <style>4 /* Canvas com dimensoes 600x480 pixels via Css */5 canvas{width: 600; height: 480;}6 </style>7 <head>8 <title>Pong com HTML5 e JavaScript</title>9 </head>

10 <body>11 <canvas id="myCanvas"></canvas>12 </body>13 </html>

Também é possível criar um Canvas apenas por meio do JavaScript.Embora essa abordagem seja um pouco mais complicada ela pos-sui uma vantagem sobre as demais, pois permite criarmos umCanvas de acordo com o tamanho da tela do seu PC.

Veja como isso é possível.

1 <script >2 canvas = document.createElement("myCanvas");3 canvas.width = 600;4 canvas.height = 480;5 document.body.appendChild(canvas);6 </script>

A primeira linha cria o elemento Canvas e o guarda na variávelcanvas (c minusculo). Na segunda e na terceira está declarado ovalor dos atributos width e height.

Como foi dito, a vantagem dessa abordagem é que podemoscontrolar o tamanho do Canvas de acordo com o tamanho da telado seu PC, celular ou qualquer outro dispositivo.

6

Page 7: Construção de Jogos PONG

1 <script>2 function Tela(){3 ALTURA = window.innerHeight;4 LARGURA = window.innerWidth;5 if(LARGURA >= 700){6 LARGURA = 600;7 ALTURA = 480;8 }else{9 LARGURA = 400;

10 ALTURA = 320;11 }12 };13

14 Tela();15

16 canvas = document.createElement("myCanvas");17 canvas.width = ALTURA;18 canvas.height = LARGURA;19

20 /* Cria uma borda preta ao redor do Canvas */21 document.body.appendChild(myCanvas);22 canvas.style.border = "1px solid #000";23 </script>

O innerHeight retorna a altura da tela do browser em seu dis-positivo enquanto o innerWidth a largura. Se (if) a largura formaior ou igual a 700 pixel então as dimensões do Canvas será de600x480 pixeis. Caso contrário (else), será de 400x320 pixeis.

2.3 O Que Vamos Precisar?

Para desenvolver com o DHTML você precisa apenas de umnavegador atualizado e um editor de texto simples. Eu recomendoo Sublime Text como editor de texto e o Google Chrome comonavegador. No entanto, você pode usar o bloco de notas e o IE.O problema é que o IE só conseguem interpretar bem o DHTML apartir da sua 9 versão (IE9).

O que você não deve fazer é usar o Word ou WordPad comoeditores. Isso porque esses programas têm o habito de "mudar" otexto que escrevemos.

Como já disse, o HTML5 é uma tecnologia que ainda está sendoimplementada nos navegadores de modo que é bom ter um se-gundo navegador para testar. Como segundo navegador eu re-comendo o Firefox. Um programa que funciona bem no Chrome e

7

Page 8: Construção de Jogos PONG

no Firefox normalmente bem funciona nos demais.

2.4 Desenho no Canvas

Dado um Canvas com dimensões de 600x480 pixeis vamos de-senhar alguns retângulos na tela. Vou assumir que o leitor estejaoptando por utilizar o Canvas através do JavaScript.

1 <script>2 canvas = document.createElement("myCanvas");3 canvas.width = 600;4 canvas.height = 480;5 document.body.appendChild(myCanvas);6 </script>

Para alinhar o Canvas no centro do navegador aplicamos umpouco de Css.

1 <style>2 canvas{3 position: absolute;4 top: 0px;5 bottom: 0px;6 left: 0px;7 right: 0px;8 margin: auto;9 background-color: black;

10 }11 </style>

A formatação acima não só centraliza o Canvas como tam-bém coloca-lhe um fundo negro. Sem a cor de fundo tudo o queveríamos é uma página em branco.

Apesar do Canvas ser um elemento do HTML seu uso é feitoexclusivamente por meio do JavaScript. Nesta apostila vamos uti-lizar o JavaScript dentro da área do body mas, fique a vontade emutilizá-lo dentro do head ou mesmo em um arquivo externo (maisindicado).

Agora que centralizamos o Canvas precisamos capturar seucontexto gráfico antes de começar a desenhar no Canvas.

8

Page 9: Construção de Jogos PONG

1 <script>2 canvas = document.createElement("myCanvas");3 canvas.width = 600;4 canvas.height = 480;5 document.body.appendChild(myCanvas);6 /* Capturando o contexto grafico */7 ctx = canvas.getContext ("2d");8 </script>

O contexto gráfico é o objeto que realiza de fato as tarefas dedesenho no Canvas. O contexto é obtido pelo método getContextdo Canvas. Como parâmetro, passamos uma string identificandoo contexto desejado. Infelizmente até o momento o JavaScript sópossui o contexto 2d ("d" em minúsculo!). Não ha um 3d ainda.

Para desenhar os nossos retângulos vamos utilizar dois méto-dos: o context.fillStyle e context.fillRect.

O primeiro método indica a cor que será usada para desenharno Canvas. Note que esse método usa a variável context.

//Síntese do métodocontext.fillStyle = ’cor’;

O segundo método (fillRect), desenha os retângulos.

//Síntese do métodocontext.fillRect(x, y, w, h);

Os valores x e y correspondem a posição do canto superioresquerdo do retângulo. O w a largura e h a altura. Note que eletambém utiliza a variável context.

9

Page 10: Construção de Jogos PONG

As coordenadas para a tela do navegador funcionam como nafigura acima.

Finalmente desenhamos na tela o cenário do nosso jogo.

1 <script>2 canvas = document.createElement("myCanvas");3 canvas.width = 600;4 canvas.height = 480;5 document.body.appendChild(myCanvas);6 ctx = canvas.getContext ("2d");7

8 /* Muda a cor dos desenhos para branco */9 ctx.fillStyle = ’white’;

10 /* Desenha a barra esquerda */11 ctx.fillRect(10, 190, 25, 100);12 /* Desenha a bola */13 ctx.fillRect(295, 230, 20, 20);14 /* Desenha a barra direita */15 ctx.fillRect(560, 190, 25, 100);16 </script>

O resultado no navegador será o seguinte.

10

Page 11: Construção de Jogos PONG

Esta é mais ou menos a cara do jogo.

2.5 Começando o Pong

Vamos dividir nosso jogo em três três etapas que eu chamareide: processamento de ativos, atualização da lógica do jogo e ren-derização. Estas etapas se repetem até o jogador finalizar a exe-cução do aplicativo.

1 <script>2 function CarregaAtivos(){3 /* Carrega imagens, sons etc, para usar no jogo */4 }5 function AtualizaGame(){6 /* Atualiza jogo */7 }8 function RenderGame(){9 /* Exibe o jogo na tela */

10 }11 CarregaAtivos();12 </script>

Na etapa de processamento de ativos (representada pelafunção CarregaAtivos) carregamos as imagens, sons e tudo o quenecessitamos carregar antes do jogo ser executado. Na atualiza-ção da lógica do jogo (representada pela função AtualizaGame),

11

Page 12: Construção de Jogos PONG

atualizamos os dados do jogo. E na etapa de renderização (rep-resentada pela função RenderGame), desenhamos os elementosdo jogo na tela.

Anteriormente aprendemos duas coisas: a primeira foi criarum Canvas. Ele deve ser a primeira coisa a ser carregada pelobrowser. Vamos coloca-lo dentro da função CarregaAtivos.

1 <script>2 function CarregaAtivos(){3 canvas = document.createElement("canvas");4 var canvas.width = 600;5 var canvas.height = 480;6 document.body.appendChild(canvas);7 ctx = canvas.getContext("2d");8 RenderGame();9 };

10 CarregaAtivos();11 </script>

A segunda coisa que aprendemos foi a desenhar os objetos dojogo. Esses desenhos ficarão dentro da função RenderGame.

1 <script>2 function RenderGame(){3 ctx.fillStyle = ’white’;4 ctx.fillRect(10, 190, 25, 100);5 ctx.fillRect(295, 230, 20, 20);6 ctx.fillRect(560, 190, 25, 100);7 };8 </script>

Na próxima página está o código completo resumindo tudo oque foi dito até agora. Aproveite para estuda-lo pois ele será abase do nosso jogo.

12

Page 13: Construção de Jogos PONG

2.6 Final de Seção

No final de cada seção será dado o código completo desen-volvido até o momento. Isso servirá tanto para que você possaacompanhar o próximo capitulo, caso você venha a se perder emalguma passagem, quanto para que você consiga se organizarmelhor.

Até o momento o que temos é do nosso jogo é o seguinte:

1 <!DOCTYPE html>2 <html lang = "pt-br">3 <head>4 <style type="text/css">5 canvas{6 position: absolute;7 top: 0px;8 bottom: 0px;9 left: 0px;

10 right: 0px;11 margin: auto;12 background-color: black;13 }14 </style>15 <title>Pong com HTML5 e JavaScript</title>16 </head>17 <body>18 <script type="text/javascript">19 function CarregaAtivos(){20 canvas = document.createElement("canvas");21 canvas.width = 600;22 canvas.height = 480;23 document.body.appendChild(canvas);24 ctx = canvas.getContext("2d");25 RenderGame();26 };27 function AtualizaGame(){28 /*Codigos*/29 }30 function RenderGame(){31 ctx.fillStyle = ’white’;32 ctx.fillRect(10, 190, 25, 100);33 ctx.fillRect(295, 230, 20, 20);34 ctx.fillRect(560, 190, 25, 100);35 }36 CarregaAtivos();37 </script>

13

Page 14: Construção de Jogos PONG

38 </body>39 </html>

14

Page 15: Construção de Jogos PONG

3 OBJETOS COM JAVASCRIPT

Observe novamente a tela que desenhamos para o nosso jogoaté agora.

Em termos simples os objetos que possuímos até agora nonosso jogo são três polígonos simples. Cada um desses polí-gonos possui algumas características em comum. Como cor, umalargura e altura, mesmo que não sejam as mesmas. Cada umadessas características são chamadas de atributo. E um con-junto de atributos é chamado de classe. Esses dois conceitossão muito importantes para compreender o que é um objeto. Porisso lembre-se: uma classe é um conjunto de atributos. Enquantoum atributo é apenas um elemento da classe.

É bastante obvio que podemos guardar valores em uma var-iável. Outra coisa que uma variável pode guardar no JavaScript éuma classe. Associar uma classe a uma variável é um processochamado de instância. Uma classe instanciada é um objeto.Complicado? No começo pode parecer confuso, mas a medidaque você vai aprendendo como declarar programaticamente umobjeto as coisas ficarão mais claras. Até então espero ter dado aomenos uma ideia do que é um objeto.

Teremos no jogo três objetos (cada um dos polígonos). O primeiroobjeto será chamado de jogadorEsquerda. E como o próprio

15

Page 16: Construção de Jogos PONG

nome sugere esse objeto será a raquete a mais a esquerda datela. O segundo objeto, será chamado de jogadorDireita e seráa raquete mais a direita da tela. Por último teremos o objeto bola.Que como o nome deixa claro será a bola do jogo.

1 var jogadorDireita = {2 altura: 100,3 largura: 25,4 x: 10,5 y: 1906 }7 var jogadorEsquerda = {8 altura: 100,9 largura: 25,

10 x: 560,11 y: 19012 }13 var bola = {14 altura: 20,15 largura: 20,16 x: 295,17 y: 23018 }

Acima criamos três variáveis e guardamos em cada uma delasuma classe que na mais é do do que um conjunto de atributos.Essa forma de criar um objeto é chamada de forma literal.

Existe outro modo de declarar um objetos em JavaScript sendoas vazes até mais eficiente em termos de economia de código.Veja como:

Primeiro criamos uma função chamada Retangulo. Essa funçãoirá guardar um conjunto de atributos. Em outras palavras a funçãoRetangulo terá o papel de classe.

1 function Retangulo(x,y,largura,altura){2 this.x = x;3 this.y = y;4 this.largura = largura;5 this.altura = altura;6 }

Em seguida fazemos a instância da classe criando o objeto jo-gadorEsquerda.

16

Page 17: Construção de Jogos PONG

1 var jogadorEsquerda = new Retangulo(10,190,25,100);

A vantagem desse método é que podemos reaproveitar a classeretângulo para criar os objetos jogadorDireita e bola. Assim, reaproveita-mos código.

1 function Retangulo(x,y,largura,altura){2 this.x = x;3 this.y = y;4 this.largura = largura;5 this.altura = altura;6 }7 var jogadorEsquerda = new Retangulo(10,190,25,100);8 var jogadorDireita = new Retangulo(560,190,25,100);9 var bola = new Retangulo(295,230,20,20);

Usar funções como classe é um pouco mais complicado no ini-cio contudo, ela possibilitará uma economia na escrita dos seusjogos.

Vamos aproveitar agora e acrescentar a nossa classe cincoatributos que mais a frente serão importantes. O atributo speed,que determinará a velocidade com que o objeto irá se movimen-tar. E o atributo placar. Que guardará a pontuação de cada jo-gador. E os atributos dirx, diry e mod.

1 function Retangulo(x,y,largura,altura,speed){2 this.x = x;3 this.y = y;4 this.largura = largura;5 this.altura = altura;6 this.speed = speed;7 this.dirx = -1;8 this.diry = 1;9 this.mod = 1;

10 }11 var jogadorEsquerda = new Retangulo(10,190,25,100,12);12 var jogadorDireita = new Retangulo(560,190,25,100,12);13 var bola = new Retangulo(295,230,20,20,20);

Também acrescentei em cada instância de objeto mais umvalor. Isso porque a função (ou classe chama como quiser), re-cebeu mais um parâmetro o speed. Assim o valor do atributo dojogadorEsquerda e jogadorDireita é 12 enquanto do objeto bolaserá de 12.

17

Page 18: Construção de Jogos PONG

Como a bola estará ora se deslocando para a direita ora para aesquerda, as vezes para cima outras para baixo, precisaremos dedois atributos que controlem essa mudança. Esses atributos sãojustamente o dirx (controla a mudança de direção no eixo x), e odiry (controla a mudança de direção no eixo y).

O atributo que chamamos de mod (modificador) controlará avelocidade da bola. Que irá aumentar a medida que o jogo estarásendo executado. Assim como ocorre num jogo de Pong padrão.

3.1 Usando os Objetos Que Criamos

Observe o conteúdo da função RenderGame.

1 function RenderGame(){2 ctx.fillStyle = ’white’;3 ctx.fillRect(10, 190, 25, 100);4 ctx.fillRect(295, 230, bola.largura, 20);5 ctx.fillRect(560, 190, 25, 100);6 };

Vamos alterar essa função para aproveitar os objetos que cri-amos.

1 function RenderGame(){2 ctx.fillStyle = ’white’;3 ctx.fillRect(jogadorEsquerda.x, jogadorEsquerda.y,

jogadorEsquerda.largura, jogadorEsquerda.altura);4 ctx.fillRect(bola.x, bola.y, bola.largura, bola.altura);5 ctx.fillRect(jogadorDireita.x, jogadorDireita.y,

jogadorDireita.largura, jogadorDireita.altura);6 };

Basicamente o que fizemos aqui foi mudar os valores de cadamétodo fillRect pelos atributos de cada objeto. O resultado deveser o mesmo que o da página 9, uma vez que os valores dosatributos eram iguais aos valores nos métodos.

3.2 Melhorando o Código

Uma regra básica da programação é escrever o mínimo pos-sível. Podemos minimizar um pouco do que escrevemos usandoum prototype.

18

Page 19: Construção de Jogos PONG

1 Retangulo.prototype.draw = function(){2 ctx.fillStyle = ’white’;3 ctx.fillRect(this.x, this.y, this.largura, this.altura);4 };

Um prototype é um atributo de um objeto, no entanto, esseatributo guarda uma ação ao invés de um valor. Como os atributosque vimos até agora.

No nosso caso o prototype (que chamei de draw), irá desenharos objetos na tela. O this indica que está sendo usado os valoresdos atributos presente dentro da classe Retangulo.

A vantagem de usar protótipos no lugar de funções comuns éque prototypes consomem menos memória. Para verificar o fun-cionamento do protótipo draw basta apenas apagar o conteúdoda função RenderGame e colocar a chamada do protótipo.

1 function RenderGame(){2 bola.draw();3 jogadorDireita.draw();4 jogadorEsquerda.draw();5 };

Antes de finalizar esta seção vamos fazer mais algumas mu-danças visuais na tela do jogo. Vamos incluir uma linha vertical eo placar dos jogadores.

Uma linha dentro do Canvas é desenhada usando Paths (cam-inhos). Um path e um conjunto de comandos de desenho que fi-cam registrados na memória, aguardando os métodos fill (preencher)ou stroke (contornar) serem chamados. O código a seguir mostracomo uma linha é desenhada.

1 /* Inicia o modo de desenho */2 context.beginPath();3 /* Posiciona a caneta virtual no ponto (x,y) */4 context.moveTo(canvas.width/2, 0);5 /* traca uma linha virtual do ponto atual ate o ponto

indicado */6 context.lineTo(canvas.width/2, canvas.height);7 /* Configurar a espessura da linha */8 context.lineWidth = 2;9 /* Configura a cor da linha */

10 context.strokeStyle = ’red’;

19

Page 20: Construção de Jogos PONG

11 /* Traca fisicamente a linha virtual */12 context.stroke();

Já o placar é feito do seguinte modo:

1 /* Scoore */2 context.font = "20px Arial";3 context.fillText("Jogador 1: " + jogadorEsquerda.placar,

50, 20);4 context.fillText("jogador 2: " + jogadorDireita.placar,

440, 20);

Todo esse código pode ser usado dentro da função RenderGamemas, para não poluir muito a função (que será a principal), vamoscriar mais uma função.

1 function cena(){2 /* Desenha o placar */3 context.font = "20px Arial";4 context.fillText("Jogador 1: " + jogadorEsquerda.placar,

50, 20);5 context.fillText("jogador 2: " + jogadorDireita.placar,

440, 20);6 /* Desenha a linha vertical */7 context.beginPath();8 context.moveTo(canvas.width/2, 0);9 context.lineTo(canvas.width/2, canvas.height);

10 context.lineWidth = 2;11 context.strokeStyle = ’red’;12 context.stroke();13 };

E chama-la na função RenderGame.

1 function RenderGame(){2 bola.draw();3 jogadorDireita.draw();4 jogadorEsquerda.draw();5 cena();6 };

20

Page 21: Construção de Jogos PONG

O resultado final esta na imagem a seguir.

O interessante agora é que como a linha passa no centro entãoisso significa que a bola não está devidamente centralizada.

Para centralizar a bola alteramos os dois primeiros valores doobjeto para o seguinte:

var bola = new Retangulo(300,240,20,20,20);

Alterando a cor da linha para branco o resultado será a imagemseguinte.

21

Page 22: Construção de Jogos PONG

Também é possível modificar o formato da bola para um circulousando um path. Mas, como um circulo tem uma forma bem difer-ente de um polígono então não podemos aproveitar o protótipodraw criado. Sendo necessário criar um protótipo exclusivo.

1 Retangulo.prototype.drawBola = function(){2 ctx.beginPath();3 ctx.arc(this.x, this.y, 14, 0, Math.PI*2, true);4 ctx.closePath();5 ctx.fillStyle = ’white’;6 ctx.fill();7 };

E dentro da função RenderGame alteramos a chamada bola.draw()para bola.drawBola().

O resultado será uma bola de diâmetro igual a 14 pixeis:

22

Page 23: Construção de Jogos PONG

A partir de agora usaremos essa configuração para a bola.

23

Page 24: Construção de Jogos PONG

3.3 Final de Seção

Finalizada mais uma seção vamos rever todo o código escritoaté agora.

1 <script type="text/javascript">2 function Retangulo(x,y,largura,altura,speed){3 this.x = x;4 this.y = y;5 this.largura = largura;6 this.altura = altura;7 this.speed = speed;8 this.placar = 0;9 this.dirx = -1;

10 this.diry = 1;11 this.mod = 1;12 };13 Retangulo.prototype.draw = function(){14 ctx.fillStyle = ’white’;15 ctx.fillRect(this.x, this.y, this.largura, this.altura);16 };17 Retangulo.prototype.drawBola = function(){18 ctx.beginPath();19 ctx.arc(this.x, this.y, 14, 0, Math.PI*2, true);20 ctx.closePath();21 ctx.fillStyle = ’white’;22 ctx.fill();23 };24 var jogadorEsquerda = new Retangulo(10,190,25,100,12);25 var jogadorDireita = new Retangulo(560,190,25,100,12);26 var bola = new Retangulo(295,230,20,20,20);27

28 function cena(){29 /* Desenha o placar */30 ctx.font = "20px Arial";31 ctx.fillText("Jogador 1: " + jogadorEsquerda.placar, 50,

20);32 ctx.fillText("jogador 2: " + jogadorDireita.placar, 440,

20);33 /* Desenha a linha vertical */34 ctx.beginPath();35 ctx.moveTo(canvas.width/2, 0);36 ctx.lineTo(canvas.width/2, canvas.height);37 ctx.lineWidth = 2;38 ctx.strokeStyle = ’white’;39 ctx.stroke();40 };41

24

Page 25: Construção de Jogos PONG

42 function CarregaAtivos(){43 canvas = document.createElement("canvas");44 canvas.width = 600;45 canvas.height = 480;46 document.body.appendChild(canvas);47 ctx = canvas.getContext("2d");48 RenderGame();49 };50 function AtualizaGame(){51 /*Codigos*/52 };53 function RenderGame(){54 bola.drawBola();55 jogadorDireita.draw();56 jogadorEsquerda.draw();57 cena();58 };59 CarregaAtivos();60 </script>

25

Page 26: Construção de Jogos PONG

4 DETECÇÃO DE TECLA

As barras ou "personagens" do PONG devem ser controladaspelas teclas do seu teclado. Por este motivo é necessário fazercom que o jogo seja capaz de detectar quando uma tecla é pres-sionada ou quando uma tecla que foi pressionada é solta. Quemrealiza estas ações são os ouvintes (Listener) do JavaScript.

Um listener é uma função JavaScript que executa uma ação emresposta a um evento. Essa função pode receber um parâmetroque é preenchido automaticamente com dados sobre o eventoocorrido. Para associar um listener a um elemento da página,usamos o método addEventListener:

Sua síntese é a seguinte:

// Exemplo Teóricoelemento.addEventListener(’evento’, função, false);

Primeiro indicamos o elemento o qual o Listener será associ-ado. Em seguida damos o nome do evento. Sempre que o eventoindicado ocorrer o método irá chamar uma função (function call-back). Essa função tem seu nome escrito após o nome do evento.

Na pratica o código para a detecção de teclas fica assim:

1 /* Exemplo Pratico */2 var teclas = {};3 document.addEventListener(’keydown’, Keydown, false);4 function Keydown(evento){5 teclas[evento.keyCode] = true;6 alert(evento.keyCode);7 };

No exemplo acima primeiro criamos um objeto vazio chamadoteclas. Um objeto nada mais é do que um tipo especial de ar-ray, assim, podemos declarar um array como objeto sem nenhumproblema. Se você preferir no lugar de var teclas = { };

poderíamos usar tanto o:

26

Page 27: Construção de Jogos PONG

1 var teclas = new Array();

como até mesmo a própria declaração de array.

1 var teclas = [];

ou mesmo funções construtoras.

1 function Teclado(){ };2 var teclas = new Teclado();

Qualquer forma de declaração de objeto que você use trará omesmo resultado, e substituirá perfeitamente a declaração de umarray.

A função do objeto teclas será apenas guardar um registro dasteclas que serão pressionadas.

Em seguida aplicamos o addEventListener ao document.Poderíamos aplica-lo diretamente ao elemento Canvas, mas casoo usuário por acaso clicasse fora do Canvas o método passaria anão funcionar. Aplicando-o a todo o documento garantimos que ométodo sempre estará disponível.

Em JavaScript, são três os eventos associados ao teclado: key-down, keypress e keyup. Mas para jogos somente dois são im-portantes.

� keydown: ocorre quando uma tecla e pressionada (abaix-ada). Se o usuário a mantiver segurando, o evento edisparado repetidamente;

� keyup: ocorre uma única vez, quando uma tecla e solta.

1 var teclas = {};2 document.addEventListener(’keydown’, Keydown, false);3 function Keydown(evento){4 teclas[evento.keyCode] = true;5 alert(evento.keyCode);6 };

27

Page 28: Construção de Jogos PONG

No código acima estamos usando o evento keydown assim,sempre que uma tecla do teclado é pressionada a função Keydowné chamada. No exemplo nomeamos a função com o mesmo nomedo evento (exceto pelo "K" maiúsculo), mas na prática essa funçãopode ter qualquer nome.

E o que a função Keydown está fazendo? Vamos olha-la nova-mente.

1 function Keydown(evento){2 teclas[evento.keyCode] = true;3 alert(evento.keyCode);4 };

A função Keydown seta para true os elementos do objeto teclas.Quando a função Keydown é chamada o AddEventListener auto-maticamente passa para ela o parâmetro evento. Você pode darqualquer nome a esse parâmetro como, por exemplo, evt.

Esse parâmetro é o caractere digitado. O keycode fornece ocódigo ASCII desse caractere. O código ASCII da tecla "W" porexemplo, é 83.

Supondo que o usuário pressione a tecla "W" a função Keydowncria e seta para true o array teclas[83]. O valor lógico deste arrayé o que indicará que a tecla "W" foi pressionada.

teclas[83] = true;

Agora que você deve ter entendido como funciona a funçãoKeycode atualize o seu código e teste no seu navegador pression-ando, por exemplo, a tecla up. Como resultado deve ocorrer umajanela de alerta como a seguir.

28

Page 29: Construção de Jogos PONG

O alerta indica que a função Keydown está realmente recebendoo parâmetro evento e que seu valor é 38. Esse número é o códigoque identifica a tecla up na tabela ASCII.

Com isso também criamos o array teclas[38] com valor igual atrue. Que indica que a tecla foi pressionada.

Para fazer com que a tecla volte ao seu estado inicial (sem nen-hum valor lógico) quando ela for solta, usamos mais um EventListener.Que pode ser declarado logo abaixo do primeiro.

1 /* Exemplo Pratico */2 document.addEventListener(’keyup’, Keyup, false);3 function Keyup(evento){4 delete teclas[evento.keyCode];5 };

Agora usamos o evento keyUp. Pois a tecla só deve voltar aoseu estado inicial depois que ela for liberada.

O delete esvazia o objeto teclas. Assim, se antes a variávelteclas[38] tinha o valor true e o JavaScript reconhecia essa teclacomo pressionada, quando ela é solta o evento keyUp dispara a

29

Page 30: Construção de Jogos PONG

função que deleta esse array do objeto, fazendo com que a teclaque foi pressionada volte para seu estado inicial.

30

Page 31: Construção de Jogos PONG

4.1 Final de Seção

Como nesse capítulo foram poucas as alterações feitas no nossoscript será colocado apenas o trecho específico em que elas ocor-reram. Isso será o suficiente para que você possa se localizar.

1 /* ...Codigos */2 var jogadorEsquerda = new Retangulo(10,190,25,100,12);3 var jogadorDireita = new Retangulo(560,190,25,100,12);4 var bola = new Retangulo(300,240,20,20,20);5 var teclas = {};6

7 document.addEventListener(’keydown’, Keydown, false);8 function Keydown(evento){9 teclas[evento.keyCode] = true;

10 alert(evento.keyCode);11 };12 document.addEventListener(’keyup’, Keyup, false);13 function Keyup(evento){14 delete teclas[evento.keyCode];15 };16

17 function cena(){18

19 /* Codigos... */

31

Page 32: Construção de Jogos PONG

5 MOVIMENTO [Parte Um]

O que queremos agora é fazer com que a barra da direita semova para cima e para baixo quando apertamos a tecla up e downrespectivamente. Mas, como podemos fazer isso?

A primeira coisa que faremos é retirar a função de alerta dafunção keydown.

1 document.addEventListener(’keydown’, keydown, false);2 function keydown(evento){3 teclas[evento.keyCode] = true;4 };

Dentro da função AtualizaGame coloque o seguinte.

1 function AtualizaGame(){2 if (38 in teclas)3 jogadorDireita.y -= jogadorDireita.speed;4 };

Finalmente altere a função RenderGame para:

1 function RenderGame(){2 ctx.clearRect(0, 0, canvas.width, canvas.height);3 bola.drawBola();4 jogadorDireita.draw();5 jogadorEsquerda.draw();6 cena();7 AtualizaGame();8 setTimeout(RenderGame, 15);9 };

Agora experimente rodar o programa no seu navegador e pres-sionar aos poucos a tecla up. Se você fez tudo certo verá que abarra direita agora é capaz de deslizar para cima.

32

Page 33: Construção de Jogos PONG

5.1 Explicando o Que Aconteceu

Na function AtualizaGame escrevemos o seguinte:

1 function AtualizaGame(){2 if(38 in teclas)3 jogadorDireita.y -= jogadorDireita.speed;4 };

Se a tecla de código 38 estiver dentro do objeto teclas então avariável y do objeto jogadorDireita sofre um decremento igualao valor da variável speed também do objeto jogadorDireita.

Já na function RenderGame a primeira linha limpa todo o Can-vas antes de começar a desenhar enquanto a segunda chama afunção movimento.

A última linha setTimeout realiza um loop. A cada 15 milisse-gundos ele chama novamente a function RenderGame e a cadachamada os dados da mesma são atualizados.

Na verdade, quando você vê um jogo na tela de um computa-dor o que você está de fato vendo são várias imagens sendo re-produzidas em sequência numa velocidade extremamente alta.

O problema da implementação feita até agora é que a barraacaba passando da área do Canvas e não é isso que queremosque aconteça. Para resolver este problema dentro da function At-ualizaGame completamos o código anterior rescrevendo a função.

1 function movimento(){2 if(38 in teclas && jogadorDireita.y > 0)3 jogadorDireita.y -= jogadorDireita.speed;4 };

Repare que agora a barra sobe até o limite do Canvas e para.

Para descer a barra acrescentamos mais uma condição na função.Como foi feito a seguir.

33

Page 34: Construção de Jogos PONG

1 function AtualizaGame(){2 if(38 in teclas && jogadorDireita.y > 0)3 jogadorDireita.y -= jogadorDireita.speed;4 /* O 100 eh a altura da barra */5 if(40 in teclas && jogadorDireita.y + 100 < canvas.height

)6 jogadorDireita.y += jogadorDireita.speed;7 };

Para movimentar a barra esquerda fazemos praticamente amesma coisa. Colocamos mais dois if dentro da função Atual-izaGame.

1 /* Movimento da barra direita */2 function AtualizaGame(){3 if(38 in teclas && jogadorDireita.y > 0)4 jogadorDireita.y -= jogadorDireita.speed;5 if(40 in teclas && jogadorDireita.y + 100 < canvas.height

)6 jogadorDireita.y += jogadorDireita.speed;7 /* Movimento da barra esquerda */8 if(87 in teclas && jogadorEsquerda.y > 0)9 jogadorEsquerda.y -= jogadorEsquerda.speed;

10 if(83 in teclas && jogadorEsquerda.y + 100 < canvas.height)

11 jogadorEsquerda.y += jogadorEsquerda.speed;12 };

Agora experimente rodar o programa no navegador usando asteclas up, down, "W" e "S".

5.2 SetTimeout E SetInterval

Tradicionalmente, quando queremos executar tarefas periódi-cas em páginas web, usamos os métodos window.setTimeout ouwindow.setInterval, passando a função desejada e o intervaloem milissegundos. Os resultados são satisfatórios para tarefassimples, no entanto, o controle do tempo pelo browser não e to-talmente preciso.

E preciso lembrar que os sistemas operacionais modernos sãomultitarefa, e mesmo os browsers podem ter várias guias abertas.

34

Page 35: Construção de Jogos PONG

Não é possível garantir que a CPU esteja sempre disponível nomomento exato desejado, portanto o intervalo informado sempreserá aproximado.

A solução para jogos e outras aplicações que requerem ani-mações mais precisas e trabalhar com ciclos mais curtos, aprovei-tando cada momento em que a CPU está disponível para nossoaplicativo, e nesse momento fazer o cálculo do tempo. Para isso, aespecificação do HTML5 traz o método requestAnimation Frame,que delega para o browser a tarefa de executar sua animação omais rápido possível, assim que os recursos do sistema estiveremdisponíveis.

Para usar o requestAnimationFrame fazemos o seguinte. Antesda função RenderGame chamamos o método e no final da funçãosubstituímos o setTimeout por requestAnimationFrame. Comoé mostrado a seguir.

1 requestAnimationFrame(RenderGame);2 function RenderGame(){3 /* ...Codigos */}4 AtualizaGame();5 requestAnimationFrame(RenderGame);6 };

Se você fez as alterações corretamente irá notar que agoraas barras anda bem depressa. Isto ocorre porque o requestAni-mationFrame trabalha com ciclos curtos, aproveitando o primeiromomento em que a CPU e o browser puderem executar o proces-samento da função de animação.

Para o caso do PONG essa velocidade é um tanto prejudicial,por isso continuaremos a usar o setTimeout. Embora exista umaforma eficiente de controlar o AnimationFrame para obter ciclosmaiores.

35

Page 36: Construção de Jogos PONG

5.3 Final de Seção

1 <script type="text/javascript">2 /* ...Codigos */3

4 var jogadorEsquerda = new Retangulo(10,190,25,100,12);5 var jogadorDireita = new Retangulo(560,190,25,100,12);6 var bola = new Retangulo(300,240,20,20,20);7 var teclas = {};8

9 document.addEventListener(’keydown’, Keydown, false);10 function Keydown(evento){11 teclas[evento.keyCode] = true;12 };13 /* ...Codigos */14

15 function AtualizaGame(){16 /* Movimento da barra direita */17 if(38 in teclas && jogadorDireita.y > 0)18 jogadorDireita.y -= jogadorDireita.speed;19 if(40 in teclas && jogadorDireita.y + 100 < canvas.height

)20 jogadorDireita.y += jogadorDireita.speed;21 /* Movimento da barra esquerda */22 if(87 in teclas && jogadorEsquerda.y > 0)23 jogadorEsquerda.y -= jogadorEsquerda.speed;24 if(83 in teclas && jogadorEsquerda.y + 100 < canvas.

height)25 jogadorEsquerda.y += jogadorEsquerda.speed;26 };27 function RenderGame(){28 ctx.clearRect(0, 0, canvas.width, canvas.height);29 bola.drawBola();30 jogadorDireita.draw();31 jogadorEsquerda.draw();32 cena();33 AtualizaGame();34 setTimeout(RenderGame, 15);35 };36 CarregaAtivos();37 </script>

36

Page 37: Construção de Jogos PONG

6 MOVIMENTO DA BOLA E COLISÃO

Agora vamos escrever dentro da função AtualizaGame os co-mandos que darão movimento a bola.

1 function AtualizaGame(){2 /* ...Codigos */3 bola.x += bola.speed * bola.dirx;4 bola.y += bola.speed * bola.diry;5 };

Nesse caso a bola está sendo incrementada tanto em x comoem y pela variável speed multiplicada pela variável dirx e diryrespectivamente.

Ao contrário das barras a bola têm sua posição atualizada atodo momento e por isso o código acima aparece solto (sem nen-huma estrutura condicional como o if), dentro da função atual-izaGame.

Se você testar o código acima vai perceber que a bola já estaráse deslocando. O problema é que a bola está se movimentandomuito rapidamente e "desaparece" também rapidamente da tela.Para resolver o problema da velocidade altere o valor da variávelspeed dentro do objeto bola para um valor bastante baixo, como2 por exemplo.

1 var bola = new Retangulo(300, 240, 20, 20, 2);

Fazendo a alteração acima e testando o código no seu nave-gador a bola deve se mover bem devagar. Durante os testes épossível que as vezes o seu jogo dê algumas "travadas". Comojá disse a função setTimeout não é indicada para jogos ou ani-mações. Até darmos um jeito nisso feche todos os programas queestiverem em execução no computador e encerre todos os proces-sos desnecessários deixando somente o navegador aberto. Outracoisa que você pode fazer é usar o navegador do Google (Google

37

Page 38: Construção de Jogos PONG

Crhome), ele costuma interpretar o JavaScript mais rapidamenteque os outros navegadores.

Agora vamos tratar das colisões da bola. Até agora a bolaapenas se movimenta para baixo da direita para esquerda, comoindicado na imagem a baixo.

No entanto, quando ela bate no piso ela desaparece ao invésde "quicar" como deveria fazer. Esse evento é chamado de col-isão. Que é quando um objeto se aproxima de outro e em seguidaé repelido.

Para implementar esta colisão inserimos mais uma if a funçãoAtualizaGame.

1 function AtualizaGame(){2 /* ...Codigos */3 if(bola.y >= canvas.heigh - bola.altura)4 bola.diry = - 1;5 };

Para entender o que está ocorrendo na função acima preste

38

Page 39: Construção de Jogos PONG

atenção no desenho a seguir.

A variável y dentro do objeto bola é a altura do ponto emvermelho na figura acima.

Quando a bola toca a borda inferior do Canvas a coordenaday, do ponto vermelho, será a altura do Canvas menos o diâmetroda bola.

Em pseudocódigo a colisão da bola com a borda inferior doCanvas seria escrita assim:

Se (bola.y >= canvas.height - bola.altura) então{Mude a direção da bola

};

A direção da bola é controlada pela variável diry e dirx. Comoa bola está descendo e queremos que ao tocar na borda infe-rior ela suba então mudamos o valor da variável diry para seusimétrico, isto é −1.

1 function AtualizaGame(){2 /* ...Codigos */3 if(bola.y >= canvas.height - bola.altura)4 bola.diry = -1;5 };

39

Page 40: Construção de Jogos PONG

A função acima implementa a colisão apenas com o piso in-ferior do Canvas. Contudo, a colisão com o piso superior e asparedes a direita e esquerda segue uma lógica bem similar. Su-giro que você tente implementa-las sozinho, mas caso não tenhasucesso a implementação completa de todas as colisões se en-contra a seguir.

1 function AtualizaGame(){2 /* Colisao da bola com o piso */3 if(bola.y >= (canvas.height - bola.altura))4 bola.diry=-1;5

6 /* Colisao da bola com a barra esquerda */7 if(bola.x <= jogadorEsquerda.x + bola.largura && bola.y

<= jogadorEsquerda.y + jogadorEsquerda.altura && bola.y + bola.altura >= jogadorEsquerda.y)

8 bola.dirx=1;9

10 /* Colisao da bola com o teto */11 if(bola.y <= bola.altura)12 bola.diry=1;13

14 /* Colisao da bola com a barra direita */15 if(bola.x >= jogadorDireita.x - bola.altura && bola.y <=

jogadorDireita.y + jogadorDireita.altura && bola.y >=bola.altura + jogadorDireita.y)

16 bola.dirx=-1;17 };

No if de colisão com o teto do Canvas usei

1 if (bola.y <= bola.altura)2 bola.diry = 1;

E talvez você esteja pensando, porque simplesmente não foiusado:

1 if (bola.y <= 0)2 bola.diry = 1;

Na teoria apenas o zero bastaria (e você pode até usar apenaso zero), mas a verdade é que existe um atraso na leitura de cada

40

Page 41: Construção de Jogos PONG

if de modo que o atributo altura do objeto bola minimiza esseefeito. Isso faz com que o if seja executada um pouco antes doque deveria, mas devido ao atraso ele acaba se executando nomomento certo.

Experimente, por exemplo, usar apenas o zero. Você poderáperceber que a bola entra um pouco fora do Canvas ante de serrebatida.

Neste ponto convido o leitor, se assim desejar, a corrigir essesatrasos nas demais colisões.

Após a inclusão de nossos códigos na função AtualizaGame jáserá possível experimentar o PONG que já está quase finalizado.Experimente jogar um pouco alterando os valores speed da bolae também diminuindo o setInterval.

Esses valores devem ser ajustados ao seu gosto, mas lembre-se de manter a velocidade da bola baixa. Isso porque ela deveaumentar gradualmente ao longo do jogo.

6.1 Velocidade da Bola

A incrementação da velocidade da bola se dá por meio da somada variável speed com a variável mod. Assim altere as linha aseguir disso:

1 function AtualizaGame(){2 /* ...Codigos */3 bola.x += bola.speed * bola.dirx;4 bola.y += bola.speed * bola.diry;5 };

para isso:

41

Page 42: Construção de Jogos PONG

1 function AtualizaGame(){2 /* ...Codigos */3 bola.x += (bola.speed + bola.mod) * bola.dirx;4 bola.y += (bola.speed + bola.mod) * bola.diry;5 };

Os parênteses acima são necessários pois a multiplicação devariáveis têm prioridade em cima da soma.

Queremos que a bola sofra um incremento de velocidade ape-nas quando for rebatida por uma das barras assim, colocamos oincremento do atributo mod do objeto bola apenas dentro dos if’sde colisão da bola com as barras. Como feito a seguir.

1 /* Colisao com barra esquerda */2 if(bola.x <= jogadorEsquerda.x + bola.largura && bola.y

<= jogadorEsquerda.y + jogadorEsquerda.altura && bola.y+ bola.altura >= jogadorEsquerda.y){

3 bola.dirx = 1;4 /* Modificador */5 bola.mod += 0.1;6 }7

8 /* ... Codigos */9

10 /* Colisao com barra direita */11 if(bola.x >= jogadorDireita.x - bola.altura && bola.y <=

jogadorDireita.y + jogadorDireita.altura && bola.y >=bola.altura + jogadorDireita.y){

12 bola.dirx = -1;13 /* Modificador */14 bola.mod += 0.1;15 }

O valor de 0.1 é opcional. Experimente o valor que mais lheagradar. Quanto maior mais rapidamente a bola sofrerá uma vari-ação de velocidade.

Os outros fatores que influenciam na velocidade do seu jogo éo valor inicial do atributo mod, speed do objeto bola e o valor comque a função setTimeout está chamando a função RenderGame.

42

Page 43: Construção de Jogos PONG

6.2 Fim de Seção

1 <script type="text/javascript">2

3 /* ...Codigos */4

5 var jogadorEsquerda = new Retangulo(10,190,25,100,12);6 var jogadorDireita = new Retangulo(560,190,25,100,12);7 var bola = new Retangulo(300,240,20,20,2);8 var teclas = {};9

10 /* ...Codigos */11

12 function AtualizaGame(){13 /* Movimento da barra direita */14 if(38 in teclas && jogadorDireita.y > 0)15 jogadorDireita.y -= jogadorDireita.speed;16 if(40 in teclas && jogadorDireita.y + 100 < canvas.height

)17 jogadorDireita.y += jogadorDireita.speed;18 * Movimento da barra esquerda */19 if(87 in teclas && jogadorEsquerda.y > 0)20 jogadorEsquerda.y -= jogadorEsquerda.speed;21 if(83 in teclas && jogadorEsquerda.y + 100 < canvas.

height)22 jogadorEsquerda.y += jogadorEsquerda.speed;23

24 bola.x += (bola.speed)*bola.dirx;25 bola.y += (bola.speed + bola.mod)*bola.diry;26

27 if(bola.y >= (canvas.height - bola.altura))28 bola.diry = -1;29

30 /* Colisao da bola com a barra esquerda */31 if(bola.x <= jogadorEsquerda.x + bola.largura && bola.y

<= jogadorEsquerda.y + jogadorEsquerda.altura && bola.y + bola.altura >= jogadorEsquerda.y){

32 bola.dirx = 1;33 bola.mod += 0.1;34 }35 /* Colisao da bola com o teto */36 if(bola.y <= bola.altura)37 bola.diry = 1;38 /* Colisao da bola com a barra direita */39 if(bola.x >= jogadorDireita.x - bola.altura && bola.y <=

jogadorDireita.y + jogadorDireita.altura && bola.y >=bola.altura + jogadorDireita.y){

40 bola.dirx=-1;

43

Page 44: Construção de Jogos PONG

41 bola.mod += 0.1;42 }43 };44

45 /* Codigos... */46 </script>

44

Page 45: Construção de Jogos PONG

7 Placar

Talvez você ainda não tenha percebido, mas quando a bola nãoé rebatida por nenhuma barra isso faz com que ela desapareçapor alguns instantes e logo em seguida surja atrás das barras queusamos para rebater a bola. Vamos resolver este problema con-struindo um sistema de score.

Primeiro criamos uma nova função chamada pontuação.

1 function pontuacao(ponto){2 /* Pontos do jogo */3 if(ponto == 1)4 jogadorDireita.placar += 1;5 if(ponto == 2)6 jogadorEsquerda.placar += 1;7

8 /* Zerando o modificador} */9 bola.mod = 0;

10

11 /* Volta bola para posicao inicial */12 bola.y = canvas.height/2;13 bola.x = canvas.width/2;14 };

E no final da função AtualizaGame acrescente o seguinte:

1 /* Chama funcao de pontuacao */2 if(bola.x < jogadorEsquerda.x){3 pontuacao(1);4 }else if(bola.x > (jogadorDireita.x + jogadorDireita.

largura)){5 pontuacao(2);6 }

Essas duas linhas ficam responsáveis por chamar a funçãoplacar e passar a ela um parâmetro. Dependendo do valor pas-sado a função marca um ponto para o jogador direito ou esquerdo.

45

Page 46: Construção de Jogos PONG

7.1 Final de Seção

Finalizando esta apostila apresento o código completo do pro-jeto.

1 <!DOCTYPE html>2 <html lang = "pt-br">3 <head>4 <style type="text/css">5 canvas{6 position: absolute;7 top: 0px;8 bottom: 0px;9 left: 0px;

10 right: 0px;11 margin: auto;12 background-color: black;13 }14 </style>15 <title>Pong com HTML5 e JavaScript</title>16 </head>17 <body>18 <script type="text/javascript">19 function Retangulo(x,y,largura,altura,speed){20 this.x = x;21 this.y = y;22 this.largura = largura;23 this.altura = altura;24 this.speed = speed;25 this.placar = 0;26 this.dirx = -1;27 this.diry = 1;28 this.mod = 1;29 };30 Retangulo.prototype.draw = function(){31 ctx.fillStyle = ’white’;32 ctx.fillRect(this.x, this.y, this.largura, this.

altura);33 };34 Retangulo.prototype.drawBola = function(){35 ctx.beginPath();36 ctx.arc(this.x, this.y, 14, 0, Math.PI*2, true);37 ctx.closePath();38 ctx.fillStyle = ’white’;39 ctx.fill();40 };41 /* OBJETOS */42 var jogadorEsquerda = new Retangulo(10,190,25,100,12);

46

Page 47: Construção de Jogos PONG

43 var jogadorDireita = new Retangulo(560,190,25,100,12);44 var bola = new Retangulo(300,240,20,20,2);45 var teclas = {};46

47 /* OUVINTES DE TECLADOS */48 document.addEventListener(’keydown’, Keydown, false);49 function Keydown(evento){50 teclas[evento.keyCode] = true;51 };52 document.addEventListener(’keyup’, Keyup, false);53 function Keyup(evento){54 delete teclas[evento.keyCode];55 };56

57 /* PONTUACAO */58 function pontuacao(ponto){59 if(ponto == 1)60 jogadorDireita.placar += 1;61 if(ponto == 2)62 jogadorEsquerda.placar += 1;63

64 /* reniciando o modificador e posicao da bola */65 bola.mod = 1;66 bola.y = canvas.height/2;67 bola.x = canvas.width/2;68 };69

70 /* DESENHA PLACAR E LINHA DE CAMPO */71 function cena(){72 /* Desenhando o placar */73 ctx.font = "20px Arial";74 ctx.fillText("Jogador 1: " + jogadorEsquerda.placar,

50, 20);75 ctx.fillText("jogador 2: " + jogadorDireita.placar,

440, 20);76 /* Desenhando a linha vertical */77 ctx.beginPath();78 ctx.moveTo(canvas.width/2, 0);79 ctx.lineTo(canvas.width/2, canvas.height);80 ctx.lineWidth = 2;81 ctx.strokeStyle = ’white’;82 ctx.stroke();83 };84

85 /* CRIANDO O ELEMENTO CANVAS */86 function CarregaAtivos(){87 canvas = document.createElement("canvas");88 canvas.width = 600;89 canvas.height = 480;

47

Page 48: Construção de Jogos PONG

90 document.body.appendChild(canvas);91 ctx = canvas.getContext("2d");92 RenderGame();93 };94 function AtualizaGame(){95 /* Movimento da barra direita */96 if(38 in teclas && jogadorDireita.y > 0)97 jogadorDireita.y -= jogadorDireita.speed;98 if(40 in teclas && jogadorDireita.y + 100 < canvas.

height)99 jogadorDireita.y += jogadorDireita.speed;

100 /* Movimento da barra esquerda */101 if(87 in teclas && jogadorEsquerda.y > 0)102 jogadorEsquerda.y -= jogadorEsquerda.speed;103 if(83 in teclas && jogadorEsquerda.y + 100 < canvas.

height)104 jogadorEsquerda.y += jogadorEsquerda.speed;105 /* Movimento da bola */106 bola.x += (bola.speed + bola.mod)*bola.dirx;107 bola.y += (bola.speed + bola.mod)*bola.diry;108 /* Colisao da bola com o piso */109 if(bola.y >= (canvas.height - bola.altura)){110 bola.diry = -1;111 }112 /* Colisao da bola com a barra esquerda */113 if(bola.x <= jogadorEsquerda.x + bola.largura && bola.y

<= jogadorEsquerda.y + jogadorEsquerda.altura &&bola.y + bola.altura >= jogadorEsquerda.y){

114 bola.dirx = 1;115 bola.mod += 0.1;116 }117 /* Colisao da bola com o teto */118 if(bola.y <= bola.altura)119 bola.diry = 1;120 /* Colisao da bola com a barra direita */121 if(bola.x >= jogadorDireita.x - bola.altura && bola.y

<= jogadorDireita.y + jogadorDireita.altura && bola.y >= bola.altura + jogadorDireita.y){

122 bola.dirx=-1;123 bola.mod += 0.1;124 }125 /* Chama funcao de pontuacao */126 if(bola.x < jogadorEsquerda.x){127 pontuacao(1);128 }else if(bola.x > (jogadorDireita.x + jogadorDireita.

largura)){129 pontuacao(2);130 }131 };

48

Page 49: Construção de Jogos PONG

132 function RenderGame(){133 ctx.clearRect(0, 0, canvas.width, canvas.height);134 bola.drawBola();135 jogadorDireita.draw();136 jogadorEsquerda.draw();137 cena();138 AtualizaGame();139 setTimeout(RenderGame, 15);140 };141 CarregaAtivos();142 </script>143 </body>144 </html>

49

Page 50: Construção de Jogos PONG

8 MELHORANDO A PERFORMASSE [Opcional]

Para finalizar vamos diminuir os "travamentos" do jogo. Primeiromodificamos a função Render Game para o seguinte:

1 var anterior = new Date().getTime();2 requestAnimationFrame (RenderGame);3 function RenderGame(){4 var agora = new Date().getTime();5 var decorrido = agora - anterior;6 /* ...Codigos */7 AtualizaGame();8 anterior = agora;9 requestAnimationFrame(RenderGame);

10 };

A primeira linha captura a data em milissegundos atual. Nalinha 4 capturamos novamente a data e na linha 5 calculamos adiferença entre elas.

Na linha, 8 a variável anterior é atualizada para ser usada no-vamente quando a função RenderGame for novamente chamada.

Essa diferença que calculamos será usada para moderar a ve-locidade da bola. Assim primeiro declaramos a variável decor-rido no início do script.

1 var decorrido = 1000;

E depois ajustamos as linhas de movimento da bola disso:

1 bola.x += (bola.speed + bola.mod)*bola.dirx;2 bola.y += (bola.speed + bola.mod)*bola.diry;

para isso

1 bola.x += (bola.speed*(decorrido/1000) + bola.mod)*bola.dirx;

2 bola.y += (bola.speed*(decorrido/1000) + bola.mod)*bola.diry;

50

Page 51: Construção de Jogos PONG

Talvez seja necessário reajustar as velocidades das barras e dabola. Uma sugestão é usar as barras com velocidade igual a 5. Ebola com velocidade igual a 0.5.

1 var jogadorEsquerda = new Retangulo(10,190,25,100,5);2 var jogadorDireita = new Retangulo(560,190,25,100,5);3 var bola = new Retangulo((canvas.width/2), (canvas.height

/2), 20, 20, .5);

O resultado final deve ser satisfatório.

Como já dito o RequestAnimation Frame trabalha com ciclosbastantes curtos assim pode ser necessário reduzir a velocidadedos objetos. Contudo, justamente por trabalhar com ciclos muitopequenos de tempo isso acaba reduzindo as paralisias do jogo.

51

Page 52: Construção de Jogos PONG

9 LIVROS INDICADOS

Desenvolva jogos com HTML5 Canvas e JavaScript. Éder-son Cássio. 2013.

W3Schools. Html5 canvas.

Logica de Programação: Crie seus primeiros programasusando JavaScript e HTML. Paulo Silveira. Adriano Almeida.

[email protected] Oliveira

52