Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Per què Programar 
jocs en JavaScript?
...perquè ara podem!!!
Tecnologies relacionades amb la WEB
Desenvolupament de Jocs
Eines per desenvolupar 
ASTEROIDS amb JavaScript
Overview
Darrera el Navegador...
GET / HTTP/1.1
HTTP/1.1 200 OK
HTTP és un protocol
sense estat!
Cada petició és independent de les altres
No recorda res de les peticions anteriors!
WEB 1.0
WEB 2.0
WEB 3.0
  • HTTP + HTML
  • Només text i imatges
  • Documents estàtics que calia editar manualment
  • El contingut i la presentació es barrejaven
  • HTTP + HTML + CSS + PHP + MYSQL
  • Documents dinàmics generats per scripts de servidor
  • CSS permet separar el contingut de la presentació
  • S'afegeixen elements multimedia mitjançant plug-ins
  • Enormes incompatibilitats entre navegadors
  • HTTP + HTML5 + CSS3 + JavaScript + AJAX + PHP + BBDDD
  • Major estandardització --> Menys diferències entre navegadors
  • Suport multimèdia en el mateix navegador
  • Millora en la interactivitat de les aplicacions WEB
Evolució de la WEB
HTML5
  • Simplifica la sintaxi

  • Suport per Audio i Vídeo sense necessitar plugins 
 
  • Element Canvas per poder dibuixar directament al navegador

  • Nous elements que afegeixen info semàntica (article, main, section...)

  • Nous elements per entrar dades als formularis (email...)

  • Permet a l'usuari editar el contingut d'alguns elements

  • Noves funcionalitats per facilitar la validació de les dades entrades

  • Local Storage: Permet desar informació sense accedir al sistema de fitxers

  • Permet utilitzar GeoLocalització
CSS3
  • Permet seleccionar elements basant-se en el valor dels seus atributs
 
  • Permet arrodonir els cantons de les vores dels elements

  • Permet utilitzar una imatge per dibuixar les vores

  • Permet afegir ombres i gradients als elements i al text

  • Permet afegir transparències (RGB + canal alpha)

  • Permet transformar els elements amb rotacions 

  • Permet afegir Web Fonts a les pàgines

JavaScript
  • Creat al 1995 per Brendan Eich a Netscape Corporation
  • No té cap relació amb Java (apart del nom)
  • Llenguatge de Script (o Interpretat)
  • Actualment es troba estandarditzat per la ECMA amb el nom EcmaScript
  • Dèbilment tipat (no cal definir el tipus de variables)
  • Multiparadigma: Orientació a Objectes, Imperatiu,  Funcional
  • Basat en prototipus enlloc de classes
  • Pràcticament tot en JS són "objectes"
  • Els objectes en JS són arrays associatius (parells nom-valor)
  • Les funcions són elements first-class ( de fet són objectes )
  • Suporta funcions anònimes i closures
  • La sintaxi és molt flexible, podent fer el mateix de moltes formes diferents!!!
  • Els navegadors actuals fan servir compilació just-in-time per millorar la eficiència
  • Disposa d'entorns d'execució fora del navegador (node.js)
JavaScript EC5 vs EC6
  • Gran millora en el rendiment dels motors JavaScript
 
  • Estandardització i millora en la compatibilitat entre navegadors

  • Nous elements en el llenguatge que incrementen la seva potència

  • Millores en la sintaxi per facilitar la llegibilitat del codi

  • Permet utilitzar variables amb àmbit de bloc (Block Scope)

  • Les Promises milloren el suport a les crides asíncrones

  • Suport natiu per utilitzar mòduls (millora la reutilització de codi)

Jocs vs Aplicacions 
  • Control exclusiu dels recursos hardware
  • Cal actualitzar el joc encara que l'usuari no faci res
  • El temps determina la situació del joc
  • N'hi ha prou amb crear la il·lusió de realitat
  • L'aspecte gràfic pot ser més important que la funcionalitat
  • Prioritzen l'entreteniment
  • Intenten incentivar que es segueixi jugant

  • Han de conviure amb altres tasques
  • La major part del temps estan inactives esperant les accions de l'usuari
  • El temps no és important
  • Cal fer les tasques de manera efectiva
  • Prioritzen la productivitat de l'usuari


Estructura d'un joc
Carregar elements
Inicialitzar el joc
  •  Capturar les entrades de l'usuari
  •  Actualitzar el joc segons les entrades de l'usuari
  •  Actualitzar el joc segons les seves regles
  •  Mostrar el resultat
