Exportar (0) Imprimir
Expandir Tudo
Web
Expandir Minimizar

HTML5 - Modernize seu jogo HTML5 Canvas: Dimensionamento de hardware e CSS3

David Rousset

Technical Evangelist

Navegadores modernos como o Internet Explorer 10 estão implementando versões estáveis de alguns recursos HTML5 interessantes, inclusive as APIs offline, de arrastar e soltar e de arquivo. Esses recursos estão nos trazendo uma nova era de aplicativos Web e cenários de jogos novos e rapidamente emergentes.

Neste artigo em duas partes, mostrarei como usei esses recursos novos para modernizar meu último jogo HTML5, um jogo de plataforma HTML5. Neste artigo, falarei sobre dimensionamento de hardware e CSS. Na Parte 2, cobrirei as APIs offline, de arrastar e soltar e de arquivo. Espero que você tenha algumas ótimas ideias novas para seus próprios jogos!

JJ938016.note(pt-br,MSDN.10).gifNote:
A URL da demo está no final deste artigo. Sinta-se à vontade para jogar usando seu navegador favorito e assista ao vídeo do jogo no Internet Explorer 10.

Dimensionamento entre dispositivos

Se você estiver criando um jogo HTML5, provavelmente está interessado na natureza multiplataforma dessa linguagem de programação padrão. Mas, compatibilidade com uma variedade ampla de dispositivos significa que você tem de levar em consideração um grande número de resoluções. Comparado com o SVG, o Canvas—em princípio—parece despreparado para lidar com isso.

Contudo, com um jogo casual baseado em sprites, há uma solução simples de implementar. David Catuhe fez um ótimo trabalho descrevendo isso em seu blog, Libere o poder do HTML 5 Canvas para jogos - Parte 1 (veja a seção chamada “Usando o recurso de dimensionamento de hardware” para detalhes específicos).

A ideia é igualmente simples e inteligente. Você vai trabalhar em uma tela com uma resolução fixa e previsível e vai alongá-la para a resolução atual exibida usando as propriedades canvas.style.

Etapa 1: Alongue

No caso de meu pequeno jogo de plataforma HTML5, os ativos e a lógica de nível foram definidos em 800x480. Assim, se eu quiser preencher uma tela de 1080p ou um tablet de 1366x768, preciso criar ativos de resolução mais alta para corresponderem àquelas especificações.

Antes de criar todos aqueles ativos, posso tentar uma operação de dimensionamento—junto com suavização apropriada—para aumentar a qualidade da imagem. Vamos tentar.

A operação de dimensionamento requer simplesmente este código:

  1. window.addEventListener("resize", OnResizeCalled, false);
  2. function OnResizeCalled() {
  3. canvas.style.width = window.innerWidth + 'px';
  4. canvas.style.height = window.innerHeight + 'px';
  5. }

Isso mesmo!

Com navegadores acelerados por hardware, sua GPU executará essa operação sem problemas. Até suavização pode ser habilitada. Por isso David Catuhe pensou que valia a pena mencionar em seu artigo de desempenho do Canvas.

A propósito, esse truque não é específico para o HTML5. A maioria dos jogos de console modernos não é computado internamente em 720p ou 1080p. Quase todos eles são renderizados em resoluções mais baixas (como 1024x600) e deixam que a GPU lide com o processo de dimensionamento/suavização. Na maioria dos casos, o método descrito aqui pode ajudá-lo a aumentar o número de quadros por segundo (FPS).

Mas, por si só, essa ação gera um problema de proporção. De fato, quando a tela tinha um tamanho fixo de 800x480, a proporção estava controlada. Agora eu obtenho o resultado estranho mostrado na Figura 1 quando redimensiono a janela do navegador. O jogo ainda é jogável, mas também está claramente longe do ideal.

JJ938016.B2E3D6CD6FE3BA436654EF97BFD336C7(pt-br,MSDN.10).png

Figura 1 - A aplicação de dimensionamento isolado pode produzir resultados estranhos

