Tutorial HTML 5 – Parte 1/3

Prometido no ano passado, finalmente o tutorial de HTML 5 chegou! Neste tutorial em 3 partes veremos o básico sobre como usar o objeto <canvas> em conjunto com técnicas que permitem a criação de jogos de forma semelhante ao que já fazemos em outras linguagens.

Nesta parte 1 aprenderemos como inicializar o canvas e carregar e exibir imagens.

A primeira coisa que precisamos saber para criar jogos em HTML 5 é… bem, HTML! É necessário o conhecimento básico de tags e de como criar pelo menos uma página vazia para conter o jogo.

A segunda coisa é um pouco de CSS, que serve para configurar os elementos inseridos na página (bordas, cores, tamanhos, etc). Jogos mais avançados em HTML utilizam muitos elementos fora do <canvas>, que vamos ver nesse tutorial, tirando proveito de outros elementos HTML para apresentar dados e de CSS para formatar este dados.

Finalmente, precisamos saber também Javascript (JS) para fazer a programação da lógica do jogo. A sintaxe é parecida com Java ou C++ e oferece suporte a objetos, embora não seja de fato uma linguagem orientada a objetos. Não oferece, por exemplo, recurso para herança, embora seja possível simular isto com construções mais avançadas.

Vou assumir que você entende pelo menos o mínimo de HTML e CSS e que sabe incluir scripts em uma página. Mas a necessidade disto é tão pequena para este tutorial que é até possível você aprender o necessário só estudando os exemplos.

Dito isso, vamos em frente.

O elemento <canvas>

Uma das novidades que a versão 5 da HTML trouxe foi a tag <canvas>, que cria na página um elemento que permite o desenho direto. Antes disso, para exibir imagens era preciso inserir um elemento <img> para cada uma. Ess elemento cria um objeto gráfico no navegador para armazenar e apresentar a imagem – este tipo de objeto consome recursos do sistema. Se todas imagens fossem sprites animados, teríamos um página bem pesada para o navegador renderizar. Com o canvas, no entanto, podemos desenhar nele todas imagens necessárias e o navegador só vai renderizar o canvas – como se fosse uma única imagem.

Além disso, com o canvas podemos desenhar primitivas gráficas, como linhas, retângulos e texto, além de ter efeitos de composição na aplicação das imagens. A grosso modo, o canvas é como uma imagem cujo conteúdo pode ser modificado. Utilizamos ele como se fosse a tela, desenhando nele cada quadro do jogo.

A inclusão de um elemento canvas na página é feita com a tag <canvas>>. No exemplo de código abaixo temos uma página HTML que contém esta tag e também um elemento <div> acima do canvas, dentro do qual vai uma informação textual.

<html>
    <head>
        <script src="aoj/aojcanvas.js"></script>
    </head>
    <body>
        <div id="info">Abrindo o Jogo - exemplo de uso do elemento canvas</div>
        <canvas id="canvas1" width="960" height="600"></canvas>
    </body>
</html>

Note que esta página inclui dois arquivos externos:

css/estilos.css: Contém o código CSS de formatação dos elementos. Esse código se refere aos elementos pelo seu ID, sendo que o div possui o ID “info” e o canvas possui o ID “Canvas1″.

O conteúdo deste arquivo é o seguinte:

body {
    margin: 0px;
    border: none;
    background-color: black;
}
#canvas1 {
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -480px;
    margin-top: -300px;
    background-color: white;
}
#info {
    background-color: blue;
    color: yellow;
    font-family: Arial;
    font-size: 14px;
    font-weight: bold;
    padding: 5px;
    text-align: center;
}

Basicamente o código deste arquivo muda o fundo da página para preto, centraliza o canvas na tela e aplica estilo de fundo, cor e fonte ao div que apresenta o texto. É comum colocarmos os arquivos de estilo dentro de uma pasta “css”.

