lunes, 10 de diciembre de 2012

Ejecutar una función al cargar la página

Buenas a todos!!
Ejecutar una función al cargar la página puede ser de gran utilidad, sobretodo en páginas que requieren cargar recursos al principio, realizar llamadas ajax o cachear elementos del DOM.

<html>
<head>
<title>Función que se ejecuta al inicio</title>
</head>
<body>
    <div id='c'></div>

    <script type="text/javascript">

        var div_c;
        function init() {

             //Carga de recursos
             //Cacheo de variables
             div_c = document.getElementById("c");

             //Peticiones AJAX
        }
     
        window.onload = init;
         
    </script>
</body>
</html>


En el código anterior defino una función init(), que será la que se ejecutará al cargarse la página, para conseguir esto es tan simple como:

window.onload = init;

Un saludo a todos!


Cambiar el contenido de un DIV

Buenas a todos!!
Para cambiar el contenido de un DIV de forma dinámica, lo más fácil es modificar el contenido del atributo innerHTML del elemento div.

 <html>
<head>
<title>Div</title>
</head>
<body>
    <div id='c'></div>
 

    <script languaje="JavaScript">
        var divContainer = document.getElementById("c");
        function init() {
            divContainer.innerHTML = "Nuevo contenido en del div!";
        }

       
        window.onload = init;
       
    </script>
</body>
</html> 


En el código anterior tenemos un div con id "c".
Por si quisieramos cambiar el contenido del div varias veces, creamos la variable 'divContainer' que guardará en memoria la instancia del elemento div, así no tendremos que buscar en el DOM del documento HTML el elemento con id "c", cada vez que queramos cambiar o consultar su contenido.

var divContainer = document.getElementById("c");

Ahora simplemente hemos creado una función init(), que se ejecutará cuando el contenido del documento HTML haya sido cargado por completo en el navegador.

window.onload = init;

Como podéis ver solamente hace falta asignar al atributo innerHTML el nuevo String que contendrá el div.

divContainer.innerHTML = "Nuevo contenido en del div!";

Para cambiar en una sola línea el contenido de un div, es tan simple como lo siguiente:

document.getElementById("c").innerHTML = "Cambiar contenido en el div";

El string que asignamos puede contener tags html, con esto tenemos la posibilidad de insertar nuevos elementos en un div, o dar estilo al texto:

document.getElementById("c").innerHTML = "Cambiar contenido </br> en el div";

Eso es todo!! Un saludete!

miércoles, 31 de octubre de 2012

Compatibilidad con el Canvas


Buenas a todos!!
Comprobar la compatibilidad del navegador con el Canvas es muy simple:

<html>
   <head><title>Compatibilidad canvas</title></head> 
   <body>
   <canvas id='c'>Canvas no soportado!</canvas>
   <script languaje="JavaScript">
      var canvas;
      var ctx;
      var WIDTH = 480;
      var HEIGHT = 320;
      function init() {
         canvas = document.getElementById('c');
         if(canvas.getContext){
            canvas.width = WIDTH;
            canvas.height = HEIGHT;
            ctx = canvas.getContext('2d');
            ctx.fillStyle = '#73CC00';
            ctx.beginPath();
            ctx.rect(0, 0, WIDTH, HEIGHT);
            ctx.closePath();
            ctx.fill();
         }else{
            alert("Canvas no soportado!");
         }
      }
      window.onload = init;
      </script>
   </body>
</html>

Cuando recogemos un elemento <canvas>, si comprobamos que contiene la función getContext, entonces significa que es compatible, en caso contrario el navegador no da soporte al canvas.


canvas = document.getElementById('c');
if(canvas.getContext){
   //Soporta el canvas
}else{
   //No soporta el canvas
}

El texto que incluimos entre los tags <canvas>, será visible en caso de que el navegador no de soporte al canvas.

<canvas id='c'>Canvas no soportado!</canvas>

Así de fácil! Un saludete!

martes, 21 de agosto de 2012

HTML5 - Eventos en el canvas

Hola a todos!!
En el siguiente tutorial vamos a crear una clase llamada EventManager. Esta clase nos permitirá recoger los eventos del ratón y táctiles generados sobre el canvas.

La idea principal es tener una instancia accesible desde cualquier punto de la aplicación, y que contenga los datos referentes a la entrada del ratón o táctil.
No nos limitaremos a tener definida la clase EventManager, vamos a instanciarla para poder utilizarla desde los listeners de los eventos.
Los listeners serán funciones globales que registraremos en el canvas.

Función constructora de EventManager

function EventManager(){
  this.touchdown = 0;
  this.touchup = 0;

  this.canX;
  this.canY;
  this.canvas;
  this.currentEvents = [mouseDown,

                        mouseXY,
                        touchDown,
                        touchXY,
                        touchUp,
                        mouseUp,
                        touchUp];
}


