lunes, 10 de junio de 2013

CraftJS: Componentes

*NOTA PREVIA:  En este capítulo se usa el término herencia muy a la ligera. Se ruega a los puristas del léxico que miren sólo los dibujitos y no lean el texto.

*NOTA PREVIA 2:  He observado que la plataforma que he escogido para alojar el código: Github, funciona de pena con el Chrome. A pesar de que según las estadísticas de visita a mi blog, la mayoría usáis Chrome, os recomiendo que de momento y hasta que alguien lo solucione, uséis el Explorer para verlo bien, o que pulséis sobre el enlace view rar que encontraréis bajo el código. 

En el capítulo anterior, creamos una serie de entidades que eran muy parecidas, de hecho sólo cambiaba el color:

Crafty.e('2D, Canvas, Color')
  .attr({
     x: x * Game.anchoCelda,
     y: y * Game.altoCelda,
     w: Game.anchoCelda,
     h: Game.altoCelda,
  })
  .color('black');
Crafty.e('2D, Canvas, Color')
  .attr({
     x: x * Game.anchoCelda,
     y: y * Game.altoCelda,
     w: Game.anchoCelda,
     h: Game.altoCelda,
  })
  .color('brown');

Componentes

Vamos a sacar factor común (como en mates) de estas dos entidades y las meteremos dentro de un componente llamado rejilla que define sus propiedades y/o comportamientos.

Crafty.c('Rejilla'', {
   init: function( ) {
      this.attr({
         x: x * Game.anchoCelda,
         y: y * Game.altoCelda,
         w: Game.anchoCelda,
         h: Game.altoCelda
     })
   }
 }) ;

Con esto podemos crear otros componentes que 'hereden' las propiedades de 'Rejilla':

Crafty.c('MuroNegro', {
   init: function( ) {
      this.requires('2D, Canvas, Rejilla, Color');
      this.color('black');
  },
});
Crafty.c('MuroMarron', {
   init: function( ) {
      this.requires('2D, Canvas, Rejilla, Color');
      this.color('brown');
  },
});

Es más... podemos volver a sacar factor común (lo llamaremos Actor):

Crafty.c('Actor', {
   init: function( ) {
      this.requires('2D, Canvas, Rejilla, Color');
    },
});

Crafty.c('MuroNegro', {
   init: function( ) {
      this.requires('Actor, Color');
      this.color('black');
  },
});
Crafty.c('MuroMarron', {
   init: function( ) {
      this.requires('Actor, Color');
      this.color('brown');
  },
});

Con lo que ya podemos crear nuestra entidad 'heredando' del componente Muro:

Crafty.e('MuroNegro');

Cada cosa en su fichero

Ya tenemos el código, sólo nos queda meter los componentes en un fichero llamado componentes.js, guardarlo en nuestra carpeta de fuentes (/src) y llamarlo en nuestro index.html.
Esto acarrea un problema y es que perdemos las referencias a las variables x e y que usa el componente 'Rejilla', así que debemos modificar el componente para que las pueda recibir como parámetro:

Crafty.c('Rejilla'', {
   init: function( ) {
      this.attr({
         w: Game.anchoCelda,
         h: Game.altoCelda
     })
   },
   en: function(x, y) {
      this.attr({ x: x * Game.anchoCelda, y: y * Game.altoCelda });
      return this;
   }
 });

Y lo llamaremos así:

Crafty.e('MuroNegro').en(x,y);

Veamos el código completo cada cosa en su sitio:

Sobra decir que el resultado que obtendremos es el mismo que el capítulo anterior.

Algunas consideraciones sobre los componentes

  • Las propiedades o métodos que empiezan con guión bajo se consideran privadas.
  • El método llamado init se ejecutará en el momento que añadamos el componente a la entidad.
  • Un método con el mismo nombre del componente se considerará un constructor y se usa para pasar datos.
  • A pesar de que hemos dicho que los métodos con guión bajo se consideran privados, no es más que una convención. Esto será así mientras el método sea un valor, pero si trabajamos con objetos o arrays, JavaScript tratará el objeto por referencia y en consecuencia se modificará para todos los componentes en los que se haya heredado.
 