aoj/aojcanvas.js: este arquivo de script possui o código para inicialização e uso do canvas, contendo algumas rotinas criadas para facilitar a programação. Veremos como usar o canvas a seguir.

Usando o elemento canvas

Para obter uma referência ao elemento canvas, usamos o comando document.getElementById(), passando o ID que especificamos para nosso canvas. Obtemos a referência e atribuímos para uma variável, assim:

    var _aojCanvas = document.getElementById(canvasId);

Para desenhar algo nele, precisamos obter um contexto gráfico, o que é feito com o método getContext do canvas. Esse método requer um parâmetro que, atualmente, só pode ser “2d”.

Depois de obter o contexto, atribuindo ele a uma variável, usamos os métodos dele para desenhar. Veja abaixo:

window.onload = function() {
    var _aojCanvas = document.getElementById('canvas1');
    var ctx = _aojCanvas.getContext('2d');
    ctx.beginPath(); // inicia um desenho.
    ctx.fillStyle = 'blue'; // especifica a cor de preenchimento.
    ctx.strokeStyle = 'red'; // especifica a cor de contorno.
    ctx.rect(10, 10, 200, 100); // especifica um retângulo.
    ctx.rect(220, 10, 50, 50); // especifica outro retângulo.
    ctx.stroke(); // contorna o desenho (dois retângulos).
    ctx.fill(); // preenche o desenho (dois retângulos).
    ctx.beginPath(); // inicia outro desenho.
    ctx.strokeStyle = 'black'; // muda a cor de contorno.
    ctx.rect(50, 50, 100, 100); // especifica um retângulo.
    ctx.stroke(); // contorna o desenho (um retângulo).
}

O código acima desenha dois retângulos preenchidos de azul dentro do canvas. Cada desenho é iniciado com beginPath. Se este método não fosse chamado na segunda vez, o terceiro retângulo especificado ainda seria parte do primeiro desenho e o comando stroke iria contornar os três retângulos.

Perceba que o código foi colocado dentro de uma função atribuída ao evento onload da janela, para que seja executado apenas depois dela carregar completamente. Isso é importante porque se não for feito, o código executaria assim que fosse baixado – o que poderia ocorrer antes mesmo da declaração do canvas ter sido carregada – o que resultaria em erro porque o objeto canvas não existira ainda na página.

Métodos de atalho

A utilização do canvas para desenhar é algo de baixo nível. São precisos vários comandos para desenhar um retângulo na tela, por exemplo.

Para facilitar a programação, é interessante criar funções auxiliares que incluem todas chamadas necessárias para realizar determinadas ações. Assim criamos uma biblioteca própria. O arquivo aojcanvas.js é um exemplo de biblioteca deste tipo, embora incompleta.

Vejamos algumas funções deste arquivo para entender essa prática:

function aojSetCanvas(canvasId) {
    _aojCanvas = document.getElementById(canvasId);
}
 
function aojFillStyle(optionalNewValue) {
    var ctx = _aojCanvas.getContext('2d');
    if (optionalNewValue)
        ctx.fillStyle = optionalNewValue;
    return ctx.fillStyle;
}
 
function aojFillRect(x, y, w, h, optionalFillStyle) {
    var ctx = _aojCanvas.getContext('2d');
    ctx.beginPath();
    if (optionalFillStyle) {
        ctx.fillStyle = optionalFillStyle;
    }
    ctx.rect(x, y, w, h);
    ctx.fill();
}

A função aojSetCanvas() é usada para informar à nossa biblioteca qual elemento canvas desejamos usar – podemos ter mais de um canvas na nossa página. Passamos o ID como parâmetro e o elemento é obtido é armazenado em uma variável global, acessível para todas as demais funções.

aojFillStyle() permite obter o estilo de preenchimento atual, e também modificá-lo. Se for passado um parâmetro, ele é usado para modificar o estilo, que em seguida é retornado. Se não for passado o parâmetro, o estilo atual não é modificado, apenas retornado.