touchdown: si es 1 indicará que se está presionando el botón del mouse o la pantalla, si es 0 lo contrario.
touchup: si es 1 indicará que acaba de dejarse de presionar el botón del mouse, la duración de este estado haremos que sea de 1 iteración.
canX: es un número entero que contiene la coordenada x donde está situado el mouse o el dedo. (píxeles)
canY: es un número entero que contiene la coordenada y donde está situado el mouse o el dedo. (píxeles)
canvas: contiene una referencia al elemento del dom <canvas>.
currentEvents: es un array que contiene las referencias de las funciones globales que registraremos como listeners de eventos del canvas.

[Para los que no estéis familiarizados con la creación de clases en javascript revisad mi tutorial!]

La instancia que crearemos se llamará EM, la crearemos de la siguiente forma:
var EM = new EventManager();

Creación de los Event Listeners

Los events listeners son funciones que registramos en el canvas para que se disparen al darse determinados eventos. Estas funciones son las que modifican las propiedades de la instancia EM, cambiando las coordenadas del mouse y el estado del click (touchdown, touchup).

function mouseUp() {
  EM.touchup = 1;
  EM.touchdown = 0;
  mouseXY();
}

function touchUp() {
  EM.touchup = 1;
  EM.touchdown = 0;

  touchXY();
}

function mouseDown() {
  EM.touchup = 0;
  EM.touchdown = 1;
  mouseXY();
}

function touchDown() {
  EM.touchup = 0;
  EM.touchdown = 1;
  touchXY();
}

function mouseXY(e) {
  EM.canX = e.pageX - EM.canvas.offsetLeft;
  EM.canY = e.pageY - EM.canvas.offsetTop;
}

function touchXY(e) {
  e.preventDefault();
  EM.canX = e.targetTouches[0].pageX - EM.canvas.offsetLeft;
  EM.canY = e.targetTouches[0].pageY - EM.canvas.offsetTop;
}


Al llamar al constructor de EventManager, almacenamos las referencias a estas funciones en la instancia EM dentro del array EM.currentEvents.

Registrar un event listener en el canvas

Para registrar un event listener en el canvas, emplearemos la función addEventListener.
Esta función requiere 3 parámetros:

canvasElement.addEventListener( DOMString type,  
                                EventListener listener, 
                                boolean useCapture);

type: mediante un String indicamos que tipo de evento será el que dispare la función.
Los siguientes tipos de eventos son equivalentes, unos responden al mouse y a entradas táctiles.
  "mousedown" = "touchstart"
  "mousemove" =  "touchmove"
  "mouseup" = "touchend"

listener: es la función que se ejecutará al dispararse el evento indicado.
useCapture: si es true, el event listener se dispara en la fase de captura del evento, si es false se dispara en la fase de destino y propagación del evento. Yo siempre los empleo como false.

Para eliminar un event listener del canvas, tenemos la función removeEventListener, que admite los mismos parámetros que addEventListener.

Para facilitar el registro y eliminación de event listeners, vamos a añadir dos funciones al prototipo de nuestra clase EventManager.


EventManager.prototype.addEventsListeners = function(){
  this.canvas.addEventListener("mousedown", this.currentEvents[0], true);
  this.canvas.addEventListener("mousemove", this.currentEvents[1], false);
  this.canvas.addEventListener("touchstart", this.currentEvents[2], false);
  this.canvas.addEventListener("touchmove", this.currentEvents[3], true);
  this.canvas.addEventListener("touchend", this.currentEvents[4], false);
  document.body.addEventListener("mouseup", this.currentEvents[5], false);
}

EventManager.prototype.removeEventsListeners = function(){
  this.canvas.removeEventListener("mousedown", this.currentEvents[0], false);
  this.canvas.removeEventListener("mousemove", this.currentEvents[1], false);
  this.canvas.removeEventListener("touchstart", this.currentEvents[2], false);
  this.canvas.removeEventListener("touchmove", this.currentEvents[3], true);
  this.canvas.removeEventListener("touchend", this.currentEvents[4], false);
  document.body.removeEventListener("mouseup", this.currentEvents[5], false);
}


Estas funciones emplean la referencia al canvas actual que gestiona la instancia EM y las referencias a las funciones event listener que hemos almacenado en el array currentEvents.
Gracias a estas funciones podremos activar y desactivar los eventos sobre nuestro canvas de forma sencilla.

Activar eventos:
EM.addEventsListeners();

Desactivar eventos:
EM.removeEventsListeners();

Comprobar si se está pulsando el mouse o si se ha dejado de pulsar

Ahora tenemos una instancia EM, mediante los event listeners se actualizan las propiedades de esta instancia, las coordenadas del mouse y si se está presionando o si se acaba de dejar de presionar.
Ahora necesitamos dos funciones que faciliten al usuario controlar si se han dado eventos o no.

EventManager.prototype.isTouchDown = function(){
return (this.touchdown == 1);
}

EventManager.prototype.isTouchUp = function(){
if(this.touchup == 0) return false;
else{
this.touchup = 0; return true;
}
}