Game Loop
Game
LOOPS
FPS
(Frames Per Second)
  • Vídeo i pel·lícules fan servir 24-25 FPS
  • Els jocs requereixen al menys 20FPS
  • Es considera òptim uns 60FPS
  • Natros no sóm capaços de distingir +60FPS
  • Els FPS estàn limitats per la potència del hardware
  • Cal que les pantalles s'actualitzin prou ràpid
  • Molts monitors CRT d'ordinador treballen a 60Hz
  • Molts LCD moderns treballen a 60, 75 o 144Hz
  • Els jocs actuals són Frame-Independents
  • Si es "perden" Frames el moviment es veu a salts
while (true) {
  processarEntradaUsuari();
  actualitzarElementsJoc();
  mostrarJoc();
}
while (true) {
  processarEntradaUsuari();
  actualitzarElementsJoc();
  MostrarJoc();
                                        
  for (i=1;i<1000;i++){}
}
  • S'executa a la velocitat del processador
  • El moviment pot ser massa ràpid
  • Consumeix molts recursos de CPU
  • Segueix depenent de la velocitat del processador
var FPS = 60;
function gameLoop() {
   processarEntradaUsuari();
   actualitzarElementsJoc();
   MostrarJoc();
}
setInterval(gameLoop, 1000/FPS);}

var FPS = 60;
function gameLoop() {
   processarEntradaUsuari();
  actualitzarElementsJoc();
   MostrarJoc();
   setTimeout(gameLoop, 1000/FPS);
}
gameLoop();
  • Executa la funció (tarda uns ms)
  • Espera l'interval (1000/FPS)
  • Torna a executar la funció
  • Interval entre crides > 100/FPS
  • Es poden "perdre" cicles
  • No s'atura amb si el joc no està actiu
  • Chrome ho ralentitza fins 1fps
  • Crida la funció cada 1000/FPS
  • Es posa en cua si no ha acabat l'anterior
  • Pot consumir el 100% de la CPU
  • Garanteix una animació més fluida
function gameLoop() {
   processarEntradaUsuari();
   actualitzarElementsJoc();
   MostrarJoc();
}
requestAnimationFrame(gameLoop);
  • El navegador només dibuixa el joc quan pot
  • No es fa feina de bades
  • S'atura el procés si la pestanya està inactiva o amagada
  • Permet als navegadors optimitzar el Frame Rate (FPS)
  • Redibuixa totes les animacions una sola vegada
  • No permet indicar els FPS a que volem actualitzar el joc
requestAnimationFrame
Phaser utilitza rAF si pot i si no fa servir setTimeout
Es pot forçar utilitzar setTimeout
Versió "òptima" de setTimeOut
var FPS = 60;
var darreraCrida = new Date().getTime();

function gameLoop() {
   processarEntradaUsuari();
   actualitzarElementsJoc();
   MostrarJoc();

   var ara = new Date().getTime();
   var seguentCrida = Math.max(0, 1000/FPS - (ara - darreraCrida));
   setTimeout(gameLoop, seguentCrida);
   darreraCrida = ara + seguentCrida;
}
gameLoop();
  • Intenta tenir en compte la durada de l'execució
  • S'aproxima al màxim als FPS demanats
Framework per a Jocs
Totalment en JavaScript
Pot fer servir Canvas o WebGL
Diferents sistemes de Física
Arcade Physics
P2
Ninja Physics
Box2D (comercial)
Informació sobre PHASER
  • Documentació oficial:
         http://phaser.io/docs/2.4.6/index
  • Guies:
         http://phaser.io/examples
  • Exemples de codi (molt il·lustratius i útils):
         http://phaser.io/examples
  • Fòrum (molt actiu):
         http://www.html5gamedevs.com/forum/14-phaser/
  • Cóm començar (guia pas a pas):
         http://phaser.io/tutorials/making-your-first-phaser-game
Eines per
desenvolupar
amb
JavaScript
  • Programa per executar aplicacions JavaScript fora del navegador.
  • Runtime JavaScript basat en el motor V8 de Chrome
  • Arquitectura orientada a events
  • I/O Asíncrona i sense bloquejar els recursos
  • Codi Obert, suporta múltiples plataformes
Node.js
$sudo apt-get update

$sudo apt-get install curl

$curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -

$sudo apt-get install -y nodejs
Per Instal·lar-lo a Linux
  • Node.js Package Manager
  • Gestor de Paquets per Node.js i altres entorns
  • Gestiona les dependències entre paquets
  • Disposa d'una gran quantitat de paquets