viernes, 31 de mayo de 2013

Apunts d'Anàlisi Matemàtica (UOC)

A tenor del aumento que están teniendo las descargas de mis apuntes de Álgebra, (será porque llegan los exámenes), os comparto también los apuntes  (en lengua catalana) que corresponden a la asignatura d'Anàlisi Matemàtica (05.558) del 'Grau d'Enginyeria Informàtica' de la UOC (Universitat Oberta de Catalunya).

Espero que le valgan a alguien!   :-)

Descargar en formato PDF
Descargar en formato MSWord

Si optáis por la descarga en formato Word, pensad que se abrirá una sesión del Google Docs, que entre otras cosas es incompatible con las fórmulas de Word y no se verán. Se soluciona descargando el archivo.

Si no usáis MS Office, descargaros el PDF o tendréis el mismo problema.


También podéis descargaros PACs de años anteriores aquí 
exámenes aquí .    (Actualizado Otoño 2015)

También existen exámenes de Matemáticas II con contenido común aquí , y PACs de la misma 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, 30 de mayo de 2013

CraftyJS: Un juego típico en 2D

Los juegos en dos dimensiones, ya sea un Arkanoid, un Comecocos o un juego de naves, se resuelven dividiendo la pantalla en una rejilla que servirá de base para localizar los elementos de nuestro juego.

Quizá el ejemplo más gráfico sea un laberinto. La idea es tener una matriz que describa cada celda de nuestra rejilla.

Tomemos el ejemplo de este laberinto apto para cualquiera de nuestros dirigentes:


Podemos ver que hay 3 tipos de celdas:

Una celda tipo 0, que será el suelo, o la nada si lo queréis llamar así.
Una celda tipo 1, que serán los muros exteriores.
Una celda tipo 2, que serán las paredes interiores del laberinto.

A efectos prácticos, el juego reaccionará de la misma manera en una celda tipo 1 y tipo 2, es decir, no dejará pasar a nuestro personaje. Sin embargo, el dibujo será distinto y de ahí, su diferenciación.

La matriz

Ya nos ha quedado claro que nuestro laberinto quedará definido por una matriz, así que intuitivamente haríamos lo siguiente:

  var mapa = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                      [1, 0, 2, 2, 0, 2, 0, 2, 2, 1],
                      [1, 0, 0, 2, 0, 2, 0, 0, 0, 1],
                      [1, 2, 0, 2, 0, 2, 2, 2, 0, 1],
                      [1, 2, 0, 0, 0, 0, 0, 2, 0, 1],
                      [1, 2, 2, 2, 0, 2, 0, 2, 0, 1],
                      [1, 0, 0, 0, 0, 2, 0, 2, 0, 1],
                      [1, 0, 2, 2, 0, 2, 0, 2, 0, 1],
                      [1, 0, 2, 2, 0, 2, 0 ,0 ,0, 1],
                      [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];

Pero reflexionemos ahora realmente que posiciones representan estos elementos en la tabla:

[0][0]   [0][1]   [0][2]   [0][3]   ...
[1][0]   [1][1]   [1][2]   [1][3]   ...
[2][0]   [2][1]   [2][2]   [2][3]   ...
   ...         ...          ...         ...

Si representamos intuitivamente las posiciones de la tabla por las coordenadas (x,y), vemos que las horizontales vienen representadas por las 'y'  y las verticales por las 'x'. Es decir, justo al contrario de lo que hemos intuido.

¿Cómo podemos resolverlo?