Ambas funciones retornan un valor booleano, es decir, true o false.
El funcionamiento de isTouchDown es muy simple! mientras el ratón se está presionando o mientras se mantiene presionada la pantalla la propiedad touchdown adquiere el valor 1, y isTouchDown() retornará true, de otro modo retornará false.

El funcionamiento de isTouchUp está pensado para que cuando dejemos de hacer click o justo cuando levantemos el dedo de la pantalla, si comprobamos si esto acaba de ocurrir llamando a isTouchUp() esta función indique true, pero si inmediatamente volvemos a comprobarlo, la función nos dirá false. Así conseguimos que únicamente el estado isTouchUp dure una iteración, y no que sea un estado que se alargue durante todo el rato que no estemos presionando el botón del mouse.

El código completo de la clase EventManager y los event listeners

Para tener el código más ordenado aconsejo que tengáis este código en un fichero javascript separado, llamado EventManager.js:


function EventManager(){
  this.touchdown = 0;
  this.touchup = 0;
  this.currentEvents =  

                [mouseDown,mouseXY,touchDown,touchXY,touchUp,mouseUp,touchUp];
  this.canX;
  this.canY;
  this.canvas;
}

EventManager.prototype.addEventsListeners = function(){
  this.canvas.addEventListener("mousedown", this.currentEvents[0], true);
  this.canvas.addEventListener("mousemove", this.currentEvents[1], false);
  this.canvas.addEventListener("touchstart", this.currentEvents[2], false);
  this.canvas.addEventListener("touchmove", this.currentEvents[3], true);
  this.canvas.addEventListener("touchend", this.currentEvents[4], false);
  document.body.addEventListener("mouseup", this.currentEvents[5], false);
}

EventManager.prototype.removeEventsListeners = function(){
  this.canvas.removeEventListener("mousedown", this.currentEvents[0], false);
  this.canvas.removeEventListener("mousemove", this.currentEvents[1], false);
  this.canvas.removeEventListener("touchstart", this.currentEvents[2], false);
  this.canvas.removeEventListener("touchmove", this.currentEvents[3], true);
  this.canvas.removeEventListener("touchend", this.currentEvents[4], false);
  document.body.removeEventListener("mouseup", this.currentEvents[5], false);
}

EventManager.prototype.isTouchDown = function(){
  return (this.touchdown == 1);
}

EventManager.prototype.isTouchUp = function(){
  if(this.touchup == 0) return false;
  else{ this.touchup = 0; return true; }
}

/*************EVENT LISTENERS***************/
function mouseUp() {
  EM.touchup = 1;
  EM.touchdown = 0;
  mouseXY();
}

function touchUp() {
  EM.touchup = 1;
  EM.touchdown = 0;
  touchXY();
}

function mouseDown() {
  EM.touchup = 0;
  EM.touchdown = 1;
  mouseXY();
}

function touchDown() {
  EM.touchup = 0;
  EM.touchdown = 1;
  touchXY();
}

function mouseXY(e) {
  EM.canX = e.pageX - EM.canvas.offsetLeft;
  EM.canY = e.pageY - EM.canvas.offsetTop;
}

function touchXY(e) {
  e.preventDefault();
  EM.canX = e.targetTouches[0].pageX - EM.canvas.offsetLeft;
  EM.canY = e.targetTouches[0].pageY - EM.canvas.offsetTop;
}

var EM = new EventManager();


Fijaros que al final incluyo la creación de la instancia EM!

Ejemplo de utilización

Lo más importante es que durante la fase de inicialización del juego configuremos la instancia correspondiente del elemento canvas y activemos el registro de los event listeners.

function init() {
  can = document.getElementById("c");
  ctx = can.getContext("2d");
  can.width = 400;
  can.height= 350;
  EM.canvas = can;
  EM.addEventsListeners();

  setInterval(gameLoop, 1000/15);
}


Una vez configurado el objeto EM y activados los event listeners, ya podemos en nuestro bucle de juego capturar los eventos:

if(EM.isTouchUp()) {
  alert(EM.canX + " , " + EM.canY);
}


El código anterior, comprueba si se acaba de hacer click sobre el canvas y nos muestra un alert con las coordenadas donde se hizo click.
Del mismo modo haríamos lo mismo para detectar si se está pulsando el canvas, empleando isTouchDown().


Eso es todo! Ha sido un tutorial realmente largo, espero que todo haya quedado claro.
Esta implementación pertenece a la librería que he desarrollado y espero que os sea útil o que os de ideas para gestionar vuestros eventos sobre el canvas.

La clase es susceptible de muchas ampliaciones, como por ejemplo el soporte para pantallas multitouch, o el guardado de una secuencia de coordenadas para implementar caminos o gestos, podéis extenderla y adaptarla a vuestras necesidades!

Un saludete!!

miércoles, 8 de agosto de 2012

HTML5 - Sprite