Per Instal·lar-lo a Linux
$curl -sL https://npmjs.org/install.sh | sudo -E bash -
  • Servidor Web fet amb JavaScript
  • No requereix cap configuració
  • Serveix fitxers locals
  • Utilitza per defecte el port 8080
HTTP-Server
Per Instal·lar-lo a Linux
$sudo npm install http-server -g
  • Gestor de versions de programari
  • Escalable, molt potent i ràpid
  • Molt robust per evitar pèrdua de dades
  • Fet per Linus Torvalds (en menys d'una setmana!!)
Per Instal·lar-lo a Linux

$sudo apt-get install git

Brackets
  • Fet amb HTML, CSS i JavaScript
  • Editor orientat al desenvolupament Web
  • Permet editar codi CSS inline
  • Desenvolupat per ADOBE
  • Open Source (MIT License)
  • Live Preview (visualitza en Chrome els canvis fets al codi)
  • Permet importar elements i colors des de PhotoShop
Per Instal·lar-lo a Linux
$curl -L -o brackets.deb https://github.com/adobe/brackets/releases/download/release-1.6%2Beb4/Brackets.1.6.Extract.64-bit.deb

$sudo dpkg -i brackets.deb

Presentacions amb HTML5 + CSS3 + JavaScript
  • Es poden visualitzar en qualsevol navegador
  • Poden tenir transicions visualment atractives
  • Totalment personalitzables
  • Fàcils de convertir a altres formats (pdf...)
  • Hi ha moltes llibreries per fer presentacions
Editors HTML WYSIWYG OnLine
  • Permeten editar documents HTML sense instal·lar res
  • Fets amb JavaScript
  • Podem copiar el codi HTML generat
Eines WYSIWYG CSS3 OnLine
  • Ajuden a crear el codi CSS pels estils
  • Simplifiquen obtenir resultats efectius
ASTEROIDS
Instal·lar totes les eines per desenvolupar

$sudo apt-get update

$sudo apt-get install curl

$curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -

$sudo apt-get install -y nodejs

$curl -sL https://npmjs.org/install.sh | sudo -E bash -

$sudo npm install http-server -g

$curl -L -o brackets.deb https://github.com/adobe/brackets/releases/download/release-1.6%2Beb4/Brackets.1.6.Extract.64-bit.deb

$sudo dpkg -i brackets.deb

$sudo apt-get install git

Agafar el repositori GitHub amb tot el codi

$git clone https://github.com/jaumeramos/asteroids

Passos per programar Asteroids
1. Carregar el fons i animar-lo

2. Dibuixar la nau i associar-li el motor de la física ARCADE

3. Controlar el moviment de la nau amb els cursors

4. Controlar la sortida de la nau per la pantalla,
   de forma que torni a entrar per la part oposada.

5. Fer que la nau dispari al prémer la tecla espai.
   Hi ha d'haver un nombre limitat de bales, i han de tenir
   un temps de vida fins que desapareixien, per evitar omplir
   la pantalla de bales. Cal deixar un temps entre bala i bala.  

6. Fer aparèixer un asteroide cada segon, controlant que no
   surti massa prop de la nau. Cal revisar que si l'asteroide
   surt de la pantalla torni a aparèixer per l'altra banda.

7. Determinar si hi ha col·lisions bala-asteroide, i si n'hi ha
   mostrar una explosió i actualitzar la puntuació del joc.

8. Determinar si hi ha col·lisions nau-asteroide, i si n'hi ha
   mostrar una explosió i restar una vida.

9. Mostrar la puntuació del joc i el nombre de vides restant.

10. Aturar el joc quan no quedin més vides.

Crear un joc amb PHASER
var game = new Phaser.Game(
    800,          /* Amplada del joc window.innerWidth fa que ocupi tot l'ample*/
    600,          /* Alçada del joc window.innerHeight fa que ocupi tot l'alt */
    Phaser.AUTO,  /* Renderer a fer servir (CANVAS o WEBGL) */
    '',           /* Element HTML on posa el canvas. Si no s'indica és <body>*/
    {
        init:    ferInit,     /*  Codi per inicialitzar el joc*/
        preload: ferPreload,  /*  Codi per carregar els elements gràfics*/
        create:  ferCreate,   /*  Codi per crear la situació inicial del joc*/
        update:  ferUpdate,   /*  Game Loop, codi que es repeteix a 60 FPS*/
        render:  ferRender    /*  Game Loop, després de dibuixar tots els elements*/
    }
);
Phaser permet definir diferents estats per un joc. Cada estat té els seus mètodes init, preload, create i update.
En aquest tutorial només farem servir un únic estat pel nostre joc.


Callbacks per crear un joc amb PHASER

A Phaser aquestos callback van asociats a un estat del joc. En un joc hi pot haver diferents estats (nivells). Això permet alliberar recursos i anar carregant i descarregant els elements per fases.


  • init:
    • Es crida en primer lloc al iniciar el joc.
  • preload:
    • Serveix principalment per carregar els elements gràfics. Encara no ha començat el Game Loop.
  • loadUpdate:
    • Durant preload, permetria mostrar una barra de progrés mentre es carrega el joc.
  • loadRender:
    • Durant preload, no acostuma a utilitzar-se, tot el codi es pot posar en loadUpdate. Permetria separar totalment el codi que actualitza el joc (update) del que el mostra (render).
  • create:
    • Es crida en acabar preload i abans d'iniciar el Game Loop. Permet crear tots els elements gràfics a partir dels objectes carregats en el preload. Ha de contenir tot el codi per iniciar el joc.
  • update:
    • Cridada per cada frame (per defecte 60FPS) és on hem de posar la majoria del codi del nostre joc: Capturar l'ínput de l'usuari, actualitzar la posició dels elements, comprovari si hi ha col·lisions....
  • render:
    • Cridada després de mostrar d'actualitzar el joc (CANVAS o WEBGL) i permet afegir efectes post-renderitzat. Moltes vegades s'utilitza per sobreposar informació de depuració al joc.
  • resize:
    • Només es crida en cas de modificar les dimensions del contenidor del joc, sempre que aquest s'hagi creat amb el mode RESIZE. Rep dos paràmetres: Amplada i altura del nou contenidor. Permet reposicionar els elements del joc per fer jocs responsive.
  • shutdown
    • Es crida al tancar un estat del joc, bé per acabar el joc, bé per passar a un altre estat.
Àmbit de les variables en JavaScript
(Cal aclarir-ho o ens pot donar algun bon maldecap!!!)
Global:
Local:
Bloc:
  • Variables definides amb var fora d'una funció
  • Qualsevol variable no definida esdevé global de forma implícita!!
  • MOLT amb compte! Podem modificar accidentalment variables alienes!
  • Variables definides amb var dins de qualsevol funció
  • Es pot fer servir el mateix nom en diferents funcions
  • TOTES les variables es defineixen a l'inici de la funció


  • No es poden definir variables a nivell de bloc!

var v1 = 0;    /* GLOBAL*/

function f(){
   v1=3;       /* LOCAL (definida baix)  */
   var v1 = 2; /* LOCAL amaga la V.Global */
   v2 = 3;     /* GLOBAL implícitament */
}

Step 1
/* Variables pel fons del joc*/
var fonsNebulosa, fonsPedres;
       
/* Crea el joc i associa les funcions de Callback*/
var game = new Phaser.Game(600, 800, Phaser.AUTO, '',
    {preload: ferPreload, create: ferCreate, update: ferUpdate});
        
function ferPreload(){

    /* Carrega els elements gràfics pel fons*/
    game.load.image('nebulosa', 'assets/nebulosa.png');
    game.load.image('pedres', 'assets/pedres.png');
                
}
        
function ferCreate(){

    /* Posa el fons del joc*/
    game.stage.backgroundColor = '#000000';
    fonsNebulosa = game.add.tileSprite(0, 0, 
     game.width, game.height, 'nebulosa');
    fonsPedres = game.add.tileSprite(0, 0, 
     game.width, game.height, 'pedres');
                
}
        
function ferUpdate(){
        
    /* Mou cap cap a la dreta les pedres*/
    fonsPedres.tilePosition.x += 0.5;
        
}

Carregar el fons 
i animar-lo
Previsualitzar el codi amb Brackets
  • Només funciona amb Chrome
  • Permet veure immediatament el resultat
  • Obre una nova finestra del navegador

Step 2
/* Variable per la nau*/
var nau;
        
function ferPreload(){                
  /* Carrega la imatge de la nau. Hi ha dos imatges: */
  /*una quan acelera i l'altra amb els motors apagats*/
  game.load.spritesheet('nau', 'assets/nau-x2.png', 90, 90);
}
        
function ferCreate(){                
  /* Inicialitza el motor de física ARCADE*/
  game.physics.startSystem(Phaser.Physics.ARCADE);

  /* Dibuixa la nau*/
  nau = game.add.sprite(game.width / 2, game.height / 2, 'nau');

  /* Indica el punt de referència de la nau*/
  nau.anchor.x = 0.5;
  nau.anchor.y = 0.5;

  /* Associa el motor físic amb la nau per controlar-la*/
  game.physics.enable(nau, Phaser.Physics.ARCADE);

  /* Defineix el fregament de la nau*/
  nau.body.drag.set(100);
  nau.body.angularDrag = 200;

  /* Defineix la màxima velocitat de la nau*/
  nau.body.maxAngular = 200;
  nau.body.maxVelocity.set(200);
}

Dibuixar la nau i 
associar-li el motor
de la física ARCADE
Punters amb PHASER

A Phaser hi ha diferents punters per controlar tant el ratolí com els dispositius tàctils.

  • game.input.mousePointer:
    • Sempre correspón amb el ratolí (si n'hi ha, es clar!)
  • game.input.activePointer:
    • El darrer punter actiu (es a dir, que el que ha generat el darrer event)
  • game.input.pointer1 fins game.input.pointer10:
    • Permet controlar fins a 10 punters per a jocs multi-touch. Phaser només inicialitza per defecte dos punters, si en necessitem més els hem d'iniciar natros.
    • L'ordre dels punters s'assigna seqüencialment, 1 per la primera pulsacio, i així succesivament. Si s'axeca un dit el punter queda lliure i pot ser tornat a agafar al tornar a tocar el dispositiu.

Als punters poden associar-se callbacks pels següents events. Els callback reben un paràmetre punter que és un objecte amb tota la informació sobre la posició clicada, tipus de punter, identificador....

  • onDown:
    • Al prèmer el botó dret del ratolí o prèmer un dispositiu tàctil. Només es dispara un cop, encara que premem una estona.
  • onUP:
    • Al deixàr de prèmer el botó del ratolí o el dispositiu tàctil.
  • onTap:
    • Es crida si es produeixen els events down i up dins un periode de temps.
  • onHold:
    • Es crida si es manté premut durant una estona (bastant llarga).

Tot i que en aquest exemple no ho farem servir, també es poden associar callbacks a events produits sobre un sprite o sobre un botó. Els events als que podem associar callbacks són:

  • onInputOver
  • onInputOut
  • onInputDown
  • onInputUp
  • onDragStart
  • onDragStop
Step 3
/* Variables per les tecles que controlen el joc*/
var acelerar, girarDreta, girarEsquerra, disparar;
 
function ferCreate() { 
   acelerar = game.input.keyboard.addKey(Phaser.Keyboard.UP);
   acelerar.onDown.add(function() {
       game.physics.arcade.accelerationFromRotation(
            nau.rotation, 200, nau.body.acceleration
       );
       nau.frame = 1;
   });
   acelerar.onUp.add(function() {
       nau.body.acceleration.set(0, 0);
       nau.frame = 0;
   });
   girarDreta = game.input.keyboard.addKey(Phaser.Keyboard.RIGHT);
   girarDreta.onDown.add(function() {
       nau.body.angularAcceleration = 100;
   });
   girarDreta.onUp.add(function() {
       nau.body.angularAcceleration = 0;
   });
   girarEsquerra = game.input.keyboard.addKey(Phaser.Keyboard.LEFT);
   girarEsquerra.onDown.add(function() {
       nau.body.angularAcceleration = -100;
   });
   girarEsquerra.onUp.add(function() {
       nau.body.angularAcceleration = 0;
   });
 
   /* Evita que les tecles es propaguin al navegador*/
  this.game.input.keyboard.addKeyCapture([Phaser.Keyboard.UP,
        Phaser.Keyboard.RIGHT, Phaser.Keyboard.LEFT
   ]);
}

Controlar el 
moviment de 
la nau amb 
els cursors
Step 4
function ferUpdate() {

    /* Verifica si la nau surt de la pantalla*/
    surtPantalla(nau);

}


function surtPantalla(sprite) {

    /* Comprova si surt horitzontalment*/
    if (sprite.x < 0) {
        sprite.x = game.width;
    } else if (sprite.x > game.width) {
        sprite.x = 0;
    }

    /* Comprova si surt verticalment*/
    if (sprite.y < 0) {
        sprite.y = game.height;
    } else if (sprite.y > game.height) {
        sprite.y = 0;
    }

}

Controlar la sortida de la 
nau per la pantalla, de 
forma que torni a entrar 
per la part oposada.
Step 5
function ferPreload() {
    /* Carrega la imatge de una bala*/
    game.load.image('bala', 'assets/bala.png');
}

function ferCreate() {
    /* Crea un conjunt de bales amb 30 bales*/
    bales = game.add.group();
    bales.enableBody = true;
    bales.physicsBodyType = Phaser.Physics.ARCADE;
    bales.createMultiple(30, 'bala');
    bales.setAll('anchor.x', 0.5);
    bales.setAll('anchor.y', 1);

    /* Controla la tecla per disparar*/
    disparar = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
    disparar.onHoldCallback = function (e) {
        if (game.time.now > seguentBala) {
            bala = bales.getFirstExists(false); /* Reviu una bala*/
            if (bala) {
                bala.reset(nau.body.x + (nau.body.width / 2),
                           nau.body.y + (nau.body.height / 2));
                bala.lifespan = 1000; /* Temps de vida (1seg)*/
                bala.rotation = nau.rotation;
                game.physics.arcade.velocityFromRotation(
                           nau.rotation, 400, bala.body.velocity);
                seguentBala = game.time.now + 80; /* Espera 80ms*/ 
            }
        }
    };

    /* Evita que les tecles es propaguin al navegador*/
    this.game.input.keyboard.addKeyCapture([Phaser.Keyboard.SPACEBAR]);
}

Fer que la nau dispari 
al prémer la tecla espai. 
Hi ha d'haver un nombre 
limitat de bales, i han de 
tenir un temps de vida 
fins que desapareixien, per 
evitar omplir la pantalla 
de bales. 
Cal deixar un temps entre 
bala i bala.  
Step 6
/* Variable pel conjunt d'asteroides*/
var asteroides;
/* Variable per demorar un temps fins el següent asteroide*/
var seguentAsteroide = 0;

function ferPreload() {
    /* Carrega la imatge de un asteroide*/
    game.load.image('asteroide', 'assets/asteroide.png');
}

function ferCreate() {
    /* Crea conjunt d'asteroides amb 12 asteroides*/
    asteroides = game.add.group();
    asteroides.enableBody = true;
    asteroides.physicsBodyType = Phaser.Physics.ARCADE;
    asteroides.createMultiple(12, 'asteroide');
    asteroides.setAll('anchor.x', 0.5);
    asteroides.setAll('anchor.y', 0.5);
}

function ferUpdate() {
    /* Comprova el temporitzador per crear un nou asteroide*/
    if (game.time.now > seguentAsteroide && nau.alive) {
        creaAsteroide();
    }
    /* Verifica que no surtin de la pantalla*/
    asteroides.forEachExists(surtPantalla, this);
}

function creaAsteroide() {
    var asteroide = asteroides.getFirstExists(false);
    if (asteroide) {
        /* Evita que l'asteroide surti massa prop de la nau*/
        do {
            asteroide.reset(game.rnd.integerInRange(0, game.width),
                            game.rnd.integerInRange(0, game.height));
        } while (game.physics.arcade.distanceBetween(asteroide, nau) < 100);

        asteroide.body.angularVelocity = game.rnd.integerInRange(-300, 300);
        asteroide.body.velocity.setTo(game.rnd.integerInRange(-30, 60),
                                      game.rnd.integerInRange(-30, 60));
        seguentAsteroide = game.time.now + 1000;
    }
}

Fer aparèixer un asteroide 
cada segon, controlant que 
no surti massa prop de la nau. 
Cal revisar que si l'asteroide 
surt de la pantalla torni a 
aparèixer per l'altra banda.
Step 7
/* Variable pel conjunt d'explosions*/
var explosions;

function ferPreload() {
    /* Carrega la imatge per fer una explosió*/
    game.load.spritesheet('explosio', 'assets/explosio.png', 128, 128);
}

function ferCreate() {
    /* Crea conjunt d'explosions  */
    explosions = game.add.group();
    explosions.createMultiple(12, 'explosio');
    explosions.setAll('anchor.x', 0.5);
    explosions.setAll('anchor.y', 0.5);
    explosions.forEach(function (explosio) {
        explosio.animations.add('explosio');
    }, this);
}

function ferUpdate() {
    /* Revisa les colisions entre el grup de bales i el grup d'asteroides*/
    game.physics.arcade.overlap(bales, asteroides, function (bala, asteroide) {
        /* Amaga la bala i l'asteroide*/
        bala.kill();
        asteroide.kill();
        /* Crea una explosió*/
        var explosio = explosions.getFirstExists(false);
        explosio.reset(asteroide.body.x, asteroide.body.y);
        explosio.play('explosio', 30, false, true);
        explosio.kill;
        /* Suma punts*/
        punts += 10;
    }, null, this);
}

Determinar si 
hi ha col·lisions 
bala-asteroide, i 
si n'hi ha mostrar 
una explosió i 
actualitzar la 
puntuació del joc.
Step 8

/* Variable per comptar les vides que ens queden*/
var vides = 3;

function ferUpdate() {

    /* Revisa les colisions entre nau i asteroides        */
    game.physics.arcade.overlap(nau, asteroides, function (nau, asteroide) {
        /* Fa desapareixer l'asteroide*/
        asteroide.kill();
        /* Mostra una explosió*/
        var explosio = explosions.getFirstExists(false);
        explosio.reset(asteroide.body.x, asteroide.body.y);
        explosio.play('explosio', 30, false, true);
        vides--;
    }, null, this);

}

Determinar si hi 
ha col·lisions 
nau-asteroide, i 
si n'hi ha mostrar 
una explosió i 
restar una vida.
Step 9

Mostrar la puntuació 
del joc i el nombre de 
vides restant.
var textPunts, textVides;

function ferCreate() {

    /* Afegim la informació dels punts i les vides*/
    textPunts = game.add.text(10, 10, "Punts: " + punts, {
        font: '34px Arial',
        fill: '#fff'
    });
    textVides = game.add.text(game.width-150, 10, "Vides: "+vides, {
        font: '34px Arial',
        fill: '#fff'
    });

}


function ferUpdate() {

    /* Afegim la informació dels punts i les vides*/
    textPunts.text = "Punts: " + punts;
    textVides.text = "Vides: " + vides;

}

Step 10

Aturar el joc quan 
no quedin més vides.


function ferUpdate() {
    /* Step_8 */
    /* Revisa les colisions entre nau i asteroides        */
    game.physics.arcade.overlap(nau, asteroides, function (nau, asteroide) {

        .......

        /* Step_10 */
        if (vides <= 0) {
         textEstat = game.add.text(game.world.centerX,
                                   game.world.centerY,
                                   'GAME OVER',
                                   {font: '30px Arial', fill: '#fff'}
                                  );
         textEstat.anchor.setTo(0.5, 0.5);
         asteroides.callAll('kill');
         nau.kill();
        }

    }, null, this);

}

Controls tàctils
  • Cal trobar formes senzilles i intuïtives
  • Dividirem la pantalla en dos zones
  • La zona dreta per disparar
  • La zona esquerra per controlar el moviment
Al tocar la nau dispara
L'angle amb la posició inicial
indica la direcció

La distància a la posició
inicial indica la velocitat

Depurar el codi en un dispositiu mòbil
  • Cal connectar el dispositiu mòbil per USB
  • Anar a la pàgina http://chrome://inspect/#devices
  • Escollir el dispositiu i la pestanya a monitoritzar
  • Al dispositiu acceptar la petició per depurar
  • S'obre una nova finestra chrome amb les eines de depuració

Step 11 (a)

Controls tàctils
per dispositius
mòbils!!!
/* Variables pels controls tàctils*/
var touchDreta, touchEsquerra,
    cercleEsquerra, cercleDreta
    touchEsquerraPosInicial = new Phaser.Point(0, 0);

function ferCreate() {
    /* Step_11 */
    /* Defineix els callbacks pels dispositius mòbils*/
    if (game.device.desktop === false) {
        game.input.onDown.add(function (punter) {
            if (punter.pointerMode == 3 || punter.punterMode == Phaser.PointerMode.CONTACT) {
                if (punter.positionDown.x < game.world.centerX && !touchEsquerra) {
                    touchEsquerra = punter;
                    touchEsquerraPosInicial.copyFrom(punter.positionDown);

                } else if (punter.positionDown.x > 100 /*game.world.centerY*/ && !touchDreta) {
                    touchDreta = punter;
                }
            }
        }, this);
        game.input.onUp.add(function (punter) {
            if (punter.pointerMode == 3 || punter.punterMode == Phaser.PointerMode.CONTACT) {
                if (touchEsquerra && punter.id == touchEsquerra.id) {
                    touchEsquerra = null;
                    touchEsquerraPosInicial.setTo(0, 0);
                } else if (touchDreta && punter.id == touchDreta.id) {
                    touchDreta = null;
                }
            }

        }, this);
    }
}

Step 11 (b)

Controls tàctils
per dispositius
mòbils!!!
function ferUpdate() {

    /* Step_11 */
    /* Control tàctil*/
    if (game.device.desktop === false) {
        if (cercleEsquerra) {
            cercleEsquerra.destroy();
        }
        if (cercleDreta) {
            cercleDreta.destroy();
        }
        if (touchEsquerra) {
            cercleEsquerra = game.add.graphics(0, 0);
            cercleEsquerra.lineStyle(6, 0x00ff00);
            cercleEsquerra.drawCircle(touchEsquerraPosInicial.x, touchEsquerraPosInicial.y, 40);
            cercleEsquerra.lineStyle(2, 0x00ff00);
            cercleEsquerra.drawCircle(touchEsquerraPosInicial.x, touchEsquerraPosInicial.y, 60);
            /* Moviment de la nau*/
            var distancia = touchEsquerraPosInicial.distance(touchEsquerra, true);
            var angRad = touchEsquerraPosInicial.angle(touchEsquerra);
            var angDeg = touchEsquerraPosInicial.angle(touchEsquerra, true);
            if (distancia > 10) {
                nau.rotation = angRad;
                game.physics.arcade.velocityFromAngle(angDeg, distancia * 2, nau.body.velocity);
            } 
        } else {
            nau.body.acceleration.set(0);
            nau.body.angularAcceleration = 0;
        }
        if (touchDreta) {
            cercleDreta = game.add.graphics(0, 0);
            cercleDreta.lineStyle(6, 0xff0000);
            cercleDreta.drawCircle(touchDreta.x, touchDreta.y, 40);
            cercleDreta.lineStyle(2, 0xff0000);
            cercleDreta.drawCircle(touchDreta.x, touchDreta.y, 60);
            dispararBala();
        }
    }

}


Música i sons amb PHASER

Phaser permet carregar diferents tipus de fitxers d'audio: mp3, ogg.. Ho fa mitjançant el objecte sound, que permet reproduïr audio. Al crear l'objecte hem d'indicar si volem que reprodueixi l'arxiu de forma contínua en un bucle (loop) o si només es reprodueix un cop.

 

Els principals mètodes del objecte Sound són

  • play i stop:
    • Inicia o atura la reproducció
  • pause i resume:
    • Pausa o segueix la reproducció
  • restart:
    • Resitua el punter de l'arxiu a l'inici
  • fadeIn i fadeOut:
    • Inicia o atura la reproducció amb un increment/decrement progressiu del volum

Les principals proietats del objecte Sound són:

  • volume:
    • Propietat que permet ajustar el volum de reproducció
  • mute:
    • Permet silenciar o  donar volum a la reproducció
Step 12

Afegir Sons:
-Música de fons
-Accelerar
-Explosions
/* Sons del joc*/
var musica_sound, accelera_sound, explota_sound;

function preload() {
    /* Carrega els sons*/
    game.load.audio('musica', 'assets/musica.ogg');
    game.load.audio('accelera', 'assets/thrust.ogg');
    game.load.audio('explosio', 'assets/explosio.ogg');
}

function create() {
    /* Crea els elements d'audio */
    musica_sound = game.add.audio('musica', 0.5, true);
    accelera_sound = game.add.audio('accelera', 1, true);
    explosio_sound = game.add.audio('explosio');

    /* Step_3 */
    /* Controla les tecles que gestionen el moviment de la nau */
    acelerar = game.input.keyboard.addKey(Phaser.Keyboard.UP);
    acelerar.onDown.add(function () {
        if (!accelera_sound.isPlaying) {
            accelera_sound.play();
        }

    });
    acelerar.onUp.add(function () {
        accelera_sound.stop();
    });
    /* Inicia la reproducció del fons musical */
    musica_sound.play();
}

function ferUpdate() {
    /* Step_7 */
    /* Revisa les colisions entre el grup de bales i el grup d'asteroides */
    game.physics.arcade.overlap(bales, asteroides, function (bala, asteroide) {
        explosio_sound.play();
    }, null, this);


    /* Hem de fer el mateix al Step_8 */

}
To Do...
  • Mostrar les vides com un grup de imatges de la nau
  • Afegir una vida al fer un cert nombre de punts
  • En acabar, permetre reiniciar el joc prement una tecla
  • Mostrar una pantalla de benvinguda a l'inici del joc
  • En acabar, aturar les accions tàctils, música...
  • Crear diferents gràfics pels asteroides i mostrar-los
  • Al tocar un asteroide gros mostrar-de dos de petits
  • Incrementar progressivament la dificultat
  • Registrar les puntuacions màximes
  • ...
ASTEROIDS

Fes servir l'espai o les fletxes dels cursors per navegar