martes, 28 de enero de 2014

Introducción a CakePHP (I)

CakePHP es un framework que pretende facilitarnos la vida programando en php. Por poner un ejemplo, se ha terminado el hacer consultas a la base de datos...
Insisto en este artículo, que el propósito de este blog no es más que plasmar mis propias anotaciones sobre los sistemas que ensayo, aunque siendo conocedor que no voy a ser el único que se aproveche de ello, me gusta darle apariencia de tutorial y dirigirme a un posible público como 'profesor' simplemente como diversión y porque me gusta escribir.
Aclarado esto, una vez me he metido en harina en este sistema que estoy probando, me he dado cuenta que el tutorial es un absoluto desastre, por lo que lo voy a reescribir a mi manera.

Instalación

1.- Descargamos CakePHP de la página oficial y lo descomprimimos.
2.- Ahora crearemos una carpeta que llamaremos por ejemplo /cake20 en la raíz de nuestro servidor web (ya sea un hosting en la red o un servidor web en nuestro PC como EasyPHP)
3.- Copiamos o subimos al servidor los archivos descomprimidos en la carpeta que hemos creado anteriormente.
4.- Creamos una base de datos.
5.- Configuramos la base de datos en CakePHP.
Para ello nos dirigimos a la carpeta /app/Config y copiamos el fichero database.php.default y lo renombramos simplemente como database.php.
Editamos el fichero y configuramos la base de datos:
public $default = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => 'localhost',
    'port' => '',
    'login' => 'cakeBlog',
    'password' => 'c4k3-rUl3Z',
    'database' => 'cake_blog_tutorial',
    'schema' => '',
    'prefix' => '',
    'encoding' => ''
);
 6.- Configuramos la encriptación, más que nada porque si no CakePHP se quejará.

Editamos el fichero core.php que se encuentra en la carpeta /app/Config.

Buscamos la línea Configure::write('Security.salt', 'pl345e-P45s_7h3*S@l7!'); y cambiamos la parte que he marcado en fosforito por la cadena de caracteres que nos de la gana.

Así mismo buscamos Configure::write('Security.cipherSeed', '7485712659625147843639846751'); y cambiamos los números por otra numeració cualquiera.

Y con esto ya hemos acabado.

Como funciona CakePHP

Pues funciona sólo. De hecho, en el manual se habla varias veces de la magia de CakePHP y en ocasiones parece que sea así.
De hecho para saber lo que tiene que hacer CakePHP usa una serie de convenciones en la nomenclatura y la estructura de carpetas y lo veremos con un ejemplo: una lista de artículos (o lo que viene a ser un blog)

Así que lo primero que haremos será rellenar la base de datos con tres artículos para probar. Así que usando nuestro gestor de base de datos (p. ej. PhpMyAdmin) ejecutaremos los siguientes comandos:

/* tabla para nuestros artículos */
CREATE TABLE articulos (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(50),
    body TEXT,
    created DATETIME DEFAULT NULL,
    modified DATETIME DEFAULT NULL
);

/* algunos valores de test */
INSERT INTO articulos (title,body,created)
    VALUES ('El título', 'Esto es el cuerpo del artículo.', NOW());
INSERT INTO articulos (title,body,created)
    VALUES ('Un título otra vez', 'Y sigue el cuerpo del artículo.', NOW());
INSERT INTO articulos (title,body,created)
    VALUES ('El título vuelve', 'Esto es realmente excitante! No?', NOW());

Pues bien, aquí viene la primera convención. Fijaos que hemos llamado a la tabla articulos en minúscula. Es más si hubiera sido nombre compuesto la hubiéramos llamado en minúscula y con un underscore ( _ ) entre palabras.

Esta tabla podríamos considerar que es una entidad, un objeto o como llama CakePHP, un modelo.

Los modelos se nombran en mayúscula y en singular y se guardan en la carpeta /app/model. En nuestro caso tendríamos un fichero llamado Articulo.php en esa carpeta. En ese archivo tendremos la declaración del modelo y sus validaciones.

Sólo por usar esa nomenclatura, CakePHP supondrá que en la carpeta /app/Controller, tendremos un fichero llamado ArticulosController.php. Como podemos imaginar, este tipo de objeto se llamará genéricamente controlador y gestionará la lectura y escritura de los datos.