Buenas a todos!
En este tutorial vamos a crear una clase Sprite animado, que nos permitirá incluir objetos animados sobre  nuestro canvas.
Un sprite es un mapa de bits 2D, que contiene un conjunto de elementos que queremos pintar. Estos elementos pueden ser por ejemplo, todos los fotogramas de una animación en concreto, texto estático que queremos mostrar, objetos que queremos ir repitiendo en un escenario, backgrounds, etc.
Para vuestros sprites, os recomiendo que uséis el formato .PNG, ya que os permite tener transparencias, son ficheros que ocupan relativamente poco y sobretodo porque es ampliamente soportado por la mayoría de librerías, plataformas y software de edición gráfica.

La imagen que vamos a emplear para el tutorial es la siguiente: "spriteRun.png"

El resultado que obtendremos es el siguiente:

Creación de la clase Sprite Animado

Para los que no estéis familiarizados con la creación de clases en JavaScript os recomiendo que os leáis mi tutorial "Classes in javascript", si tenéis cualquier duda no dudéis en preguntar!

Para tener el código más ordenado, os recomiendo que guardéis el siguiente código en un fichero .js, en el ejemplo, "SpriteAnimated.js". Si tenéis dudas de como vincular este fichero a vuestro html podéis ver el tutorial "Vincular un archivo javascript externo".

function SpriteAnimated(img, frameArray, loop, x, y){ 
  this.img = img; 
  this.frameArray = frameArray;
  this.currentFrame = 0;
  this.loop = loop;
  this.x = x;
  this.y = y;
  this.width = this.frameArray[this.currentFrame][2];
  this.height = this.frameArray[this.currentFrame][3];
}