Etapa 2: Controle sua proporção

A ideia aqui é controlar como a tela é preenchida quando a janela do navegador é redimensionada. Em vez de alongar ainda mais qualquer coisa, vou adicionar espaço vazio à direita se a janela for muito larga, ou na parte inferior, caso ela seja muito alta. A Figura 2 mostra o código que eu usei.

  1. var gameWidth = window.innerWidth;
  2. var gameHeight = window.innerHeight;
  3. var scaleToFitX = gameWidth / 800;
  4. var scaleToFitY = gameHeight / 480;
  5. var currentScreenRatio = gameWidth / gameHeight;
  6. var optimalRatio = Math.min(scaleToFitX, scaleToFitY);
  7. if (currentScreenRatio >= 1.77 && currentScreenRatio <= 1.79) {
  8. canvas.style.width = gameWidth + "px";
  9. canvas.style.height = gameHeight + "px";
  10. }
  11. else {
  12. canvas.style.width = 800 * optimalRatio + "px";
  13. canvas.style.height = 480 * optimalRatio + "px";
  14. }

Figura 2 - Este código adiciona espaço vazio para ajudar a controlar proporções quando a janela é redimensionada

A instrução if cria uma exceção. Se você pressionar F11 em seu navegador para alternar para exibição em tela inteira e tiver uma tela 16:9 (como meu Sony VAIO Z 1920x1080 ou o tablet Samsung BUILD 1366x768), o jogo ficará completamente alongado. Essa experiência foi bastante surpreendente. Sem essa exceção, o tipo de resultado que você verá é mostrado na Figura 3. Note as áreas pretas abaixo e à direita do jogo, controlando a proporção.

JJ938016.4EDED08610D6D57EBF3F646F25A84C3B(pt-br,MSDN.10).png

Figura 3 - Espaços vazios melhoram a experiência

Etapa 3: Centralize o jogo com o CSS Grid Layout

Seria ainda melhor se o jogo estivesse centralizado, dando um efeito de filme em tela widescreen, certo? Vamos fazer isso, então.

Centralizar um elemento HTML às vezes pode ser complicado. Existem várias maneiras de se fazer isso—e há muitos recursos na Web para ajudar. Eu gosto de usar uma nova especificação chamada CSS Grid Layout (atualmente suportado apenas pelo Internet Explorer 10), que é a base de nosso layout estilo Metro no Windows 8.

Centralizar um elemento com o CSS Grid Layout é fácil:

  1. Alterne a tela do contêiner para display:grid.
  2. Defina 1 coluna e 1 linha.
  3. Centralize o elemento interno com as propriedades column-align e row-align.

A Figura 4 mostra a CSS que eu usei em meu caso.

  1. .canvasHolder {
  2. width: 100%;
  3. height: 100%;
  4. display: -ms-grid;
  5. -ms-grid-columns: 1fr;
  6. -ms-grid-rows: 1fr;
  7. }
  8. #platformerCanvas {
  9. -ms-grid-column: 1;
  10. -ms-grid-row: 1;
  11. -ms-grid-column-align: center;
  12. -ms-grid-row-align: center;
  13. }

Figura 4 - CSS usado para trabalhar com o CSS Grid Layout

Você notará que o prefixo é “-ms” para o Internet Explorer 10. A Mozilla anunciou recentemente que também suportará a especificação CSS Grid Layout para o Firefox em 2012, o que é uma ótima notícia. Enquanto isso, esse truque de centralização funciona apenas com o Internet Explorer 10. A Figura 5 mostra como fica.

JJ938016.5B063AEB086370C37BD6CB58CDC8ADDA(pt-br,MSDN.10).png

Figura 5 - Centralização com o CSS Grid Layout

Janelas do Internet Explorer 10 exibirão barras pretas verticais ou horizontais, similares às que se veem em uma tela de televisão. Em outros navegadores, os resultados corresponderão aos da etapa 2, porque a especificação CSS3 Grid Layout será ignorada.

Utilização de animações suaves

