Você está na página 1de 11

HTML5 - - Modernize seu jogo HTML5 Canvas:

https://msdn.microsoft.com/pt-br/library/jj9380

HTML5 - - Modernize seu jogo HTML5 Canvas: APIs offline, de arrastar e soltar e de arquivo

David Rousset Technical Evangelist

Recursos HTML5 em navegadores modernos como o Internet Explorer 10 possibilitam uma classe totalmente nova de aplicativos Web e de cenários de jogos. Este artigo em duas partes demonstra como usei alguns desses recursos novos para modernizar meu último, jogo de plataforma HTML5. Na Parte 1 deste artigo, falei sobre como usar transformações 3D, transições e layout de grade CSS3. Neste artigo, mostrarei como usar as APIs offline, de arrastar e soltar e de arquivo para implementar algumas ideias interessantes.

Jogo no modo offline

A versão original de meu jogo funcionava somente se o seu dispositivo estivesse conectado à Internet. Se você quisesse jogar meu jogo fabuloso no trem, em um táxi ou qualquer outro lugar sem uma conexão de Internet, estava sem sorte—preso sem acesso àquela maravilha. E isso era uma pena, porque realmente não há nada em meu jogo que precise de uma conexão ativa com o servidor Web uma vez que todos os recursos tenham sido baixados. Felizmente, APIs offline fornecem uma solução para isso em HTML5.

Etapa 1: Escolha os recursos que quiser armazenar no cache

Na verdade é bem fácil dizer ao navegador que recursos você quer armazenar no cache para uso offline. Mas, antes de ir adiante, recomendo que você leia estes dois artigos:

Criação de experiências offline com o AppCache e IndexedDB HTML5 de nosso blog do IE de nosso blog do IE

Application Cache API ("AppCache"), da documentação do MSDN , da documentação do MSDN

Para o meu jogo, criei o arquivo dragDropLogic.js contendo o código mostrado na Figura 1.

Java

contendo o código mostrado na Figura 1. Java CACHE MANIFEST # Version 1.5 CACHE: index.html
contendo o código mostrado na Figura 1. Java CACHE MANIFEST # Version 1.5 CACHE: index.html

CACHE MANIFEST # Version 1.5 CACHE:

index.html modernplatformer.css img/MonsterA.png up to img/MonsterD.png img/Player.png img/offlinelogoblack.png

HTML5 - - Modernize seu jogo HTML5 Canvas:

https://msdn.microsoft.com/pt-br/library/jj9380

img/Backgrounds/Layer0_0.png

up to

img/Backgrounds/Layer2_2.png

img/Tiles/BlockA0.png

up to

img/Tiles/BlockA6.png

img/Tiles/BlockB0.png

img/Tiles/BlockB1.png

img/Tiles/Gem.png img/Tiles/Exit.png img/Tiles/Platform.png overlays/you_died.png overlays/you_lose.png overlays/you_win.png src/dragDropLogic.js src/main.js

src/ModernizrCSS3.js

src/easeljs/utils/UID.js

src/easeljs/geom/Matrix2D.js

src/easeljs/events/MouseEvent.js

src/easeljs/utils/SpriteSheetUtils.js

src/easeljs/display/SpriteSheet.js

src/easeljs/display/Shadow.js

src/easeljs/display/DisplayObject.js

src/easeljs/display/Container.js

src/easeljs/display/Stage.js

src/easeljs/display/Bitmap.js

src/easeljs/display/BitmapAnimation.js

src/easeljs/display/Text.js

src/easeljs/utils/Ticker.js

src/easeljs/geom/Rectangle.js

src/easeljs/geom/Point.js

src/easeljs/XNARectangle.js

src/easeljs/PlatformerHelper.js

src/easeljs/ContentManager.js

src/easeljs/Tile.js

src/easeljs/Gem.js

src/easeljs/Enemy.js

src/easeljs/Player.js

src/easeljs/Level.js

src/easeljs/PlatformerGame.js

NETWORK:

*

Figura 1 - Platformer.cache

Inseri todos os arquivos PNG contendo meus sprites, fundo, camadas e sobreposições; os arquivos JS necessários da estrutura EaseJS; e minha própria lógica de jogo e os principais arquivos HTML e de CSS. Depois simplesmente indico que quero usar esse arquivo de manifesto em minha página HTML principal. Neste caso, é index.html:

HTML
HTML

HTML5 - - Modernize seu jogo HTML5 Canvas:

https://msdn.microsoft.com/pt-br/library/jj9380

<!DOCTYPE html> <html manifest="platformer.cache"> <head> <title>HTML5 Platformer Game</title> // </head> <html>

Note que o arquivo de seu manifesto deve ser servido como “text/cache-manifest”. Para o meu jogo, adicionei um novo tipo de conteúdo .cache mapeado para text/cache-manifest, pois é armazenado no armazenamento de blob do Windows Azure.

Tenha em mente que essa especificação não permite alterações delta. Mesmo que um de seus arquivos mude, você precisa forçar um redownload completo para o navegador se atualizar para a nova versão. Contudo, qualquer alteração no arquivo de seu manifesto será excluída pelo navegador, que então baixa todos os recursos especificados no arquivo. A alteração pode ser um número de versão, uma data, um GUID—o que quer que funcione para você—no início do arquivo através de um comentário (“Versão 1.5” na Figura 1).

Etapa 2: Modificação da lógica para o carregamento dos níveis

A versão original de meu código baixava cada nível através de uma chamada de XHR para o servidor Web.

Preciso mudar isso para fazer meu jogo funcionar no modo offline. Além disso, gostaria de indicar ao usuário que ele está jogando offline no modo offline incluindo o logotipo HTML5 associado "oficial" dentro da tela do jogo.

Vejamos as mudanças para fazer isso acontecer. Na primeira vez que o usuário lançar meu jogo, todos os níveis serão baixados (descritos nos arquivos {x}.txt) para o armazenamento local. Essa operação é amplamente suportada (desde o Internet Explorer 8) e bastante fácil de usar—e, mais importante, está disponível no modo offline.

A Figura 2 mostra o código que eu adicionei em PlatformerGame.js.

Java

mostra o código que eu adicionei em PlatformerGame.js. Java PlatformerGame.prototype.DownloadAllLevels = function () {
mostra o código que eu adicionei em PlatformerGame.js. Java PlatformerGame.prototype.DownloadAllLevels = function () {

PlatformerGame.prototype.DownloadAllLevels = function () { // Searching where we are currently hosted var levelsUrl = window.location.href.replace('index.html', '') + "levels/"; var that = this; for (var i = 0; i < numberOfLevels; i++) { try {

var request = new XMLHttpRequest(); request.open('GET', levelsUrl + i + ".txt", true); request.onreadystatechange = makeStoreCallback(i, request, that); request.send(null);

}

catch (e) { // Loading the hard coded error level to have at least something // to play with console.log("Error in XHR. Are you offline?");

if (!window.localStorage["platformer_level_0"]) {

HTML5 - - Modernize seu jogo HTML5 Canvas:

https://msdn.microsoft.com/pt-br/library/jj9380

window.localStorage["platformer_level_0"] = hardcodedErrorTextLevel;

}

}

}

};

// Closure of the index function makeStoreCallback(index, request, that) { return function () { storeLevel(index, request, that);

}

}

function storeLevel(index, request, that) {

if (request.readyState == 4) { // If everything was OK if (request.status == 200) { // storing the level in the local storage

// with the key "platformer_level_{index} window.localStorage["platformer_level_" + index] = request.responseText.replace(/[\n\r\t]/g, ''); numberOfLevelDownloaded++;

}

else { // Loading a hard coded level in case of error

window.localStorage["platformer_level_" + index] = hardcodedErrorTextLevel;

}

if (numberOfLevelDownloaded === numberOfLevels) { that.LoadNextLevel();

}

}

}