Finalmente necesitaremos un formato de salida en pantalla, un template para entendernos. Sin embargo, no necesitaremos el mismo si mostramos una tabla para seleccionar un registro o el registro en sí, de lo que deduciremos que podremos tener varios. Estos archivos, que llamaremos vistas, llevan extensión '*.ctp' y se alojan en la carpeta /app/View/Nombre_controlador. En nuestro caso /app/View/Articulos/  (Artículos en plural). Los archivos con extensión '*.ctp' pueden tener cualquier nombre.

Con estas 4 cosas y unas pocas líneas de código, podemos desarrollar un mantenimiento CRUD completo. Pero esto, ya lo iremos viendo...

La importancia de las convenciones

Como ya se ha apuntado si seguimos una rígida normativa, CakePHP hará muchas cosas por nosotros.
La normativa para los modelos es que se escriben en singular y en UpperCamelCase si son compuestas.
La normativa para las tablas de la base de datos es que se ecriben en plural y con underscores ( _ ) en lugar de espacios si son compuestas.

Esto significa que si tenemos un modelo llamado Articulo, CakePHP manejará automáticamente la tabla articulos, y si tenemos un modelo llamado ArticuloLargoCakePHP gestionará automáticamente la tabla articulo_largos. (Sí, ya se que en la lengua de Espronceda queda un poco raro, pero hay que hacer un esfuerzo)

Pero aún hay más! Si nuestra tabla tiene el campo name o title las usará como etiquetas en ciertas ocasiones (manda title sobre name) y si tenemos creados los campos created o modified se estamparán las fechas automáticamente! Y es más! (aunque yo no lo he conseguido) pero en principio si el campo id es de tipo int, se rumorea que CakePHP lo gestiona también y si es de tipo char(36) gestiona un identificador UUID)

Y eso es todo por ahora...  hasta la próxima.

lunes, 20 de enero de 2014

CraftyJS - Viewport (I) o cómo posicionar la cámara.

Aunque en principio parezca más propio de los juegos en 3D, el viewport no es más que la cámara que filma la acción. Para ver su funcionamiento acudiremos a un ejemplo que se consta de:
  1. Un helicóptero como protagonista  (Éste)
  2. Una ventana de juego de 480 x 320 píxeles.
  3. Una foto que actuará de fondo de 4608 x 3072 píxeles. (O sea, ésta)
Como os habréis dado cuenta, la foto es mucho más grande que la ventana. Esto lo he ideado así, para que se vea el desplazamiento real del helicóptero. Sobre un fondo monocromático no apreciaríamos visualmente el movimiento.

Si ahora montamos el fondo y el helicóptero sobre la imagen, veremos algo así. Como veis, la foto sale cortada porque no cabe.


Como es algo que a estas alturas ya sabemos hacer, no publico el código aquí, aunque lo podéis ver en funcionamiento junto con el código aquí.

Posicionar la cámara sobre la entidad.

Si ahora movemos el helicóptero a la posición 1000, 1000:

avion = Crafty.e('2D, Canvas, Fourway, avion')
.attr({
   x: 1000,
   y: 1000,
   w: 244,
   h: 982
   })
.fourway(4);

Es fácil imaginar que éste saldrá de pantalla y no lo veremos. Ésto lo podemos subsanar moviendo la cámara sobre el helicóptero, y es más, lo podemos hacer de forma inmediata o aplicando un lapso de tiempo.

Para ello utilizaremos la siguiente instrucción:

Crafty.viewport.centerOn(avion, 10000);

Si os habéis fijado antes al crear la entidad, la he asignado a una variable (avion) que la identifica entre otras instancias. Cuando centro la cámara, lo hago usando la variable.

El siguiente parámetro es el número de milisegundos que tardará la cámara en posicionarse sobre el objetivo (haciendo una especie de travelling). Evidentemente si ponemos un cero, la cosa será inmediata.

Podéis ver un ejemplito de ésto junto al código aquí.  Como la imagen es muy grande se puede perder parte del efecto, así que cuando haya cargado todo, pulsad [F5] para forzar la recarga de la página con la imagen ya en caché.