Agora que estamos lidando com múltiplas resoluções com uma operação de dimensionamento fácil, seria bom usar uma transição suave quando o usuário redimensiona a janela. Também seria ótimo mostrar uma animação legal enquanto cada nível se carrega. Para isso, vamos usar as ferramentas de Transições de CSS3 e de Transformações 3D de CSS3. Na maioria das plataformas, a aceleração de hardware é fornecida pela GPU.

Animação de cada mudança feita nas propriedades do estilo de tela

Transições de CSS3 são fáceis de usar e produzem animações suaves e eficientes. Para descobrir como usá-las, você pode ler o excelente artigo de meu colega, Introdução a transições de CSS3, ou brincar em nosso site de test-drive do Internet Explorer, Prática: transições.

Defini uma transição global para todas as minhas propriedades de tela, graças a estas regras:

  1. #platformerCanvas {
  2. -ms-grid-column: 1;
  3. -ms-grid-row: 1;
  4. -ms-grid-column-align: center;
  5. -ms-grid-row-align: center;
  6. -ms-transition-property: all;
  7. -ms-transition-duration: 1s;
  8. -ms-transition-timing-function: ease;
  9. }

A tela com a platformerCanvasID agora refletirá automaticamente qualquer alteração feita em suas propriedades de estilo em uma animação de um segundo gerada por uma função de easing.

Graças a essa nova regra, redimensionar a janela do navegador reduz ou aumenta o tamanho da tela como uma animação suave. Adoro o efeito que isso produz—tudo com apenas três linhas de CSS.

JJ938016.note(pt-br,MSDN.10).gifNote:
Também adicionei os diferentes prefixos (-moz, -webkit e -o para Mozilla, WebKit, e Opera, respectivamente) para compatibilidade. Você deve se lembrar de fazer o mesmo.

Criação de uma animação legal entre cada nível

Agora eu gostaria de usar transformações 3D de CSS3 para fazer a tela desaparecer temporariamente. Farei isso com uma rotação animada de 90 graus no eixo Y. Carregarei o nível seguinte depois que a animação girar 90 e voltar para a posição inicial (0 grau de rotação). Para entender melhor o efeito, você pode brincar com nossa Hands On: transformações 3D no site de test-drive do Internet Explorer. A Figura 6 mostra um exemplo.

JJ938016.9FD48942E3E20C807607524500FA907A(pt-br,MSDN.10).png

Figura 6 - Teste de efeitos de rotação

Também vamos brincar com a as propriedades scale e rotateY para criar uma animação divertida. Para isso, estou adicionando duas regras de CSS e visando duas classe, mostradas na Figura 7.

  1. .moveRotation
  2. {
  3. -ms-transform: perspective(500px) rotateY(-90deg) scale(0.1);
  4. -webkit-transform: perspective(500px) scale(0);
  5. -moz-transform: perspective(500px) rotateY(-90deg) scale(0.1);
  6. }
  7. .initialRotation
  8. {
  9. -ms-transform: perspective(500px) rotateY(0deg) scale(1);
  10. -webkit-transform: perspective(500px) scale(1);
  11. -moz-transform: perspective(500px) rotateY(0deg) scale(1);
  12. }

Figura 7 - Regras e classes visadas relacionadas com animação

Primeiro, minha tela tem a classe initialRotation definida:

  1. <canvas id="platformerCanvas" width="800" height="480"
  2. class="initialRotation"></canvas>

Agora, a ideia é esperar até que o jogador vença o nível atual Uma vez feito isso, mudamos a classe da tela de initialRotation para moveRotation. Isso dispara automaticamente as transições 3D de CSS que definimos antes de gerar a animação.