Figura 2 - PlatformerGame.js

Todos os níveis no construtor PlatformerGame serão baixados de forma assíncrona. Uma vez que todos os níveis tenham sido baixados (numberOfLevelDownloaded = = = numberOfLevels), o primeiro nível é carregado. Aqui está o código para a nova função:

1.

// Loading the next level contained into the localStorage in

2.

// platformer_level_{index}

3.

PlatformerGame.prototype.LoadNextLevel = function () {

4.

this.loadNextLevel = false;

5.

// Setting back the initialRotation class will trigger the transition

6.

this.platformerGameStage.canvas.className = "initialRotation";

7.

this.levelIndex = (this.levelIndex + 1) % numberOfLevels;

8.

var newTextLevel = window.localStorage["platformer_level_" +

9.

this.levelIndex];

10.

this.LoadThisTextLevel(newTextLevel);

11.

};

O início do código lida com as transições de CSS3 descritas na Parte 1. O jogo simplesmente acessará o

HTML5 - - Modernize seu jogo HTML5 Canvas:

https://msdn.microsoft.com/pt-br/library/jj9380

armazenamento local através da chave apropriada para recuperar o conteúdo baixado anteriormente.

Etapa 3: Confirmação de online/offline e exibição de um logotipo quando lançado no modo offline

Dois testes são necessários para confirmar que o jogo está sendo executado no modo offline. O primeiro é se

o navegador implementou eventos offline/online, como a maioria dos navegadores faz. Se o navegador

disser que o usuário está offline, isso é confirmado e o jogo deve se alternar automaticamente para a lógica offline Contudo, frequentemente essa verificação simples não é suficiente. O navegador pode dizer que está online, mas não sabe se o servidor Web ainda está online ou não. Assim, você precisa de uma segunda verificação executando ping no servidor com uma XHR simples. A Figura 3 mostra código para as duas verificações.

1.

PlatformerGame.prototype.CheckIfOnline = function () {

2.

if (!navigator.onLine) return false;

3.

var levelsUrl = window.location.href.replace('index.html', '') +

4.

"levels/";

5.

try {

6.

var request = new XMLHttpRequest();

7.

request.open('GET', levelsUrl + "0.txt", false);

8.

request.send(null);

9.

}

10.

catch (e) {

11.

return false;

12.

}

13.

if (request.status !== 200)

14.

return false;

15.

else

16.

return true;

17.

};

Figura 3 - Verificação do modo offline

Meu teste é tentar baixar o primeiro nível. Se falhar, o jogo alterna para a parte offline de meu código. Agora aqui está o código lançado na parte do construtor de PlatformerGame.js:

1.

PlatformerGame.IsOnline = this.CheckIfOnline();

2.

// If we're online, we're downloading/updating all the levels

3.

// from the webserver

4.

if (PlatformerGame.IsOnline) {

5.

this.DownloadAllLevels();

6.

}

7.

// If we're offline, we're loading the first level

8.

// from the cache handled by the local storage

9.

else {

10.

this.LoadNextLevel();

11.

}

E aqui está o código exibindo o logotipo de offline em Level.js na função CreateAndAddRandomBackground:

1. if (!PlatformerGame.IsOnline) {

HTML5 - - Modernize seu jogo HTML5 Canvas:

2. offlineLogo.x = 710;

3. offlineLogo.y = -1;

4. offlineLogo.scaleX = 0.5;

5. offlineLogo.scaleY = 0.5;

6. this.levelStage.addChild(offlineLogo);

7. }

https://msdn.microsoft.com/pt-br/library/jj9380

Com essas alterações implementadas, a Figura 4 mostra a aparência de meu jogo quando é lançado sem uma conexão de rede.

de meu jogo quando é lançado sem uma conexão de rede. Figura 4 - Jogo de

Figura 4 - Jogo de plataforma HTML5 no modo offline

O logotipo de offline é exibido logo acima da taxa de quadros, indicando ao usuário que o jogo está sendo

