socialgekon.com
  • Principal
  • Talento Ágil
  • De Outros
  • Europa
  • Processo Interno
Web Front-End

Fazendo um jogo baseado em tela HTML5: um tutorial usando AngularJS e CreateJS

O desenvolvimento de jogos é uma das técnicas de programação mais interessantes e avançadas que desafia constantemente a indústria de desenvolvimento de software.

Existem muitas plataformas de programação usadas para desenvolver jogos, e uma infinidade de dispositivos para jogá-los, mas quando se trata de jogar em um navegador da web, o desenvolvimento baseado em Flash ainda lidera.

Reescrevendo jogos baseados em Flash para HTML5 A tecnologia Canvas nos permitiria reproduzi-los em navegadores móveis também. E, com Apache Cordova, desenvolvedores web qualificados poderia facilmente envolvê-los em aplicativos de jogos móveis de plataforma cruzada.



Gente em CreateJS comece a fazer isso e muito mais.

EaselJS , parte do pacote do CreateJS, torna o desenho no HTML5 Canvas simples. Imagine construir uma visualização de dados customizada com alto desempenho e milhares de elementos. O Scalable Vector Graphic (SVG) não é a escolha certa, porque usa elementos DOM. Os navegadores ficam sobrecarregados quando, com cerca de 600 elementos DOM, as renderizações iniciais, os redesenhos e a animação tornam-se operações caras. Com o HTML5 Canvas, podemos facilmente contornar esses problemas; Os desenhos em tela são como tinta no papel, sem elementos DOM e seus custos associados.

Isso significa que o desenvolvimento baseado em Canvas precisa de mais atenção quando se trata de separar elementos e anexar eventos e comportamentos a eles. EaselJS vem ao resgate; podemos codificar como se estivéssemos lidando com elementos individuais, deixando a biblioteca EaselJS lidar com seus movimentos do mouse, cliques e colisões.

A codificação baseada em SVG tem uma grande vantagem: o SVG tem uma especificação antiga e há muitas ferramentas de design que exportam ativos SVG para uso no desenvolvimento, para que a cooperação entre designers e desenvolvedores funcione bem. Bibliotecas populares, como D3.JS e bibliotecas mais novas e poderosas como SnapSVG , traga muito para a mesa.

Se o fluxo de trabalho de designer para desenvolvedor for o único motivo pelo qual você usaria SVGs, considere extensões para Adobe Illustrator (AI) que geram código a partir de formas criadas em AI. Em nosso contexto, tais extensões geram código EaselJS ou código ProcessingJS, sendo que ambos são bibliotecas baseadas em HTML5 Canvas

Resumindo, se você está começando um novo projeto, não há mais razão para usar SVGs!

SoundJS faz parte da suíte CreateJS; ele fornece uma API simples para especificações de áudio HTML5.

PreloadJS é usado para pré-carregar ativos como bitmaps, arquivos de som e outros. Ele funciona bem em combinação com outras bibliotecas CreateJS.

EaselJS, SoundJS e PreloadJS tornam o desenvolvimento de jogos muito fácil para qualquer ninja JavaScript. Seus métodos de API são familiares a qualquer pessoa que use o desenvolvimento de jogos baseados em Flash.

“Isso tudo é ótimo. Mas, e se tivermos uma equipe de desenvolvedores convertendo vários jogos de Flash para HTML5? É possível fazer isso com esta suíte? ”

A resposta: “Sim, mas apenas se todos os seus desenvolvedores estiverem no nível Jedi!”.

Se você tem uma equipe de desenvolvedores de conjuntos de habilidades variados, o que geralmente é o caso, pode ser um pouco assustador usar o CreateJS e esperar um código escalável e modular. E se juntarmos a suíte CreateJS com AngularJS ? Podemos reduzir esse risco trazendo o melhor e mais adotado framework JS de front-end?

sim , e este tutorial de jogo HTML5 Canvas irá ensiná-lo a criar um jogo básico com CreateJS e AngularJS!

Tutorial do jogo HTML5 Canvas com CreateJS e AngularJS

Plantando a Semente