NOTA: En CraftyJs 6.0.2. esto deja de funcionar. Para subsanarlo debéis buscar la línea:
ctx.setTransform(view._scale, 0, 0, view._scale, view._x*view._scale, view._y*view._scale);
y substituirla por:
ctx.setTransform(view._scale, 0, 0, view._scale, Math.floor(view._x*view._scale), Math.floor(view._y*view._scale));


Follow the lider, lider, lider...

El siguiente paso es de cajón, que la cámara siga al helicóptero durante su movimiento. Como mantenemos quieto el fondo, el resultado será un efecto de scroll.

Para conseguir este efecto usaremos la siguiente instrucción:

Crafty.viewport.follow(Objeto, desplazamiento_x, desplazamiento_y)

El primer parámetro es como en el comando centerOn el nombre de la variable en la que se ha instanciado el objeto que queremos seguir.

Los siguientes parámetros indican el desplazamiento del objeto respecto a la cámara (que siempre estará en el centro).

Por ejemplo, mientras Crafty.viewport.follow(avion, 0, 0) dejaría la cámara sobre el helicóptero ( y en consecuencia éste quedaría centrado como en la imagen de arriba del todo de este artículo),  una instrucción del tipo  Crafty.viewport.follow(avion, 100, 100)  dejaría la imagen así:



Crafty.viewport.follow(avion, -100, -100) así:


Recordad que podéis trastear con todo esto Aquí.



viernes, 3 de enero de 2014

CraftyJS - Sonido

Para finalizar nuestro juego sólo nos queda ponerle sonido, cosa muy sencillita y que hará que este capítulo sea muuuy cortito.

Crafty.audio

Con esta clase podremos reproducir archivos de tipo mp3, ogg y WAV.   Es más, podemos incluso cargar los tres formatos simultáneamente para evitar problemas de compatibilidad. Es decir, yo podría tener el sonido de una moneda repicando y cargarlo así:

Crafty.audio.add("coin", [
"sounds/coin.mp3",
"sounds/coin.ogg",
"sounds/coin.wav"
]);

En nuestro ejemplo en particular, tendremos un par de archivos en de sonido que llamaremos desde la escena principal de carga:

Crafty.scene('Loading', function(){
 ...
  Crafty.load(function(){
  ...
Crafty.audio.add({
coin: ['assets/coin.wav'],
hymn: ['assets/hymn.mp3']
});

  Crafty.scene('Game');
  })
});

Ciertamente podríamos haber sido más finos y preguntar antes de cargar si nuestro sistema soportaba el formato con Crafty.audio.supports("mp3") que nos devolvería verdadero si el navegador es capaz de reproducir el tipo de archivo indicado o falso en caso contrario.

Cuando queramos escuchar el archivo de sonido pulsamos el play:

Crafty.audio.play('hymn');

Y cuando queramos detener la reproducción el stop:

Crafty.audio.play('stop');

Si no vamos a usar más el sonido y queremos detener la reproducción liberando además memoria en el navegador podemos usar:  Crafty.audio.remove("hymn").

Y con esto ya hemos terminado esta parte y de hecho el tutorial de introducción a CraftyJS.

Sólo nos quedaría ver cómo queda nuestro juego ya con sonido pulsando aquí, descargar los fuentes aquí o aquí y despedirnos hasta otra.

Que seáis mu felices.

martes, 10 de diciembre de 2013

CraftyJS: Animación del movimiento

IMPORTANTE: Los métodos de animación en CraftyJS cambiaron a partir de la versión 0.6, con lo que este artículo es sola válido a partir de dicha versión (y hasta nuevo cambio)  :-)

En el artículo anterior ya habíamos finalizado nuestro laberinto, sólo nos quedaba el detalle del personaje principal que era un cuadrito amarillo y que ahora substituiremos por un personaje animado.

Esto implica que tendremos una serie de frames (al que llamaremos reel) que crearán los efectos de movimiento a la derecha, izquierda ,arriba y abajo. Para ello cargaremos el mapa de sprites con el que ya habíamos trabajado en el artículo anterior y cogeremos el frame que queremos que muestre nuestro personaje al aparecer en pantalla (antes de moverse):