E a função aojFillRect() serve para desenhar um retângulo preenchido. Ela pode usar o estilo previamente definido, mas também aceita um quarto parâmetro opcional que, se informado, é usado como estilo para o retângulo.

Este tipo de comando permite mudar nosso exemplo para o seguinte:

window.onload = function() {
    aojSetCanvas('canvas1');
    aojFillRect(10, 10, 200, 100, 'blue'); // preenche um retângulo azul.
    aojFillRect(220, 10, 50, 50, 'blue'); // preenche outro retângulo azul.
    aojStrokeRect(10, 10, 200, 100, 'red'); // contorna um retângulo vermelho.
    aojStrokeRect(220, 10, 50, 50, 'red'); // contorna outro retângulo vermelho.
    aojStrokeRect(50, 50, 100, 100, 'black'); // contorna um retângulo preto.
}

Este exemplo ficaria ainda mais claro e resumido se criássemos uma função para desenhar um retângulo preenchido e já contornado. Até que ponto devemos ir na criação de nossa própria biblioteca de funções vai depender da natureza de cada projeto – aqueles procedimento que são repetidos muitas vezes são os que devem ser transformados em funções. Não recomendo tentar criar uma porção de funções de antemão porque você acabará com muitas que nunca vai utilizar, e mesmo assim não eliminará o risco de precisar de uma que não lembrou.

Desenhando imagens no canvas

É importante saber como desenhar primitivas gráficas no canvas, mas o principal recurso ainda é a apresentação de imagens, afinal, quase todo jogo é feito de sprites.

Para carregar uma imagem, basta criar um objeto do tipo Imagem e atribuir a URL do arquivo para o atributo “src”. Opcionalmente podemos atribuir uma função para o atributo onload – esta função será chamada quando o arquivo de imagem for carregado. Este é um recurso importante de usar em jogos com muitas imagens, para garantir que todas tenham sido carregadas antes de iniciar o jogo.

Novamente, para facilitar o trabalho, criamos uma função na nossa biblioteca:

function aojNewImage(imgURL, optionalLoadCallback) {
    var img = new Image();
    img.src = imgURL;
    img.onload = optionalLoadCallback;
    return img;
}

Esta função recebe a URL do arquivo da imagem e opcionalmente uma função de callback, que será chamada quando a imagem for carregada.

Para desenhar uma imagem no canvas, temos outra função:

function aojDrawImage(img, x, y) {
    var ctx = _aojCanvas.getContext('2d');
    ctx.drawImage(img, x - img.width / 2, y - img.height / 2);
    if (_aojShowImageCenter) {
        ctx.arc(x, y, 2, 0, 2*Math.PI, false);
        ctx.fill();
    }
}

Nesta função, apenas as duas primeiras linhas são responsáveis por desenhar a imagem no canvas. O IF é usado para desenhar um círculo no ponto (x,y) onde a imagem é desenhada, de forma a enxergarmos onde fica esse ponto. É útil para debugar posicionamento.

Transformações geométricas

O canvas oferece métodos para aplicar transformações geométricas no que é desenhado nele. Por exemplo, podemos rotacionar ou aumentar e diminuir uma imagem no momento de desenhá-la.

É importante saber, no entanto, que uma vez especificada uma transformação, ela fica em efeito para tudo que for desenhado depois. Portanto, depois de aplicar uma rotação, por exemplo, e desenhar a imagem desejada, é preciso aplicar a rotação inversa para deixar o canvas no estado normal antes de desenhar as próximas imagens.

Abaixo está uma função para desenhar uma imagem com transformação de escala. Como parâmetros ela recebe o objeto imagem, a posição (x, y) onde ele deve ser desenhado e os fatores de escala sx e sy.