Para saber quando a animação terminou, um evento é acionado. Ele tem nomes diferentes em cada navegador. Aqui está o código que eu usei para registrar o evento e visar o Internet Explorer 10, Firefox, WebKit e Opera:

  1. // Registering to the various browsers vendors transition end event
  2. PlatformerGame.prototype.registerTransitionEndEvents = function () {
  3. // IE10, Firefox, Chrome & Safari, Opera
  4. this.platformerGameStage.canvas.addEventListener("MSTransitionEnd",
  5. onTransitionEnd(this));
  6. this.platformerGameStage.canvas.addEventListener("transitionend",
  7. onTransitionEnd(this));
  8. this.platformerGameStage.canvas.addEventListener("webkitTransitionEnd",
  9. onTransitionEnd(this));
  10. this.platformerGameStage.canvas.addEventListener("OTransitionEnd",
  11. onTransitionEnd(this));
  12. };

E aqui está o código que será retornado:

  1. // Function called when the transition has ended
  2. // We're then loading the next level
  3. function onTransitionEnd(instance) {
  4. return function () {
  5. if (instance.loadNextLevel === true) {
  6. instance.LoadNextLevel();
  7. }
  8. }
  9. };

E, por fim, a Figura 8 mostra o código de meu jogo que define a classe moveRotation na tela.

  1. // Perform the appropriate action to advance the game and
  2. // to get the player back to playing.
  3. PlatformerGame.prototype.HandleInput = function () {
  4. if (!this.wasContinuePressed && this.continuePressed) {
  5. if (!this.level.Hero.IsAlive) {
  6. this.level.StartNewLife();
  7. }
  8. else if (this.level.TimeRemaining == 0) {
  9. if (this.level.ReachedExit) {
  10. // If CSS3 Transitions is supported
  11. // We're using smooth & nice effects between each levels
  12. if (Modernizr.csstransitions) {
  13. this.loadNextLevel = true;
  14. // Setting the moveRotation class will trigger the css
  15. // transition
  16. this.platformerGameStage.canvas.className =
  17. "moveRotation";
  18. }
  19. // If CSS3 Transition is not supported, we're jumping
  20. // directly to the next level
  21. else {
  22. this.LoadNextLevel();
  23. }
  24. }
  25. else
  26. this.ReloadCurrentLevel();
  27. }
  28. this.platformerGameStage.removeChild(statusBitmap);
  29. overlayDisplayed = false;
  30. }
  31. this.wasContinuePressed = this.continuePressed;
  32. };

Figura 8 - Definição da classe moveRotation

Note que estou usando o Modernizr para fazzer uma detecção de recurso de transições de CSS. Finalmente redefinimos a classe initialRotation dentro da função LoadNextLevel:

  1. // Loading the next level
  2. PlatformerGame.prototype.LoadNextLevel = function () {
  3. this.loadNextLevel = false;
  4. // Setting back the initialRotation class will trigger the transition
  5. this.platformerGameStage.canvas.className = "initialRotation";
  6. // ... loadNextLevel logic stuff...
  7. };
JJ938016.note(pt-br,MSDN.10).gifNote:
Você deve ter notado que não estou definindo para o WebKit a mesma transformação (e animação) que defini para o Internet Explorer 10 e o Firefox em meu bloco de CSS anterior. Faço isso porque, no meu caso, o Chrome não se comportará da mesma forma que o Internet Explorer 10 e o Firefox 11. Criei um caso de reprodução simples em jsFiddle aqui: http://jsfiddle.net/5H8wg/2/.

Vídeo e URL da demo

Aqui está um vídeo curto demonstrando os recursos do Internet Explorer 10 cobertos neste artigo:

Baixar o vídeo: MP4, WebM, HTML5 Video Player de VideoJS

JJ938016.A2009F3358A9F5779653D30F1FAF002A(pt-br,MSDN.10).png

Você também pode brincar com esse demo no Internet Explorer 10 ou seu navegador favorito em Jogo de plataforma HTML5 moderno.

JJ938016.91106CE3430C81D5A826436E28DFBCC6(pt-br,MSDN.10).png

No artigo “APIs offline, de arrastar e soltar e de arquivo”, mostrarei como implem, entar a API offline para fazer meu jogo funcionar sem conexões de rede e como a API de arrastar e soltar pode criar outro recurso legal.

Mostrar:
© 2015 Microsoft