executado puramente offline.

Etapa 4: Download condicional dos arquivos MP3 ou OGG e armazenamento deles como blob em IndexedDB

Isso é algo que não implementei, mas gostaria de compartilhar o conceito com você como um bônus, para que você mesmo possa implementá-lo.

Você pode ter notado que eu não incluí os efeitos sonoros e a música de meu jogo no arquivo do manifesto na Etapa 1. Quando escrevi esse jogo HTML5, meu primeiro objetivo era que fosse compatível com o maior número de navegadores possível. Para isso, tenho duas versões dos sons: MP3 para o Internet Explorer e o Safari, e OGG para o Chrome, Firefox e o Opera. O gerenciador de downloads de conteúdo baixa apenas o tipo de codec suportado pelo navegador que lançar meu jogo. Isso porque não há necessidade de baixar a versão OGG dos arquivos se eu estiver jogando o jogo no Internet Explorer, assim como não é preciso baixar a versão MP3 para o Firefox.

O problema com o arquivo de manifesto é que você não indica continuamente qual recurso carregar com

base no suporte do navegador do momento. Cheguei a três soluções para contornar essa limitação:

1. Baixar as duas versões colocando todas as versões de arquivo no arquivo de manifesto. Isso é muito simples de implementar e funciona bem, mas os usuários estarão baixando alguns arquivos que nunca

HTML5 - - Modernize seu jogo HTML5 Canvas:

https://msdn.microsoft.com/pt-br/library/jj9380

serão usados por alguns navegadores. 2. Criar um arquivo de manifesto dinâmico no lado do servidor detectando o agente do navegador para reconhecer o codec suportado. Essa é definitivamente uma prática muito ruim! 3. Usar um recurso no lado do cliente para detectar o suporte a codec no objeto do gerenciador de conteúdo e depois baixar o formato de arquivo apropriado para IndexedDB ou para o armazenamento local para uso offline.

Creio que a terceira solução é a melhor, mas você precisa ficar atendo a algumas coisas para fazê-la funcionar:

Se estiver usando armazenamento local, precisa codificar os arquivos em base64, e pode se deparar com limites de cota se tiver muitos arquivos ou se estes forem grandes demais.ficar atendo a algumas coisas para fazê-la funcionar: Se estiver usando IndexedDB, você pode armazenar a

Se estiver usando IndexedDB, você pode armazenar a versão codificada em base64 dos arquivos ou armazená-los como um blob.se tiver muitos arquivos ou se estes forem grandes demais. A abordagem de blob é definitivamente

A abordagem de blob é definitivamente a solução mais inteligente e eficiente, mas requer um navegador muito atual, como a última versão do Internet Explorer 10 (PP5) ou do Firefox (11). Se estiver curioso com esta ideia, veja a demo do complemento para Facebook de nosso site de test-drive do IE aqui:

para Facebook de nosso site de test-drive do IE aqui: Você encontrará mais detalhes sobre essa

Você encontrará mais detalhes sobre essa demo neste arquivo: Atualizações de IndexedDB para o IE10 e aplicativos estilo Metro.

Na versão do jogo fornecida com esse artigo, decidi armazenar todos os formatos no cache (solução 1). Posso atualizar isso em um artigo futuro implementando um armazenamento de IndexedDB em cache. Fique ligado!

APIs de arrastar e soltar e de arquivo

Aqui está um recurso novo divertido que tira proveito das novas APIs de arrastar e soltar e de arquivo. O usuário pode criar ou editar um nível usando seu editor de texto favorito e depois simplesmente arrastá-lo eu explorador de arquivos e soltá-lo no jogo HTML5 e jogar!

Não entrarei em muitos detalhes sobre arrastar e soltar, pois isso foi muito bem coberto em Arrastar e soltar HTML5 no IE10, que explica como a demo Magnetic Poetry foi criada. Recomendo a leitura daquele artigo primeiro para um entendimento completo do código a seguir.

Para o meu jogo, criei o arquivo dragDropLogic.js contendo o código mostrado na Figura 5.