Veja que para o efeito ser aplicado corretamente é preciso usar uma outra transformação em conjunto – a translação. Fazemos a translação para que a posição da imagem seja transferida para a origem (ponto (0,0)) e então a escala é aplicada. Depois de desenhada a imagem, desfazemos a escala e a translação aplicando estas transformações com o valor inverso.

function aojDrawImageScale(img, x, y, sx, sy) {
    var ctx = _aojCanvas.getContext('2d');
    ctx.translate(x, y);
    ctx.scale(sx, sy);
    ctx.drawImage(img, -img.width / 2, -img.height / 2);
    ctx.scale(1/sx, 1/sy);
    ctx.translate(-x, -y);
    if (_aojShowImageCenter) {
        ctx.arc(x, y, 2, 0, 2*Math.PI, false);
        ctx.fill();
    }
}

No arquivo aojcanva.js existem outras funções deste tipo. Este arquivo e os demais estão no Zip no final da página.

Conclusão

Neste artigo vimos o basico da utilização do canvas para mostrar imagens.

No site abaixo há um guia de referência do canvas para ser impresso, com todos os comandos. O Autor (Jacob Seidelin) também escreveu um livro sobre jogos em HTML 5.
http://blog.nihilogic.dk/2009/02/html5-canvas-cheat-sheet.html

No próximo artigo veremos como implementar um game loop e utilizar o teclado e mouse.

Autor: Luiz Nörnberg Ver todos os posts de
Sou Bacharel em Ciência da Computação pela Universidade Católica de Pelotas (UCPel), onde também atuei como professor. Desde a época da faculdade (mais de quinze anos atrás) a paixão por jogos tem sido importante no meu direcionamento profissional. Sou sócio-fundador do Izyplay Game Studio, onde exerço o cargo de Diretor de Tecnologia. Sempre tive grande foco em desenvolvimento em Java, embora tenha migrando para a tecnologia Adobe AIR em função de sua portabilidade. Ah, e é claro, dou meus palpites no game design.