O AngularJS reduz significativamente a complexidade permitindo que sua equipe de desenvolvimento faça o seguinte:

  1. Adicionando modularidade de código, para que os membros da equipe possam se concentrar em diferentes aspectos do jogo.
  2. Dividir o código em partes separadas para teste e manutenção.
  3. Habilitando a reutilização de código, de forma que uma classe de fábrica possa ser instanciada várias vezes e reutilizada para carregar recursos e comportamentos diferentes, mas semelhantes.
  4. Acelerando o desenvolvimento porque vários membros da equipe podem trabalhar em paralelo, sem pisar nos calcanhares uns dos outros.
  5. Protegendo os desenvolvedores contra o uso de padrões inadequados (Javascript carrega partes notoriamente ruins com ele e o JSLint pode nos ajudar muito).
  6. Adicionando uma estrutura de teste sólida.

Se, como eu, você é um 'consertador' ou um aprendiz tátil, você deve obter o código de GitHub e comece a aprender. Minha sugestão é examinar meus check-ins e entender as etapas que executei para obter os benefícios de adicionar a bondade do AngularJS ao código CreateJS.

Executando Seu Projeto Semente AngularJS

Se você ainda não fez isso, você precisa instalar nodeJS antes de executar esta demonstração.

Depois de criar um projeto seed AngularJS, ou baixá-lo de GitHub , execute npm install para baixar todas as dependências para a pasta do seu aplicativo.

Para executar seu aplicativo, execute npm start da mesma pasta e navegue até http://localhost:8000/app/#/view1 no seu navegador. Sua página deve ser semelhante à imagem abaixo.

exemplo de página

EaselJS Meets AngularJS

Adicione a referência da biblioteca CreateJS ao seu projeto de semente AngularJS. Certifique-se de que o script CreateJS esteja incluído após AngularJS.

Em seguida, limpe o aplicativo:

  • Exclua a pasta view2 da pasta do seu aplicativo
  • Remova o menu e as informações da versão do AngularJS de index.html, excluindo o código mostrado abaixo:
  • view1
  • view2
… Angular seed app: v …

Remover view2 módulo de app.js, excluindo a seguinte linha

myApp.view2,

Se você nunca usou AngularJS antes e não está familiarizado com as diretivas AngularJS, verifique este tutorial . As diretivas no AngularJS são uma forma de ensinar alguns novos truques ao HTML. Eles são o recurso mais bem pensado na estrutura e tornam o AngularJS poderoso e extensível.

Sempre que você precisar de uma funcionalidade DOM especializada ou de um componente, pesquise-o online; há uma boa chance de que já esteja disponível em lugares como Módulos angulares .

A próxima coisa que precisamos fazer é criar uma nova diretiva AngularJS que implementará o exemplo do EaselJS. Crie uma nova diretiva chamada spriteSheetRunner em um novo arquivo localizado em /app/view1/directives/spriteSheetRunner.js.