Podemos montar la matriz cambiando filas por columnas, o podemos hacer lo mismo matemáticamente con un procedimiento que calcule la matriz traspuesta (que es como se llama en matemáticas cambiar filas por columnas), o bien podemos ser mucho más guarros y hacer lo que haremos en el ejemplo:
Nos olvidaremos del detalle de que las filas y columnas están invertidas y programaremos el algoritmo como si las horizontales fueran las 'x' y las verticales las 'y', y en el momento de coger el valor de la matriz lo cogeremos como tabla[y][x], en lugar de tabla[x][y].
Ejemplo:
  for (var x = 0; x < número de columnas; x++) {
    for (var y = 0; y < número de filas; y++) {
      if (mapa[y][x]==1) {
        
            Pintamos una entidad de tipo muro exterior;

     }
   }
 }

Como que desde el momento que pintamos la celda esta adquiere un entidad propia, ya no volveremos a leer la matriz y no tendremos que volver a hacer cosas extrañas, ya que desde este punto las 'x' serán 'x' y las 'y' serán 'y'.

El canvas

El canvas es el tápiz en el que dibujaremos nuestro laberinto. El primer paso que tenemos que hacer es definir su tamaño. (Aquí lo podeis ver con más detalle). ¿Pero cuál es ese tamaño? Lo podemos deducir de la matriz.

Para ello declararemos dos propiedades que definan el tamaño de la celda:

anchoCelda : 32,
altoCelda : 32,

Así pues la anchura del cavas será el número de columnas del mapa * anchoCelda y su altura el número de filas del mapa * altoCelda.
Teniendo en cuenta que en Javascript las matrices como tal no existen si no que son arrays de arrays, el número de filas (o largo) del mapa, es el número de elementos del array, y el número de columnas (o ancho) del mapa, es el número de elementos de cualquiera de los arrays (por ejemplo el 0).

var anchoCanvas = mapa[0].length * Game.anchoCelda;
var largoCanvas = mapa.length * Game.altoCelda;

Colocando las celdas

Con todo lo anterior tenemos una matriz de 10 x 10 elementos (o celdas) para colocar sobre un tapiz (o canvas) de 320 x 320. ¿Cómo hallar las 'x' y las 'y' efectivas?  Pues multiplicando la posición de la matriz por el ancho o el alto de la celda.

Así pues:

mapa[0][0]  :   x =  0 * 32  ,   y = 0 * 32  
mapa[0][1]  :   x =  0 * 32  ,   y = 1 * 32
mapa[4][3]  :   x =  4 * 32  ,   y = 3 * 32

Notad que estoy obviando en el planteamiento lógico la transposición de la matriz como hemos dicho que haríamos.

El algoritmo

Con todo esto ya estamos en disposición de presentar el código:

Esto nos dará el siguiente resultado:


¿A que es una maravilla?

NOTA:

  1. Para ejecutar este programa debemos tenes un .html que lo llame. Lo podéis ver aquí.
  2. Si el tema de las entidades os ha sonado a chino, aquí se intenta explicar.






miércoles, 22 de mayo de 2013

CraftyJS: Entidades

Una entidad es cualquier cosa que exista en nuestro juego y que tenga un comportamiento de cualquier tipo, aunque sólo sea visualizarse. Es decir, todo lo que no sea la imagen de fondo de pantalla será seguramente una entidad.

Para crear una entidad, Crafty tiene un evento que se llama simplemente e.

Veámoslo:

Crafty.e

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

¿Qué hace esto?

Esto nos crea una entidad en las coordenadas (100,10) de nuestro canvas o lienzo, con una dimensión 100 x 100 (o sea un cuadrado) y lo pinta de azul.

Realmente sólo la primera línea del código anterior pertenece a e. Esa línea crea una entidad a la que añade los componentes 2D, Canvas y Color. Un componente especifica un conjunto de datos y comportamientos que se pueden aplicar a una o más entidad. Es más, un componente puede requerir que exista otro componente previo y pueden ofrecer comportamientos combinados, pero eso ya lo iremos viendo.