SpriteAnimated.prototype.update = function(){ 
  ctx.drawImage(
      this.img
      this.frameArray[this.currentFrame][0],
      this.frameArray[this.currentFrame][1],      
      this.frameArray[this.currentFrame][2],
      this.frameArray[this.currentFrame][3], 
      this.x
      this.y
      this.width,
      this.height); 

  if(this.currentFrame == (this.frameArray.length-1)){ 
    if(this.loop) this.currentFrame = 0; 
  }else{ 
    this.currentFrame++; 
  } 


El código anterior hace lo siguiente:
Define una clase llamada SpriteAnimated, los parámetros que recibe a través de su constructor son:
- img : objeto de tipo Image.
- frameArray : array bidimensional que contiene las coordenadas de cada uno de los fotogramas que componen la animación, dentro de la imagen "img".
      Por ejemplo:
                                   [ [0,0,32,41] , [32,0,32,41] , [64,0,32,41] ]
            Este frame array contiene 3 fotogramas,
            cada fotograma es representado por un array que indica la sección de la imagen
            que vamos a recortar, indicando las coordenadas 'x' e 'y',
            y el ancho y el alto a recortar.
            El formato para definir un fograma es el siguiente: [ x, y, ancho, alto ]
- loop: tipo booleano, true o false, nos indica si la animación se repetirá al finalizar o el sprite se quedará parado en el último fotograma.
- x: indica la coordenada x del canvas donde se pintará el sprite. En píxeles.
- y: indica la coordenada y del canvas donde se pintará el sprite. En píxeles.

Además de estos parámetros he añadido las propiedades width y height, que indican el tamaño con el que se pintará el sprite.

Una vez definida la clase Sprite, he añadido a su prototipo el método 'update()', este método es el que utilizaremos para pintar el sprite.
Lo primero que hace la función 'update()' es llamar al método del context 'drawImage' pasándole por parámetro la imagen del Sprite y los parámetros que determinan que sección de la imagen debe pintarse, y con qué posición y tamaño debe mostrarse esa sección de imagen.
Los parámetros que determinan la sección de imagen correspondiente al fotograma que queremos mostrar,  se encuentran almacenados como un array de 4 elementos, dentro del frameArray que contiene todos los fotogramas.
Los parámetros que indican la posición en la que se pintará la imagen, son las propiedades 'x' e 'y' del SpriteAnimated. Y los parámetros que indican el tamaño con el que se mostrará el sprite, son las propiedades 'width' y 'height'.


  ctx.drawImage(
      this.img
      this.frameArray[this.currentFrame][0],
      this.frameArray[this.currentFrame][1],      
      this.frameArray[this.currentFrame][2],
      this.frameArray[this.currentFrame][3], 
      this.x
      this.y
      this.width,
      this.height); 


El fragmento de código que sigue al pintado, primero comprueba si hemos llegado al último fotograma de la animación, es decir, si hemos llegado al último elemento del frameArray. En caso afirmativo, comprueba si la variable loop es true, en caso de que sea true reinicia el currentFrame a 0 para que la animación se repita indefinidamente.
En el caso de que no estemos en el fotograma final de la animación, el currentFrame se incrementa, para que en la siguiente iteración se muestre el siguiente fotograma almacenado en el frameArray.


  if(this.currentFrame == (this.frameArray.length-1)){ 
    if(this.loop) this.currentFrame = 0; 
  }else{ 
    this.currentFrame++; 
  }


Utilización de la clase Sprite Animado

Ha llegado la hora de empezar a ver como se mueve esto!! Recordad que debéis incluir en la cabecera de vuestro html, el SpriteAnimated.js que contiene la declaración de la clase!

<script type="text/javascript" src="SpriteAnimated.js"></script>


El código del tutorial es como sigue a continuación:


<canvas id="c" style="position: relative;"></canvas>
<script languaje="JavaScript">
  var WIDTH = 300;
  var HEIGHT = 50;
  var can;
  var ctx; 

  var man_img = new Image();
  man_img.src = "spriteRun.png";
  var man_fa = [[0,0,32,41],[32,0,32,41],[64,0,32,41],[96,0,32,41],[128,0,32,41], 
        [160,0,32,41],[192,0,32,41],[224,0,32,41],[256,0,32,41],[288,0,32,41],
        [320,0,32,41],[352,0,32,41],[384,0,32,41],[416,0,32,41]];
  var man_sp;

  function init() {
     can    = document.getElementById("c");
     ctx    = can.getContext("2d");
     can.width   = WIDTH; 
     can.height   = HEIGHT;
     man_sp = new SpriteAnimated(man_imgman_fatrue16,5);
     man_sp.width = 32;
     man_sp.height = 41;
     setInterval(gameLoop, 1000/15);
  } 

  function gameLoop(){
     ctx.clearRect(0, 0, WIDTH, HEIGHT);
     man_sp.update();
  }

  window.onload = init;

</script>


El fragmento de código anterior incluye la creación de un objeto de tipo Image, que contiene la imagen de nuestro sprite. Seguidamente declaramos el frameArray, que contiene las coordenadas de recorte de los fotogramas del sprite.
En la función init, invocamos el constructor de nuestra clase SpriteAnimated, pasándole la imagen, el frameArray, el comportamiento tipo bucle (true), y la posición del canvas donde queremos que se pinte.

man_sp = new SpriteAnimated(man_imgman_fatrue16,5);

Como podéis ver, las propiedades de los objetos SpriteAnimated que vais creando, pueden ser modificadas en cualquier momento, en este ejemplo modifico el tamaño del sprite.


 man_sp.width = 32;
 man_sp.height = 41;


Para que la animación no sea excesívamente rápida he programado que se ejecute el gameLoop, a 15 fotogramas por segundo, 15fps, mediante la siguiente instrucción:

setInterval(gameLoop, 1000/15);

Finalmente en cada iteración del gameLoop se ejecuta la función update del objeto "man_sp" de tipo SpriteAnimated, que es la encargada de pintar en pantalla el sprite.

man_sp.update();

La función anterior al pintado del sprite, pinta sobre el fotograma anterior un rectángulo blanco, para limpiar el canvas y que no se muestren los fotogramas del sprite uno sobre otro. Os invito a quitarla y ver lo que ocurre!!

ctx.clearRect(0, 0, WIDTH, HEIGHT);

Hasta aquí el tutorial! Espero que os sirva de gran ayuda y que os animéis a añadir mejoras a vuestra clase SpriteAnimated, como métodos que gestionen pausar la animación, dar soporte a múltiples animaciones, normalizar el tamaño y coordenadas, etc.  La clase que hemos programado es completamente funcional y os servirá como base para hacer clases más complejas de este tipo.

Voy a ir posteando nuevos tutoriales sobre la creación de videojuegos en HTML5, si estáis interesados será un placer que os suscribáis al blog! Y cualquier duda no dudéis en preguntar!
Un saludo a todos!!

martes, 7 de agosto de 2012

HTML5 - Pintar una imagen en el canvas

Buenas a todos!
Para pintar una imagen en el Canvas en HTML5, únicamente tenemos que tener una instancia del contexto perteneciente a un Canvas concreto, y una instancia de un objeto Image:

<canvas id='c'></canvas>
<script languaje="JavaScript">
  var can;
  var ctx;  

  var backgroundStars_img = new Image();
  backgroundStars_img.src = "back_stars.png";  

  function init() {
    can          = document.getElementById("c");
    ctx          = can.getContext("2d");
    can.width    = 480;
    can.height   = 320;
    ctx.drawImage(backgroundStars_img,0,0,480,320,0,0,480,320);      
  }  

 window.onload = init;

</script>
  
Las imágenes que estamos empleando para el tutorial son las siguientes:
"back_stars.png" y "ovnis.png"


 
Cuando queremos pintar varias imágenes sobre el canvas, tenemos que tener en cuenta que el orden de pintado es el orden en el que llamamos a la función drawImage, es decir, si queremos pintar un background y luego objetos sobre ese background. Primero deberemos pintar el background y luego ir pintando los objetos sobre éste.

<canvas id='c'></canvas>
<script languaje="JavaScript">
  var can;
  var ctx;  

  var backgroundStars_img = new Image();
  backgroundStars_img.src = "back_stars.png";

  var ovniVerde_img = new Image();
  ovniVerde_img.src = "ovnis.png"; 
  

  function init() {
    can          = document.getElementById("c");
    ctx          = can.getContext("2d");
    can.width    = 480;
    can.height   = 320;
    ctx.drawImage(backgroundStars_img,0,0,480,320,0,0,480,320);      

    ctx.drawImage(ovniVerde_img,0,0,148,59,324,91,79,31);
  }  

 window.onload = init;

</script>
El resultado del código anterior es el siguiente:

Si os fijáis, la imagen "ovnis.png", contiene 2 ovnis, uno naranja y uno verde, pero únicamente hemos pintado el primer ovni.
Esto es debido a que la función drawImage nos permite seleccionar la sección que queremos pintar de una imagen concreta.

     drawImage(img,sx,sy,swidth,sheight,x,y,width,height);

img: es una instancia de un objeto de tipo Image que contiene la imagen a pintar.
sx: es la coordenada x dentro de la imagen a partir de la que empezamos a recortar.
sy: es la coordenada y dentro de la imagen a partir de la que empezamos a recortar.
swidth: el ancho en píxeles del recorte que haremos a la imagen.
sheight: el alto en píxeles del recorte que haremos a la imagen.
x: la coordenada x dentro del canvas donde pintaremos la imagen.
y: la coordenada y dentro del canvas donde pintaremos la imagen.
width: el ancho que tendrá la imagen final.
height: el alto que tendrá la imagen final.

Gracias a esto, podremos juntar en un único fichero todos los fotogramas de una animación concreta, y ir recorriéndolos para obtener lo que denominamos un sprite animado.

Hay una cosa importante que no he comentado! para crear animaciones o ir moviéndo los objetos por el canvas, es vital pintar por completo todo el fotograma siguiente, (o almenos las zonas que sí que van a ser alteradas). En caso de que no lo hagamos, como ya he explicado, cada vez que llamemos a drawImage, se pintará sobre lo que ya esté pintado en el canvas (será un caos). Por esta razón es necesario crear un bucle de pintado.


<canvas id='c'></canvas>
<script languaje="JavaScript">
  var can;
  var ctx;  

  var backgroundStars_img = new Image();
  backgroundStars_img.src = "back_stars.png";  
  var ovniVerde_img = new Image();
  ovniVerde_img.src = "ovnis.png";

  function init() {
    can             = document.getElementById("c");
    ctx             = can.getContext("2d");
    can.width         = 480;
    can.height         = 320;
    setInterval(gameLoop, 1000/30);
  }  

  function gameLoop(){
    ctx.drawImage(backgroundStars_img,0,0,480,320,0,0,480,320);
    ctx.drawImage(ovniVerde_img,0,0,148,59,324,91,79,31);
  }

  window.onload = init;

</script>


Con setInterval indicamos la perioricidad con la que queremos que se ejecute una función concreta, en este caso gameLoop, que es la función en la que llamaremos a las rutinas de pintado drawImage.
 
    setInterval(gameLoop, 1000/30);

Hasta aquí el tutorial! Con estas pocas piezas ya se pueden empezar a hacer bastantes cosas!
No dudéis preguntar cualquier duda!

HTML5 - Canvas

Buenas a todos!

[Advertencia: este tutorial es de iniciación en HTML5]

Lo más importante antes de comenzar a pintar objetos y animaciones sobre un canvas es obtener una instancia del elemento <canvas> situado en el DOM de nuestro html, a través de esta instancia obtendremos el contexto de ese canvas y podremos pintar.

Para que ningún novato se pierda os pongo directamente el código html de la página:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>HTML5 Tutorial 1</title>
</head>
<body style="margin:0px;background-color:#ffffff">
<canvas id='c'></canvas>
<script languaje="JavaScript">
  var can;
  var ctx;  

  var backgroundStars_img = new Image();
  backgroundStars_img.src = "back_stars.png";  

  function init() {
    can          = document.getElementById("c");
    ctx          = can.getContext("2d");
    can.width    = 480;
    can.height   = 320;
    ctx.drawImage(backgroundStars_img,0,0,480,320,0,0,480,320);      
  }  

 window.onload = init;

</script>
</body>
</html>


En resumen el código anterior hace lo siguiente, obtiene de la página el elemento canvas con id 'c' sobre la variable 'can', a partir de esta variable obtenemos el contexto 2D del canvas sobre la variable 'ctx'. Hecho esto, configuramos el ancho y alto del canvas (en píxeles). Y finalmente pintamos una imagen sobre el canvas, empleando la función drawImage que pertenece al contexto.

Primero de todo tenemos la creación del elemento canvas como parte del cuerpo de la página, lo más importante es indicar una id para ese elemento, esto nos permitirá recogerlo desde el código javascript.

En el código javascript, primero creamos 3 variables, 'can', 'ctx' y 'backgroundStars_img'.
Inicializamos la variable backgroundStars_img como un objeto imagen y indicamos que la imagen que va a cargar es "back_stars.png".

Seguidamente se declara la función init(). Esta función configurará el canvas y pintará la imagen en su interior.

La sentencia final "window.onload = init", indica que cuando la página se haya cargado por completo, se ejecutará la función "init()".

En la función init, primero inicializamos la variable can, asignando el elemento del DOM canvas, mediante el uso de su id.

  can = document.getElementById("c");

Seguidamente asignamos el contexto 2D del canvas a la variable ctx.

  ctx = can.getContext("2d");

El siguiente paso es configurar las dimensiones del canvas, indicando su ancho y alto:

  can.width    = 480;
  can.height   = 320;


Finalmente pintamos la imagen en el canvas, a través del objeto ctx, que es el que contiene la referencia al contexto 2D del canvas.

ctx.drawImage(backgroundStars_img,0,0,480,320,0,0,480,320);  

La función drawImage permite, dada una imagen, seleccionar una sección de esta, para mostrar únicamente esa sección recortada.

     drawImage(img,sx,sy,swidth,sheight,x,y,width,height);

img: es una instancia de un objeto de tipo Image que contiene la imagen a pintar.
sx: es la coordenada x dentro de la imagen a partir de la que empezamos a recortar.
sy: es la coordenada y dentro de la imagen a partir de la que empezamos a recortar.
swidth: el ancho en píxeles del recorte que haremos a la imagen.
sheight: el alto en píxeles del recorte que haremos a la imagen.
x: la coordenada x dentro del canvas donde pintaremos la imagen.
y: la coordenada y dentro del canvas donde pintaremos la imagen.
width: el ancho que tendrá la imagen final.
height: el alto que tendrá la imagen final.

Hasta aquí este tutorial, espero que haya sido un tutorial claro y que os ayude a dar un primer paso para programar sobre el canvas de HTML5.

Aquí tenéis la imagen que he pintado sobre el canvas:


Un saludo!

lunes, 30 de julio de 2012

Redondeos en JavaScript

Buenas a todos!!
Todos los que hemos trabajado con operaciones numéricas en el navegador, nos hemos encontrado con el problema de los redondeos. No es un problema que únicamente se encuentre en aplicaciones de gestión para realizar operaciones entre campos de un formulario, también es muy común tener que realizar redondeos en los juegos, sobretodo para calcular nuevas coordenadas de posición, o vectores, etc.

Existen diferentes problemas:
- Tengo un número decimal y quiero transformarlo en un número entero!
- Tengo un número decimal y quiero quitarle decimales, pero que estos decimales queden redondeados!
- Tengo un número decimal y quiero quitarle decimales, pero que el decimal final no quede redondeado!

Redondeo: convertir número decimal a número entero

Tenemos dos opciones, emplear la función Math.round o el desplazamiento de bits (bit shifting),
actualmente el bit shifting es la opción que presenta un mejor rendimiento en la mayoría de navegadores, así que es la que recomiendo utilizar.

Bit shifting:
var a = 14.678;
var b = (0.5 + (a)) << 0;

Math.round():
var a = 14.678;
var b = Math.round(a);

Ambos métodos obtienen el mismo resultado, la variable b contiene el valor 15.

Redondeo: redondear un número decimal a un número de decimales concreto

Supongamos que quiero únicamente quedarme con 2 decimales:
Math.round():
var a = 14.678;
var b = Math.round(a*100)/100;

number.toFixed(x):
var a = 14.678;
var b = parseFloat(a.toFixed(2));

Con esto, la variable b contiene el valor 15.68.

Es importante que indique, que la función toFixed(x) es una función para dar formato a un número decimal y que el valor que retorna no es un valor númerico, es un String, por esa razón si queremos realizar operaciones con la variable b, es necesario hacer el casting a float, con parseFloat().

Mucha gente se encuentra con el problema de que está trabajando con toFixed, y que al realizar operaciones con un número convertido usando toFixed, el número resultante es el temido NaN (Not a Number), miran en el log o realizan alerts, y ven que el número es correcto!, tras varios siglos volviéndose locos se dan cuenta de que era un STRING!!

Eliminar decimales de un número sin redondearlo

Ahora no deseamos que se realice ese redondeo final en los decimales:
Bit shifting:
var a = 14.678;
var b = ((a*100) << 0) / 100;

La variable b contiene el valor 15.67.

Bien! Espero haber resuelto dudas sobre este tema!
Un saludo a todos!!


jueves, 29 de marzo de 2012

Classes in javascript

Hola a todos!! Llevaba ya mucho tiempo sin escribir!

El caso es que estoy enfrascado en la implementación de un framework en JavaScript para la creación de juegos en HTML5.
Algo esencial para conseguir que el framework sea lo suficientemente general, reutilizable y flexible, es que esté basado en clases!

Para no extenderme! Las clases en javascript son un recurso impresionante!! son fáciles de implementar, ahorran tiempo, y obtenemos un código limpio, fácil de leer y modificar.

En los lenguajes para la parte del servidor web como Java y PHP la palabra clave para definir una clase es "class"! En JavaScript la palabra clave es la ya conocida function!

Así es! las clases en JavaScript son funciones!

Imaginemos que vamos a hacer un programa web en JS, (si digo JS digo JavaScript que nadie se vuelva loco!), el programa tendrá muchos robots, podrán ser de muchos colores y cada robot tendrá unas coordenadas de posición 'x' e 'y'.
La clase sería como sigue:

function Robot(){
this.x = 0;
this.y = 0;
this.color = "#112233";
}

La palabra this, nos permite definir las propiedades y métodos propios de la clase.

Ya tenemos la clase creada!, ¿cómo creamos un objeto de tipo robot?

var robot1 = new Robot();
De esta forma hemos conseguido definir una variable llamada "robot1" de tipo Robot!!
Lo que ha pasado es lo siguiente, se ha ejecutado la función Robot() (llamada función constructora de la clase), al emplearse la palabra clave "new" el intérprete de JS ha guardado en memoria una instancia concreta de Robot, que contiene 3 espacios de memoria donde están definidos los valores de "x", "y", "color", que son las propiedades definidas como propias de la clase, gracias al uso de la palabra clave "this".

Acceder a la lectura de las propiedades del objeto es tan fácil como esto:


var coordenadax = robot1.x;
var coordenaday = robot1.y;
var color = robot1.color;



Y modificar sus propiedades es tan simple como esto:


robot1.x = 10;
robot1.y = 2;
robot1.color = "#112233";

La clase que hemos definido tan sólo contiene propiedades, pero algo vital en las clases son las funciones!!
Supongamos que tenemos 3 robots en el programa y necesitamos pintar las coordenadas de cada robot siguiendo un formato en concreto:
"x:valor,y:valor"
Podríamos hacer lo siguiente:

document.write("x:"+robot1.x+",y:"+robot1.y);
document.write("x:"+robot2.x+",y:"+robot2.y);
document.write("x:"+robot3.x+",y:"+robot3.y);

Este caso es simple, pero y si la función de pintado requiriera ejecutar un proceso más complejo, con condicionales, bucles, etc? Deberíamos repetir todas esas líneas de código por cada robot!!

Esto en cambio es más fácil!!


function Robot(){
this.x = 0;
this.y = 0;
this.color = "#112233";
this.paintCoords = function(){
document.write("x:"+this.x+",y:"+this.y);
}

}

De la misma forma que definíamos las propiedades de la clase, usando la sintaxis "this.nombre_funcion = function(){...}" definimos los métodos propios de la clase.

Ahora podemos llamar al método paintCoords de cada objeto!

robot1.paintCoords();
robot2.paintCoords();
robot3.paintCoords();

Hay algo IMPORTANTE que he comentado antes! Cuando definimos algo dentro de la función mediante la palabra "this", el intérprete crea en memoria un espacio determinado para esa variable propia de la clase, ya sea una propiedad o método!! Es decir, que por cada variable que creemos de tipo Robot, estaremos copiando el código de las funciones que estén definidas mediante "this"!! QUÉ DESPILFARRO DE MEMORIA!!

Por suerte, JavaScript tiene un recurso: prototype
Como indica la palabra, prototype nos permite definir el prototipo de la clase, es decir, definir la propiedad o función que estará disponible para todas y cada una de las instancias de la clase. Así pues solamente existirá una copia de dicha propiedad o función en memoria, independientemente del número de instancias o variables de clase que creemos.

Vamos a redefinir el método "paintCoords"! Ahora lo incluiremos en el prototipo de la clase!

function Robot(){
this.x = 0;
this.y = 0;
this.color = "#112233";
}
Robot.prototype.paintCoords = function(){
document.write("x:"+this.x+",y:"+this.y);
}

Como podéis ver, la sintaxis es:
NombreClase.prototype.nombreFuncion = function(){...}
Para incluir una propiedad compartida por todas las intancias sería:
NombreClase.prototype.nombrePropiedad = valor;

Una vez definidos tanto métodos como propiedades propios de la clase, su método de empleo es el mismo que para los que están definidos mediante this:

robot1.paintCoords();

Con todo esto, ya podéis crear de forma eficiente vuestras clases propias y usarlas además de una forma eficiente sin consumir en exceso la memoria de los navegadores!

Con esto termina el tutorial sobre la creación de Classes in JavaScript. Espero que os sea de gran ayuda!
Un saludo a todos!!

martes, 10 de enero de 2012

Dog Eastwood

Aquí va una foto!
Una mañana cuando iba a tomarme el café al bar de siempre, me encontré a este perro al más puro estilo Harry Callahan (Clint Eastwood).

Eso es lucir unas gafas.