Java

contendo o código mostrado na Figura 5. Java (function () { "use strict" ; var DragDropLogic
contendo o código mostrado na Figura 5. Java (function () { "use strict" ; var DragDropLogic

(function () { "use strict"; var DragDropLogic = DragDropLogic || {}; var _elementToMonitor;

HTML5 - - Modernize seu jogo HTML5 Canvas:

https://msdn.microsoft.com/pt-br/library/jj9380

var _platformerGameInstance; // We need the canvas to monitor its drag&drop events

// and the platformer game instance to trigger the loadnextlevel // function DragDropLogic.monitorElement = function (elementToMonitor, platformerGameInstance) { _elementToMonitor = elementToMonitor; _platformerGameInstance = platformerGameInstance; _elementToMonitor.addEventListener("dragenter", DragDropLogic.drag,false); _elementToMonitor.addEventListener("dragover", DragDropLogic.drag, false); _elementToMonitor.addEventListener("drop", DragDropLogic.drop, false); }; // We don't need to do specific actions // enter & over, we're only interested in drop DragDropLogic.drag = function (e) { e.stopPropagation(); e.preventDefault(); }; DragDropLogic.drop = function (e) { e.stopPropagation(); e.preventDefault(); var dt = e.dataTransfer; var files = dt.files; // Taking only the first dropped file var firstFileDropped = files[0]; // Basic check of the type of file dropped if (firstFileDropped.type.indexOf("text") == 0) { var reader = new FileReader(); // Callback function reader.onload = function(e){ // get file content var text = e.target.result; var textLevel = text.replace(/[\s\n\r\t]/g, ''); // Warning, there is no real check on the consistency // of the file. _platformerGameInstance.LoadThisTextLevel(textLevel);

}

// Asynchronous read reader.readAsText(firstFileDropped);

}

}; window.DragDropLogic = DragDropLogic; })();

Figura 5 - dragDropLogic.js

O código de arrastar e soltar é chamado dentro de main.js na função startGame:

Java
Java

HTML5 - - Modernize seu jogo HTML5 Canvas:

https://msdn.microsoft.com/pt-br/library/jj9380

// Callback function once everything has been downloaded function startGame() { platformerGame = new PlatformerGame(stage, contentManager, 800, 480, window.innerWidth, window.innerHeight); window.addEventListener("resize", OnResizeCalled, false); OnResizeCalled(); DragDropLogic.monitorElement(canvas, platformerGame); platformerGame.StartGame();

}

E isso é tudo! Por exemplo, copie e cole este bloco de texto em um arquivo .txt novo:

.1

######

#####

###

.G.G.GGG.G.G.G

.GGG G GGG.G

.G.G G G.G.GGG

.X

C.

####################

Agora arraste e solte-o no meu jogo. O novo nível será carregado como mágica, como pode ver na Figura 6.

HTML5 - - Modernize seu jogo HTML5 Canvas:

https://msdn.microsoft.com/pt-br/library/jj9380

Canvas: https://msdn.microsoft.com/pt-br/library/jj9380 Figura 6 - Um novo nível adicionado através da API de

Figura 6 - Um novo nível adicionado através da API de arrastar e soltar

Demo e código-fonte

Se você quiser ver uma demonstração no Internet Explorer de todos os recursos implementados neste artigo, assista a este vídeo curto:

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

o vídeo: MP4 , WebM , HTML5 Video Player de VideoJS Você também pode brincar com

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

no Internet Explorer 10 ou seu navegador favorito aqui:. Jogo de plataforma HTML5 moderno . 10

HTML5 - - Modernize seu jogo HTML5 Canvas:

https://msdn.microsoft.com/pt-br/library/jj9380

Como você fez a gentileza de ler este artigo inteiro, desfrute o código-fonte inteiro aqui: Código-fonte do jogo de plataforma HTML5 moderno.

| Home | Artigos Técnicos | Comunidade

© 2016 Microsoft