El caso es que .attr es un método del componente 2D que inicializa sus propiedades.

Entre ellas tenemos x e y, que posicionan en nuestro canvas la esquina superior izquierda de nuestra entidad. La posición (0,0) del canvas está también en la esquina superior izquierda. La x es la componente horizontal y aumenta hacia la derecha. La y es la componente vertical y aumenta hacia abajo.
 
w es el ancho de la entidad y h su altura.


NOTA: También existe una componente z (cosa rara trabajando en 2D). Su única función es que cuando dos entidades se superponen, quien tenga la z mayor, se mostrará sobre el resto.

Otras de las propiedades de 2D son:

alpha: Indica la transparencia de una entidad. Toma un valor decimal comprendido entre 0.0 que es transparente y el 1.0 que es totalmente opaco.
 
rotation: Provoca que la entidad gire un número de grados determinado sobre su punto (x,y), es decir, sobre su esquina superior izquierda. (El punto de rotación puede cambiarse pero ya se verá). La rotación se efectúa en sentido de las agujas del reloj, si bien podemos poner valores negativos.
 
visible: Exactamente eso. Puede tomar los valores TRUE y FALSE.

Por último, como veréis en el ejemplo, el color puede definirse también dando la descomposición RGB.
 
 Veamos ahora el ejemplo:


Este código generará esta maravilla de ilustración:

 
Os recuerdo que para ejecutar este código debéis instalar Crafty y llamar el código desde un .html.
Los pelos y señales los encontrareis aquí.



martes, 21 de mayo de 2013

Crafty: Desarrollo de juegos en HTML5 y Javascript

Parece que después de años de reinado de Flash en los juegos de navegador, se empieza a imponer el HTML5 gracias a los dispositivos móviles que no soportan Flash.
 
Esto me ha despertado la curiosidad y he hecho un pequeño estudio del tema. Lo que más me ha llamado la atención ha sido la multitud de 'frameworks' o librerías en Javascript para facilitar el desarrollo de juegos en esta plataforma. Podéis ver unos cuantos aquí.
 
El caso es que después de estudiármelos todos el que más me ha llamado la atención es Crafty.
 
Y ¿por qué?  Porque es gratuito, tiene bastante documentación y parece bastante sencillito.

Vamos a probarlo:

Instalación de CraftyJS


1.- Nos bajamos CraftyJS de su página. Click aquí.

2.- Creamos una carpeta en nuestro disco.

3.- Por convención, dentro de nuestra carpeta creamos otras tres.

\assets     Donde colocaremos los archivos multimedia que utilicemos en nuestro desarrollo.
\lib           Ahí irá la librería de Crafty que nos acabamos de bajar.
\scr           Aquí irán nuestros fuentes.

4.- Copiamos la librería de Crafty en la carpeta \lib.

Y ya está!

Nuestro primer programa


1.- Creamos un fichero que se llame game.js en nuestra carpeta de fuentes. ¿Recordamos cuál es? Sí, muy bien \scr.

2.- Copiamos el siguiente código dentro de game.js

Game = {
   // Inicializa y arranca nuestro juego
   start: function() {
   // Inicia crafty y establece un color de fondo para que podamos ver que funciona
   Crafty.init(480, 320);
   Crafty.background('green');
   }
}

Analicemos esto:

Ésto es una clase que se llama game, en la que definimos una propiedad llamada start que inicializamos mediante una función.
 
Esta función, inicializa Crafty dando el tamaño del canvas o lienzo sobre el que ejecutaremos nuestro programa.
 
3.- Pero todo corre en una página web, con lo que tendremos que tener un html que soporte esto. Crearemos un archivo index.html en la carpeta raíz que hemos creado y le copiaremos el siguiente código:

<!DOCTYPE html>
<html>
<head>
    <script src="lib/crafty.js"></script>
    <script src="src/game.js"></script>
    <script>
       window.addEventListener('load', Game.start);
    </script>