Crafty.sprite(32, 'assets/furniman.png', { ladron:        [00]  });




Ya podemos imaginar que con el mapa de sprites anterior crearmos cuatro reels que irán cambiando cuando cambie la dirección de nuestro personaje. Por lo que lo primero que tenemos que preguntarnos es ¿Cómo saber hacia que dirección se mueve nuestro prota?

NewDirection

De esto no hemos hablado, pero CraftyJS lanza una serie de eventos que podemos interceptar mediante el comando .bind.  Cuando una entidad que usa el componente Fourway (o multiway) cambia de dirección, lanza el evento global NewDirection que interceptaremos y al que le preguntaremos hacia qué lado vamos.
Este evento devuelve una clase con los atributos x e y cuyo signo puede ser positivo y negativo.

Todo esto lo definiremos en nuestro componente:

Crafty.c('Personaje', {
    init: function() {
       
   this.bind('NewDirection', function(direccion) {
  
         if (direccion.x > 0) {this.animate('derecha',    -1);} else
        if (direccion.x < 0) {this.animate('izquierda',  -1);} else
         if (direccion.y > 0) {this.animate('abajo',       -1);} else
        if (direccion.y < 0) {this.animate('arriba',      -1);} 
        else {this.pauseAnimation();}
      })
}); 

Vemos que este trozo de código es harto intuitivo.  Si vamos a la derecha, animamos la derecha, si vamos a la izquierda animamos la izquierda... y si no nos movemos, detenemos la animación. Si no hiciéramos esto nuestro muñeco seguiría moviéndose a pesar de estar parado.  O_o

Decir que animate lo que hace es crear un 'reel' (o serie de frames) para la animación de ese componente y definir el número de veces que imprimirá la secuencia. (Es fácil imaginar que -1 significa hasta el infinito y más allá). - Jolín, mira que me repatea la gente que dice esa gilipollez y ahora estoy yo aquí con lo mismo -).

El caso es que tenemos el reel, pero el reel no tiene nada...

Reel

Un reel básicamente lo que debería contener es una secuencia de frames que conforman la animación. (vamos, el concepto del zoótropo).

Sintaxis:

.reel( nombre, duración, posX, posY, númeroDeFrames)
  • La duración se expresa en milisegundos.
  • La posX y posY son la fila y columna que ocupa el primer frame (fila y columna relativa, medida en frames y no es píxeles.  (más datos aquí)
  • El número de frames es eso. Los cogerá de manera secuencial. (Si ponemos este parámetro en negativo iremos marcha atrás).
Así que ahora que crearemos la entidad, le indicaremos que es una animación de sprites, definiremos su imagen de inicio (definida anteriormente al cargar el mapa)  y daremos contenido a los reel.

    Crafty.e('2D, Canvas, Fourway, SpriteAnimation, Personaje, ladron)
     .attr({ x: 100, y: 10, w: 32, h: 32 })
     .fourway(4)
     .reel('arriba',     500, 0, 0, 2)
     .reel('abajo',      500202)
     .reel('derecha',  500, 2, 1, 2)
     .reel('izquierda', 500, 0, 1, 2);

Fijaos que le hemos dicho a Crafty que la entidad que estamos creando tiene el comportamiento SpriteAnimation y que su Sprite antes de moverse es el que habíamos definido para ladrón.

Y ya no necesitamos nada más... nuestro muñeco se moverá ahora con plena libertad...

Veamos como queda aquí.

El código es éste:




Y es más... veamos como quedaría todo esto si lo aplicamos a nuestro juego del laberinto aquí.
Además podemos bajarnos el código aquí o aquí



lunes, 25 de noviembre de 2013

CraftyJS: Sprites

Mmm... creo que el tutorial se está haciendo muy farragoso y al final no se entenderá nada, así que voy a tratar el contenido de este tema de manera independiente: El fantabuloso mundo de los

Sprites

Retomemos nuestro laberinto, pero ahora démosle color:


Como veis he dividido el mapa en cuadritos (que corresponden con el array que definíamos aquí). Como veis cada cuadrado tiene un dibujo que es una simple imagen (jpg, png...).  Pues bien, el dibujo en sí mismo, es lo que llamamos sprite. En la imagen sólo sale el escenario, pero es fácil deducir que nuestro personaje será también un sprite o una sucesión de ellos para crear el efecto de la animación.

Mapa de Sprites

Hemos dicho que los sprites son archivos gráficos que podemos cargar uno a uno o bien todos de golpe metidos en un archivo. Al contenido del archivo le llamaremos mapa de sprites y será algo de este tipo (tan grande como queramos):



Crafty.sprite

En CraftyJS la sintaxis para definir un sprite es esta:

Crafty.sprite( tamaño de la celdafichero, {mapa}, interespaciado)

Tamaño de la celda (opcional):

Medido en pixels, podemos darle sólo la anchura (x) o bien la anchura y la altura (x,y). Esto implicará que a la hora de definir el mapa nos referiremos a él en posición absoluta o relativa, ejemplo:

Como se indica, este parámetro es opcional. Si no definimos el tamaño, y quisiéramos referirnos al cofre en el ejemplo de arriba deberíamos acceder a la posición [64,64] (teniendo en cuenta que cada celda es de 32x32 pixels). Si definimos el tamaño (32,32) accederemos al cofre en la posición [2,2]. (La primera posición es el 0).

Por otro lado vemos que podemos especificar sólo la anchura (en cuyo caso se asumirá que la celda es cuadrada) o la anchura y la altura, lo que sugiere que aunque es menos habitual las celdas no tienen porque ser cuadradas.

Fichero: No tiene más historia. La ruta en la que se encuentra nuestro sprite o mapa de sprites.

Mapa:  Aquí está el meollo de la cuestión. El formato es:

 {nombre del mapa: [columna, fila, ancho, alto]}

Ejemplo para acceder al cofre sin haber definido tamaño de celda:
       Crafty.sprite('/dir/nombrefich.ext', {cofre: [64,64,32,32]});

Ejemplo para acceder al cofre habiendo definido tamaño de celda:
      Crafty.sprite(32,'/dir/nombrefich.ext', {cofre: [2,2]});

Ejemplo para acceder a todos los dibujos de Rajoy habiendo definido tamaño de celda:
 
     Crafty.sprite(32,'/dir/nombrefich.ext', {rajoyx8: [0,0,4,2]});      

 NOTA: Cuidadito aquí, aunque hemos cogido 8 casillas, estas se redimensionarán al tamaño de nuestra entidad que puede ser de 32x32 o cualquier otro tamaño.

Ejemplo para coger varios sprites a la vez:
     Crafty.sprite(32,'/dir/nombrefich.ext',{
            arriba:[0,0],
            abajo: [2,0],
            dcha:  [2,1],
            izda:   [0,1]
     });


Interespaciado: (opcional). Definimos interespaciado como el espacio que hay entre celda y celda, vamos, algo así como el margen. Podemos definir sólo las x o bien las x,y. Si no ponemos nada se asumirá que es 0. Si no ponemos las y se asumirá que coincide con las x.

Y oiga, ¿Todo esto como se usa?

Es muy sencillo. Al fin y al cabo, lo que arriba hemos denominado 'nombre del mapa'  no es más que un componente, así que, como tal, se usa.

    Crafty.e('2D, Canvas, Fourway, cofre')
      .attr({
              x: 100,
              y: 10,
              w: 100,
              h: 100
            });

Un ejemplito por el amor de dios...


Si queréis ver como queda, se podría ver aquí. Notad que aunque el tamaño de las celdas del mapa de sprites sea de 32x32, nuestro componente es de 100x100.

Si aterrizáis por primera ve por aquí quizá deseéis saber cómo ejecutar esto.

Retomando el juego...

Ahora vamos a trasladar todo esto a nuestro juego y vamos a seguir desde aquí.

Tomaremos el mapa de sprites que hay al principio de este documento y lo guardaremos en la carpeta /assets con el nombre de furniman.png. 

Ahora sólo debemos cargarlo y asignar cada sprite a un componente que será usado cuando creemos las entidades. ¿Y dónde lo haremos? ¿Recordáis la escena 'Loading' que espera a que esté todo cargado para iniciar el juego?

Crafty.scene('Loading', function(){

  Crafty.e('2D, DOM, Text')
    .text('Cargando...')
    .attr({ x: 110, y: 140 })
    .textFont({size:'13px'});

  Crafty.load(['assets/furniman.png'], function(){

   Crafty.sprite(32, 'assets/furniman.png', {
spr_muro:   [0, 2],
        spr_suelo:   [1, 2],
spr_tesoro: [2, 2]
    });
  Crafty.scene('Game');
  })
});

Ahora haremos que en el fichero de los componentes, éstos hereden los sprites que hemos definido, sin embargo si recordáis, teníamos entidades para los muros, pues nos interesaba que se detectara la colisión contra ellos, pero no teníamos nada para el suelo. Ahora el suelo deberá tener un dibujito y por tanto también tendrá que ser una entidad. 

Crafty.c('MuroMarron', {
   init: function( ) {
      this.requires('Actor, Pared, spr_muro');
  },
});

Crafty.c('Suelo', {
   init: function( ) {
      this.requires('Actor, spr_suelo');
  },
});

Crafty.c('Tesoro', {
  init: function() {
    this.requires('Actor, spr_tesoro')
  },
 
  /* ...  */

});

Ya sólo queda pintarlos en la escena del juego. Fijaos especialmente en el tesoro que cuando lo cojamos y desaparezca debajo tendrá que tener un suelo!!!

Crafty.scene('Game', function() {

// Colocamos cada cosa en su lugar
  for (var x = 0; x < mapa[0].length; x++) {
    for (var y = 0; y < mapa.length; y++) {
        
      if (mapa[y][x]==0) {  Crafty.e('Suelo').en(x,y);             }        
      if (mapa[y][x]==1) {  Crafty.e('MuroNegro').en(x,y);    }
      if (mapa[y][x]==2) {  Crafty.e('MuroMarron').en(x,y);  }

      if (mapa[y][x]==3) {
         Crafty.e('Suelo').en(x,y);
         Crafty.e('Tesoro').en(x,y);
       }
    }
  }

//Colocamos el personaje principal en el mundo.
 Crafty.e('Politico').en(1, 8);

});

Y con esto ya lo tenemos todo!

Si queréis ver el resultado pinchad aquí.
Si queréis bajaros los fuentes pinchad aquí o aquí

miércoles, 20 de noviembre de 2013

Apuntes de Fonaments físics de la informàtica (UOC)

Actualizado Enero 2017

Sí, lo sé.  Mis apuntes están de puta madre. Sin embargo esta vez voy a compartir unos que empiezan muy bien, pero que flojean en el último tema: 'òptica i fotónica'.  La verdad es que iba tan apurado de tiempo que tuve que dedicarme al escaneo manual con boli y libreta de apuntes, y sinceramente... eso paso de colgarlo.


El caso es que os comparto los documentos de 'Fonaments físics de la informàtica' (05.611del 'Grau d'Enginyeria Informàtica' de la UOC (Universitat Oberta de Catalunya), por si queréis aprovecharlos. De hecho, no estaría mal que si alguien los completa, me los comparta aquí para que pueda colgarlos. Supongo que lo agradeceríamos todos. La verdad es que bastante gente se descarga mis apuntes, lo cual me llena de una hondo orgullo y satisfacción y ruptura de cadera.




Además podéis descargaros PAC's de la asignatura aquí

También exámenes resueltos aquí

Por cierto, si queréis colaborar en tener un buen repositorio para la asignatura, mandadme vuestras PAC's y Exámenes corregidos y los iré incluyendo en beneficio de los futuros estudiantes.

Debéis mandar un correo a   furnimanQUITAESTO@terra.com  (evidentemente quitando el QUITAESTO) :-)

jueves, 7 de noviembre de 2013

CraftyJS - Escenas

En este punto, podríamos decir que ya hemos programado todo nuestro juego. Sin embargo es un poco triste, que después de sufrir financiando nuestro partido, una vez lo consigamos no salga ni un triste mensaje.

Una solución sería poner un mensaje felicitándonos sobreimpresionada. Esto ya lo sabemos hacer, lo vimos aquí, pero sería más elegante tener una pantalla nueva.

Los juegos se componen de menús, pantallas y créditos. Incluso hay juegos que las pantallas difieren mucho unas de otras (tanto que pueden ser un juego nuevo). Es cada uno de estos casos estamos hablando de:

Escenas

Así pues, vamos a dividir lo que teníamos hecho en tres escenas:
  • Una inicial de carga por si nuestro juego tarda mucho en cargarse y que ya os anuncio que ni la vamos a ver...   :-)
  • La propia pantalla del juego
  • La pantalla de fin de juego, albricias y felicitaciones.
Estas escenas las crearemos en un fichero nuevo llamado scenes.js que NO deberemos olvidar incluir en nuestro index.html:

<!DOCTYPE html>
<html>
<head>
    <script src="lib/crafty.js"></script>
    <script src="src/game.js"></script>

    <script src="src/componentes.js"></script>

    <script src="src/scenes.js"></script>
    <script>
       window.addEventListener('load', Game.start);
    </script>
</head>
<body>
</body>
</html>

Pantalla Final

Yo creo que con esto queda la escena autoexplicada:

Crafty.scene('Victory', function() {

//Ponemos el texto
  Crafty.e('2D, Canvas, Text')
    .attr({ x: 10, y: 150 })
    .textFont({size:'13px'})
    .text('Felicidades! Has conseguido financiar tu partido!');
  this.restart_game = this.bind('KeyDown', function() {
// Llamamos a la escena del juego
      Crafty.scene('Game');
  });
}, function() {
    this.unbind('KeyDown');
});

Como se puede intuir esto pone el mensaje y espera a que se pulse una tecla para mandarnos a la escena 'Game'.

----------------------------

Pantalla 'Game'

// Escena principal 'Game':  Crea las entidades del mapa y del político.

Crafty.scene('Game', function() {

// Colocamos cada cosa en su lugar
  for (var x = 0; x < mapa[0].length; x++) {
    for (var y = 0; y < mapa.length; y++) {
            
      if (mapa[y][x]==1) {
          Crafty.e('MuroNegro').en(x,y);
      }
      
      if (mapa[y][x]==2) {
         Crafty.e('MuroMarron').en(x,y);
      }

      if (mapa[y][x]==3) {
         Crafty.e('Tesoro').en(x,y);
       
      }
    }
  }

//Colocamos el personaje principal en el mundo.
    Crafty.e('Politico').en(1, 8);
});

Como se ve, aquí dibujamos el mapa y plantamos el personaje en el mismo. No tenemos nada más que hacer ya que todos los comportamientos están definidos en las entidades.

----------------------------

Pantalla Loading...

Crafty.scene('Loading', function(){
  Crafty.e('2D, DOM, Text')
    .text('Cargando...')
    .attr({ x: 110, y: 140 })
    .textFont({size:'13px'})

  Crafty.scene('Game');
});

Y esta es la pantalla de carga que no veremos nunca...  :-)

___________________________________________________________________

Victoria!!!!

Hay un tema que queda pendiente. Y es cómo llamamos a la escena de victoria. 

Aquí vimos como hacer que el tesoro se destruyera al pasar por encima de él. Lo que haremos ahora será preguntar si queda algún tesoro y si no queda ninguno llamaremos a la escena de victoria. Por lo tanto modificaremos el componente Tesoro en el fichero componentes.js.

Crafty.c('Tesoro', {
  init: function() {
    this.requires('Actor, Color')
        .color('yellow');
  },
    
  recogido: function() {
     this.destroy();

     // Si no queda ningún tesoro ya hemos terminado.
     if (!Crafty('Tesoro').length) {  
Crafty.scene('Victory');
     }  
  } 
});

__________________________________________________

Código completo

Sólo queda explicar el fichero inicial game.js.  Lo único que hace es definir el tamaño del canvas y llamar a la escena 'Loading'. Hago en él una cosa rara y es sacar fuera la tabla del mapa como global, para que se a accesible también desde el fichero de escenas, ya que la escena 'Game' la usa. Ya se que no es muy ortodoxo, pero es lo que tiene saltomatacaballear.




Ah se me olvidaba...  si queréis ver como queda....  PINCHAD AQUÍ!!!!