angular.module('myApp.directives', []) .directive('spriteSheetRunner', function () { 'use strict'; return { restrict : 'EAC', replace : true, scope :{ }, template: '', link: function (scope, element, attribute) { var w, h, loader, manifest, sky, grant, ground, hill, hill2; drawGame(); function drawGame() { //drawing the game canvas from scratch here //In future we can pass stages as param and load indexes from arrays of background elements etc if (scope.stage) { scope.stage.autoClear = true; scope.stage.removeAllChildren(); scope.stage.update(); } else { scope.stage = new createjs.Stage(element[0]); } w = scope.stage.canvas.width; h = scope.stage.canvas.height; manifest = [ {src: 'spritesheet_grant.png', id: 'grant'}, {src: 'sky.png', id: 'sky'}, {src: 'ground.png', id: 'ground'}, {src: 'hill1.png', id: 'hill'}, {src: 'hill2.png', id: 'hill2'} ]; loader = new createjs.LoadQueue(false); loader.addEventListener('complete', handleComplete); loader.loadManifest(manifest, true, '/app/assets/'); } function handleComplete() { sky = new createjs.Shape(); sky.graphics.beginBitmapFill(loader.getResult('sky')).drawRect(0, 0, w, h); var groundImg = loader.getResult('ground'); ground = new createjs.Shape(); ground.graphics.beginBitmapFill(groundImg).drawRect(0, 0, w groundImg.width, groundImg.height); ground.tileW = groundImg.width; ground.y = h - groundImg.height; hill = new createjs.Bitmap(loader.getResult('hill')); hill.setTransform(Math.random() * w, h - hill.image.height * 4 - groundImg.height, 4, 4); hill.alpha = 0.5; hill2 = new createjs.Bitmap(loader.getResult('hill2')); hill2.setTransform(Math.random() * w, h - hill2.image.height * 3 - groundImg.height, 3, 3); var spriteSheet = new createjs.SpriteSheet({ framerate: 30, 'images': [loader.getResult('grant')], 'frames': {'regX': 82, 'height': 292, 'count': 64, 'regY': 0, 'width': 165}, // define two animations, run (loops, 1.5x speed) and jump (returns to run): 'animations': { 'run': [0, 25, 'run', 1.5], 'jump': [26, 63, 'run'] } }); grant = new createjs.Sprite(spriteSheet, 'run'); grant.y = 35; scope.stage.addChild(sky, hill, hill2, ground, grant); scope.stage.addEventListener('stagemousedown', handleJumpStart); createjs.Ticker.timingMode = createjs.Ticker.RAF; createjs.Ticker.addEventListener('tick', tick); } function handleJumpStart() { grant.gotoAndPlay('jump'); } function tick(event) { var deltaS = event.delta / 1000; var position = grant.x 150 * deltaS; var grantW = grant.getBounds().width * grant.scaleX; grant.x = (position >= w grantW) ? -grantW : position; ground.x = (ground.x - deltaS * 150) % ground.tileW; hill.x = (hill.x - deltaS * 30); if (hill.x hill.image.width * hill.scaleX <= 0) { hill.x = w; } hill2.x = (hill2.x - deltaS * 45); if (hill2.x hill2.image.width * hill2.scaleX <= 0) { hill2.x = w; } scope.stage.update(event); } } } });

Depois que sua diretiva for criada, adicione uma dependência ao aplicativo atualizando /app/app.js como abaixo:

'use strict'; // Declare app level module which depends on views, and components angular.module('myApp',[ 'ngRoute', 'myApp.view1', 'myApp.version', 'myApp.services', 'myApp.uiClasses', 'myApp.directives']) .config(['$routeProvider', function($routeProvider) { $routeProvider.otherwise({redirectTo: '/view1'}); }]);

Inclua o código da diretiva em index.html adicionando uma referência a spriteSheetRunner.js.

app/view/view1.html

Estamos quase prontos! Copie os ativos do jogo para a pasta do seu aplicativo. Eu preparei as imagens, fique à vontade para baixá-las e salvá-las em sua pasta de aplicativos / ativos.

  • app / assets / spritesheet_grant.png
  • app / assets / ground.png
  • app / assets / hill1.png
  • app / assets / hill2.png
  • app / assets / sky.png

Como uma etapa final, adicione nossa diretiva recém-criada à página. Para fazer isso, altere seu loaderSvc.js arquivo e torná-lo um de uma linha:

/app/view1/services

Inicie seu aplicativo e você colocará seu corredor em movimento :)

corredor em movimento

Se este é seu primeiro aplicativo AngularJS ou CreateJS, comemore, você acabou de fazer algo muito legal!

Pré-carregamento de ativos em um serviço

Os serviços no AngularJS são singletons usados ​​principalmente para compartilhar o código e os dados. Usaremos um serviço para compartilhar os 'ativos do jogo' em todo o aplicativo. Para saber mais sobre os serviços AngularJS, verifique o Documentação AngularJS .

Serviços de desenvolvimento AngularJS fornecem um mecanismo eficaz para carregar e gerenciar todos os ativos em um só lugar. As alterações de ativos são propagadas para cada instância individual de um serviço, tornando nosso código muito mais fácil de manter.

Crie um novo arquivo JS denominado //app/view1/services/loaderSvc.js myServices.service('loaderSvc', function () { var manifest = [ {src: 'spritesheet_grant.png', id: 'grant'}, {src: 'sky.png', id: 'sky'}, {src: 'ground.png', id: 'ground'}, {src: 'hill1.png', id: 'hill'}, {src: 'hill2.png', id: 'hill2'} ], loader = new createjs.LoadQueue(true); this.getResult = function (asset) { return loader.getResult(asset); }; this.getLoader = function () { return loader; }; this.loadAssets = function () { loader.loadManifest(manifest, true, '/app/assets/'); }; }); em seu app.js pasta.

myApp.services

O AngularJS exige que registremos qualquer serviço que estivermos usando. Para fazer isso, atualize seu 'use strict'; // Declare app level module which depends on views, and components angular.module('myApp',[ 'ngRoute', 'myApp.view1', 'myApp.version', 'myApp.services', 'myApp.directives']) .config(['$routeProvider', function($routeProvider) { $routeProvider.otherwise({redirectTo: '/view1'}); }]); var myServices = angular.module('myApp.services', []); arquivo para incluir referência a app/view1/directives/spriteSheetRunner.js.

angular.module('myApp.directives', []) .directive('spriteSheetRunner', ['loaderSvc', function (loaderSvc) { 'use strict'; return { restrict : 'EAC', replace : true, scope :{ }, template: '', link: function (scope, element, attribute) { var w, h, manifest, sky, grant, ground, hill, hill2; drawGame(); function drawGame() { //drawing the game canvas from scratch here //In future we can pass stages as param and load indexes from arrays of background elements etc if (scope.stage) { scope.stage.autoClear = true; scope.stage.removeAllChildren(); scope.stage.update(); } else { scope.stage = new createjs.Stage(element[0]); } w = scope.stage.canvas.width; h = scope.stage.canvas.height; loaderSvc.getLoader().addEventListener('complete', handleComplete); loaderSvc.loadAssets(); } function handleComplete() { sky = new createjs.Shape(); sky.graphics.beginBitmapFill(loaderSvc.getResult('sky')).drawRect(0, 0, w, h); var groundImg = loaderSvc.getResult('ground'); ground = new createjs.Shape(); ground.graphics.beginBitmapFill(groundImg).drawRect(0, 0, w + groundImg.width, groundImg.height); ground.tileW = groundImg.width; ground.y = h - groundImg.height; hill = new createjs.Bitmap(loaderSvc.getResult('hill')); hill.setTransform(Math.random() * w, h - hill.image.height * 4 - groundImg.height, 4, 4); hill.alpha = 0.5; hill2 = new createjs.Bitmap(loaderSvc.getResult('hill2')); hill2.setTransform(Math.random() * w, h - hill2.image.height * 3 - groundImg.height, 3, 3); var spriteSheet = new createjs.SpriteSheet({ framerate: 30, 'images': [loaderSvc.getResult('grant')], 'frames': {'regX': 82, 'height': 292, 'count': 64, 'regY': 0, 'width': 165}, // define two animations, run (loops, 1.5x speed) and jump (returns to run): 'animations': { 'run': [0, 25, 'run', 1.5], 'jump': [26, 63, 'run'] } }); grant = new createjs.Sprite(spriteSheet, 'run'); grant.y = 35; scope.stage.addChild(sky, hill, hill2, ground, grant); scope.stage.addEventListener('stagemousedown', handleJumpStart); createjs.Ticker.timingMode = createjs.Ticker.RAF; createjs.Ticker.addEventListener('tick', tick); } function handleJumpStart() { grant.gotoAndPlay('jump'); } function tick(event) { var deltaS = event.delta / 1000; var position = grant.x + 150 * deltaS; var grantW = grant.getBounds().width * grant.scaleX; grant.x = (position >= w + grantW) ? -grantW : position; ground.x = (ground.x - deltaS * 150) % ground.tileW; hill.x = (hill.x - deltaS * 30); if (hill.x + hill.image.width * hill.scaleX <= 0) { hill.x = w; } hill2.x = (hill2.x - deltaS * 45); if (hill2.x + hill2.image.width * hill2.scaleX <= 0) { hill2.x = w; } scope.stage.update(event); } } } }]);

Atualize seu código de diretiva, em 'use strict'; // Declare app level module which depends on views, and components angular.module('myApp',[ 'ngRoute', 'myApp.view1', 'myApp.version', 'myApp.services', 'myApp.uiClasses', 'myApp.directives']) .config(['$routeProvider', function($routeProvider) { $routeProvider.otherwise({redirectTo: '/view1'}); }]); var uiClasses = angular.module('myApp.uiClasses', []); var myServices = angular.module('myApp.services', []); arquivo, para remover o código de pré-carregamento e usar o serviço.

uiClasses.factory('Sky', [ 'loaderSvc', function (loaderSvc) { function Sky(obj) { this.sky = new createjs.Shape(); this.sky.graphics.beginBitmapFill(loaderSvc.getResult('sky')).drawRect(0, 0, obj.width, obj.height); } Sky.prototype = { addToStage: function (stage) { stage.addChild(this.sky); }, removeFromStage: function (stage) { stage.removeChild(this.sky); } }; return (Sky); }]);

Criação de UI Elements Factory

Reutilizar e repetir sprites no desenvolvimento de jogos é muito importante. Para habilitar a instanciação de classes UI (que são sprites em nosso caso), usaremos AngularJS Factories.

A fábrica é registrada no aplicativo como qualquer outro módulo AngularJS. Para criar a fábrica uiClasses, modifique o arquivo app.js para ficar assim:

uiClasses.factory('Hill', [ 'loaderSvc', function (loaderSvc) { function Hill(obj) { this.hill = new createjs.Bitmap(loaderSvc.getResult(obj.assetName)); this.hill.setTransform(Math.random() * obj.width, obj.height - this.hill.image.height * obj.scaleFactor - obj.groundHeight, obj.scaleFactor, obj.scaleFactor); } Hill.prototype = { addToStage: function (stage) { stage.addChild(this.hill); }, removeFromStage: function (stage) { stage.removeChild(this.hill); }, setAlpha: function (val) { this.hill.alpha = val; }, getImageWidth: function () { return this.hill.image.width; }, getScaleX: function () { return this.hill.scaleX; }, getX: function () { return this.hill.x; }, getY: function () { return this.hill.y; }, setX: function (val) { this.hill.x = val; }, move: function (x, y) { this.hill.x = this.hill.x + x; this.hill.y = this.hill.y + y; } }; return (Hill); }]);

Vamos usar a nova fábrica para criar céu, colina, solo e nosso corredor. Para fazer isso, crie arquivos JavaScript conforme listado abaixo.

  • app / view1 / uiClasses / sky.js
uiClasses.factory('Ground', [ 'loaderSvc', function (loaderSvc) { function Ground(obj) { var groundImg = loaderSvc.getResult('ground'); this.ground = new createjs.Shape(); this.ground.graphics.beginBitmapFill(groundImg).drawRect(0, 0, obj.width + groundImg.width, groundImg.height); this.ground.tileW = groundImg.width; this.ground.y = obj.height - groundImg.height; this.height = groundImg.height; } Ground.prototype = { addToStage: function (stage) { stage.addChild(this.ground); }, removeFromStage: function (stage) { stage.removeChild(this.ground); }, getHeight: function () { return this.height; }, getX: function () { return this.ground.x; }, setX: function (val) { this.ground.x = val; }, getTileWidth: function () { return this.ground.tileW; }, move: function (x, y) { this.ground.x = this.ground.x + x; this.ground.y = this.ground.y + y; } }; return (Ground); }]);
  • app / view1 / uiClasses / hill.js
uiClasses.factory('Character', [ 'loaderSvc', function (loaderSvc) { function Character(obj) { var spriteSheet = new createjs.SpriteSheet({ framerate: 30, 'images': [loaderSvc.getResult(obj.characterAssetName)], 'frames': {'regX': 82, 'height': 292, 'count': 64, 'regY': 0, 'width': 165}, // define two animations, run (loops, 1.5x speed) and jump (returns to run): 'animations': { 'run': [0, 25, 'run', 1.5], 'jump': [26, 63, 'run'] } }); this.grant = new createjs.Sprite(spriteSheet, 'run'); this.grant.y = obj.y; } Character.prototype = { addToStage: function (stage) { stage.addChild(this.grant); }, removeFromStage: function (stage) { stage.removeChild(this.grant); }, getWidth: function () { return this.grant.getBounds().width * this.grant.scaleX; }, getX: function () { return this.grant.x; }, setX: function (val) { this.grant.x = val; }, playAnimation: function (animation) { this.grant.gotoAndPlay(animation); } }; return (Character); }]);
  • app / view1 / ground.js
index.html
  • app / view1 / uiClasses / character.js
myDirectives.directive('spriteSheetRunner', ['loaderSvc','Sky', 'Ground', 'Hill', 'Character', function (loaderSvc, Sky, Ground, Hill, Character) { 'use strict'; return { restrict : 'EAC', replace : true, scope :{ }, template: '', link: function (scope, element, attribute) { var w, h, sky, grant, ground, hill, hill2; drawGame(); function drawGame() { //drawing the game canvas from scratch here if (scope.stage) { scope.stage.autoClear = true; scope.stage.removeAllChildren(); scope.stage.update(); } else { scope.stage = new createjs.Stage(element[0]); } w = scope.stage.canvas.width; h = scope.stage.canvas.height; loaderSvc.getLoader().addEventListener('complete', handleComplete); loaderSvc.loadAssets(); } function handleComplete() { sky = new Sky({width:w, height:h}); sky.addToStage(scope.stage); ground = new Ground({width:w, height:h}); hill = new Hill({width:w, height:h, scaleFactor: 4, assetName: 'hill', groundHeight: ground.getHeight()}); hill.setAlpha(0.5); hill.addToStage(scope.stage); hill2 = new Hill({width:w, height:h, scaleFactor: 3, assetName: 'hill2', groundHeight: ground.getHeight()}); hill2.addToStage(scope.stage); ground.addToStage(scope.stage); grant = new Character({characterAssetName: 'grant', y: 34}) grant.addToStage(scope.stage); scope.stage.addEventListener('stagemousedown', handleJumpStart); createjs.Ticker.timingMode = createjs.Ticker.RAF; createjs.Ticker.addEventListener('tick', tick); } function handleJumpStart() { grant.playAnimation('jump'); } function tick(event) { var deltaS = event.delta / 1000; var position = grant.getX() + 150 * deltaS; grant.setX((position >= w + grant.getWidth()) ? -grant.getWidth() : position); ground.setX((ground.getX() - deltaS * 150) % ground.getTileWidth()); hill.move(deltaS * -30, 0); if (hill.getX() + hill.getImageWidth() * hill.getScaleX() <= 0) { hill.setX(w); } hill2.move(deltaS * -45, 0); if (hill2.getX() + hill2.getImageWidth() * hill2.getScaleX() <= 0) { hill2.setX(w); } scope.stage.update(event); } } } }]);

Não se esqueça de adicionar todos esses novos arquivos JS em seu uiClasses.

Agora, precisamos atualizar a diretiva do jogo.

keyDown

Observe que mover handleComplete() fora da diretiva reduziu o tamanho da diretiva em 20%, de 91 para 65 linhas.

Além disso, podemos escrever testes de forma independente para cada classe de fábrica para simplificar sua manutenção.

Observação: o teste é um tópico que não é abordado nesta postagem, mas Aqui é um bom lugar para começar.

Interação das teclas de seta

Neste ponto em nosso tutorial de jogo HTML5 Canvas, clique com o mouse ou toque em um celular fará nosso cara pular, e não podemos pará-lo. Vamos adicionar controles de teclas de seta:

  • Seta para a esquerda (pausa o jogo)
  • Seta para cima (salto)
  • Seta para a direita (começar a correr)

Para fazer isso, crie o function keydown(event) { if (event.keyCode === 38) {//if keyCode is 'Up' handleJumpStart(); } if (event.keyCode === 39) {//if keyCode is 'Right' if (scope.status === 'paused') { createjs.Ticker.addEventListener('tick', tick); scope.status = 'running'; } } if (event.keyCode === 37) {//if keyCode is 'Left' createjs.Ticker.removeEventListener('tick', tick); scope.status = 'paused'; } } window.onkeydown = keydown; função e adicione um ouvinte de evento como última linha de loadQueue função.

PreloaderJS

Tente executar o jogo novamente e verifique os controles do teclado.

Deixe a música tocar

Jogos não são divertidos sem música, então vamos tocar um pouco de música.

Primeiro precisaremos adicionar arquivos MP3 à nossa pasta de aplicativos / ativos. Você pode baixá-los nos URLs fornecidos abaixo.

  • app / assets / jump.mp3
  • app / assets / runningTrack.mp3

Agora, precisamos pré-carregar esses arquivos de som usando nosso serviço de carregador. Usaremos app/view1/services/loaderSvc.js de myServices.service('loaderSvc', function () { var manifest = [ {src: 'spritesheet_grant.png', id: 'grant'}, {src: 'sky.png', id: 'sky'}, {src: 'ground.png', id: 'ground'}, {src: 'hill1.png', id: 'hill'}, {src: 'hill2.png', id: 'hill2'}, {src: 'runningTrack.mp3', id: 'runningSound'}, {src: 'jump.mp3', id: 'jumpingSound'} ], loader = new createjs.LoadQueue(true); // need this so it doesn't default to Web Audio createjs.Sound.registerPlugins([createjs.HTMLAudioPlugin]); loader.installPlugin(createjs.Sound); this.getResult = function (asset) { return loader.getResult(asset); }; this.getLoader = function () { return loader; }; this.loadAssets = function () { loader.loadManifest(manifest, true, '/app/assets/'); }; }); biblioteca. Atualize seu myDirectives.directive('spriteSheetRunner', [ 'loaderSvc', 'Sky', 'Ground', 'Hill', 'Character', function (loaderSvc, Sky, Ground, Hill, Character) { 'use strict'; return { restrict : 'EAC', replace : true, scope :{ }, template: '', link: function (scope, element, attribute) { var w, h, sky, grant, ground, hill, hill2, runningSoundInstance, status; drawGame(); function drawGame() { //drawing the game canvas from scratch here if (scope.stage) { scope.stage.autoClear = true; scope.stage.removeAllChildren(); scope.stage.update(); } else { scope.stage = new createjs.Stage(element[0]); } w = scope.stage.canvas.width; h = scope.stage.canvas.height; loaderSvc.getLoader().addEventListener('complete', handleComplete); loaderSvc.loadAssets(); } function handleComplete() { sky = new Sky({width:w, height:h}); sky.addToStage(scope.stage); ground = new Ground({width:w, height:h}); hill = new Hill({width:w, height:h, scaleFactor: 4, assetName: 'hill', groundHeight: ground.getHeight()}); hill.setAlpha(0.5); hill.addToStage(scope.stage); hill2 = new Hill({width:w, height:h, scaleFactor: 3, assetName: 'hill2', groundHeight: ground.getHeight()}); hill2.addToStage(scope.stage); ground.addToStage(scope.stage); grant = new Character({characterAssetName: 'grant', y: 34}); grant.addToStage(scope.stage); scope.stage.addEventListener('stagemousedown', handleJumpStart); createjs.Ticker.timingMode = createjs.Ticker.RAF; createjs.Ticker.addEventListener('tick', tick); // start playing the running sound looping indefinitely runningSoundInstance = createjs.Sound.play('runningSound', {loop: -1}); scope.status = 'running'; window.onkeydown = keydown; } function keydown(event) { if (event.keyCode === 38) {//if keyCode is 'Up' handleJumpStart(); } if (event.keyCode === 39) {//if keyCode is 'Right' if (scope.status === 'paused') { createjs.Ticker.addEventListener('tick', tick); runningSoundInstance = createjs.Sound.play('runningSound', {loop: -1}); scope.status = 'running'; } } if (event.keyCode === 37) {//if keyCode is 'Left' createjs.Ticker.removeEventListener('tick', tick); createjs.Sound.stop(); scope.status = 'paused'; } } function handleJumpStart() { if (scope.status === 'running') { createjs.Sound.play('jumpingSound'); grant.playAnimation('jump'); } } function tick(event) { var deltaS = event.delta / 1000; var position = grant.getX() + 150 * deltaS; grant.setX((position >= w + grant.getWidth()) ? -grant.getWidth() : position); ground.setX((ground.getX() - deltaS * 150) % ground.getTileWidth()); hill.move(deltaS * -30, 0); if (hill.getX() + hill.getImageWidth() * hill.getScaleX() <= 0) { hill.setX(w); } hill2.move(deltaS * -45, 0); if (hill2.getX() + hill2.getImageWidth() * hill2.getScaleX() <= 0) { hill2.setX(w); } scope.stage.update(event); } } } }]); para pré-carregar esses arquivos.

index.html

Modifique sua diretiva de jogo para reproduzir sons em eventos de jogo.

app/view1/view1.html Relacionado: Melhores práticas e dicas do AngularJS por desenvolvedores do ApeeScape

Adicionando pontuação e indicadores de vida

Vamos adicionar a pontuação do jogo e os indicadores de vida (coração) ao jogo HTML5 Canvas. A pontuação será mostrada como um número no canto superior esquerdo e os símbolos de coração, no canto superior direito, indicarão a contagem de vidas.

Usaremos uma biblioteca de fontes externa para renderizar corações, portanto, adicione a seguinte linha ao seu

Score: {{score}}

Life: 1' class='fa fa-heart'> 2' class='fa fa-heart'> .top-left { position: absolute; left: 30px; top: 10px; } .top-right { position: absolute; right: 100px; top: 10px; float: right; } Arquivo:

lifesCount

Para posicionar adequadamente nossos indicadores, precisamos adicionar classes CSS para canto superior esquerdo e canto superior direito em app/view1/view1.js Arquivo.

'use strict'; angular.module('myApp.view1', ['ngRoute']) .config(['$routeProvider', function($routeProvider) { $routeProvider.when('/view1', { templateUrl: 'view1/view1.html', controller: 'View1Ctrl' }); }]) .controller('View1Ctrl', ['$scope', function($scope) { $scope.score = 0; $scope.lifesCount = 3; }]);

Inicialize a pontuação e ... replace : true, scope :{ score: '=score', lifesCount: '=lifesCount' }, template: ... variáveis ​​em handleComplete() controlador.

scope.score = 10; scope.lifesCount = 2; scope.$apply();

Para ter certeza de que os indicadores estão atualizados corretamente, modifique a diretiva principal do jogo para usar as variáveis ​​de escopo.

app/view1/view1.js

Para testar a ligação de escopo, adicione essas três linhas no final de $window método.

'use strict'; angular.module('myApp.view1', ['ngRoute']) .config(['$routeProvider', function($routeProvider) { $routeProvider.when('/view1', { templateUrl: 'view1/view1.html', controller: 'View1Ctrl' }); }]) .controller('View1Ctrl', ['$scope', '$window', function($scope, $window) { $scope.windowWidth = $window.innerWidth; $scope.gameHeight = 400; $scope.score = 0; $scope.lifesCount = 3; }]);

Ao executar o aplicativo, você deverá ver a pontuação e os indicadores de vida.

pontuação e indicadores de vida

O espaço em branco adicional, à direita da página, continuará presente porque ainda estamos codificando a largura e a altura do jogo neste ponto em nosso tutorial de programação de jogos em HTML5.

Adaptando a largura do jogo

O AngularJS vem com métodos e serviços úteis. Um deles é $ window, que fornece uma propriedade innerWidth que usaremos para calcular a posição de nossos elementos.

Modifique o seu ... scope :{ width: '=width', height: '=height', score: '=score', lifesCount: '=lifesCount' }, ... drawGame(); element[0].width = scope.width; element[0].height = scope.height; w = scope.width; h = scope.height; function drawGame() { ... para injetar

|_+_|
serviço.

|_+_|

Estenda a diretiva principal do jogo com propriedades de largura e altura e é isso!

|_+_|

Agora você tem o jogo se ajustando à largura da janela do navegador.

Se você deseja portar isso para um aplicativo móvel, sugiro ler meu outro tutorial de desenvolvimento de aplicativo móvel sobre usando a estrutura Ionic para criar aplicativos móveis . Você deve ser capaz de criar um aplicativo de semente iônica, copiar todo o código deste projeto e começar a jogar no seu dispositivo móvel em menos de uma hora.

A única coisa que não estou abordando aqui é a detecção de colisão. Para saber mais sobre isso, eu li Este artigo .

Embrulhar

Eu acredito que ao longo deste tutorial de desenvolvimento de jogos você percebeu que AngularJS e CreateJS são uma dupla vencedora para o desenvolvimento de jogos baseados em HTML5. Você tem todos os fundamentos e tenho certeza de que reconheceu os benefícios de combinar essas duas plataformas.

Você pode baixar o código deste artigo em GitHub , fique à vontade para usar, compartilhar e torná-lo seu.

Relacionado: 18 erros mais comuns do AngularJS que os desenvolvedores cometem

Apresentando Battlescripts: Bots, Ships, Mayhem!

Web Front-End

Apresentando Battlescripts: Bots, Ships, Mayhem!
O impacto do Brexit no setor de serviços financeiros

O impacto do Brexit no setor de serviços financeiros

Processos Financeiros

Publicações Populares
Melhores práticas de fusões e aquisições na América Latina
Melhores práticas de fusões e aquisições na América Latina
As 25 melhores predefinições do Lightroom Mobile para fotos impressionantes do iPhone
As 25 melhores predefinições do Lightroom Mobile para fotos impressionantes do iPhone
EUA: corrida para prefeito de Honolulu segue para segundo turno
EUA: corrida para prefeito de Honolulu segue para segundo turno
Como fazer autenticação JWT com um Angular 6 SPA
Como fazer autenticação JWT com um Angular 6 SPA
Como editar fotos no iPhone com iOS Photos
Como editar fotos no iPhone com iOS Photos
 
React Test-driven Development: From User Stories to Production
React Test-driven Development: From User Stories to Production
Criação de uma API REST segura em Node.js
Criação de uma API REST segura em Node.js
Um guia de campo para DesignOps
Um guia de campo para DesignOps
Donald Trump encontra o Papa Francisco no Vaticano, jura não esquecer sua mensagem
Donald Trump encontra o Papa Francisco no Vaticano, jura não esquecer sua mensagem
Automação no Selenium: Modelo de objeto de página e fábrica de página
Automação no Selenium: Modelo de objeto de página e fábrica de página
Categorias
NutriçãoVida DesignerGestão De EngenhariaPessoas E Equipes De ProdutoFamíliaCiclo De Vida Do ProdutoAprendendoFerramentas E TutoriaisKpis E AnálisesFuturo Do Trabalho

© 2023 | Todos Os Direitos Reservados

socialgekon.com