</head>
<body>
</body>
</html>

Aquí lo que hacemos es cargar nuestras librerías, tanto la de crafty como la de nuestro código y cargamos nuestra clase Game llamando a su propiedad start.

Hemos de terminar viendo esta maravilla:

lunes, 29 de abril de 2013

Android Manifest (IV) - etiqueta activity

En la parte III del estudio del archivo manifest.xml, vimos la etiqueta 〈application〉 y terminamos referenciando a la ayuda para ampliar información.

Pues bien, en la ayuda pudimos ver que la etiqueta 〈application〉 podía contener las siguientes subetiquetas: 
  • 〈activity〉
  • activity-alias
  • 〈service〉
  • 〈receiver〉
  • 〈uses-library〉     
  En esta entrada nos ocuparemos de la

Etiqueta 〈activity〉

Cuando habíamos creado nuestro proyecto, si no le hemos dado otro nombre, se nos habrá creado una actividad principal llamada MainActivity.

Desde el mismo manifest.xml, en la pestaña Application, podemos configurar sus propiedades:



Estas modificaciones se trasladarán al fichero '.xml', dentro de la etiqueta <Activity>:


android:name especifica el nombre de la actividad. En el ejemplo ponemos todo el nombre completo, aunque podíamos haber puesto sólo .MainActivity ya que tenemos el nombre del package definido más como atributo del elemento manifest.

android:label también lo tenemos definido en la etiqueta Application. Concretamente, el contenido de este atributo aparecerá en la barra de título de la actividad si la tuviera. También se usará en el lanzador de la aplicación si definimos esta actividad como el punto de entrada de nuestra aplicación. En el ejemplo usamos app_name del archivo strings.xml, aunque podíamos haber usado un string puro entre comillas, P.ej: "Mi actividad". Si no lo definimos, se utilizará el label definido en la etiqueta <application>.

android:screenOrientation define la orientación de la aplicación - portrait o landscape (apaisado) -. Si no definimos este atributo, se usará el que el dispositivo tenga predeterminado, incluido el variable en función del acelerómetro. Cuando la pantalla cambia de orientación la actividad se destruye y eso en un juego, no queremos que suceda.


android:configChanges: En Android, el cambio de orientación o la aparición del teclado se considera un cambio de configuración, lo que hace que la pantalla se redibuje para adaptarse a los cambios. En este atributo definimos los eventos que queremos manejar nosotros con el fin de evitar que se destruya la actividad. Los diferentes efectos se separan con la barra vertical o Pipe ( | )

SubEtiqueta 〈intent-filter〉

Podemos ver como la etiqueta activity tiene una subetiqueta llamada <intent-filter>.


En Android no existe un único punto de entrada para nuestra aplicación. Podemos iniciarla a través de múltiples activities o services que pueden ser iniciados a partir de intents específicos que puede enviar el sistema u otra aplicación. Para decir a Android ante qué intent debe reaccionar y cómo, existe el <intent-filter>.

Si los palabros que acabo de utilizar te suenan a chino mandarín, a menos que seas chino pulsa aquí.
  • Con el elemento <action>, estamos indicando que esta activity va a ser un punto de entrada para nuestra aplicación. Sólo puede haber una  activity que reaccione a este intent.
  • Con elemento <category> le decimos a Android que queremos que esta activity sea añadida al lanzador de la aplicación. Pueden haber varias activities que reaccionen a este intent.
De esta manera Android sabe que al ser pulsado el icono de la aplicación, debe iniciar esta activity. 

Si no hubiéramos establecido el <intent-filter>, esta activity sólo se podría llamar desde dentro de la aplicación.

Fijémonos que ambos elementos sólo tienen el atributo name siendo su valor el nombre del intent.

Y hasta aquí esta entrada. Como siempre referenciaros al vídeo original de Jesús Conde, del que estoy tomando estas anotaciones.