23 Comentários em "Tutorial HTML 5 – Parte 1/3"

  1. Rinaldo 18/02/2012 at 16:36 - Reply

    Muito bem explicado. Ajuda a desmitificar o canvas.
    talvez seria interessante ja mostrar um canvas logo depois dos codigos. tornaria o tutorial mais visual. pena que o pessoal ainda usa muitos navegadores sem suporte a HTML 5.

    ótimo tutorial.

  2. Tiago A. 21/03/2012 at 13:09 - Reply

    Muito bom o tutorial! Mas só tem um errinho ali no primeiro exemplo que fala da tag canvas que não se encontra no código mostrado.

    • Luiz Nörnberg 21/03/2012 at 20:20 - Reply

      Olá Tiago. Obrigado pela dica! Infelizmente faltava mais coisa. Agora já está o código completo da página.

  3. Felipe Bormann 17/05/2012 at 22:49 - Reply

    sinceramente é algo ótimo, sou jovem, 16 ^^’ e pra mim é animador novas tecnologias ; )

  4. Daniel 06/02/2013 at 18:19 - Reply

    Bom Tutorial. Queria pedir para você fazer um tutorial em vídeo criando o jogo HTML5.
    Tenho 15 anos e não sei nada sobre apenas fiz um curso básico de computação (que não vem ao caso), aos poucos estou conseguindo entender o HTML5 (sendo na cidade onde eu moro não tem cursos de programação que utilize HTML5).
    Obrigado pelo Tutorial.

  5. fabio 27/02/2013 at 16:37 - Reply

    Muito legal seu tutorial, já procurei de todas as formas talvez eu não esteja sabend procurar, mas será que vc pode me dar uma dica de que livro comprar ou onde procurar um tutorial que me permita fazer isto em canvas: http://www.dhteumeuleu.com/lab/m3D.html

    Pois os tutorias que eu achei encinam a desenhar em 2D mas não insinam a criar um ambiente e dar movimento a ele.

  6. Cristhian 22/03/2013 at 22:03 - Reply

    Muito bom o post, não conhecia toda essa praticidade e poder do html5.

  7. Laís 22/04/2013 at 15:13 - Reply

    Olá, parabéns pelo blog. Tem como deixar a canvas por trás do plano de fundo?

    • Luiz Nörnberg 23/04/2013 at 17:58 - Reply

      Olá Lais. O elemento CANVAS pode ser ordenado com relação a qualquer outro elemento (DIVs, por exemplo), só não podendo ficar por trás do elemento BODY, já que esse é o elemento mais externo.
      Então, será preciso tirar o plano de fundo (background) do BODY e colocar ele em um DIV. Ajuste o CSS desse DIV para absolute e especifique 100% em suas dimensões. Assim ele fica do tamanho do BODY e o background cobre toda página.
      Tudo que estava dentro do BODY deverá ficar dentro desse DIV, que passa a ser o container externo da página. Tudo que for colocado dentro dele ficará por cima do background.
      E o CANVAS, esse sim, fica por fora desse DIV, podendo ser posicionado por trás dele (via propriedade z-index do CSS).
      Claro que esta dica depende muito da complexidade da sua página, e pode demorar um pouco até acertar os valores no CSS. Mas de forma geral a dica é tirar o background do BODY e colocá-lo em um DIV, de forma que ele possa ser ordenado em relação aos demais elementos da página.

  8. valdiney 21/05/2013 at 16:15 - Reply

    Maravilhoso material, porém falastes que javascript não é de fato orientado a objeto! Quando na verdade se trata de uma linguagem totalmente orientada a objetos! Ela não simula! Ela é orientada.

    Apenas não tem suporte padrão para class, porém pode ser simulada facilmente através de funções construtoras. E sim, disponibiliza recursos para enrança através do Prototype. Mas o post está muito bom, parabéns…

  9. Priscila Roeder 07/06/2013 at 10:45 - Reply

    Muito bom!!

  10. Michel 01/08/2013 at 12:56 - Reply

    Ola Prof. Bom tutorial. Será que vai dar pra fazer igual como o canvas do java? Isto utilizando java Script …

  11. Guilherme 10/09/2013 at 11:28 - Reply

    É possível conectar um código c++ (uma classe com simples soma) ao HTML5?

    O usuário entra com os valores na web e o cálculo é executado no servidor?

    Abraços

    • Luiz Nörnberg 11/09/2013 at 17:19 - Reply

      Sim, é possível usando o que chamamos de CGI. Procurando por esse termo + html você encontra como fazer. No entanto, o C++ não é a linguagem mais adequada para a criação de backend – ou seja, da parte de “trás” de uma página web, a parte que roda no servidor. O ideal seria uma linguagem como PHP. Você encontra facilmente tutoriais sobre essa linguagem na web.

      Você vai ver que a maioria dos exemplos iniciará mostrando como enviar dados para os servidor via formulário na página web. Isso faz com que toda página seja recarregada. Em um jogo isso nem sempre é possível – geralmente precisamos enviar dados para o servidor mantendo o jogo carregado. Para fazer isso, deve-se usar AJAX (outra palavra chave para pesquisares) e eu recomendo a utilização de uma biblioteca pronta para isso. Minha sugestão é a biblioteca JQuery. Procure pelos métodos ajax, get e getJson dessa biblioteca.

      HTML usando JQuery + PHP no servidor é um combinação simples de trabalhar e ao mesmo tempo bem poderosa no que é possível fazer.

  12. Thales Renan 28/09/2013 at 17:32 - Reply

    Olá, parabéns, ótimo tutorial, eu gostaria de saber se é possível eu colocar uma imagem em cima da outra, informando isso através de código, por que estou tentando fazer um pequeno jogo, primeiro estou desenhando uma imagem que será o fundo do jogo, e depois tento desenhar outra por cima mais a imagem do background fica por cima dessa que eu desenhei depois, não tem como informar se uma imagem poderá sobre posicionar as outras através de linhas de código?

    • Jonas Eduardo 15/10/2013 at 22:51 - Reply

      Assim Thales Renan.. tu pode usar a propriedade z-index do css que define qual elemento terá mais(ou menos) prioridade de visualização.

      Como conseguimos manipular as propriedades do css via javascript, podemos dar uma mexidinha básica na nossa função aojNewImage, acrescentando um parâmetro “priority” na qual você irá passar um número que corresponde a prioridade da imagem (quanto maior for o número, maior a importância), ficando assim…

      function aojNewImage(imgURL,priority,optionalLoadCallback){
      var img = new Image();
      img.src = imgURL;
      img.onload = optionalLoadCallback;
      img.style.zIndex = priority;
      return img;
      }

      Na hora de chamar a função, ficaria algo mais ou menos assim..

      var image1 = aojNewImage(“assets/images/car.png”,2,function(){
      aojDrawImage(this,100,100);
      });

      var image2 = aojNewImage(“assets/images/car.png”,1,function(){
      aojDrawImage(this,120,120);
      });

      Por mais que a image2 tenha uma importância padrão maior que a image1 (porque a image2 foi criada por último) ela vai ficar atrás da image1, por causa da prioridade que foi setada no parâmetro. Creio que seja isso (:

  13. Jonas Eduardo 15/10/2013 at 22:06 - Reply

    Muito interessante seu tutorial, creio que seja um dos poucos tutoriais de qualidade sobre esse assunto que conseguiremos encontrar em português.
    Só tenho uma observação a fazer.. numa parte do código tu da um ctx.beginPath(), não seria interessante, ao terminar o desenho, dar um ctx.closePath()?

    • Luiz Nörnberg 16/10/2013 at 09:14 - Reply

      Olá Jonas. Obrigado pelo elogio! O comando closePath serve para fechar a figura graficamente, ou seja, gerar uma linha do ponto atual para o ponto inicial do path. Ele não deve ser chamado se quisermos que a figura fique aberta (sem a conexão entre o pontos inicial e final) e pode ser substituído por uma chamada a lineTo para o ponto final. Note que ele não é o contrário do beginPath. O beginPath reinicia o marcador de desenho, agindo sobre a memória e não sobre o desenho em sí. Já o closePath é um comando gráfico apenas (desenha uma linha), não fechando o path na memória como se poderia supor. Podemos seguir usando comandos como lineTo depois de ter usado o closePath. O path fica aberto até que o beginPath seja chamado novamente. Para um exemplo, veja esse tópico: http://goo.gl/QuLFKS

  14. Daniel 03/11/2013 at 13:01 - Reply

    Muito difícil isso.

  15. Junior Cesar 09/04/2014 at 08:28 - Reply

    Olá Luiz,
    Parabéns pelo tutorial é muito bom, com o Jonas comentou não encontramos bons tutoriais disponíveis em português.
    Eu que era um fãs de flash agora me tornei de HTML5.

  16. Antonio Rodrigues Firmino da Costa 28/04/2014 at 15:32 - Reply

    Ola, primeiramente quero parabeniza-lo pelo blog e desejar-lhe sucesso. Gostaria de saber se com o html5 e css3 é possivel fazer jogos de tabuleiro e de cartas como por exemplo xadrez, damas, dominó, bingo, truco, tranca, cacheta, poker. E se é possivel será que vc pode me ensinar a faze-los.
    meu skype: rfirmino2014

    obrigado pela atenção!

  17. Antonio Camargo 07/03/2016 at 14:40 - Reply

    Primeiramente gostaria de parabeniza-lo pelo tutorial, não encontramo como o Junior Cesar disse bons tutoriais como este em português, será de grande ajuda em minha vida profissional!

Deixar um Comentário