Sie sind auf Seite 1von 515

HTML5 Canvas referencia y

ejemplos
Juan Carlos Reyes C.

Todos los nombres propios de programas, sistemas operativos,


equipos, hardware, etc. que aparezcan en este libro son marcas
registradas de sus respectivas compaas u organizaciones.

Reservado todos los derechos. El contenido de esta obra est


protegida por la ley, que establece penas de prisin y/o multas, adems
de las correspondientes indemnizaciones por daos y perjuicios, para
quienes reprodujeran, plagiaren, distribuyeren o comunicaren
pblicamente, en todo o en parte, una obra literaria, artistica o cientiica,
o su transformacin, interpretacin o ejecucin artstica ijada en
cualquier tipo de soporte o comunicada a travs de cualquier medio ,
sin la preceptiva autorizacin.

BUBOK PUBLISHING S L., 2013 Primera Edicin


ISBN:
Impreso enEspaa / Printed in Spain Editado por Bubok
Agradecimientos
Ante todo me es muy necesario darles las gracias a mi querida esposa
Sissi, quin me ha soportado durante mucho tiempo al embarcarme en
cada uno de mis proyectos, incluso por mas tiempo del que me hubiera
atrevido a pedirle. Te quiero Sissi.

Tambin me gustara darles las gracias a Yensi, mi hermana, por tu gran


colaboracin en mantenernos siempre unidos y tranquilos, en darle
ese calor necesario a nuestro hogar y a mi familia mientras yo me
embarcaba en este y algunos otros proyectos.

Y por ltimo, quisiera agradecerles a mis hijos y en especial a ti Sara


por tu gran ayuda en mis largas horas de preparacin de este
proyecto, y en general a todos por su gran aporte a este trabajo, ya
que son ellos los que cada da me impulsan y motivan a iniciar cada
uno de mis proyectos nuevos, aunque ironicamente muchas veces
estos proyectos me roben el tiempo que pudiera dedicarles, gracias
Sara, Juan David y Camila.

Sissi, si se pudo!
Juan Carlos Reyes C.

Tiene unos 15 aos de experiencia en diseo y desarrollo web. Ha


trabajado en y para muchas empresas privadas y agencias de
publicidad, tales como Roberto Eliaschev, Ghersi-Quintero, Puma
pblicidad, Laboratorios Leti, Merck, Aventis, Calox, SmithKline Beecham,
Krat, Empresas Polar entre otras. Juan Carlos es creador de diferentes
sotware de codigo abierto para blogs, cms, e-commerce y analitica web.

Durante su carrera freelance y profesional, Juan Carlos ha construido


y colaborado en la construccin de mas de 6o sitios y aplicaciones
web. Con una perspectiva fuera de lo ordinario, durante toda su
carrera, ya que se mueve entre el diseo grico y el desarrollo de
aplicaciones web, su trabajo ha abarcado desde simples logotipos,
creacin de empaques hasta grandes y complejos sitios web vistosos,
funcionales y optimos.
Indice
Agradecimientos........................................................................................................
Sobre el
autor..............................................................................................................................
Indice...........................................................................................................................
Introduccin..............................................................................................................
Para quin es este
libro................................................................................................................14
Convenciones usadas en este
libro............................................................................................14
Cmo est organizado el
libro...................................................................................................15
Iconos y
terminologa................................................................................................................
Cdigo fuente de los ejemplos de este
libro.............................................................................16
Prologo........................................................................................................................
Lo
bsico..........................................................................................................................
Qu es exactamente el canvas de
HTML5...............................................................................19
Las 5 principales caractersticas del
canvas.............................................................................19
Dispositivos del
cliente...............................................................................................................20
Navegadores
web........................................................................................................................20
Navegadores
mobiles.................................................................................................................20
Websites y pginas
web..............................................................................................................21
HTML5..........................................................................................................................
Javascript....................................................................................................................
Fundamentos de un objeto
javascript......................................................................................25
Crear
Objetos.........................................................................................................................
Propiedades de
objetos..............................................................................................................26
Literales de
objetos.................................................................................................................... 29
Objetos como propiedades de un objeto
window.................................................................. 31
Que hay en un
nombre...............................................................................................................33
Funciones como
callbacks..........................................................................................................36
La variable
this........................................................................................................................... 36
Closures......................................................................................................................
La
referencia..................................................................................................................
El elemento
canvas.....................................................................................................................46
Como trabaja el objeto
canvas..................................................................................................46
Atributos y mtodos del objeto
canvas....................................................................................46
Width............................................................................................................................
Height...........................................................................................................................
Context2d...................................................................................................................
getContext()...............................................................................................................
toDataURL()...............................................................................................................
toBlob()........................................................................................................................
save()...........................................................................................................................
restore().......................................................................................................................
La matriz de
transformacin.................................................................................................... 5
Mtodos primarios de
transformacin.................................................................................. 51
scale()..........................................................................................................................
rotate().........................................................................................................................
translate()....................................................................................................................
setTransform()............................................................................................................
Mtodos de
Path........................................................................................................................65
beginPath().................................................................................................................
closePath()..................................................................................................................
arc()..............................................................................................................................
rect().............................................................................................................................
ill().................................................................................................................................
stroke().........................................................................................................................
moveTo()......................................................................................................................
lineTo().........................................................................................................................
arcTo()..........................................................................................................................
quadraticCurveTo()..................................................................................................
bezierCurveTo()........................................................................................................
clip()..............................................................................................................................
isPointInPath()............................................................................................................
drawSystemFocusRing().........................................................................................
drawCustomFocusRing()........................................................................................
scrollPathIntoView()..................................................................................................
ellipse()........................................................................................................................
Mtodos de
rectngulos...........................................................................................................10
clearRect()..................................................................................................................
strokeRect()................................................................................................................
illRect().........................................................................................................................
Mtodos de gradientes y
patrones...........................................................................................106
createLinearGradient()...........................................................................................
createRadialGradient()...........................................................................................
createPattern()...........................................................................................................
Mtodos de
Imagen..................................................................................................................112
drawImage()...............................................................................................................
Mtodos de
Texto......................................................................................................................118
illText().........................................................................................................................
strokeText().................................................................................................................
measureText()............................................................................................................
Mtodos de manipulacin de imagenes Image
Data........................................................133
getImageData()..........................................................................................................
putImageData()..........................................................................................................
createImageData()....................................................................................................
Mtodos de
accesibilidad........................................................................................................14
drawSystemFocusRing().........................................................................................
drawCustomFocusRing()........................................................................................
setCaretSelectionRect()..........................................................................................
caretBlinkRate().........................................................................................................
La regin
clipping.....................................................................................................................14
Las propiedades del
contexto..................................................................................................145
canvas..........................................................................................................................
illStyle...........................................................................................................................
font................................................................................................................................
globalAlpha................................................................................................................
globalCompositeOperation....................................................................................
lineCap........................................................................................................................
lineWidth.....................................................................................................................
lineJoin........................................................................................................................
miterLimit......................................................................................................................
shadowBlur.................................................................................................................
shadowOfsetX............................................................................................................
shadowOfsetY.............................................................................................................
strokeStyle...................................................................................................................
textAlign.......................................................................................................................
textBaseline................................................................................................................
La regin
Hit............................................................................................................................162
addRegionHit()..........................................................................................................
removeRegionHit()...................................................................................................
Introduccin
Estoy convencido de que el canvas de HTML5 representa uno de los
avances ms importantes en internet desde la creacin del primer
navegador web en los aos 90. El canvas integra una poderosa
herramienta de desarrollo grico con la tecnologa de los navegadores
web, lo que hace suponer, que cualquier desarrollador web con
conocimientos de cdigo javascript, puede agregar animacin y
gricos impresionantes a sus websites.

Los gricos que son generados en el canvas con tecnologa basada


en el navegador, diieren de los gricos generados con tecnologas
basadas en el servidor. Los cdigos generados por el canvas y
mostrados en el dispositivo del cliente son ejecutados por el
navegador web y no por el servidor donde esta hospedada la pgina
web. Esto signiica que tu puedes agregar elementos canvas con
impresionantes gricos y animaciones directamente a tus pginas web
sin necesidad de escribir ni una sola linea de cdigo del lado del
servidor.

En este libro podrs consultar y revisar todos los aspectos tcnicos del
canvas, tales como sus clases, sus mtodos y sus propiedades, al igual
que examinar ejemplos prcticos en cada uno de los apartados
tcnicos del canvas, con el objetivo de que puedas entender facil y
claramente para que sirven y como trabajan. No pretendemos ser una
obra para el aprendizaje de esta tecnologa ni tampoco ha sido
concebida para ensear aspectos como por ejemplo el artstico, esto es
solo una obra de consulta, que se puede usar para aprender aspectos
tcnicos y teoricos, bsicos o complejos, pero estamos seguros de que
puede ser, como en efecto lo es, un gran recurso de apoyo a todos los
diseadores y desarrolladores web que hayan trabajado, trabajen o
se esten iniciando con el canvas de HTML5.

El estandar del canvas de HTML5 esta teniendo una rpida y gran


aceptacin y la mayora de los grandes navegadores web ya lo estn
implementando.

Para quien es este libro

Este libro se ha enfocado para ser usado por diseadores y


desarrolladores web, desde principiantes hasta avanzados, que
quieran dominar y conocer a fondo el canvas de sus pginas HTML5 y
generar buenas aplicaciones web interactivas y animadas. Los
profesionales que deseen crear grandes aplicaciones basados en
canvas como juegos, animaciones o gricos complejos, aqu tendrn
una gran herramienta de trabajo y estudio, una gua de bolsillo y
consulta diaria, de lectura, etc., porque de alguna manera se que son
ustedes los que le podrn sacar el mximo provecho a esta obra.

Los principiantes quizas encuentren algo complicadas ciertas


secciones y terminos en este libro, pero esto no debe ser un
impedimento para que tambin sea una gran gua de consulta, de
aprendizaje y sobre todo de estudio contnuo.

En lo personal se que muchas veces hace falta un medio, ademas de


internet, para poder aprender y consultar, para que son cada una de
las herramientas que nos ofrecen algunos lenguajes de programacin,
y se que no siempre tenemos internet al alcance de la mano para estas
consultas, y con la idea en mente de que siempre es necesario, y que
nunca pasar de moda, y no solo para consultar sino hacerlo una guia
de aprendizaje, he concebido este libro para ofrecerles cubrir esta
necesidad que tenemos muchos, de cada da ser mejores
profesionales, y esto solo se consigue cuando conocemos
verdaderamente todas y cada una de las herramientas disponibles
para su uso y no una consulta exporadica a los sitios web de
informacin, aunque estos tambien resulten muy tiles.

Tanto como si eres novato o si tiene mucha experiencia en el


desarrollo de aplicaciones web basadas en canvas, obtendrs un
beneicio adicional al incluir este libro dentro de las herramientas
necesarias cuando vas a desarrollar tus ideas y aplicaciones, estoy
seguro de que el contenido de este libro te ser de gran ayuda.

Convencin usada en este libro

Los cdigos de ejemplos en este libro estan escritos con un texto


monoespacial sobre un marco negro al 5% de tinta.
var canvas =
document.getElementById(canvas),
context = canvas.getContext(2d);
Los nombres de los archivos de los ejemplos usados para ilustrar cada
uno de los mtodos, propiedades, atributos, etc. estan resaltado de
esta manera:
nombre del archivo - composicionCanvas.js
Los links a pginas web, nombres de mtodos, funciones, variables, o
cualquier cdigo escrito en este libro, estn en un texto monoespacial:
http://www.google.com

Como est organizado este libro

Este libro esta organizado en tres secciones, cada uno de los cuales
contiene lo siguiente:

Seccin 1 - Lo bsico
En esta seccin comenzaremos por deinir lo que es el canvas, de
donde proviene, lo que hoy en da signiica y lo que podemos hacer
con el, luego pasaremos a deinir algunos conceptos bsicos por lo que
comenzaremos deiniendo que es HTML5, su inicio, su importancia
dentro del contexto canvas y sus nuevas e impresionantes
caractersticas, hablaremos tambien de javascript y la importante labor
en el canvas, te mostraremos los aspectos bsicos que hay que saber
para poder iniciar el trabajo con canvas y haremos un breve repaso
por sus principales caractersticas.

Seccin 2 - La referencia
En la seccin 2 vamos directo a la accin y explicaremos cada uno de
los mtodos y propiedades del elemento canvas dentro del contexto
2d, en la cual estar enfocado este libro, pero tambin daremos un
repaso por los objetos fuera del contexto 2d y que son usados por
este, adems de otros conceptos tiles de la API. deiniremos cada uno
de ellos, tratando de dar una explicacin breve y fcil de entender, y
en su mayora seguidos de un ejemplo que ira avanzando en
complejidad a medida que vayamos avanzando en el estudio de cada
uno de los complementos del canvas.
Seccin 3 - Los proyectos
Una vez que hayamos estudiado todos y cada uno de los
complementos del canvas, pasaremos directamente a la accin y
mostraremos algunos proyectos profesionales que pueden ser tiles
tanto para aprender como para aplicar a tus propios proyectos e ir
construyendo tus propios patrones. En esta seccin trataremos de
explicar brevemente cada uno de los conjunto de algoritmos usados
para cada una de las funciones que hagamos.

Seccin 4 - Ayuda en lnea


Como en cualquier caso despes de haber inalizado la instruccin, la
pregunta propia que nos hacemos, es: Y ahora que?, bueno tratamos
de ayudarte un poco con esta pregunta y te mostramos los links a
muchas pginas de ayudas en linea, tutoriales, tips, curiosidades,
proyectos, trabajos terminados, etc. Para que cada quien pueda
consultar y moverse dentro de esta nueva tecnologa que an esta en
sus primeros pasos e ir avanzando con ella.

Iconos y terminologa grfica usada en este libro

Slo usaremos un icono enmarcado dentro de un gradiente para


indicar una nota importante o destacada del item actual, este es similar
al siguiente:
Nota Destacada
El valor por defecto para la propiedad textAlign es start y cuando el
navegador muestra el texto desde la izquierda a la derecha, significa
que el atributo dir del elemento canvas es ltr, left es lo mismo
que
Atento

start y right es lo mismo que end. De igual manera, cuando el


navegador muestra los textos de derecha a izquierda, significa que el
valor para el atributo dir esrtl, right es lo mismo que start y
left es lo mismo que end.

Cdigo fuente de los ejemplos de este libro

Para desarrollar los ejemplos de este libro puedes optar por introducir
manualmente el cdigo o utilizar los archivos que acompaan al libro.
En el sitio web de juassi studios, dirgete a la seccin libros y all
encontrars una seccin con los cdigos fuentes de cada libro
publicado, selecciona el tuyo y click en descargar zip. Los ejemplos
estn organizados con el nombre de cada una de las propiedades y
mtodos listados en este libro, ademas de una seccin con
aplicaciones varias mostrada para ver la amplitud de posibilidades que
ofrece el canvas de html5, todos estos ejemplos pueden ser ejecutados
en un servidor web local, tal como apache o con tu navegador web
preferido, ya que no son necesarios en la mayora de los ejemplos usar
un servidor.

Todos los ejemplos han sido probado en varios navegadores que


incluyen Internet Explorer, Firefox, Safari, Google Chrome y Opera.
Prologo
Este libro documenta la API de javascript para dibujar en la etiqueta
canvas de HTML5. Por lo tanto asumimos que conoces del lenguaje de
programacin del lado del cliente javascript y tiene por lo menos los
conceptos bsicos del uso de javascript en las pginas web.
Lo bsico
Canvas fue originalmente creado por Apple en el ao 2004 para ser
aplicados en los widgets y dar mayor poder a sus gricos en el
navegador Safari. Luego esta tecnologa fue adoptada por Firefox,
Opera y Google Chrome. Hoy en da canvas es parte de la nueva
especiicacin HTML5 para las prximas generaciones de tecnologa
web.

El canvas de HTML5 es una etiqueta HTML que puedes incrustar en un


documento HTML5 con el proposito de dibujar gricos en javascript. El
canvas de HTML5 es solo un bitmap, cada pixel dibujado dentro del
canvas es sobrescrito sobre el.

Que es exactamente el canvas de HTML5

El canvas es un estandar para aplicaciones escritas en javascript que


corren dentro de una pgina web descargada desde un servidor y
mostrada por un navegador en un dispositivo del cliente.

Las 5 principales caracteristcas del canvas

Es Interactivo : El canvas de HTML5 puede estar atento y responder


ante cualquier accin del usuario. Mover el mouse, presionar un botn,
trazos con el dedo. Todo esto gracias a tu cdigo javascript y la
aplicacin de manegjo de acciones usado.

Es animado: Los objetos pueden moverse dentro de un canvas HTML5,


desde un simple bote de una bola hasta grandes y complejas
animaciones.

Es accesible: Hoy en da la mayora de los navegadores web soportan


todo o gran parte del canvas HTML5. Tus aplicaciones basadas en el
elemento canvas pueden ser usadas en un gran rango de dispositivos,
desde inmensos y poderosos ordenadores hasta smartphone y
tabletas.

Es flexible: Un canvas de HTML5 puede ser usado para mostrar textos,


lineas, formas, imagenes, videos,..., todo con o sin animaciones. Esto es
un medio superlexible.
Esta creciendo rpidamente: HTML5 y las caracteristicas del elemento
canvas estn ganando popularidad.

Dispositivos del cliente

Los dispositivos del cliente incluyen ordenadores tales como PCs de


sobremesa o de escritorio y dispositivos mobiles tales como
smartphone, tabletas y porttiles. El dispositivo del cliente es donde tu
navegador web reside y tu canvas es mostrado. El sitio web que deine
tu canvas, esta hospedado en un servidor. Tus pginas web son
descargadas desde el servidor y mostrado por tu navegador web.

Navegadores web

Los navegadores web son aplicaciones que construyen y muestran


pginas web basadas en instrucciones de Hypertext Markup
Language (HTML). Los grandes navegadores web y sus sitios de
descargas son listados a continuacin:

Internet Explorer: www.windows microsot.com/en-


US/internetexplorer/downloads/ie Firefox: www.mozilla.org/irefox
Chrome: www.google.com/chrome
Safari: www.apple.com/support/safari
Opera: www.opera.com

Navegadores mobiles

Los navegadores mobiles son cargados en tu dispositivo mobil como


App, que a su vez son descargados desde las tiendas virtuales
especiicadas por cada una de las marcas comercializadoras de esta
tecnologa. Para buscar navegadores en las tiendas de App, dirigete a
la seccin de navegadores o escribe en el buscador de App, el nombre
del navegador que desees, tales como: internet explorer, irefox,
chrome, safari, opera.

Websites y pginas web

Los websites son un grupo de pginas web deinidas por unos


elementos HTML llamadas tags o etiquetas, las tags o etiquetas HTML
deinen las hojas de las pginas web y sus contenidos, incluyendo el
canvas.

Ejemplo de algunas de las tags o etiquetas HTML ms usadas en las


aplicaciones web basadas en canvas:

<!DOCTYPE HTML> : declara el documento para la pgina web.


<html>: delimita el cdigo HTML usado.
<head>: deine el cdigo que contiene toda la informacin acerca de
tus pginas web.
<script>: delimita un area para cdigos script como por ejemplo el
canvas. <body>: deine el area principal de tus pginas web.
<div>: provee informacin formateda a tus pginas web.
<canvas>: deine el area del canvas.

HTML5

El HTML5 (HyperText Markup Language, versin 5) es la quinta


revisin del lenguaje de programacin bsico de la World Wide
Web, el HTML. Esta nueva versin pretende remplazar al actual
(X)HTML, corrigiendo problemas con los que algunos desarrolladores
web se encuentran, as como redisear el cdigo actualizandolo a
nuevas necesidades que demanda la web de hoy en da.

Actualmente el uso de HTML5 est creciendo a pasos agigantados, y


ya existen muchas empresas en todo el mundo que estn
desarrollando sus sitios webs en esta versin del lenguaje. A diferencia
de otras versiones de HTML, los cambios en HTML5 comienzan
aadiendo semntica y accesibilidad implcitas, especiicando cada
detalle y borrando cualquier ambigedad. Se tiene en cuenta el
dinamismo de muchos sitios webs (facebook, twenti, etc), donde su
aspecto y funcionalidad son ms semejantes a aplicaciones webs que
a documentos.

Se estaba o se esta siendo muy abusivo en el uso de elementos DIV


para estructurar una web en bloques. El HTML5 nos brinda varios
elementos que perfeccionan esta estructuracin estableciendo qu es
cada seccin, eliminando as DIV innecesarios. Este cambio en la
semntica hace que la estructura de la web sea ms coherente y fcil
de entender por otras personas y los navegadores podrn darle ms
importancia a segn qu secciones de la web, facilitndole adems la
tarea a los buscadores, as como cualquier otra aplicacin que
interprete sitios web.

Una pregunta muy comn en estos tiempos es: Cmo puedo empezar
a utilizar HTML5 si existen navegadores antiguos que no lo soportan?
Pero la pregunta en s se ha formulado de forma errnea. El HTML5 no
es una cosa grande como un todo, sino una coleccin de elementos
individuales, por consiguiente lo que s se podr ser detectar si los
navegadores soportan cada elemento por separado.

Cuando los navegadores realizan un render de una pgina,


construyen un Modelo de Objeto de Documento (Document Object
Model - DOM), una coleccin de objetos que representan los elementos
del HTML en la pgina. Cada elemento - <p>, <div>, <span> - es
representado en el DOM por un objeto diferente.

Todos los objetos DOM comparten unas caractersticas comunes,


aunque algunos tienen ms que otros. En los navegadores que
soportan rasgos del HTML5, algunos objetos tienen una nica
propiedad y con una simple ojeada al DOM podremos saber las
caractersticas que soporta el navegador.

Existen cuatro tcnicas bsicas para saber cuando un navegador


soporta una de estas particulares caractersticas, desde las ms
sencillas a las ms complejas.

1. Comprueba si determinadas propiedades existen en objetos


genricos o globales (como window o navigator). Por ejemplo al
comprobar soporte para la Geolocalizacin .

2. Crear un elemento, luego comprobar si determinadas propiedades


existen en ese elemento. Por ejemplo al comprobar soporte para
canvas.
3. Crear un elemento, comprobar si determinados mtodos existen en
ese elemento, llamar el mtodo y comprobar los valores que devuelve.
Por ejemplo: comprobar qu formatos de video soporta.
4. Crear un elemento, asignar una propiedad a determinado valor,
entonces comprobar si la propiedad mantiene su valor. Ejemplo:
comprobar que tipo de <input> soporta.

Las webs se dividirn en los siguientes elementos:

<section></section> - Se utiliza para representar una seccin


general dentro de un documento o aplicacin, como un captulo de
un libro. Puede contener subsecciones y si lo acompaamos de h1-h6
podemos estructurar mejor toda la pgina creando jerarquas del
contenido, algo mu favorable para el buen posicionamiento web.

<article></article> - El elemento de artculo representa un


componente de una pgina que consiste en una composicin
autnoma en un documento, pgina, aplicacin, o sitio web con la
intencin de que pueda ser reutilizado y repetido. Podra utilizarse
en los artculos de los foros, una revista o el artculo de peridico, una
entrada de un blog, un comentario escrito por un usuario, un widget
interactivo o gadget, o cualquier otro artculo independiente de
contenido.
Cuando los elementos de <article> son anidados, los elementos de
<article> interiores representan los artculos que en principio son
relacionados con el contenido del artculo externo. Por ejemplo, un
artculo de un blog que permite comentarios de usuario, dichos
comentarios se podran representar con <article>.

<aside></aside> - Representa una seccin de la pgina que


abarca un contenido tangencialmente relacionado con el contenido
que lo rodea, por lo que se le puede considerar un contenido
independiente. Este elemento puede utilizarse para efectos
tipogricos, barras laterales, elementos publicitarios, para grupos de
elementos de la navegacin, u otro contenido que se considere
separado del contenido principal de la pgina.

<header></header> - Elemento <header> representa un grupo


de artculos introductorios o de navegacin.

<nav></nav> - El elemento <nav> representa una seccin de una


pgina que es un link a otras pginas o a partes dentro de la pgina:
una seccin con links de navegacin. No todos los grupos de enlaces
en una pgina tienen que estar en un elemento <nav>, slo las
secciones que consisten en bloques principales de la navegacin son
apropiadas para ser utilizadas con el elemento <nav>. Puede utilizarse
particularmente en el pie de pgina para tener un men con un listado
de enlaces a varias pginas de un sitio, como el Copyright; home page,
poltica de uso
y privacidad. No obstante, el elemento <footer> es plenamente
suiciente sin necesidad de tener un elemento <nav>.

<footer></footer> - El elemento <footer> representa el pi de


una seccin, con informacin acerca de la pgina/seccin que poco
tiene que ver con el contenido de la pgina, como el autor, el copyright
o el ao.

El elemento input adquiere gran relevancia al ampliarse los elementos


que se permitiran en el type .
<input type=search> para cajas de bsqueda.
<input type=number> para adicionar o restar nmeros
mediante botones. <input type=range> para seleccionar un
valor entre dos valores predeterminados.
<input type=color> seleccionar un color.
<input type=tel> nmeros telefnicos.
<input type=url> direcciones web.
<input type=email> direcciones de email.
<input type=date> para seleccionar un da en un
calendario. <input type=month> para meses.
<input type=week> para semanas.
<input type=time> para fechas.
<input type=datetime> para una fecha exacta, absoluta y
tiempo. <input type=datetime-local> para fechas
locales y frecuencia.

Otros elementos muy interesantes:


<audio> y <video> - Nuevos elementos que permitirn
incrustar un contenido multimedia de sonido o de vdeo,
respectivamente. Es una de las novedades ms importantes e
interesantes en este HTML5, ya que permite reproducir y controlas
vdeos y audio sin necesidad de plugins como el de Flash.
El comportamiento de estos elementos multimedia ser como el de
cualquier elemento nativo, y permitir insertar en un video, enlaces o
imgenes, por ejemplo. Youtube, ya ha anunciado que deja el Flash y
comienza a proyectar con HTML5.

<embed> - Se emplea para contenido incrustado que necesita


plugins como el Flash. Es un elemento que ya reconocen los
navegadores, pero ahora al formar parte de un estndar, no habr
conlicto con <object>.

<canvas> - Este es un elemento complejo que permite que se


generen gricos al hacer dibujos en su interior. Es utilizado en Google
Maps y en un futuro permitir a los desarrolladores crear aplicaciones
muy interesantes.

Para una lista completa de las nuevas caractersticas de HTML5, visita:


www.w3.org/TR/html5-dif/#new-elements

Javascript

Es tu cdigo javascript el que dibujar imagenes en tus canvas. Sin


javascript, un canvas es solo un espacio blanco.

Javascript fue desarrollado por Netscape a mediados de los 90, es un


lenguaje totalmente diferente de Java, la cual fue desarrollado por Sun
Mycrosystem a principios de los 90.
No vamos a realizar un estudio exhaustivo de todo el lenguaje
javascript, ya que no es el objetivo de este libro. Sin embargo hay
algunos detalles que es importante resaltar y entender para poder
trabajar con mayor claridad en el elemento canvas de HTML5. El ms
importante de estos detalles es entender que las funciones son objetos
de primera clase de javascript, que es consecuencia de la forma en
que este lenguaje las deine y las maneja. Que quiere decir esto?.

Para poder entender lo que signiica que una funcin es un objeto,


primero debemos entender que es un objeto javascript. Luego
abordaremos lo que signiica primera clase.

Fundamentos de un objeto javascript


La mayora de los lenguajes orientados a objetos (OO) deine un tipo
object fundamental del cual se deriva el resto. En javascript ocurre
exactamente esto pero hasta aqui llega la similitud. A nivel bsico, el
object de javascript tiene poco en comn con el objeto fundamental
deinido en la mayora de los lenguajes OO.

A primera vista, un object javascript puede parecer un objeto


montono y trivial. Una vez que esta creado no contiene datos ninguno
y adems una semantica reducida. Pero precisamente esta
caracterstica es la que le proporciona un gran potencial.

Crear Objetos
Un nuevo objeto se crea a travs del operador new asociado con el
constructor Object. Establecer un objeto es tan fcil como lo
hacemos a continuacin:
var nuevoValor = new Object();
Podra ser incluso ms sencillo ( ms adelante lo demostraremos),
aunque por ahora es suiciente.

Y ahora?Que podemos hacer con este objeto? Aparentemente, no


contiene nada: ni informacin, ni semntica compleja, nada. Nuestra
creacin no ser interesante hasta que empecemos a aadirle
propiedades.

Propiedades de objetos
Como los homlogos del lado del servidor, los objetos javascript
pueden contener datos y poseen mtodos (en realidad, una especie
de mtodos pero estaramos adelantandonos). A diferencia de ellos,
estos elementos no son declarados previamente para un objeto; los
creamos de una forma dinmica segn los necesitemos.

Vamos a ver el siguiente fragmento de cdigo:

var coche = new Object();


coche.marca = ford;
coche.modelo = mondeo;
coche.anio = 2013;
coche.fechaCompra = new Date(2013, 01, 08);

Aqui hemos creado una nueva instancia de Object y le asignamos


una variable llamada coche. A continuacin, la completamos con un
nmero de propiedades de diferentes tipos: dos cadenas, un numero y
una instancia Date.

No necesitamos declarar estas propiedades antes de asignarlas,


simplemente, existirn por el slo hecho de darles un valor. Esto nos da
mucha lexibilidad. Pero, antes de alegrarse demasiado, recuerde que
esta operatividad tiene un precio.

Por ejemplo, supongamos que en el siguiente cdigo de nuestra


pgina con script HTML queremos cambiar el valor de la fecha de
compra:
coche.fechaCompra = new Date(2013, 03, 09);
No es ningn problema, a no ser que cometamos un error involuntario
como:
coche.fehcaCompra = new Date(2013, 03, 09);

No existe un compilador que nos advierta que hemos cometido un


error; hemos creado una nueva propiedad llamada fehcaCompra y ms
tarde nos preguntaremos porqu la nueva fecha no fumciona cuando
hacemos referencia a la propiedad deletrendola correctamente. Tene
un gran poder conlleva a una gran responsabilidad (lo ha odo
alguna vez?), por lo tanto hay que estar muy atento con lo que se
escribe.

En este ejemplo hemos aprendido que una instancia Object de


javascript, a la que nos referimos como object de aqu en adelante,
es una coleccin de propiedades, cada una de las cuales contiene un
nombre y un valor. El nombre de la propiedad es una cadena y el valor
puede ser cualquier objeto de javascript, sea Number, String,
Date, Array, un object bsico o cualquier otro tipo de objeto
javascript (incluyendo funciones, como veremos un poco ms
adelante).
Esto signiica que el objetivo principal de una instancia Object es
servir como contenedor para una coleccin determinada de otros
objetos. Esto le podra hacer recordar conceptos de otros lenguajes,
como por ejemplo, un mapa Java o diccionario o hashes de otros
lenguajes.

Las propiedades no estn limitadas a los tipos String o Number,


ya que puede ser otra instancia Object, que a su vez tiene su
priopio conjunto de caractersticas, que tambin pueden ser objetos
con propiedades determinadas y as sucesivamente hasta cualquier
nivel que sea sensato y tenga sentido para el modelo de datos que
estamos intentando crear.
Supongamos que aadimos una nueva propiedad a nuestra instancia
coche que identiica al propietario. sta es otro objeto javascript que
contiene propiedades como el nombre y la ocupacin del propietario:

var propietario = new Object();


propietario.nombre = Juan Reyes;
propietario.profesion = animador;
coche.propietario = propietario;

Para acceder a la propiedad anidada escribiremos lo siguiente:


var nombrePropietario =
coche.propietario.nombre;

No hay limites en los niveles de anidado que podemos utilizar (salvo el


que imponga el sentido comn). Cuando lleguemos a este punto, la
jerarqua de nuestro objeto ser como la que se muestra en el cuado
siguiente:
Cadena La jerarqua muestra que los objeJuan Reyes
tos son contenedores para hacer referencias a otros objetos o tipos
Cadena incluidos en javascript.
animador
Nota destacada
Esto no es necesario para todas las variables intermedias (como
propietario), que hemos creado como un objeto pedaggico. En breve,
veremos formas ms compactas y eficaces para declarar objetos y sus
propiedades.
Atento

Hasta aqu hemos referenciado las propiedades de un objeto


utilizando el carcter punto. Pero, en realidad, esto es un sustituto de
un operador mas general para hacer referencia a propiedades.

Que pasara si tuviramos una propiedad denominada


color.scheme?Se ha ijado en el punto que existe en el medio
del nombre? Esto aade diicultad debido a que el intrprete de
javascript tratar de buscar scheme como una propiedad anidada de
color.

Podra pensar simplemente en no hacerlo de esta forma. Pero que


pasara con los caracteres espacio?Y que ocurre con otros caracteres
que podran ser confundidos con delimitadores en lugar de ser parte
de un nombre?

Y lo ms importante, Que sucede si ni siquiera sabemos cul es el


nombre de la propiedad pero es el valor de otra variable o se obtiene
como resultado de evaluar una expresin?
Para todos estos casos, el carcter punto no es adecuado y debemos
utilizar una notacin ms general si queremos acceder a las
propiedades. El formato del operador general para hacer referencia a
un operador es

object [propertyNameExpression]

donde propertyNameExpression es una expresin javascript


cuya evaluacin como cadena deine el nombre de la propiedad a la
que se quiere hacer referencia. Por ejemplo, las siguientes son
equivalentes entre ellas:

coche.marca
coche[marca]
coche[m + a + r + c + a]

Lo mismo ocurre con estas otras referencias:


var m = marca; coche[m];
Utilizar el operador general es la nica forma de mencionar
propiedades cuyos nombres no deinen identiicadores javascript
vlidos, como por ejemplo,
coche[el nombre de algunas propiedades!]
que contiene caracteres no vlidos para identiicadores javascript, o
cuyos nombres son los valores de otras variables.

Construir objetos creando nuevas instancias con el operador new y


asignar cada propiedad utilizando sentencias de asignacin
separadas puede ser una tarea tediosa. En el prximo apartado
veremos una notacin ms compacta y fcil de leer para declarar
objetos y sus propiedades.
Literales de objetos
En la seccin anterior, diseamos un objeto que deina algunas de las
caractersticas de un coche, asignandole una variable llamada
coche. Para ello, utilizamos dos operadores new, una variable
intermedia llamada propietario y una serie de sentencias de
asignacin. Esto es montono (ademas de farragoso y con ms
posibilidades para cometer un error) y tambin es difcil analizar
visualmente la estructura del objeto cuando realizamos una inspeccin
rpida del cdigo.

Afortunadamente, podemos usar una notacin ms compacta y fcil de


revisar de forma visual. Considere la siguiente sentencia:

var coche = {
marca : Ford,
modelo : Mondeo,
anio : 2013,
fechaCompra : new Date(2013,01,08),
propietario: {

nombre : Juan Reyes,


profesion : animador

}
};
Utilizando un literal del objeto, este fragmento crea el mismo objeto
coche que construimos anteriormente con la sentencia de asignacin
de la seccin precedente.

Esta notacin que se denomina JSON (para ms informacin consulte


la pagina web: http://www.json.org), es preferida por la
mayora de creadores de pginas, en lugar de la creacin del objeto
mediante mltiples asignaciones. Su estructura es simple, un objeto se
deine como un listado de propiedades separadas por comas, todo ello
entre llaves. Cada una se establece listando un nombre y su valor,
separadas por el carcter dos puntos (:).

Nota destacada
Tcnicamente, en JSON no se pueden expresar valores de fechas, en
principio porque javascript carece de cualquier tipo de literal de fecha.
Cuando se utiliza en un script, normalmente se utiliza el constructor
Date, como se
Atento

muestra en el ejemplo anterior. Al emplearla como formato de


intercambio, las fechas se suelen expresar como una cadena que
contiene el formato ISO 8601 o como un nmero que hace referencia a
la fecha como un valor en milisegundos que se obtiene como resultado
de utilizar Date.getTime(). Cuando emplea JSON como formato
de intercambio, existen algunas reglas estrictas que debe seguir, como
escribir los nombres de propiedades entre comillas. Vase
http://www.json.org o RFC 4627
(http://www.ietf.org/rfc/rfc4627.txt) para ms
detalles.

Cuando se observa en la propiedad propietario, las declaraciones de


objetos se pueden anidar. Por otra parte, tambien podemos expresar
arrays en JSON colocando la lista con los elementos separados por
comas dentro de corchetes, como en la siguiente expresin:
var algunosValores =
[a,b,c,d,e,f,g,h,i,j,k,l,m,n];

Como hemos visto en los ejemplos de esta seccin, las referencias a


objetos se almacenan habitualmente en variables o en propiedades de
otros objetos. Vamos un caso especial de esto ltimo.

Objetos como propiedades de un objeto window


Hasta ahora hemos visto dos formas de lamacenar una referencia a un
objeto javascript: variables y propiedades. Ambas utilizan notaciones
diferentes, como se muestra en el siguiente fragmento de cdigo:

var estaVariable = Antes yo estaba contigo, ahora estoy solo.;


algunObjeto.estaVariable = No te preocupes, siempre he estado aqu.;

Cada una de estas sentencias asigna una instancia String (creada


a travs de literales) a algo: una variable en la primera sentencia y una
propiedad de objeto en la segunda. Pero estas sentencias realizan
operaciones diferentes? Realmente no.

Cuando se utiliza la palabra clave var a alto nivel, fuera del cuerpo de
cualquier funcin, se trata de una notacin de programacin para
hacer referencia a una propiedad del objeto javascript predeinido
window. Cualquier referencia que se deine a alto nivel,
implcitamente esta deinida en la instancia window.

Esto signiica que las siguientes sentencias, si se utilizan fuera del


mbito de una funcin, son equivalentes:
var somos = son;
y
window.somos = son;
y
somos = son;

Independientemente de la notacin que utilicemos, se crear una


propiedad window llamada somos (si no existe antes) y se le
asignar el valor son. Adems, como son no tiene ningun valor, se
asume que es una propiedad de window.

Esto cubre todos los aspectos sobre nuestro repaso del Object de
javascript. A continuacin, se enuncian las conclusiones ms
importantes que debemos extraer de este estudio:

Un objeto javascript es una coleccin de propiedades sin orden.


Las propiedades consisten en un nombre y un valor. Los objetos se
pueden declarar utilizando literales de objetos. Las variables de alto
nivel son propiedades de window.

Ahora veamos que queramos decir cuando nos referamos a las


funciones javascript como objetos de primera clase.
Funciones como objetos de primera clase

En muchos lenguajes OO tradicionales los objetos pueden contener


datos y tambin pueden poseer mtodos. Los datos y los mtodos
usualmente son conceptos diferentes, sin embargo, Javascript sigue
otro camino.

Las funciones se consideran objetos, como cualquiera de los otros


tipos deinidos en javascript, por ejemplo String, Number o Date.
De la misma forma que en cualquier objeto, las funciones son
establecidas por un constructor javascript, en este caso Function, y
pueden ser:

Asignadas a variables.
Asignadas como una propiedad de un objeto.
Pasadas como un parmetro.
Devueltas como el resultado de una funcin.
Creadas utilizando literales.

Debido a que las funciones son tratadas de la misma manera que otros
objetos de este lenguaje, decimos que son objetos de primera clase.

Pero podra pensar que son diferentes de otros tipos de objetos, como
String o Number, debido a que no slo poseen un valor (en el
caso de la instancia Function, su cuerpo) sino tambin un nombre.
Vamos esto en detalle.

Que hay en un nombre


Un gran nmero de programadores de javascript trabajan asumiendo
el falso concepto de que las funciones son entidades deinidas, cuando
realmente no es as. Como con otras instancias de objetos (por ejemplo
String, Date o Number), se hace referencia a ella slo cuando
son asignadas a variables, propiedades o parmetros.

Consideremos objetos del tipo Number: con frecuencia, expresamos


instancias de Number en su notacin literal, como por ejemplo 135.
La sentencia
135;

es perfectamente vlida, pero tambin es intil. La instancia Number


no servir para nada a no ser que se asigne a una propiedad o a una
variable, o se vincule con el nombre de un parmetro. Si no es as, no
existe ninguna forma de hacer referencia a ella. Lo mismo se aplica
para las instancias de los objetos Function.

Pero podra preguntarse que pasa con el siguiente cdigo:

function hacerAlgunaCosa(){ alert(haces


alguna cosa);
}

Acaso no se crea una funcin denominada hacerAlgunaCosa?

No es as. Aunque esta notacin le pueda resultar familiar y sea muy


utilizada para generar funciones de alto nivel, se trata de la misma
sintaxis empleada por var para crear propiedades window. La palabra
clave function crea, automticamente, una instancia Function y la
asigna a una propiedad window establecida mediante la funcin
deinida , como en la siguiente sentencia:

hacerAlgunaCosa = function() { alert(haces alguna cosa);


}

Si le parece extraa, considere otra que utiliza exactamente el mismo


formato, excepto que ahora se utiliza el literal de Number:
unNumeroMaravilloso = 135;

No hay nada raro en ella y la que asigna una funcin a una variable
de alto nivel ( la propiedad window) no es diferente; se utiliza el
literal de una funcin para crear una instancia de Function y, a
continuacin, se establece para la variable hacerAlgunaCosa, de
la misma forma que nuestro literal 135 tipoNumber se utiliz para
asignar una instancia Number a la variable
unNumeroMaravilloso.

Si nunca ha visto la sintaxis del literal de una funcin, le podr parecer


rara. Se compone de la palabra clave function, seguida de su lista
de parmetros entre llaves y luego el cuerpo. Cuando declaramos una
funcin deinida, se crea una instancia Function y se asigna una
propiedad de window, que se origina automticamente mediante el
nombre de dicha funcin. La instancia Function consiste en un
nico nombre, al igual que un literal de Number o de String. El
siguiente cuadro ilustra este concepto.

Nmero 135 Funcin

(){
alert(haces alguna cosa);
}

window

unNumeroMaravilloso hacerAlgunaCosa

Una instancia Function es un objeto sin nombre como el nmero 135 o


cualquier otro valor de javascript. Slo se deine cuando se referencia
la misma

Recuerde que una variable de alto nivel en una pgina HTML se crea
como una propiedad de la instancia window. Por lo tanto, las siguientes
sentencias son equivalentes:

function holaMundo() { alert(hola a todos!); } holaMundo = function() {


alert(hola a todos!); } window holaMundo = function() { alert(hola a
todos!); }

Aunque esto pueda parecerse a hacer juego de malabares con la


sintaxis, es importante entender que las instancias Function son
valores que se pueden asignar a variables, propiedades o parmetros,
como las que se realizan sobre otros tipos de objetos. Y, de la misma
forma que ocurre con ellos, las que no poseen un nombre no tienen
ninguna utilidad, a no ser que se asigne a una variable, propiedad o
parmetro a travs del cual se les pueda hacer referencia.
Hemos visto ejemplos de asignacin de funciones a variables y
propiedades pero podramos preguntarnos como pasarlas como
parmetros. Vamos a ver la manera de hacerlo y su porqu.

Navegadores Gecko y los nombres de las funciones


Los navegadores basados en el motor de diseo Gecko, como Firefox
y Camino, almacenan el nombre de las funciones definidas utilizando la
sintaxis de alto nivel en una propiedad no estndar de la instancia de
la funcin
Atento
denominada name. Aunque esto puede que no sea muy til en
general, en el caso particular de navegadores Gecko es muy
aprovechable para los desarrolladores de plugins y depuradores de
navegadores.
Funciones como callbacks
Las funciones de alto nivel estn muy bien cuando nuestro cdigo
sigue un lujo sncrono ordenado pero la naturaleza de las pginas
HTML (una vez abiertas) estn muy lejos del sincronismo. Estemos
manejando eventos, iniciando temporizadores o realizando peticiones
Ajax, la naturaleza del cdigo en una pgina web es asncrona. Y uno
de los conceptos mas importantes es el de la funcin callback.

Utilicemos el ejemplo de un temporizador. Podemos iniciarlo


(supongamos que est establecido en cinco segundos) pasndole el
valor adecuado de la duracin al mtodo
window.setTimeout().Pero como nos informa este mtodo de
que el temporizador ha terminado para que podamos hacer lo que sea
que estemos esperando hacer? Nos avisara llamando a una funcin
que le proporcionaremos nosotros.

Cosideremos el siguiente cdigo:


function holaMundo() { alert(hola a
todos!); } setTimeout(holaMundo,5000);

Declaramos una funcin llamada holaMundo y establecemos el


inicio de un temporizador en 5 segundos, expresaos como 5000
milisegundos en el segundo parmetro. En el primero del mtodo
setTimeout() pasamos una referencia a la funcin. Pasar una
funcin como parmetro no es diferente de hacerlo con cualquier otro
valor, igual que asignamos un Number como segundo parmetro.

Cuando el temporizador termina, se llama a la funcin holaMundo.


Debido a que el mtodo setTimeout() realiza una llamada a un
elemento de nuestro propio cdigo, esta funcin se denomina
callback.

Este cdigo de ejemplo podra ser considerado ingenuo, por los


desarrolladores de javascript de nivel avanzado, ya que la creacin
del nombre holaMundo es innecesaria. A no ser que vaya a ser
llamado en algn lugar de la pgina, no hay necesidad de crear la
propiedad holaMundo de window para almacenar
momentanemente la instancia Function, que se pasar como el
parmetro callback. Una forma ms elegante de codiicar este
fragmento sera:

setTimeout(function(){alert(hola a
todos!);},5000);
en la cual expresamos el literal de la funcin directamente en la lista de
parmetros y no se genera ningn nombre innecesario.

Las que hemos creado en los ejemplos que hemos visto hasta ahora
son funciones de alto nivel (que conocemos como propiedades
window de alto nivel) o bien se asignan a parmetros en una llamada
a la funcin. Tambien podemos establecer instancias Function a las
propiedades de objetos y aqu es donde las cosas se ponen realmente
interesantes.

La variable this

Los lenguajes OO automticamente proporcionan los medios para


hacer referencia a la instancia actual de un objeto desde el interior de
un mtodo. En lenguajes como Java y C++, una variable llamada this
seala la instancia actual. En javascript, existe un concepto similar e
incluso se utiliza la misma palabra clave this, que tambin permite el
acceso a un objeto asociado con una funcin. Pero hay que advertir a
los programadores de lenguajes OO que tengan precaucin. La
implementacin de this en javascript se diferencia de la de sus
homlogos de forma stil pero signiicativa.

En lenguajes OO basados en clases, el puntero this, generalmente,


hace referencia a la instancia de la clase para el mtodo que se ha
declarado. En javascript, donde las funciones son objetos de primera
clase que no son declarados como parte de nada, el objeto
referenciado por this (denominado contexto de la funcin) no se
determina por como se declara la funcin, sino por como se invoca.
Esto signiica que la misma funcin puede tener diferentes contextos
dependiendo de como se realice la llamada Al principio, puede
parecer algo extrao pero es bastante til.
En el caso por defect, el contexto (this) de la invocacin de una funcin
es el objeto cuya propiedad contiene la referencia utilizada para hacer
la llamada. Volvamos al ejemplo del coche para aclarar este concepto,
modiicando la creacin del objeto del siguiente modo (con la parte
aadida resaltada):
var coche = {

marca : Ford,
modelo : Mondeo,
anio : 2013,
fechaCompra : new Date(2013,01,08),
propietario: {

nombre : Juan Reyes,


profesion : animador
}
quienSoy : function() {
return this.anio+ +this.marca+
+this.modelo;
}
};
Hemos aadido al ejemplo original una propiedad llamada quienSoy
que hace referencia a la instancia Function. La nueva jerarqua del
objeto se muestra en la siguiente igura:

Cadena Ford
Cadena Mondeo Nmero 2013
Fecha
08-01-2013
Cadena Juan Reyes

Cadena animador nombre profesion

Objeto
recoge las propiedades del objeto a travs del cual fue invocada por
medio de this.

Lo mismo ocurre para las funciones de alto nivel. Recuerde que son
propiedades de window, por lo que su contexto es el propio objeto
window.

Aunque esto puede ser el comportamiento implcito habitual, javascript


nos proporciona los medios para controlar explcitamente lo que se va
a utilizar como contexto de la funcin.

Podemos deinirlo con lo que queramos, haciendo la llamada a travs


de los mtodos call() o apply() de Function.
S, incluso las funciones tienen mtodos deinidos por el constructor de
Function por ser objetos de primera clase.

El mtodo call() hace la llamada especiicando como primer parmetro


el objeto que se va a utilizar como contexto, mientras que el resto de
los parmetros se convertiran en los de la funcin invocada (el
segundo parmetro de call() se convierte en el primer argumento de la
funcin invocada y as sucesivamente). El mtodo apply() funciona de
forma similar, excepto en que lo que se espera de su segundo
parmetroes que sea un array de objetos, los cuales se convierten en
los argumentos de la funcin invocada. Por si esto le parece algo
confuso, ha llegado el momento de realizar un ejemplo ms completo.
Considere el cdigo del ejemplo siguiente:

Ejemplo 1. El valor del contexto de la funcin depende de cmo se


llama a la misma.
nombre del archivo - funcionContexto.html
<!DOCTYPE html>
<html>

<head>
<title>funcion Contexto</title> <script>

var o1 = { handle:o1 }; var o2 = {


handle:o2 }; var o3 = { handle:o3 };
window.handle = window;

function quienSoy(){ return this.handle;


}

o1.identifyMe= quienSoy;

alert(quienSoy()); alert(o1.identifyMe());
alert(quienSoy.call(o2));
alert(quienSoy.apply(o3));

</script>
</head>
<body>
</body>

</html>

En este ejemplo se deinen tres objetos simples, cada uno de ellos con
una propiedad handle que facilita la identiicacin de cada uno dada
una referencia (lneas 5 a 7 del cdigo). Tambin aadimos una
propiedad handle a la instancia window, de forma que es fcilmente
localizable.
A continuacin, establecemos una funcin de alto nivel que devuelve el
valor de la propiedad handle para el objeto que se est utilizando
como contexto (lneas 9 y 10 del cdigo) y asignamos la misma
instancia de la funcin a una propiedad del objeto o1 denominada
identifyMe, aunque es importante destacar que la funcin se declara
independientemente del objeto.

Para terminar, enviamos cuatro alertas, cada una de las cuales utiliza
un mecanismo diferente para invocar la misma instancia de la funcin.
Cuando se abre en una pgina, la secuencia de las cuatro alertas ser
la mostrada en la imagen 1.1.

La secuencia de alertas ilustra lo siguiente:

Cuando la funcin se llama directamente como una funcin de alto


nivel, su contexto es la instancia window(lnea 13 del cdigo).
Cuando se llama como la propiedad de un objeto (en este caso o1),
este se convierte en el contexto de la funcin (lnea 14 del cdigo). Se
puede decir que la funcin acta como un mtodo para dicho objeto,
como en los lenguajes OO. Pero tenga cuidado al considerar esta
analoga. Se puede equivocar fcilmente si no es meticuloso, como se
ver en el resto de este ejemplo.
Emplear el mtodo call() de Function hace que el contexto se deina
como el objeto que se pasa como primer parmetro a call(), en este
caso o2 (lnea 15 del cdigo). En este ejemplo, la funcin acta como
un mtodo para o2, aunque no tenga ningn tipo de asociacin (ni
siquiera como una propiedad) con o2.
Como un call(), utilizar el mtodo apply() de Function deine el
contexto como el objeto que se pasa como primer parmetro (lnea 16
Cuando se recurre a comandos y funciones que utilizan callbacks, lo
anterior demuestra ser un concepto importante.

Closures

Para los creadores de pginas con conocimientos de lenguajes OO


tradicionales o programacin basada en procedimientos, los
closures sern con frecuencia un concepto difcil de asimilar,
mientras que para aquellos que posean una base en programacin
funcional les resultar una idea con la que se sentirn cmodos y
podrn estar familizarizados con ella. Para los no iniciados, vamos a
deinir lo qu son los closures.

Dicho de la forma ms sencilla posible: un closure es una instancia


Function asociada con las variables locales de su entorno que son
necesarias para su ejecucin.

Cuando se declara una funcin, sta tiene la capacidad de hacer


referencia a cualquier variable que este en su mbito en el punto de
ejecucin en el que se declara. Esto es previsible y no debera ser una
novedad para los desarrolladores de cualquier nvel. Pero, con
closures, estas variables son llevadas junto con la funcin incluso
despus de que el lugar de la declaracin est fuera del mbito,
cerrando la declaracin.

La capacidad de las funciones callbacks de hacer referencia a


variables locales cuando ya han sido declaradas es una herramienta
esencial para escribir javascript eicaz. Utilizando de nuevo un
temporizador, veamos el ejemplo ilustrativo siguiente:

Ejemplo 2. Los closures permiten el acceso al mbito de la declaracin


de una funcin.

nombre del archivo - funcionContexto.html


<!DOCTYPE html>
<html>

<head>
<title>Closure Example</title>
<script type=text/javascript

src=javascript/jquery-1.4.js></script>
<script>

$(function(){
var local = 1;
window.setInterval(function(){

$(#display)
.append(<div>El dia + new Date()+
local=+local+</div>);
local++;
},3000);
});
</script>
</head>

<body>
<div id=display></div>
</body>
</html>
Supongamos que, debido a que el callback se va a iniciar cuando
hayan pasado tres segundos desde el momento en que se abra la
pgina (mucho despus de que el manejador ready haya terminado
de ejecutarse), el valor de local no esta deinido durante la activacin
de la funcin callback. Despus de todo, el bloque en el que se
deine local se encuentra fuera del mbito cuando el manejador
ready ha inalizado.

Pero cuando abrimos la pgina y dejamos que se ejecute durante unos


instantes, vemos el resultado que se muestra en la imagen 1 2.

Como podemos observar, funciona, pero, por qu? Aunque es cierto


que el bloque en el cual se declara local est fuera del mbito cuando
el manejador ready inaliza, el closure creado por la declaracin de la
funcin, que incluye a la variable local, permanece en su interior
mientras la funcin existe.

Nota
Quizs se haya dado cuenta que el closure se ha creado
implcitamente sin necesidad de una sintaxis explcita requerida en
otros lenguajes diferentes a javascript. Esto es un arma de doble filo, ya
que, por una parte, facilita
Atento

la creacin de closures (aunque sta no sea su intencin) pero, por


otra, puede hacer difcil su localizacin dentro del cdigo. Los closures
no intencionados pueden tener consecuencias no previstas. Por
ejemplo, las referencias circulares pueden conducir a prdidas de
memoria. Un ejemplo clsico de esto es la creacin de elementos del
DOM que vuelven ha hacer referencia a variables closure, evitando
que stas se puedan recuperar.

Otra caracterstica importante de los closures es que el contexto de una


funcin nunca se incluye como parte de los mismos. Por ejemplo, el
siguiente cdigo no se ejecutar segn lo previsto:
...
this id = algunID;
$(*).each(function(){

alert(this id); });

Recuerde que cada invocacin de la funcin tiene su propio contexto,


por lo que en el cdigo anterior el contexto de la funcin del callback
que se pasas a each() es un conjunto envuelto y no la propiedad de la
funcin externa deinida como algunID. Cada invocacin a callback
muestra un cuadro de dilogo de alerta donde se onserva
sucesivamente el id de cada elemento del conjunto envuelto.

Cuando necesitamos acceder al objeto que acta como contexto en la


funcin externa, podemos utilizar una sintaxis habitual que crea una
copia de la referencia this en una variable local que ser incluida en el
closure. Considere el siguiente cambio en el ejemplo anterior:

this id = algunID;
var propietario = this;
$(*).each(function(){

alert(propietario.id); });
La variable local propietario, a la que se le asigna una referencia al
contexto de la funcin externa, forma parte del closure y se puede
acceder a la misma en la funcin callback. Este cambio en el cdigo
har que se muestre una alerta donde se visualizar la cadena
algun D, tantas veces como elementos haya en el conjunto envuelto.
La referencia
El elemento <canvas>.

Este elemento deine una regin en el documento destinada a ser


usada como un canvas bitmap donde el cdigo script, puede ser usado
para renderizar gricos de forma interactiva. Seguramente usted
notar que la sintaxis markup de esta etiqueta es relativamente corta
comparado con lo que realmente es requerido para poder dibujar y
usar la tecnologa que esta dentro de esta, lo que nos lleva a muchos a
preguntarnos, como trabaja este objeto canvas?.

Como trabaja el objeto <canvas>

Canvas es una herramienta muy poderosa, para dibujar, crear juegos,


animaciones, etc., la mayora de profesionales se dirigen a este como
de modo inmediato. Cuando trabajas en canvas, todo lo que haces es
dibujar pixeles dentro de la pgina. Canvas no tiene ni idea en
absoluto de tus intenciones al dibujar o crear contenido en el. Todo
trata acerca de pixeles, la mayora de las creaciones canvas limpian
completamente el canvas entre cada fotograma y redibuja cada cosa
en una posicin actualizada.

Atributos y mtodos del objeto <canvas>

El objeto canvas posee dos propiedades que pueden ser accesadas


muy fcilmente a travs de cdigo javascript, estas propiedades son:
width y height. Estas dan informacin acerca del ancho y alto de
renderizado del objeto canvas dentro de una pgina HTML.
Width

Descripcin Se reiere al ancho de la supericie de dibujo del elemento


canvas. Por defecto los buscadores crean el elemento canvas con el
mismo tamao que la supericie de dibujo, Si de cualquier manera tu
sobreescribes el tamao del elemento canvas desde CSS, entonces el
buscador escalar la supericie de dibujo para reparar el elemento.

Tipo Entero no negativo


Valores permitidos
Valores por defecto

Cualquier entero valido no negativo. Tu puedes agregar un signo mas


o un espacio en blanco al comienzo, pero tu no puedes agregar un
suijo px. ya que tcnicamente no esta permitido por la especiicacin
canvas.
300

Height

Descripcin
Tipo
Valores permitidos
Valores por defecto

Se reiere al alto de la supericie de dibujo del elemento canvas. Por


defecto los buscadores crean el elemento canvas con el mismo tamao
que la supericie de dibujo, Si de cualquier manera tu sobreescribes el
tamao del elemento canvas desde CSS, entonces el buscador
escalar la supericie de dibujo para reparar el elemento.
Entero no negativo

Cualquier entero valido no negativo. Tu puedes agregar un signo mas


o un espacio en blanco al comienzo, pero tu no puedes agregar un
suijo px. ya que tcnicamente no esta permitido por la especiicacin
canvas.
150

Ejemplo de sintaxis del canvas


<!DOCTYPE html> <html>

<head> <title>Ejemplo de sintaxis


canvas</title> <style>
...
#canvas {
...
}
</style>

</head>
<body>
<canvas id=canvas width=600 height=300>

Tu navegador no soporta canvas de HTML 5


</canvas>
<script src=ejemplo.js></script>

</body>
</html>

Otros atributos de la etiqueta canvas de HTML5 son listados en la


siguiente tabla juntamente con algunos de sus valores permitidos.

atributos

accesskey class contenteditable contextmenu data-X dir draggable


hidden id itemid itemprop itemref itemscope itemtype lang spellcheck
style tabindex title

valor

lista espaciada de clave(s) de acelerador nombre(s) de la clase


true | false | inherit
id de men
datos deinidos por el usuario
ltr | rtl
true | false | auto
hidden
identiicador nico alfanmerico
id de los microdatos en el formato URL valor de microdata
lista de Ds que puedan contener microdata itemscope
tipo de microdatos en el formato URL cdigo de lenguaje
true | false
informacin de estilos
number
releja el titulo de la seccin o del canvas

Tabla 1 - atributos HTML5 de la etiqueta canvas y sus valores


Contexto 2d
El contexto 2d HTML5 (El objeto
canvasRenderingContext2d), recuperado a travs de una
llamada al mtodo getContext() del objeto canvas, es el lugar
donde se lleva a cabo toda la accin. El
canvasRenderingContext2d contiene todos los mtodos y
propiedades que necesitamos para dibujar dentro del objeto canvas.
El canvasRenderingContext2d (o contexto como lo
llamaremos de aqu en adelante), usa un sistema de coordenadas
cartesianas con 0,0 en la esquina superior izquierda del objeto
canvas, e incrementa su valor a medida que avanza desde la izquierda
y hacia abajo.
Sin embargo, todas estas propiedades y mtodos son usados en
conjunto con el estado actual (current state). Un concepto que
realmente debe ser aximilado para llegar a entender en profundidad
como trabajar con el elemento canvas de HTML5.
he current state is actually a stack of drawing state that apply globally to
the entire canvas. Tu manipulars todos estos estados cuando ests
dibujando en el objeto canvas. Estos estados incluyen:

Una matriz de transformacin


Mtodos para escalar, rotar, transformar y trasladar o mover.
La regin clipping
Creada con el mtodo clip().
Las propiedades del contexto
Propiedades incluidas: strokeStyle, illStyle, globalAlpha, lineWidth,
lineCap, lineJoin, miterLimit, shadowOfsetX, shadowOfsetY, shadowBlur,
shadowColor, globalCompositeOperation, Font, textAlign y
textBaseline.
Existen tambin seis mtodos pblicos para el objeto canvas. ellos son:
getContext(), setContext(), supportsContext(),
toDataURL(),toDataURLHD(), toBlob(),
toBlobHD() y commit(). Estos mtodos devuelven una
cadena de datos que representa la imagen bitmapeada del objeto
canvas como se encuentra renderizada en la actualidad. Esto es similar
a una captura de pantalla. Al proveer diferentes tipos M ME como
parmetros, t puedes recuperar los datos en diferentes formatos. El
formato bsico es image/png, pero image/jpeg y otros formatos
tambin pueden ser recuperados.

getContext(contextId)

Descripcin
Devuelve el contexto grico asociado con el elemento canvas. Cada
elemento

canvas tiene un contexto y cada contexto esta asociado con un


elemento canvas, es decir, si llamas nuevamente al mtodo
getContext(2d), este te devolver el mismo objeto. Este
mtodo acepta un argumento que especiica el tipo de dibujo que
quieres hacer con el canvas. Pasando la cadena 2d obtiene el objeto
canvasRenderingContext2d, con el que puedes dibujar en
dos dimensiones.
El estndar HTML5 slo deine 2d como argumento vlido para este
mtodo. Paralelamente existe otro estndar llamado WebGL,
desarrollado para gricos 3d en navegadores que lo soportan. Tu
puedes pasar webgl como argumento para este mtodo y obtener
un objeto que te permite renderizar en 3D.

Ahora bien, para efectos de este libro, solo usaremos el objeto:


canvasRenderingContext2d.

setContext(context)

Descripcin
Establece el contexto de renderizado del canvas para el objeto dado.
Lanza una excepcin InvalidStateError si se han utilizado los
mtodos getContext() o transferControlToProxy().

supportsContext(contextId)

Descripcin Devuelve false si el mtodo getContext() es


llamado con los mismos argumentos y true en caso contrario.
Este valor devuelto no es garanta de que el mtodo
getContext() devolver o no un objeto, ya que las condiciones
(por ejemplo, la disponibilidad de recursos del sistema) pueden variar
con el tiempo.
Lanza una excepcin InvalidStateError si se han utilizado los
mtodos setContext() o transferControlToProxy().

toDataURL(type, quality)

Descripcin
Devuelve una cadena con los datos URL que tu hayas asignado a la
propiedad
src de un elemento image. Este mtodo acepta dos argumentos, el
primer argumento especiica el tipo MIME de la imagen, tal como
image/jpeg o image/png, este ltimo se establece por defecto si
tu no especiicas el primer argumento. El segundo argumento, debe ser
un valor double, que va desde 0 hasta 1.0, especiica el nivel de
calidad para las imgenes jpeg. Este mtodo devuelve los datos a una
resolucin de 96ppp.

Ejemplo del mtodo toDataURL():

// Copia el contenido del canvas en un


elemento image // y pega esta imagen en el
documento
var canvas =
document.getElementById(canvas); var image
= document.createElement(img);
image.src = canvas.toDataURL();
document.body.appendChild(image);

toDataURLHD(type, quality)

Descripcin Devuelve una cadena con los datos URL que tu hayas
asignado a la propiedad src de un elemento image. Este mtodo
acepta dos argumentos, el primer argumento especiica el tipo M ME de
la imagen, tal como image/jpeg o image/png, este ltimo se
establece por defecto si tu no especiicas el primer argumento. El
segundo argumento, debe ser un valor double, que va desde 0
hasta 1.0, especiica el nivel de calidad para las imgenes jpeg. Este
mtodo devuelve los datos a la resolucin nativa del canvas.
toBlob(callback, type, args)

Descripcin crea un blob que representa un archivo que contiene la


imagen del elemento canvas. El primer argumento de este mtodo es
una funcin que invoca el navegador con una referencia al blob. El
segundo argumento especiica el tipo de imagen, tal como
image/png, la cual es el valor por defecto. El argumento inal
representan un nivel de calidad que va desde 0 hasta 1.0 ambos
inclusive, para imgenes jpeg. Otros argumentos deberan ser
agregados a este mtodo en el futuro para mayor control en las
caractersticas de la imagen. Este mtodo devuelve los datos a una
resolucin de 96 ppp.

toBlobHD(callback, type, args)

Descripcin
crea un blob que representa un archivo que contiene la imagen del
elemen

to canvas. El primer argumento de este mtodo es una funcin que


invoca el navegador con una referencia al blob. El segundo argumento
especiica el tipo de imagen, tal como image/png, la cual es el valor
por defecto. El argumento inal representan un nivel de calidad que va
desde 0 hasta 1.0 ambos inclusive, para imgenes jpeg. Otros
argumentos deberan ser agregados a este mtodo en el futuro para
mayor control en las caractersticas de la imagen. Este mtodo devuelve
los datos con la resolucin nativa del canvas.
transferControlToProxy()

Descripcin
Devuelve un objeto CanvasProxy que se puede utilizar para
transferir el

control desde este canvas a otro documento (por ejemplo, un iframe


de otro origen) o de un worker.
Lanza una excepcin InvalidStateError si se han utilizado los
mtodos getContext() o setContext().

commit()

Descripcin
Si el contexto de representacin esta enlazado a un canvas, este
mtodo muestra el fotograma actual. Este mtodo es usado para
contextos que no estn directamente ijos a un canvas especiico.
Juntamente con las propiedades anteriores, existen dos mtodos que
preservan el estado del canvas, estos son:

save()

Descripcin
Coloca una copia del estado actual de los gricos dentro de la pila de
los estados

gricos salvados. Esto permite cambiar temporalmente el estado de los


gricos para luego poder ser restaurados con una llamada al mtodo
restore(). El estado grico de un canvas incluye todas las
propiedades del objeto context (excepto para las propiedades de
solo lectura). Estn tambin incluidas la matriz de transformacin
resultante de la llamada a los mtodos rotate(), scale() y
translate().Adicionalmente, esto incluye tambin a la regin
clipping especiicada por el mtodo clip().Note, sin embargo, que el
path actual y la posicin actual no son parte del estado grico, por lo
tanto no es posible salvarlos con este mtodo.

restore()

Descripcin
Este mtodo recupera la pila de los estados gricos salvados y
restaura el valor de las propiedades del contexto, la regin clipping y
la matriz de transformacin.
Ejemplo de aplicacin de algunos mtodos de esta seccin;

nombre del archivo - reloj.html


<!DOCTYPE HTML>
<title>Clock</title>
<canvas></canvas>
<script>

var canvas =
document.getElementsByTagName(canvas)[0];
var proxy = canvas.transferControlToProxy());
var worker = new Worker(reloj2.js);
worker.postMessage(proxy, [proxy]);

</script>
nombre del archivo - sreloj2.js
onmessage = function (event) {
var context = new CanvasRenderingContext2D();
event.data.setContext(context);
// event.data is the CanvasProxy object
setInterval(function () {
context.clearRect(0, 0, context.width,
context.height);

context.commit(); }, 1000);
};

La matriz de transformacin

Mtodos primarios de transformacin

scale(float x, float y)

Descripcin Agrega una escala de transformacin a la matriz de


transformacin. Los argumentos x e y deinen cuanto ajustar en el eje
X e Y respectivamente, es decir, expande o contrae distancias a lo
largo del eje de las abscisas X e Y. Pasar valores negativos a este
mtodo da como resultado el voltear el original a travs de las
abscisas, es decir, es como si estuviera relejada en un espejo (ver
imagen2.1). Ejemplo: context scale(2,2);

referenca referenca

Original Escala en el eje X Escala en el eje X con valores negativos imagen 2.1 -
mtodo scale().
Ejemplo de aplicacin del mtodo scale();
nombre del archivo - scale.html
<!DOCTYPE html>
<html>

<head> <title>Ejemplo del m&eacute;todo


scale()</title> <style>
#contenedor{

width:600px;
margin: 0px auto;
padding-top:50px;

#canvas {
background: #eaeaea;
}
</style>
</head>
<body>
<div id=contenedor>
<canvas id=canvas width=600 height=400>
Tu navegador no soporta canvas de HTML 5
</canvas>
<script src=scale.js></script>
</div>
</body>
</html>

nombre del archivo - scale.js


var canvas =
document.getElementById(canvas); var
context = canvas.getContext(2d);
var rectWidth = 150;
var rectHeight = 75;
dibujarCuadricula(context, lightgrey, 10,
10);

//trasladamos el contexto a la posicin


indicada en las coordenadas x e y
context.translate(300, 200);

//escalamos el ancho a la mitad


context.scale(1, 0.5);
rectWidth,rectHeight);

//Funciones..................................
function dibujarCuadricula(context, color,
stepx, stepy) { context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepx + 0.5; i <
context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();
}
for (var i = stepy + 0.5; i <
context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke(); }
}

El resultado se mostrar mas o menos de esta manera:


imagen 2.3
- mtodo rotate().
referenc
ia
Ejemplo de aplicacin del mtodo rotate();

nombre del archivo - rotate.html


<!DOCTYPE html>
<html>

<head>
<title>Ejemplo del m&eacute;todo rotate()
</title> <style>
#contenedor{

width:600px;
margin: 0px auto;
padding-top:50px;

#canvas{
background:#eaeaea;
}
</style>
</head>
<body>
<div id=contenedor>
<canvas id=canvas width=600 height=400>
Tu navegador no soporta canvas de HTML 5
</canvas>
<script src=rotate.js></script>
</div>
</body>
</html>

nombre del archivo -rotate.js


var canvas =
document.getElementById(canvas); var
context = canvas.getContext(2d);

var rectWidth = 150;


var rectHeight = 75;
dibujarCuadricula(context, lightgrey, 10,
10);

//trasladamos el contexto a la posicin


indicada en las //coordenadas x e y
context.translate(300, 200);

//rotamos el contexto 45 grados en el sentido


de las agujas //del reloj
context.rotate(Math.PI / 4);
rectWidth,rectHeight);

//Funciones..................................
function dibujarCuadricula(context, color,
stepx, stepy) { context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepx + 0.5; i <
context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i,0);
context.lineTo(i,context.canvas.height);
context.stroke();
transformacin. La traslacin mueve el objeto desde el origen a la
localizacin especiicada por las coordenadas dx y dy. Ejemplo:
context translate(100, 100);

context translate()
referencia
punto de inicio punto final imagen 2.5 - mtodo translate().
Ejemplo de aplicacin del mtodo translate();

nombre del archivo - translate.html


<!DOCTYPE html>
<html>

<head>
<title>Ejemplo del m&eacute;todo translate()
</title> <style>
#contenedor{

width:600px;
margin: 0px auto;
padding-top:50px;

#canvas {
background: #eaeaea;
}
</style>
</head>
<body>
<div id=contenedor>
<canvas id=canvas width=600 height=400>
Tu navegador no soporta canvas de HTML 5
</canvas>
<script src=translate.js></script>
</div>
</body>
</html>

nombre del archivo - translate.js


var canvas =
document.getElementById(canvas); var
context = canvas.getContext(2d);

var rectWidth = 150;


var rectHeight = 75;
dibujarCuadricula(context, lightgrey, 10,
10);

//trasladamos el contexto a la posicin


indicada en las //coordenadas x e y
context.translate(300, 200);

rectWidth,rectHeight);

//Funciones..................................
function dibujarCuadricula(context, color,
stepx, stepy) { context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepx + 0.5; i <
context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();
matriz de transformacin del contexto. Es decir, que en cualquier
momento que dibujes dentro del canvas, sea esto una forma, texto o
imagen, el navegador aplica la matriz de transformacin al objeto que
hayas dibujado o ests dibujando. Por defecto la matriz de
transformacin es conocida como una matriz idntica, lo que signiica
que no le hace nada al objeto que ests dibujando. Cuando llamas a
scale(), rotate() o translate() tu estas modiicando la
matriz de transformacin en forma que ello afecte a todas las futuras
operaciones de dibujo.
La mayora de las veces estos tres mtodos sern suicientes cuando
tus intenciones sea manipular la matriz de transformaciones
directamente. Por ejemplo si deseas aplicar un efecto shear a objetos
que dibujastes y que no es posible hacerlo con cualesquiera de los
tres mtodos principales de transformacin , entonces, en ese caso,
necesitars manipular la matriz de transformacin tu mismo. El contexto
canvas provee dos mtodos que manipulan directamente la matriz de
transformacin: transform(), la cual aplica la transformacin a la
actual matriz de transformacin y setTransform(), la cual resetea
la matriz a su valor original la matriz idntica y aplica la
transformacin a esta mtriz idntica. El inconveniente que podramos
encontrarnos es que sucesivas llamadas a transform() son
acumulativas y sucesivas llamadas a setTransform() despejan la
matriz de transformacin, limpindolas en cada llamada.
Tu podrs escalar, rotar y trasladar objetos con estos dos mtodos, lo
que para muchos profesionales representa dos grandes ventajas:

1. Tu puedes manejar y/o crear efectos tales como shear, que no seran
posible solo con el uso de los mtodos scale(), rotate() y
translate().
2. Tu puedes combinar efectos, tales como escalar, rotar, trasladar y
shear en una llamada a transform() o setTransfrom().
El mayor inconveniente que podramos encontrar al usar
transform() y setTransform() es que estos mtodos no son
tan intuitivos y fciles de entender como lo son scale(),
rotate() y translate().

transform(float a, float b, float c, float d, float e, float f)

Descripcin
Aplica la transformacin especiicada por los seis (6) argumentos. Las
trans

formaciones soportadas por canvas son comnmente conocidas como


aine transform. Estos tipos de transformaciones pueden modiicar
distancias entre dos puntos y los ngulos entre las lneas. Los
argumentos de este mtodo especiica los seis argumentos no triviales
de una matriz de transformacin aine T : A C E
BD F
001

Una transformacin aine ordinaria puede ser descrita por los


argumentos desde la a hasta la f por la siguiente ecuacin:
X = AX + CY + E
Y = BX + DY + F

Nota Destacada!
Traslaciones, escalas y rotaciones pueden ser implementadas en
trminos de esta propuesta general del mtodo transform(). Para
traslacin llamar a transform(1,0,0,1,dx, dy). Para una escala llamar a
transform(sx,0,0,sy,0,0). Para rotaciones en el sentido de las agujas del
reloj llamar a transform(cos(x), sin(x), -sin(x), cos(x),0,0). Para

Atento

una transformacin shear de un factor k paralela al eje de las abscisas


X, llamar a transfrom(1,0,k,1,0,0) y para el eje de las abscisas Y llamar a
transform(1,k,0,1,0,0).
Ejemplo:
//rotar en el sentido de las agujas del reloj
alpha radianes del punto (x,y)
function rotar(c, alpha, x, y){

var ct = Math.cos(alpha);

var st = Math.sin(alpha);
context.transform(ct, -st, st, ct,
-x*ct-y*st + x,
x*st y*ct + y); }

//preparar una transformacin shear


function shear(c, kx, ky){
context.transform(1, ky, kx, 1, 0, 0);
Ejemplo de aplicacin del mtodo transform();

nombre del archivo - transform.html


<!DOCTYPE html>
<html>
<head>
<title>Ejemplo del m&eacute;todo transform()
</title> <style>
#contenedor{

width:600px;
margin: 0px auto;
padding-top:50px;

#canvas {
background: #eaeaea;
}
</style>
</head>
<body>
<divid=contenedor>
<canvas id=canvas width=600 height=400>
Tu navegador no soporta canvas de HTML 5
</canvas>
<scriptsrc=transform.js></script>
</div>
</body>
</html>

nombre del archivo - transform.js


var canvas =
document.getElementById(canvas); var
context = canvas.getContext(2d);

var rectWidth = 150;


var rectHeight = 75;
dibujarCuadricula(context, lightgrey, 10,
10);

//matrix de traslacin: //1 0 tx


//0 1 ty
//0 0 1

var tx = canvas.width / 2; var ty =


canvas.height / 2;
//aplicar transformacin context.transform(1,
0, 0, 1, tx, ty);
rectWidth,rectHeight);

//Funciones..................................
function dibujarCuadricula(context, color,
stepx, stepy) { context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepx + 0.5; i <
context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i,0);
context.lineTo(i,context.canvas.height);
context.stroke();
}
for (var i = stepy + 0.5; i <
context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}
}
identidad transformada, es decir, tu puedes trabajar con las
coordenadas raw del canvas, usando un cdigo como este:

c.save();
c.setTransform(1,0,0,1,0,0);
/* usar coordenadas raw del canvas aqu */
c.restore();

Otro Ejemplo de aplicacin del mtodo transform();

nombre del archivo - transformAvanzado.html <!DOCTYPE


html>
<html>

<head> <title>Otro ejemplo del m&eacute;todo


transform() </title>
<style>
#contenedor{

width:600px;
margin: 0px auto;
padding-top:50px;

#canvas {
background: #eaeaea;
}
</style>
</head>
<body>
<div id=contenedor>
<canvas id=canvas width=600 height=400>
Tu navegador no soporta canvas de HTML 5
</canvas>
<script src=transformAvanzado.js></script>
</div>
</body>
</html>

nombre del archivo - transformAvanzado.js


var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d),
texto=transfromar,
angulo = Math.PI/45,
clockwise = true,
tamFuente = 100,
origen = { },
pausa = true,
escala = 1.028;

//
Funciones....................................
function dibujarTexto() {
context.strokeText(texto, 0, 0); }
// Manejadores de
eventos..................................

canvas.onclick = function() { pausa = !pausa;


if (!pausa) {

clockwise = !clockwise; escala = 1/escala; }


};
//
Animacion....................................
setInterval(function() {
if (!pausa) {
context.clearRect(-origen.x, -origen.y,
canvas.width, canvas.height);

context.rotate(clockwise ? angulo : -angulo);


context.scale(escala, escala);
dibujarTexto();

}
}, 1000/60);
//
Initialization...............................
context.font = tamFuente + px Palatino;
context.strokeStyle = blue;
context.shadowColor = rgba(100, 100, 150,
0.9);
context.shadowBlur = 5;
context.textAlign = center;
context.textBaseline = middle;
origen.x = canvas.width/2; origen.y =
canvas.height/2;
context.transform(1, 0, 0, 1, origen.x,
origen.y);
dibujarTexto();

El resultado se mostrar mas o menos de esta manera:


nombre del archivo - setLineDash.html
<!DOCTYPE html>
<html>

<head>
<title>Aplicaci&oacute;n del m&eacute;todo
setLineDash() </title>
<style>

body {
background: #eaeaea;
}
#contenedor{
width:500px;
margin:0px auto;
padding-top:50px;
}
#canvas {

}
</style> </head>

<body> <div id=contenedor>


<canvas id=canvas width=500 height=150>

Tu navegador no soporta canvas de HTML5


</canvas>
</div>

<script src=javascript/setLineDash.js>
</script> </body>
</html>
nombre del archivo
- setLineDash.js
contexto =
document.getElementById(canvas).getContext(
// Esto hace que las lneas aparecen claras y
ntidas, y
//se puede prescindir de esta
contexto.translate(0.5, 0.5);
// Dibujamos el circulo contexto.beginPath();

contexto.strokeStyle = green;
contexto.setLineDash([5]);
contexto.arc(65,65,50,0,2 * Math.PI,false);
contexto.stroke();

// Dibujamos el cuadrado
contexto.beginPath();

contexto.strokeStyle = blue;
contexto.setLineDash([5,2]);
contexto.rect(130,15,100,100);
contexto.stroke();

// Dibujamos el triangulo
contexto.beginPath();

contexto.strokeStyle = black;
contexto.setLineDash([1,2]);
contexto.moveTo(245,115);
contexto.lineTo(295,15);
contexto.lineTo(345,115);
contexto.closePath();
contexto.stroke();
Mtodos de Path

La mayora de los sotware de dibujo e ilustracin, tales como scalable


vector graphics (SVG), apples cocoa y/o adobe illustrator son basados
en path. Con estos sotware tu deines un path que consecuentemente
podrs delinear, rellenar o ambos inclusive.

Path y las tintas invisibles

Una buena prctica para crear un path, y luego delinearlo o rellenarlo,


es crearlo con tintas invisibles. Todos sabemos que para leer un
documento escrito con tintas invisible necesitas elementos extras que
te hagan la tarea mucho mas sencilla.

Atento
Usar mtodos tales como rect() o arc() es similar a dibujar con
tintas invisibles. Estos mtodos crean un path invisible que tu puedes
luego hacer visible llamando a los mtodos stroke() y .

beginPath()

Descripcin Resetea el path actual, limpiando todos los subpaths


desde el path actual. Este mtodo es llamado cuando vas a comenzar
un nuevo path.

closePath()

Descripcin
Explcitamente cierra un path abierto. Este mtodo es para abrir paths
de arcos y paths creados con lneas o curvas.

arc(float x, float y, float radius, float starAngle, float


endAngle, boolean anticlockwise)

Descripcin
Agrega los subpaths que vienen a representar un arco o un crculo al
actual

path. T puedes controlar la direccin en que se dibujarn los


subpaths (a diferencia del mtodo rect()), con una variable
booleana. S existe un subpath cuando el mtodo es llamado, este
dibujar una lnea desde el ltimo punto en el subpath existente hasta
el primer punto delante del arco del path. Este mtodo toma 6
parmetros, los primeros dos parmetros representan un punto en el
centro de un crculo; el tercer parmetro representa el radio del crculo,
el cuarto y quinto parmetros representan el angulo inicial y el angulo
inal, respectivamente del crculo que el navegador dibujar. El ltimo
argumento es opcional y representa la direccin en la cual el
navegador dibujara el arco. Si el valor se establece en false, como
viene por defecto, el navegador dibujar el arco en direccin al
sentido de las agujas del reloj, si por el contrario se establece en true,
el navegador dibujar el arco en la direccin contraria al sentido de
las agujas del reloj.

la linea gruesa corresponde a:


radio
linea inicial
rgba(0,0,0,0.5);
-box-shadow: 4px 4px 8px
rgba(0,0,0,0.5);
}
</style>
</head>
<body>
<canvas id=canvas width=400 height=300>
Tu navegador no soporta canvas de HTML 5
</canvas>
<script src=arc.js></script>
</body>
</html>

nombre del archivo - arc.js


var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d);
function drawScreen() {

context.beginPath();
context.strokeStyle = black;
context.lineWidth = 2;
context.arc(200, 150, 60, (Math.PI/180)*0,
(Math.

PI/180)*360, false);
//full circle
context.stroke();
context.closePath();

}
function dibujarCuadricula(context, color,
stepx, stepy) { context.save();
context.strokeStyle = color;
context.lineWidth = 0.5;
canvas.height);

for (var i = stepx + 0.5; i <


context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();

for (var i = stepy + 0.5; i <


context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();

}
context.restore(); }
dibujarCuadricula(context, lightgray, 10,
10); drawScreen();

El resultado se mostrar mas o menos de esta manera:


de los siguientes mtodos:

context.moveTo(x, y);
context.lineTo(x + w, y);
context.lineTo(x + w, y + h);
context.lineTo(x, y + h);
context.closePath();

Ejemplo de aplicacin del mtodo rect();

nombre del archivo - rect.html


<!DOCTYPE html>
<html>

<head>
<title>
Aplicaci&oacute;n del m&eacute;todo rect()
</title>
<style>
body {
background: #eaeaea; }

#contenedor{
width:800px;
margin:0px auto;
padding-top:50px;
}
#canvas {
margin-left: 20px;
margin-right: 0;
margin-bottom: 20px;
border: thin solid #aaaaaa;
cursor: crosshair;
}
</style>
</head>

<body>
<div id=contenedor>
<canvas id=canvas width=800 height=520>

Canvas not supported


</canvas>
</div>

<script src=javascript/rect.js></script>
</body>
</html>

nombre del archivo


- rect.js
var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d);

//borramos todos los subpaths desde el path


actual context.beginPath();
//agregamos un subpath con cuatro puntos
context.rect(10, 10, 100, 100);
//delineamos el subpath que contiene los
cuatro puntos context.stroke();
//borramos todos los subpaths desde el path
actual context.beginPath();
//agregamos un subpath con cuatro puntos
context.rect(90, 90, 200, 200);
function rect(x, y, w, h, direccion) {
if (direccion) {
// En sentido contrario a las agujas del
reloj context.moveTo(x, y);
context.lineTo(x, y + h);
context.lineTo(x + w, y + h);
context.lineTo(x + w, y);

}else {
context.moveTo(x, y);
context.lineTo(x + w, y);
context.lineTo(x + w, y + h);
context.lineTo(x, y + h);

}
context.closePath();
}

fill(Path path, optional CanvasFillRule fillRule =


nonzero)

Descripcin El mtodo rellena el actual path con el color, gradiente o


patrn especiicado por la propiedad del contexto .
Cualquier subpath que no este cerrado, sern rellenos como si el
mtodo closePath() haya sido invocado (Tenga en cuenta que no
causa verdaderamente esos subpaths al ser cerrado). Rellenar un
path no borra el path. Usted puede llamar al mtodo
stroke()despues de llamar al mtodo sin redeinir el path.
Cuando el path se corta a s mismo o cuando los subpaths se
sobreponen, el mtodo aplica por defecto como argumento opcional la
nonzero winding rule , para determinar que puntos se encuentran
dentro del path y cuales estn fuera. Esto signiica, por ejemplo, que si
has deinido un path cuadrado dentro de un path circular y el subpath
del cuadrado esta en la direccin opuesta al path del crculo, entonces
el interior del cuadrado estar fuera del path y no ser rellenado.

El mtodo fill()

Este mtodo posee un parmetro opcional w, la cual si no es


especificado o si es la cadena cero , este mtodo debe rellenar todos
los subpaths utilizando la regla del trazado distinta de zero (nonzero
winding rule). Si el parmetro opcional es la cadena evenOdd , este
mtodo debe rellenar todos los subpaths utilizando la regla par-impar
(even

Atento
odd rule). Los subpaths abiertos deben ser implcitamente cerrados
cuando ha sido rellenado (sin afectar los subpaths reales).

stroke(Path path)

Descripcin El mtodo stroke() dibuja la lnea externa del actual


path. El path deine la geometra de las lneas producidas, pero la
apariencia visual de esta lnea depende de las propiedades
strokeStyle, lineWidth, lineCap, lineJoin y
miterLimit. El trmino stroke se reiere al lpiz o pincel que
dibujar la lnea, esto signiica dibujar la lnea externa de . El mtodo
stroke() contrasta con el mtodo , el cual rellena el interior del
path mientras que este delinea la lnea externa del path. Puede
aceptar un argumento opcional que representa un objeto path y
puede ser un path svg.

Nota destacada!
Como resultado de como se define el algoritmo para trazar un path,
partes de los paths que se sobreponen en una sola operacin stroke,
son tratados como si su unin fue lo dibujado.
Atento
El estilo del trazo (stroke) se ve afectada por lamatriz de transfromacin
actual durante el proceso, incluso si la trayectoria deseada es el actual
path predeterminado.

Los paths cuando se rellenan o delinean, deben ser dibujados sin


afectar al path actual predeterminado o cualquier objeto path y deben
estar sujetas a los efectos de sombras, transparencias, region clipping
y operadores de globalComposite.

Ejemplo de aplicacin de los mtodos arc(), beginPath(),closePath(),


fill(), rect() y stroke():

nombre del archivo - strokeFill.html


<!DOCTYPE html>
<html>

<head> <title> M&eacute;todos de Path</title>


<style>
#canvas {
background: #eeeeee;

}
#radios {
padding: 10px; }
</style>
</head>
<body>

<canvas id=canvas width=620 height=475>

Tu navegador no soporta canvas de HTML5


</canvas>
<script src=strokeFill.js></script>

</body>
</html>

nombre del archivo - strokeFill.js


var context =
document.getElementById(canvas).getContext(

// Dibujar
atributos....................................
context.font = 28pt Helvetica;
context.strokeStyle = green;

context.lineWidth = 1; // Line width set to


2 for text
//
Textos.......................................
context.strokeText(Lineas, 60, 80);
context.strokeText(Ambos, 440, 80);

//
Rectangulos..................................
//el ancho de las lineas establecidas en 4
para las formas context.lineWidth = 4;
context.beginPath();
context.rect(65, 150, 100, 50);
context.stroke();
context.beginPath();
context.rect(250, 150, 100, 50);

context.beginPath();
context.rect(450, 150, 100, 50);
context.stroke();

//arcos con lineas


abiertas..................................
context.beginPath();
context.arc(115, 280, 40, 0, Math.PI*3/2);
context.stroke();
context.beginPath();
context.arc(300, 280, 40, 0, Math.PI*3/2);

context.beginPath();
context.arc(500, 280, 40, 0, Math.PI*3/2);
context.stroke();

// arcos con lneas


cerradas.................................
context.beginPath();
context.arc(115, 400, 40, 0, Math.PI*3/2);
context.closePath();
context.stroke();
context.beginPath();
context.arc(300, 400, 40, 0, Math.PI*3/2);
context.closePath();

context.beginPath();
Descripcin Si estos no son subpaths en el path actual, este mtodo
hace parcialmente lo mismo que moveTo(): crea un subpath en el punto
que has especiicado. Ahora bien, si estos son subpaths en el path
actual, este mtodo agrega el punto que has especiicado a este
subpath.

Ejemplo de aplicacin de los mtodos moveTo() y lineTo():

nombre del archivo - cuadricula.html


<!DOCTYPE html>
<html>

<head> <title> M&eacute;todos de moveTo() y


lineTo() </title>

<style>
#canvas {
background: #eaeaea;

}
#radios {
padding: 10px; }

</style>
</head>
<body>

<canvas id=canvas width=620 height=475>

Tu navegador no soporta canvas de HTML5


</canvas>
<script src=cuadricula.js></script>
</body>
</html>

nombre del archivo - cuadricula.js


var context =
document.getElementById(canvas).getContext(

//
Funciones....................................
function dibujarCuadricula(context, color,
stepx, stepy) { context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepx + 0.5; i <
context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();
}
for (var i = stepy + 0.5; i <
context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}
}

//Iniciar
aplicacin...................................
nombre del archivo - arcTo.html
<!DOCTYPE html>
<html>

<head> <title>Ejemplo del m&eacute;todo


arcTo() </title> <style>
#contenedor{

width:600px;
margin: 0px auto;
padding-top:50px;

#canvas{
background:#eaeaea;
}
</style>
</head>
<body>
<div id=contenedor>
<canvas id=canvas width=600 height=400>
Tu navegador no soporta canvas de HTML 5
</canvas>
<script src=arcTo.js></script>
</div>
</body>
</html>

nombre del archivo


- arcTo.js
var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d);
dibujarCuadricula(context, lightgrey, 10,
10);

context.beginPath();
context.moveTo(150, 100);
context.arcTo(500,100,500,200,10); // esquina
superior derecha
context.arcTo(500,200,100,200,30); // esquina
inferior derecha
context.arcTo(100,200,100,100,10); // esquina
inferior izquierda
context.arcTo(100,100,200,100,10); // esquina
superior izquierda context.closePath(); //
Regresar al punto de inicio
context.stroke(); // Dibuja el path
//Funcion
es...........................................
function dibujarCuadricula(context, color,
stepx, stepy) {

context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepx + 0.5; i <
context.canvas.width; i +=

stepx) {
context.beginPath();
context.moveTo(i,0);
context.lineTo(i,context.canvas.height);
context.stroke();
Descripcin Crea un path para una curva Bzier cuadrtica. Este
mtodo acepta cuatro (4) argumentos. Los argumentos cpx y cpy
representan las coordenadas del punto de control y los argumentos x
e y representan el punto inal de la curva. Este mtodo agrega un
segmento de curva Bzier cuadrtica al subpath actual. La curva se
inicia en el punto actual y termina en las coordenadas x e y dada por
los argumentos. El punto de control (cpx, cpy) determina la forma de
la curva entre estos dos puntos.
Cuando este mtodo inaliza devuelve el punto actual como las
coordenadas x e y.

Ejemplo de aplicacin del mtodo quadraticCurveTo():

nombre del archivo - quadraticCurveTo.html


<!DOCTYPE html>
<head>

<title>Dibujar curvas bezier


cuadr&aacute;ticas</title> <style>
body {
}

#canvas {
position: absolute;
left: 0px;
margin-left: 20px;
margin-right: 20px;
border: thin solid rbga(0,0,0,1.0);
background:#eaeaea;

}
input {
margin-left: 15px;
}

</style> </head>

<body>
<canvas id=canvas width=400 height=400>
Tu navegador no soporta canvas de HTML5

</canvas>
<script src=quadraticBezierTo.js></script>
</body>
</html>

nombre del archivo - quadraticCurveTo.js


var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d),
MARGEN_FLECHA = 40,
RADIO = 6,
puntos = [
{ x: canvas.width - MARGEN_FLECHA, y:
canvas.height - MARGEN_FLECHA },

{ x: canvas.width - MARGEN_FLECHA * 2, y:
canvas.height - MARGEN_FLECHA },
{ x: RADIO,
y: canvas.height/2 },
{ x: MARGEN_FLECHA,
y: canvas.height/2 - MARGEN_FLECHA },
{ x: canvas.width - MARGEN_FLECHA, y:
MARGEN_FLECHA },
{ x: canvas.width - MARGEN_FLECHA, y:
MARGEN_FLECHA*2 },
];
//
Funciones....................................
context.beginPath();

context.strokeStyle = strokeStyle;
context.lineWidth = 0.5;
context.arc(x, y, RADIO, 0, Math.PI*2,
false);

context.stroke(); }
function dibujarPuntosBezier() { var i,
strokeStyle,
for (i=0; i < puntos.length; ++i) {
-

Style);
}
}

function dibujarFlecha() {
context.strokeStyle = lightgrey;
context.moveTo(canvas.width - MARGEN_FLECHA,
MARGEN_FLECHA*2);
context.lineTo(canvas.width - MARGEN_FLECHA,
canvas.height - MARGEN_FLECHA*2);
context.quadraticCurveTo(puntos[0].x,
puntos[0].y, puntos[1].x, puntos[1].y);
context.lineTo(MARGEN_FLECHA,
canvas.height/2 + MARGEN_FLECHA);
context.quadraticCurveTo(puntos[2].x,
puntos[2].y, puntos[3].x, puntos[3].y);
context.lineTo(canvas.width -
MARGEN_FLECHA*2, MARGEN_FLECHA);
context.quadraticCurveTo(puntos[4].x,
puntos[4].y, puntos[5].x, puntos[5].y);
context.stroke(); }

function dibujarCuadricula(context, color,


stepx, stepy) { context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepx + 0.5; i <
context.canvas.width; i +=

stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();

}
for (var i = stepy + 0.5; i <
context.canvas.height; i += stepy) {

context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();

}
}
// Iniciar
aplicacin...................................

context.clearRect(0,0,canvas.width,canvas.heig
Descripcin Agrega una curva bezier cubica al actual subpath. Este
mtodo acepta seis (6) argumentos: cpX1 y cpY1 representan las
coordenadas del punto de control asociadas al punto inicial de las
curvas (la posicin actual), cpX2 y cpY2 representan las
coordenadas del punto de control asociadas al punto inal de las
curvas y por ltimo x e y representan las coordenadas del punto inal
de las curvas.
El punto de inicio de la curva, es el punto actual del canvas y el punto
inal est representados en las coordenadas x e y de los argumentos.
Los dos puntos de control Bzier (cpX1, cpY1) y (cpX2, cpY2)
deinen la forma de la curva.

Ejemplo de aplicacin del mtodo bezierCurveTo():

nombre del archivo - bezierCurve.html


<!DOCTYPE html>
<html>

<head>
<title>Dibujar curvas bezier</title>
<style>
body {
background: #eeeeee; font-size:14px;
}

#contenedor{
width:605px;
margin: 0px auto;
padding-top:50px;

}
.controlesFlotantes {
position: absolute;
left: 570px;
top: 170px;
width: 300px;
padding: 20px;
border: thin solid rgba(0, 0, 0, 0.3);
background-color:#eaeaea ;
color: blue;
font: 14px Arial;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 6px
6px 8px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 6px 6px
8px; box-shadow: rgba(0, 0, 0, 0.2) 6px 6px
8px; display: none;

}
.controlesFlotantes p { margin-top: 0px;
margin-bottom: 20px;

#controles {
position:relative; left: 25px;
top: 25px;

#canvas {
background: #eaeaea; cursor: pointer;
margin-left: 10px; margin-top: 10px;
border:1px solid #999;

}
</style>
</head>

<body>
<div id=contenedor>
<canvas id=canvas width=605 height=400>

Tu navegador no soporta canvas de HTML5


</canvas>
<div id=controles>
Color linea:

<select id=selectEstiloLinea>
<option value=red>rojo</option> <option
value=green>verde</option> <option
value=blue>azul</option> <option
value=orange>naranja</option>

</option> <option
value=goldenrod>dorado</option> <option
value=navy selected>azul oscuro

</option>
<option value=purple>purpura</option>
</select>
Lineas guias:
<input id=checkboxLineasGuias
type=checkbox checked/> <input
id=botonBorrarTodo type=button
value=Borrar todo/> </div>
<div id=instrucciones
class=controlesFlotantes>
de control para cambiar la forma de la curva.
</p>

- va,y los puntos de control, haz click fuera


de ella para terminar.</p>

<input id=botonOkInstrucciones
type=button value=Okay autofocus/>
<input id=botonNoMasInstrucciones
type=button value=No mostrar mas las
instrucciones/>
</div>

<script src = bezierCurve.js></script>


</div>
</body>
</html>

nombre del archivo - bezierCurve.js


var canvas =
document.getElementById(canvas),
context = canvas.getContext(2d),
botonBorrarTodo =
document.getElementById(botonBorrarTodo),
selectEstiloLinea=document.getElementById(se
checkboxLineasGuias=document.getElementById(
instrucciones =
document.getElementById(instrucciones),
botonOkInstrucciones =
document.getElementById(botonOkInstrucciones
botonNoMasInstrucciones =
document.getElementById(botonNoMasInstruccion

mostrarInstrucciones = true,
ESTILO_CUADRICULA = lightgrey,
ESPACIO_CUADRICULA = 10,

RADIO_PUNTOS_DE_CONTROL = 5,
ESTILO_LINEA_PUNTO_DE_CONTROL = blue,
ESTILO_RELLENO_PUNTO_DE_CONTROL = red,

ESTILO_LINEA_PUNTO_FINAL = navy,
ESTILO_RELLENO_PUNTO_FINAL = blue,
ESTILO_LINEAS_GUIAS = rgba(0,0,230,0.4),
dibujarImageData,//Image data almacenada en
el evento mouse down
mousedown = {},//Localizacion del cursor para
el ltimo evento //mouse down
bandas = {}, // Constante actualizada para el
evento mouse down
arrastrar = false, // Si es true, usuario
esta arrastrando el //cursor
//o de control

puntosDeControl=[{},{}],//localizacin del
punto de control //(x, y)
editar = false, // Si es true, usuario esta
editando la curva

lineasGuias = checkboxLineasGuias.checked;
//
Funciones....................................
function dibujarCuadricula(context, color,
stepx, stepy) { context.save()

context.strokeStyle = color;
context.lineWidth = 0.5;
context.clearRect(0, 0, context.canvas.width,
context.canvas.

height);

for (var i = stepx + 0.5; i <


context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();

for (var i = stepy + 0.5; i <


context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();

}
context.restore(); }
function windowToCanvas(x, y) {
var bbox = canvas.getBoundingClientRect();
return { x: x - bbox.left * (canvas.width /
bbox.width), y: y - bbox.top * (canvas.height
/ bbox.height) };
}
dibujarImageData = context.getImageData(0, 0,
canvas.width, canvas.height); }
context.putImageData(dibujarImageData, 0, 0);
}
//
bandas.......................................

function actualizarBandasRectangulares(loc) {
bandas.width = Math.abs(loc.x - mousedown.x);
bandas.height = Math.abs(loc.y -
mousedown.y);

if (loc.x > mousedown.x) bandas.left =


mousedown.x; else bandas.left = loc.x;
if (loc.y > mousedown.y) bandas.top =
mousedown.y; else bandas.top = loc.y; }

function dibujarCurvasBezier() {
context.beginPath();
context.moveTo(puntosFinales[0].x,
puntosFinales[0].y);
context.bezierCurveTo(puntosDeControl[0].x,
puntosDeControl[0].y,

puntosDeControl[1].x, puntosDeControl[1].y,
puntos

Finales[1].x, puntosFinales[1].y);
context.stroke();
}

function actualizarPuntosFinControl() {
puntosFinales[0].x = bandas.left;
puntosFinales[0].y = bandas.top;

puntosFinales[1].x = bandas.left +
bandas.width; puntosFinales[1].y = bandas.top
+ bandas.height puntosDeControl[0].x =
bandas.left;
puntosDeControl[0].y = bandas.top +
bandas.height

puntosDeControl[1].x = bandas.left +
bandas.width; puntosDeControl[1].y =
bandas.top;
}

function dibujarBandas(loc) {
actualizarPuntosFinControl();
dibujarCurvasBezier();

function actualizarBandas(loc) {
actualizarBandasRectangulares(loc);
dibujarBandas(loc);

}
// Lineas
Guias........................................

function dibujarLineasGuiasHorizontales (y) {


context.beginPath();
context.moveTo(0, y + 0.5);
context.lineTo(context.canvas.width, y +
0.5); context.stroke();

function dibujarLineasGuiasVerticales (x) {


context.beginPath();
context.moveTo(x + 0.5, 0);
context.lineTo(x + 0.5,
context.canvas.height); context.stroke();

function dibujarLineasGuias(x, y) {
context.save();
context.strokeStyle = ESTILO_LINEAS_GUIAS;
context.lineWidth = 0.5;
dibujarLineasGuiasVerticales(x);
dibujarLineasGuiasHorizontales(y);
context.restore();

}
function dibujarPuntoDeControl(index) {
context.beginPath();
context.arc(puntosDeControl[index].x,
puntosDeControl[index].y,
RADIO_PUNTOS_DE_CONTROL, 0, Math.PI*2,
false);
context.stroke();
}

function dibujarPuntosDeControl() {
context.save();
context.strokeStyle =
ESTILO_LINEA_PUNTO_DE_CONTROL;

dibujarPuntoDeControl(0);
dibujarPuntoDeControl(1);
context.stroke();
context.restore(); }

function dibujarPuntoFinal(index) {
context.beginPath();
context.arc(puntosFinales[index].x,
puntosFinales[index].y, RADIO_

PUNTOS_DE_CONTROL, 0, Math.PI*2, false);


context.stroke();
}

function dibujarPuntosFinales() {
context.save();
context.strokeStyle =
ESTILO_LINEA_PUNTO_FINAL;

dibujarPuntoFinal(0); dibujarPuntoFinal(1);
context.stroke();
context.restore(); }

function dibujarPuntosControlYFinales() {
dibujarPuntosDeControl();
dibujarPuntosFinales();

}
function cursorEnPuntoFinal(loc) { var pt;
puntosFinales.forEach( function(point) {
context.beginPath();
context.arc(point.x, point.y,
RADIO_PUNTOS_DE_CONTROL, 0, Math. PI*2,
false);

if (context.isPointInPath(loc.x, loc.y)) { pt
= point;
}
});
return pt; }
function cursorEnPuntoControl(loc) { var pt;

puntosDeControl.forEach( function(point) {
context.beginPath();
context.arc(point.x, point.y,
RADIO_PUNTOS_DE_CONTROL, 0, Math.

PI*2, false);

if (context.isPointInPath(loc.x, loc.y)) { pt
= point;
}
});

return pt; }

function actualizarPuntoDeArrasytre(loc) {
puntoArrastre.x = loc.x;
puntoArrastre.y = loc.y;

}
// manejadores de eventos -
canvas..............................
canvas.onmousedown = function (e) {
e.preventDefault(); // previene el cambio del
cursor
if (!editar) {

mousedown.x = loc.x;
mousedown.y = loc.y;
actualizarBandasRectangulares(loc); arrastrar
= true;
}
else {
puntoArrastre = cursorEnPuntoControl(loc);

if (!puntoArrastre) {
puntoArrastre = cursorEnPuntoFinal(loc);
}
}
};

canvas.onmousemove = function (e) {


if (arrastrar || puntoArrastre) {
e.preventDefault(); // previene la seleccion

if(lineasGuias) {
dibujarLineasGuias(loc.x, loc.y);
}
}

if (arrastrar) {
actualizarBandas(loc);
dibujarPuntosControlYFinales();

}
else if (puntoArrastre) {
actualizarPuntoDeArrasytre(loc);
dibujarPuntosControlYFinales();
dibujarCurvasBezier();
}
};

canvas.onmouseup = function (e) {

if (!editar) {
actualizarBandas(loc);
dibujarPuntosControlYFinales();
arrastrar = false;
editar = true;
if (mostrarInstrucciones) {

instrucciones.style.display = inline; }
}
else {

if (puntoArrastre)
dibujarPuntosControlYFinales();
else
editar = false;

dibujarCurvasBezier();
} };
// Manejadores de eventos -
Control...............................

botonBorrarTodo.onclick = function (e) {


context.clearRect(0, 0, canvas.width,
canvas.height); dibujarCuadricula(context,
ESTILO_CUADRICULA, ESPACIO_CUADRICULA,

ESPACIO_CUADRICULA);
editar = false; arrastrar = false;
};

selectEstiloLinea.onchange = function (e) {


context.strokeStyle =
selectEstiloLinea.value;
};
checkboxLineasGuias.onchange = function (e) {
lineasGuias = checkboxLineasGuias.checked;
};

// Manejadores de eventos -
instrucciones......................

botonOkInstrucciones.onclick = function (e) {


instrucciones.style.display = none;
};

botonNoMasInstrucciones.onclick = function
(e) { instrucciones.style.display = none;
mostrarInstrucciones = false;

};

// Iniciar
aplicacin...................................
context.strokeStyle =
selectEstiloLinea.value;
dibujarCuadricula(context, ESTILO_CUADRICULA,
ESPACIO_CUADRICULA, ESPACIO_CUADRICULA);

El resultado se mostrar mas o menos de esta manera:


en su plenitud y seguir dibujando lo que hayas empezado, por
supuesto si es lo que quieres, de lo contrario, el canvas estar limitado
a esta rea durante toda la operacin de dibujo. Este mtodo puede
aceptar como argumentos opcionales un objeto path, que puede ser
un path svg y el otro argumento, tabin opcional es indicar la regla
de relleno que se desea usar, por defecto si no se indica alguna otra,
se usar la nonzero winding rule.

Ejemplo de aplicacin del mtodo clip():

nombre del archivo - clip.html


<!DOCTYPE html>
<html>

<head> <title>Ejemplo del m&eacute;todo


clip()</title> <style>

#contenedor{
width:600px;
margin: 0px auto; padding-top:50px;

#canvas {
background: #eaeaea;
}
</style>
</head>
<body>
<divid=contenedor>
<canvas id=canvas width=600 height=400>
Tu navegador no soporta canvas de HTML 5
</canvas>
<script src=clip.js></script>
</div>
</body>
</html>

nombre del archivo


- clip.js
var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d);

//
Funciones....................................
function dibujarCuadricula(context, color,
stepx, stepy) { context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepx + 0.5; i <
context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();
}
for (var i = stepy + 0.5; i <
context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}
}
function dibujarTexto() { context.save();
context.font = 175px Arial;
context.lineWidth = 2;
context.shadowColor = rgba(100, 100, 150,
0.8);

context.shadowBlur = 10;

context.strokeStyle = grey;
context.strokeText(canvas, 20, 250);
context.restore();

}
context.beginPath();
context.arc(canvas.width/2, canvas.height/2,
radio, 0, Math.PI*2, false); context.clip();
}
function rellenarCanvas(color) {
}
clearInterval(loop);

setTimeout( function (e) {


context.clearRect(0, 0, canvas.width,
canvas.height); dibujarCuadricula(context,
lightgrey, 10, 10); dibujarTexto();

}, 1000);
}
function dibujarFotogramaAnimacion(radio) {

rellenarCanvas(#eaeaea);
dibujarCuadricula(context, lightgrey, 10,
10); dibujarTexto();
}
function animar() {
var radio = canvas.width/2, loop;
loop = window.setInterval(function() { radio
-= canvas.width/100;
rellenarCanvas(#eaeaea);

if (radio > 0) {
context.save();
dibujarFotogramaAnimacion(radio);
context.restore();

}
else {
}
}, 16); };
// Manejadores de
eventos......................................

canvas.onmousedown = function (e) { animar();


};

// Iniciar
aplicacin...................................
dibujarCuadricula(context, lightgrey, 10,
10); dibujarTexto();

El resultado se mostrar mas o menos de esta manera:


especiicado esta dentro o en los extremos del path actual y false en
caso contrario.

Ejemplo de aplicacin del mtodo isPointPath():


nombre del archivo
- isPointInPath.html
<!DOCTYPE html>
<html>
<head>

<title>Aplicaci&oacute;n del m&eacute;todo


isPointInPath()</title>
<style>
body {
}

#contenedor{
width:600px;
margin:0px auto;
padding-top:50px;
}
#canvas {
left: 0px;
margin-left: 20px;
margin-right: 20px;
border: thin solid rbga(0,0,0,1.0);
background:#eaeaea;
}

input {
margin-left: 15px;
}

</style> </head>
<body> <div id=contenedor>
<canvas id=canvas width=600 height=400>

Tu navegador no soporta canvas de HTML5


</canvas>
</div>
<script src=isPointInPath.js></script>

</body>
</html>

nombre del archivo - isPointInPath.js


var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d);

//Funciones
.............................................
function dibujarCuadricula(context, color,
stepx, stepy) { context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepx + 0.5; i <
context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();
}
for (var i = stepy + 0.5; i <
context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}
}

//Iniciar
aplicacin...................................
dibujarCuadricula(context, lightgrey, 10,
10);

context.lineJoin = miter; context.lineWidth


= 30;
context.font = 24px Helvetica;

context.strokeStyle = blue;

context.rect(200,100,200,200); //manejadores
de
eventos......................................
context.canvas.onmousedown = function (e) {

if (context.isPointInPath(200,150)) {
} };

El resultado se mostrar mas o menos de esta manera:


segundo y tercer argumento representan las coordenadas del punto a
ser chequeado.La coordenada x debe ser un valor entre 0 y
canvas.width y la coordenada y debe ser un valor entre 0 y
canvas. height.

scrollPathIntoView(path, element)

Descripcin Este mtodo permite el desplazamiento por la trayectoria


de la vista actual. Su uso est destinado principalmente en
aplicaciones mviles o dispositivos de pequeas dimensiones. Usando
este mtodo, los desarrolladores pueden mover a la vista actual
aquella parte del canvas que se encuentra fuera de la pantalla. Este
mtodo puede aceptar como primer argumento opcional un objeto
path que puede ser un path svg.
Cuando este mtodo es invocado se deben seguir los siguientes
pasos: 1. Deje que el area especicada sea el rectangulo del cuadro
limite de la trayectoria prevista.
2. Deje que el descendiente hipotetico descendiente sea un hipotetico
elemento que es un descendiente renderizado del elemento canvas,
cuyas dimensiones son las del rectangulo especiicado.
3. El desplazamiento del hipotetico descendiente dentro de la vista con
la coniguracin de la marca superior.
4. Opcionalmente, informar al usuario de que el simbolo de
intercalacin y/o seleccin cubre el rectangulo especicado del canvas.
Los user agents pueden esperar hasta la prxima vez que el ciclo de
eventos alcance su paso actualizar el renderizado de informar
opcionalmente al usuario.
Nota destacada!

Informar al usuario, como se usa en esta seccin, puede significar


llamar a una API de accesibilidad al sistema, lo cal notificar a las
tecnologas de asistencia, tales como herramientas de magnificacin.
Para conducir correctamente la magnificacin basado en un cambio de
foco, una API de accesibilidad del sistema de conduccin de un

Atento

amplificador de pantalla, necesita de los lmites para el objeto que se


terminar centrando. Los mtodos anteriores tienen por objeto permitir
esto al permitir que el user agent informe del cuadro delimitador de la
ruta utilizada para hacer que el anillo de enfoque limite los elementos
del elemento pasado como argumento, si ese elemento esta enfocado,
y la caja de delimitacin de la zona a la que el user agent se desplaza
como cuadro delimitador de la seleccin actual.

ellipse(float x, float y, float radiusX, float radiusY, float


rotation, float startAngle, float endAngle,boolean
anticlockwise)

Descripcin
Dibuja una elipse segn los argumentos especicados. Si la trayectoria
del obje

to no posee un subpath, este mtodo aade una lnea recta desde el


ltimo punto del subpath al punto de inicio del arco. Luego aadir los
puntos de inicio y inal de la circunferencia y las conecta con un arco.
Este mtodo posee 8 argumentos:
x e y representan las coordenadas, en pixeles, del centro de el arco
en relacin con la esquina superior izquierda del canvas.
radiusX y radiusY representan las coordenadas, en pixeles, de
la ruta a seguir por el arco.
rotation representa a la rotacin, dada en radianes, y signiica que
el eje semi-mayor esta inclinado en direccin al sentido de las agujas
del reloj desde el eje x, es decir, podramos decir que representa
cuanto la elipse gira. startAngle representa el ngulo de inicio,
en radianes, donde 0 representa las 3 en punto de el arco.
endAngle representa el angulo inal, dado en radianes.
anticlockwise representa la direccin del arco a dibujar, si se
establece en true, el arco es dibujado en sentido contrario a las agujas
del relos, es decir de principio a in y por el contario si se establece en
false el arco es dibujado en la direccin del sentido de las agujas del
reloj, de principio a in.
Si dibujas una elipse full, la direccin es lo menos importante, pero, si
dibujas solo parte de una elipse, entonces, la direccin es muy
importante. Este mtodo devuelve un objeto DOM del tipo nodo.

Ejemplo de aplicacin del mtodo ellipse:

nombre del archivo - elipse.html


<!DOCTYPE html>
<html>
<head>
<title>Dibujar elipse</title> <style
type=text/css>
body {
background: #dddddd; }
#canvas {

position:absolute;
left:10px;
top:1.5em;
margin:20px;
border:thin solid #aaaaaa;

}
</style>
</head>
<body>

<canvas id=canvas width=600 height=400>

Tu navegador no soporta canvas de HTML5


</canvas>
<script src=elipse.js></script>

</body>
</html>

nombre del archivo


- elipse.js
var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d);

function dibujarCuadricula(context, color,


stepx, stepy) { context.save();
context.strokeStyle = color;
context.lineWidth = 0.5;

for (var i = stepx + 0.5; i <


context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();

}
for (var i = stepy + 0.5; i <
context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();

}
context.restore();
}

function drawScreen() { var x = 15;


var y = 15;
var rx = 20;
var ry = 10;
var rotacion = 0; var inicio = 0;

var direccion = false;

context.beginPath();
context.strokeStyle = black;
context.lineWidth = 2;

//full circle
context.stroke(); context.closePath();

}
dibujarCuadricula(context, lightgray, 10,
10); drawScreen();

resetClip()

Descripcin Este mtodo sustituye la actual regin clipping por otra


cuyas dimensiones se establecen comenzando por el punto (0,0) del
canvas (esquina superior izquierda) y su altura y anchura se
corresponde con el espacio de coordenadas del canvas, es decir, se
extiende por todo el alto y ancho de la supericie del canvas.

Mtodos de Rectangulos
La API de Canvas provee tres mtodos para aclarar o limpiar, dibujar y
rellenar rectngulos, respectivamente:

clearRect(float x, float y, float width, float height)

Descripcin Aclara todos los pixeles en la interseccin del rectngulo


especiicado y la actual regin clipping. Por defecto la regin clipping
es del tamao del canvas, es decir, si tu no has cambiado la regin
clipping, los pixeles aclarados son exactamente los pixeles
especiicados por los argumentos del mtodo. Aclarar los pixeles
signiica llevar el color a un completamente negro transparente.
Efectivamente limpia o aclara el pixel, permitindole al canvas
mostrarse.
strokeRect(float x, float y, float width, float height)

Descripcin Dibuja la lnea exterior deinida por un punto de inicio


especiicada en los argumentos x e y, desplegndose hacia los
siguientes argumentos width y height. Para este mtodo use los
atributos: lineWidth, lineCap, lineJoin, miterLimit y
strokeStyle para determinar como debe mostrarse el stroke.
Si especiicas un valor de 0 en el width o el height, el mtodo
dibujar una lnea horizontal o vertical, respectivamente. El mtodo no
har nada si le das un valor de 0 a ambos argumentos (width y
height).

fillRect(float x, float y, float width, float height)

Descripcin Rellena el rectngulo especiicado con el atributo . Si


especiicas un valor de 0 en el width o en el height, el mtodo no
har absolutamente nada.

Ejemplo de aplicacin de los mtodos de rectangulos:

nombre del archivo - rectngulos.html


<!DOCTYPE html>
<html>
<head>
<title>Dibujar rectangulos</title> <style
type=text/css>
body {

background: #dddddd;
}
#canvas {

position:absolute;
left:10px;
top:1.5em;
margin:20px;
border:thin solid #aaaaaa;

}
</style>
</head>
<body>

<canvas id=canvas width=600 height=400>

Tu navegador no soporta canvas de HTML5


</canvas>
<script src=rectangulos.js></script>

</body>
</html>

nombre del archivo - rectngulos.js


var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d);
context.lineJoin = miter;
context.lineWidth = 30;
context.font = 24px Helvetica;

context.strokeStyle = blue;
context.strokeRect(75, 100, 200, 200);

context.canvas.onmousedown = function (e) {


en esta seccin te indicarn como hacerlo.

createLinearGradient(float x0, float y0, float x1, float y1)

Descripcin Crea un gradiente lineal. Los parmetros pasados a este


mtodo representan dos puntos la cual especiica la lnea de gradiente.
El mtodo devuelve una instancia de canvasGradient, la cual se
le puede agregar color con el mtodo
canvasGradient.addColorStop().

Ejemplo de aplicacin de el mtodo createLinearGradient:

nombre del archivo - linearGradient.html


<!DOCTYPE html>
<html>
<head>
<title>Crear Gradientes Lineales</title>
<style type=text/css>
body {

background: #dddddd; }
#canvas {

position:absolute;
left:10px;
top:1.5em;
margin:20px;
border:thin solid #aaaaaa;

}
</style>
</head>
<body>

<canvas id=canvas width=600 height=400>

Tu navegador no soporta canvas </canvas>


<script src=linearGradient.js></script>

</body>
</html>

nombre del archivo - linearGradient.js


var canvas =
document.getElementById(canvas),
context = canvas.getContext(2d),
gradient =
context.createLinearGradient(canvas.width/2,
canvas. height,canvas.width/2, 100);
gradient.addColorStop(0, blue);
gradient.addColorStop(0.25, green);
gradient.addColorStop(0.5, yellow);
gradient.addColorStop(0.75, orange);
gradient.addColorStop(1, red);

context.rect(0, 0, canvas.width,
canvas.height);
El resultado se mostrar mas o menos de esta manera:
<title>Crear Gradientes Radiales</title>
<style type=text/css>
body {

background: #dddddd;
}
#canvas {

position:absolute;
left:10px;
top:1.5em;
margin:20px;
border:thin solid #aaaaaa;

}
</style>
</head>
<body>

<canvas id=canvas width=600 height=400>

Tu navegador no soporta canvas </canvas>


<script src=radialGradient.js></script>

</body>
</html>
left:10px;
top:1.5em;
margin:20px;
border:thin solid #aaaaaa;
}
</style>
</head>
<body>
<canvas id=canvas width=600 height=400>
Tu navegador no soporta canvas </canvas>
<script src=linearGradient.js></script>
</body>
</html>

nombre del archivo - radialGradient.js


var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d),
gradient = context.createRadialGradient(
canvas.width/2, canvas.height, 200,
canvas.width/2, 100, 100);
gradient.addColorStop(0, yellow);
gradient.addColorStop(0.25, green);
gradient.addColorStop(0.5, blue);
gradient.addColorStop(0.90, purple);
gradient.addColorStop(1, red);

context.rect(0, 0, canvas.width,
canvas.height);
El resultado se mostrar mas o menos de esta manera:
el canvas. La imagen usada en el patrn, especiicada con el primer
argumento del mtodo, puede ser una imagen, un canvas o un
elemento de video. El segundo argumento especiica como el
navegador repite el patrn cuando lo has usado en lneas o rellenos
de formas. Valores vlidos para el segundo argumento son: repeat,
repeat-x, repeat-y y no-repeat.

Ejemplo de aplicacin del mtodo createPattern:

nombre del archivo - pattern.html


<!DOCTYPE html>
<html>

<head>
<title> Crear Patrones</title>
<style>
#canvas {
background: #eeeeee;

}
#radios {
padding: 10px;
}

</style>
</head>
<body>

<div id=radios>
<input type=radio id=repeatRadio name=
patternRadio checked/>repeat
name=patternRadio/>repeat-x
<inputtype=radio id=repeatYRadio
name=patternRadio/>repeat-y
<inputtype=radio id=noRepeatRadio
name=patternRadio/>no repeat
</div>
<canvas id=canvas width=445 height=255>
Tu navegador no soporta canvas de HTML5
</canvas>
<script src=pattern.js></script>
</body>
</html>

nombre del archivo - pattern.js


var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d),
repeatRadio =
document.getElementById(repeatRadio),
noRepeatRadio =
document.getElementById(noRepeatRadio),

repeatYRadio =
document.getElementById(repeatYRadio),
image = new Image();
//
Funciones....................................
var pattern = context.createPattern(image,
repeatString); context.clearRect(0, 0,
canvas.width, canvas.height);

} // Manejadores de
eventos......................................
la cual, la esquina superior izquierda de la imagen es dibujada.
Los argumentos dw y dh deinen el ancho y alto en la cual la imagen
debe ser colocada dentro del canvas destino. Si estos argumentos son
omitidos, la imagen ser copiada en su tamao original.
Los argumentos sx y sy deinen la esquina superior izquierda de la
regin de la imagen recurso que esta siendo dibujada. Estos
argumentos son medidos en pixeles de imagen. Use especicamente
estos argumentos si tu quieres copiar solo una parte del recurso
imagen.
Por ltimo, los argumentos sw y sh deinen el ancho y el alto, en
pixeles de imagen, de la regin del recurso imagen que esta siendo
dibujada dentro del canvas.
Slo los primeros tres argumentos son requeridos.
El primer argumento en los tres casos anteriores es una imagen
(HTMLImageElement), pero este argumento puede ser tambin
otro canvas (HTMLCanvasElement) o un video
(HTMLVideoElement), lo que signiica que efectivamente puedes
tratar un canvas o un video como una imagen, lo cual abre puertas a
muchas posibilidades, tal como sotware de edicin de video. De las tres
posibles combinaciones de argumentos de drawImage() listadas
anteriormente, El primero se usa para dibujar una imagen en un lugar
especiico del canvas destino; el segundo nos permite dibujar una
imagen en un lugar especiico, escalados a un ancho y alto especiicado
y el tercero se usa para dibujar una imagen completa o parte de ella,
en un lugar especiico del canvas destino a un ancho y alto especiicado

destino (canvas destination)recurso (image source) dy sy dx sx


dh sh
dw imagen 2.23 - esquema de drawImage(). sw
Ejemplo de aplicacin del mtodo drawImage:

nombre del archivo - drawImage.html


<!DOCTYPE html>
<html>

<head>
<title>Aplicaci&oacute;n del m&eacute;todo
drawImage</title>
<style>
body {
background:#eaeaea; }

#contenedor{
width:800px;
margin:0px auto;
padding-top:50px;
}
#guiaDeEscala {
position:relative;
vertical-align: 10px;
width: 100px;
margin-left: 80px; }

#canvas {
margin: 10px 20px 0px 20px; border: thin
solid #aaaaaa; cursor: crosshair;
padding: 0;

#controles {
margin-left: 15px; padding: 0;
}

#escalaDeSalida {
position: absolute;
width: 30px;
height: 30px;
margin-left: 10px;
vertical-align: center;
text-align: center;
color: blue;
font: 18px Arial;
text-shadow: 2px 2px 4px rgba(100, 140, 250,
0.8);

}
</style> </head>
<body>
<div id=contenedor>

<div id=controles>
<output id=escalaDeSalida>1.0</output>
<input id=guiaDeEscala type=range min=1

max=3.0 step=0.01 value=1.0/>


</div>
<canvas id=canvas width=800 height=520>

Tu navegador no soporta canvas de HTML5


</canvas>
</div>
<script src=drawImage.js></script>

</body>
</html>

nombre del archivo - drawImage.js


var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d),
imagen = new Image(),

escalaDeSalida =
document.getElementById(escalaDeSalida);
guiaDeEscala =
document.getElementById(guiaDeEscala),
escala = guiaDeEscala.value,
escala = 1.0,
ESCALA_MINIMA = 1.0,
//
Funciones....................................

function dibujarEscalado() { var w =


canvas.width, h = canvas.height, sw = w *
escala, sh = h * escala;

// Limpiamos el canvas, y dibujamos la imagen


escalada al tamao del canvas
context.clearRect(0, 0, canvas.width,
canvas.height); context.drawImage(imagen, 0,
0, canvas.width, canvas.height);
// Dibujamos la marca de agua en el frente de
la imagen
dibujarMarcaDeAgua();
// Finalmente, dibujamos el canvas escalado
de acuerdo a la escala // actual, dentro de
el mismo. Note que el canvas recurso y el
context.drawImage(canvas, 0, 0, canvas.width,
canvas.height,
-sw/2 + w/2, -sh/2 + h/2, sw, sh); }

function dibujarTextoEscalado(value) {
var texto = parseFloat(value).toFixed(2); var
porcentaje = parseFloat(value -
ESCALA_MINIMA) /

escalaDeSalida.innerText = texto;
porcentaje = porcentaje < 0.35 ? 0.35 :
porcentaje;
em; }
function dibujarMarcaDeAgua() {

lineaDos = verano!, medidaTexto = null,


TAM_FUENTE = 118;

context.save();
context.font = TAM_FUENTE + px verdana;

medidaTexto = context.measureText(lineaUno);
context.globalAlpha = 0.4;
context.translate(canvas.width/2,canvas.height
TAM_FUENTE/2);

context.strokeText(lineaUno, -
medidaTexto.width/2, 0);
medidaTexto = context.measureText(lineaDos);
context.strokeText(lineaDos, -
medidaTexto.width/2, TAM_FUENTE);
context.restore(); }
// manejadores de
eventos......................................
guiaDeEscala.onchange = function(e) { escala
= e.target.value;
if (escala < ESCALA_MINIMA) escala =
ESCALA_MINIMA;
dibujarEscalado();
dibujarTextoEscalado(escala); }
// Iniciar
aplicacin...................................
context.strokeStyle = blue;
context.shadowColor = rgba(50, 50, 50,
1.0);
context.shadowBlur = 10;
var tamLente = 150; var escala = 1.0;

imagen.src = qqq (133).jpg;


imagen.onload = function(e) {
var radioMaximo = 200;
var porcentaje = 20;
context.drawImage(imagen, 0, 0, canvas.width,
canvas.height);
dibujarMarcaDeAgua();
dibujarTextoEscalado(guiaDeEscala.value);
};

El resultado se mostrar mas o menos de esta manera:


imagen 2.24 - aplicacin del mtodo drawImage().
Mtodos de textos

fillText(string text, number x, number y, number


maxWidth)

Descripcin Este mtodo acepta 4 argumentos de los cuales tres son


requeridos y uno es opcional. El argumento text, representa el texto
a dibujar en el canvas; los argumentos x e y representan el punto de
anclaje (anchor point) de el texto en el canvas. La interpretacin de
este punto depende de los valores asignados a las propiedades
textAlign y textBaseline, y por ltimo, esta el argumento
max, el cual es opcional y que especiica el ancho mximo para el
texto. Si el texto llegara a ser mas grande que este valor cuando
dibujamos usando la propiedad font y la actual matriz de
transformacin, entonces el texto ser dibujado una versin ms
pequea o condensada de la fuente instanciada.

dibuja texto usando la fuente actual y la propiedad . Los argumentos x


e y especiican donde el texto debe dibujarse en el canvas, pero la
interpretacin de este argumento depende de las propiedades
textAlign y textBaseline respectivamente. Si textAlign
esta en left o en start (valor por defecto), para el canvas
signiica que dibujar el texto de izquierda-a-derecha (tambin su valor
por defecto), y si esta en end para el canvas signiica dibujar el texto
de derecha-a-izquierda. Si textAlign esta en center,
entonces el texto se dibujar horizontalmente centrado en la
coordenada x especiicada. De lo contrario ( si textAlign esta en
right, o end para texto de derecha-a-izquierda, o si esta en
start para texto de izquierda-a-derecha) el texto es dibujado a la
izquierda de la coordenada x especiicada.
SitextBaseline est en alphabetic (valor por defecto),
bottom o ideographic, la mayora de los gricos aparecern
sobre la coordenada y especiicada. Si textBaseline est en
center el texto ser centrado verticalmente en la coordenada y
especiicada. Y si textBaseline esta en top o en hanging, la
mayora de los gricos aparecern mas abajo de la coordenada y
especiicada.

strokeText(string text, number x, number y, number


maxWidth)

Descripcin
Este mtodo acepta los mismos argumentos y trabaja de la misma
manera que

, con la diferencia de que en lugar de aplicrsele al relleno de las


fuentes dibujadas, lo hace a la lnea externa de la fuente dibujada,
usando para ello la propiedad strokeStyle. strokeText()
produce interesantes efectos gricos cuando es usado en fuentes mas
grandes, pero es communmente mas usado para dibujar textos que
strokeText().

measureText(string text)

Descripcin
Este mtodo acepta solo un argumento: la cadena de texto a ser
medida.

Este mtodo devuelve un objeto TextMetrics que contiene un


conjunto de propiedades que contienen las medidas del texto dado.
Estas medidas estan basadas en la fuente actual , y son todas las
medidas que se pueden obtener al momento de escribir este libro.

Configurar la fuente antes de llamar a measureText

Un error comn al llamar a measureText() es que se configura la


fuente despus de llamar al mtodo. Recuerde que este mtodo mide
el ancho de una cadena basado en la fuente actual. Es decir, si tu
cambias la fuente despus de llamar a este mtodo o lo llamas antes de
configurarla, el ancho devuelto no reflejar el ancho actual

Atento de la fuente actual.

Las medidas del texto

Tu puedes obtener muchas medidas, en pixeles CSS, de una cadena


cualquiera, con las propiedades
width,actualBoundingBoxLeft,actualBoundingBoxR
fontBoundingBoxDescent,
actualBoundingBoxAscent,
actualBoundingBoxDescent, emHeightAscent,
emHeight

Atento
Descent,hangingBaseline, alphabeticBaseline e
ideographicBaseline, de el objeto TextMetrics devuelto
por el mtodo measureText(). Este objeto TextMetrics no
tiene la correspondiente propiedad height (al momento de escribir este
libro). Sin embargo, una observacin a la historia de la medida del
texto, que como bien aclara la especificacin canvas: Los graficos
renderizados usando y strokeText() pueden sobrepasar el
tamao de la caja dado por el tamao de la fuente actual y por ende
los valores devuelto por measureText() .
Esta observacin desde la especificacin significa que el ancho
devuelto por el mtodo measureText() no es exacto y que a
menudo no es importante si estos valores son inexactos; sin embargo,
algunas veces esto es crucial, como por ejemplo: al editar una lnea de
texto en un canvas.

Ejemplo de aplicacin de los mtodos de textos:

nombre del archivo - textos.html


<!DOCTYPE html>
<html>

<head>

<title>Aplicaci&oacute;n de los
m&eacute;todos de texto<title>
<style>
body {
background: #eaeaea;
color:#555;
}
#contenedor{
width:1100px;
margin:0px auto;
padding-top:50px; }
#contenedor_canvas{
width:600px; margin:0px auto; padding-
top:50px; }
#canvas {

border:2px thin #666; margin-top:5px;


}
#textos{

padding:10px; }
#colores{

display:inline; padding:10px; }
#adicionales{

display:inline; padding:10px; }
#areaTexto{
display:inline;
padding:10px;

}
</style>
<script src=modernizr-1.6.min.js></script>

<script type=text/javascript
src=jscolor/jscolor.js></script> </head>
</head>

<body>
<div id=contenedor_canvas>
<canvas id=canvas width=600 height=300>

Tu navegador no soporta canvas de HTML5.


</canvas>
</div>
<div id=contenedor>
<form>

<div id=textos>

Texto:<input id=cajaTexto
placeholder=escribe lo que quieras/><br>
Fuente: <select id=fuenteUsada>
<option value=palatino>palatino</option>
<option value=serif>serif</option>
<option value=sans-serif>sans-serif
</option>
<option value=cursive>cursive</option>
<option value=fantasy>fantasy</option>
<option value=monospace>monospace</option>
</select>
<br>
Grosor:
<select id=grosorFuente>
<option value=normal>normal</option>
<option value=bold>bold</option> <option
value=bolder>bolder</option> <option
value=lighter>lighter</option> </select>
<br>
Estilo:
<select id=estiloFuente>
<option value=normal>normal</option>
<option value=italic>italic</option>
<option value=oblique>oblique</option>
</select>
<br>
Tama&ntilde;o: <input type=range
id=tamaoTexto
min=0 max=200 step=1 value=50/>
<br>
</div>
<div id=colores>

Relleno : <select id=tipoRelleno>

<option value=colorFill>Color de relleno</


option>
<option value=linearGradient>Gradiente
lineal</option>
<option value=radialGradient>Gradiente
radial</option>
<option value=pattern>Patrones</option>
</select>
<br>
Color Texto 1: <input class=color
id=colorRellenoTexto1 value=0C78F2/>
<br>
Color Texto 2: <input class=color
id=colorRellenoTexto2 value =EB0C22/>
<br>

Rellenar o Delinear : <select


id=RellenarODelinear>

<option value=stroke>Delinear</option>
<option value=both>Ambos</option> </select>
<br>
Alineaci&oacute;n vertical <select

id=alineacionVertical>
<option value=middle>middle</option>
<option value=top>top</option> <option
value=hanging>hanging</option> <option
value=alphabetic>alphabetic

</option>
<option value=ideographic>ideographic
</option>
<option value=bottom>bottom</option>
</select>
<br>
Alineaci&oacute;n horizontal <select
id=alineacionHorizontal>
<option value=center>center</option>
<option value=start>start</option> <option
value=end>end</option> <option
value=left>left</option> <option
value=right>right</option>

</select>
<br>

Transparencia : <input type=range


id=transparenciaTexto
min=0.0 max=1.0 step=0.01 value=1.0/>

<br>
</div>
<div id=adicionales>
min=-100
max=100
step=1
value=1/>

<br>

Sombreado Y:<input type=range


id=sombreadoY min=-100
max=100
step=1
value=1/>

<br>

Desenfoque Sombra: <input type=range


id=desenfoqueSombra
min=1
max=100
step=1
value=1 />

<br>
Color sombra: <input class=color
id=colorSombra value=707070/>
<br>

Ancho del canvas: <input type=range


id=anchoDelCanvas
min=0
max=1000 step=1
value=600/>

<br>
Alto del canvas:
<input type=range id=altoDelCanvas
min=0
max=1000
step=1
value=300/>

<br>

Estilo ancho canvas: <input type=range


id=estiloDeAnchoDelCanvas
min=0
max=1000
step=1
value=600/>

<br>
Estiloalto canvas:

<input type=range
id=estiloDeAltoDelCanvas min=0
max=1000
step=1
value=300/>

<br>

<br>
</div>
<div id=areaTexto>

<textarea id=imageDataDisplay rows=10


cols=35></textarea><br>
<input type=button id=crearImageData
value=Create Image Data>
</div>
</form>

</div>

<script src=textos.js></script> </body>


</html>

nombre del archivo


- textos.js
window.addEventListener(load,
iniciarAplicacion, false);
function aplicacionTextos() {

var mensajeBienvenida = escribe lo que


quieras; var tamanoFuente = 40;
var nombreFuente = palatino;
var colorRellenoTexto = #0C78F2;
var transparenciaTexto = 1;

var sombreadoY = 1;
var desenfoqueSombra = 1;
var colorSombra = #707070;
var alineacionVertical = middle; var
alineacionHorizontal = center;

var grosorFuente =normal;


var estiloFuente = normal; var tipoRelleno
= colorFill; var colorRellenoTexto2
=#EB0C22; var patrones = new Image();

if (!soportarCanvas()) { return;
}

var canvas =
document.getElementById(canvas); var
context = canvas.getContext(2d);
var formElement =
document.getElementById(cajaTexto);
formElement.addEventListener(keyup,
cambiarCajaTexto, false);
formElement =
document.getElementById(RellenarODelinear);
formElement.addEventListener(change,
cambiarRellenarODelinear, false);
formElement =
document.getElementById(tamaoTexto);
formElement.addEventListener(change,
cambiarTamanoTexto, false);
formElement =
document.getElementById(colorRellenoTexto1)
formElement.addEventListener(change,
cambiarColorRellenoTexto, false);
formElement =
document.getElementById(fuenteUsada);
formElement.addEventListener(change,
cambiarFuenteUsada, false);
formElement =
document.getElementById(alineacionVertical)
formElement.addEventListener(change,
cambiarAlineacionVertical, false);
formElement =
document.getElementById(alineacionHorizontal
formElement.addEventListener(change,
cambiarAlineacionHorizontal, false);
formElement =
document.getElementById(grosorFuente);
formElement.addEventListener(change,
cambiarGrosorFuente, false);
formElement =
document.getElementById(estiloFuente);
formElement.addEventListener(change,
cambiarEstiloFuente, false);
formElement.addEventListener(change,
formElement =
document.getElementById(sombreadoY);
formElement.addEventListener(change,
cambiarSombreadoY, false);
formElement =
document.getElementById(desenfoqueSombra);
formElement.addEventListener(change,
cambiarDesenfoqueSombra, false);
formElement =
document.getElementById(colorSombra);
formElement.addEventListener(change,
cambiarColorSombra, false);
formElement =
document.getElementById(transparenciaTexto)
formElement.addEventListener(change,
cambiarTransparenciaTexto, false);
formElement =
document.getElementById(colorRellenoTexto2)
formElement.addEventListener(change,
cambiarColorRellenoTexto2, false);
formElement =
document.getElementById(tipoRelleno);
formElement.addEventListener(change,
cambiarTipoRelleno, false);
formElement =
document.getElementById(anchoDelCanvas);
formElement.addEventListener(change,
cambiarAnchoDelCanvas, false);
formElement =
document.getElementById(altoDelCanvas);
formElement.addEventListener(change,
cambiarAltoDelCanvas, false);

formElement = document.getElementById(
estiloDeAnchoDelCanvas);
formElement.addEventListener(change,
cambiarTamanoCanvas, false);

formElement = document.getElementById(
estiloDeAltoDelCanvas);
formElement.addEventListener(change,
cambiarTamanoCanvas, false);

formElement =
document.getElementById(crearImageData);
formElement.addEventListener(click,
crearImageDataImpreso, false);
patrones.src = texture.jpg;
dibujarEnCanvas();
function dibujarEnCanvas() { //Fondos
context.globalAlpha = 1;
context.shadowColor = #707070;
context.shadowBlur = 0;

//Box
context.strokeStyle = #444;
context.strokeRect(0, 0, canvas.width,
canvas.height);

//Textos

context.textBaseline = alineacionVertical;
context.textAlign = alineacionHorizontal;
context.font = grosorFuente + +
estiloFuente + +

tamanoFuente + px + nombreFuente;
context.shadowColor = colorSombra;
context.shadowBlur = desenfoqueSombra;
context.globalAlpha = transparenciaTexto;
var posicionY = (canvas.height/2);

var medidasTexto = context.measureText(


mensajeBienvenida);
var anchoTexto = medidasTexto.width;

vartempColor;
if (tipoRelleno == colorFill) {
tempColor = colorRellenoTexto;
} else if (tipoRelleno == linearGradient) {
var gradient = context.createLinearGradient(

gradient.addColorStop(0,colorRellenoTexto);
gradient.addColorStop(.6,colorRellenoTexto2);
tempColor = gradient;

} else if (tipoRelleno == radialGradient) {


var gradient = context.createRadialGradient(

1);
gradient.addColorStop(0,colorRellenoTexto);
gradient.addColorStop(.6,colorRellenoTexto2);
tempColor = gradient;

} else if (tipoRelleno == pattern) {


var tempColor =
context.createPattern(patrones,repeat);

} else {
tempColor = colorRellenoTexto;
}

switch(RellenarODelinear) {

break;
case stroke:
context.strokeStyle = tempColor;
context.strokeText ( mensajeBienvenida,

break; case both:


context.strokeStyle= #000000;
context.strokeText ( mensajeBienvenida,
break; }
}

function cambiarCajaTexto(e) {
var target = e.target;
mensajeBienvenida = target.value;
dibujarEnCanvas();

function cambiarAlineacionVertical(e) { var


target = e.target;
alineacionVertical = target.value;
dibujarEnCanvas();

function cambiarAlineacionHorizontal(e) { var


target = e.target;
alineacionHorizontal = target.value;
dibujarEnCanvas();

function cambiarRellenarODelinear(e) { var


target = e.target;
RellenarODelinear = target.value;
dibujarEnCanvas();

function cambiarTamanoTexto(e) { var target =


e.target; tamanoFuente = target.value;
dibujarEnCanvas();

function cambiarColorRellenoTexto(e) { var


target = e.target;
colorRellenoTexto = # + target.value;
dibujarEnCanvas();

function cambiarFuenteUsada(e) { var target =


e.target; nombreFuente = target.value;
dibujarEnCanvas();
}

function cambiarGrosorFuente(e) { var target


= e.target; grosorFuente = target.value;
dibujarEnCanvas();

function cambiarEstiloFuente(e) { var target


= e.target; estiloFuente = target.value;
dibujarEnCanvas();

}
var target = e.target;
dibujarEnCanvas(); }

function cambiarSombreadoY(e) { var target =


e.target; sombreadoY = target.value;
dibujarEnCanvas();

function cambiarDesenfoqueSombra(e) { var


target = e.target;
desenfoqueSombra = target.value;
dibujarEnCanvas();

function cambiarColorSombra(e) { var target =


e.target; colorSombra = target.value;
dibujarEnCanvas();

}
function cambiarTransparenciaTexto(e) { var
target = e.target;
transparenciaTexto = (target.value);
dibujarEnCanvas();

function cambiarColorRellenoTexto2(e) { var


target = e.target;
colorRellenoTexto2 = # + target.value;
dibujarEnCanvas();

function cambiarTipoRelleno(e) { var target =


e.target; tipoRelleno = target.value;
dibujarEnCanvas();

function cambiarAnchoDelCanvas(e) { var


target = e.target; canvas.width =
target.value; dibujarEnCanvas();

function cambiarAltoDelCanvas(e) { var target


= e.target; canvas.height = target.value;
dibujarEnCanvas();

}
function cambiarTamanoCanvas(e) {

var styleWidth = document.getElementById(


estiloDeAnchoDelCanvas);
var styleHeight = document.getElementById(
estiloDeAltoDelCanvas);
var styleValue = width: + styleWidth.value
+ px; height: + styleHeight.value +px;;
canvas.setAttribute(style, styleValue );
dibujarEnCanvas();
}

function crearImageDataImpreso(e) {

var imageDataDisplay =
document.getElementById( imageDataDisplay);
imageDataDisplay.value = canvas.toDataURL();
window.open(imageDataDisplay.value,
canavsImage,left=0,top=0,width= +
canvas.width + ,height= + canvas.height
+,toolbar=0,resizable=0);

}
}

function iniciarAplicacion() {
aplicacionTextos();
}

function soportarCanvas () { return


Modernizr.canvas;
}

function eventWindowLoaded() {
var patrones = new Image();
patrones.src = texture.jpg;
patrones.onload = cargarRecursosAplicacion;
}

function cargarRecursosAplicacion() {
aplicacionTextos();
}

El resultado se mostrar mas o menos de esta manera:


Una matriz de datos del objeto imageData contiene cuatro enteros
por pixel, cada uno de los cuales pertenece al rojo, verde, azul y la
transparencia de cada pixel, estos valores son conocidos como los
valores alpha.
Una vez hecho esto, el ancho (width) de el objeto imageData
devuelto por el mtodo getImageData() no es necesariamente el
mismo ancho (width) que tu pasaste como argumento al mtodo
getImageData(). Esto es porque el primero representa los
pixeles del dispositivo, mientras que el ltimo representa los pixeles
CSS.

Pixeles de dispositivo y pixeles de CSS

Para imgenes con calidades superiores, los navegadores pueden


usar mltiples pixeles de dispositivos por cada pixel de css. Por
ejemplo tu puedes tener un canvas de unos 200 pixeles cuadrados,
para un total de 40000 pixeles de css, pero si el navegador representa
cada pixel de css con 2 pixeles de dispositivos, tu podras tener
160000

Atento
(400 x 400) pixeles de dispositivo. Tu puedes sacar muchos pixeles de
dispositivo con las propiedades width y height de tu objeto
imagedata.

putImageData(ImageData imagedata, float x, float y, [float


dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight])

Descripcin Coloca los datos de la imagen dentro del canvas en las


coordenadas (x, y), donde (x, y) son expresados en pixeles de CSS.
El rectngulo sucio representa los datos de la regin de la imagen que
el navegador copiar en la vista activa de el canvas. Tu especiicas ese
rectngulo en pixeles de dispositivo. Este mtodo acepta siete
argumentos, estos son:
El argumento imageData que representa un objeto imageData.
Los argumentos x e y que representan las coordenadas de un punto
de destino en el canvas. Los pixeles desde los datos de la imagen
sern copiados al inicio del canvas en este punto. Estos argumentos no
son transformados por la matrix de transformacin actual.
Los argumentos dirtyX y dirtyY que representan la ubicacin
horizontal y vertical desde la esquina superior izquierda de los datos
de la imagen, expresados en pixeles de dispositivos. Sus valores por
defecto son 0.
Y por ltimo los argumentos dirtyWidth y dirtyHeight que
representan el ancho y alto del rectngulo sucio, expresados en
pixeles de dispositivo. Sus valores por defecto son el ancho y el alto de
los datos de la imagen.

canvas
y imagedata

dirtyY dirtyX (canvas.width / imagedata.width)


x dirtyX dirtyY (canvas.he ght / imagedata.height)
dirtyW d rtyH (canvas.he ght / imagedata.height)
dirtyW (canvas.width/ magedata.width)
imagen 2.26 - esquema del mtodo putImageData()
putImageData() no es afectado por la configuracin global
Cuando tu colocas los datos de imagen dentro del canvas con el
mtodo putImageData(), estos datos de imagen no son afectados
por la configuracin global del canvas, tales como globalAlpha y
globalCompositeOperation. El navegador tampoco
considera cosas como: la composicin,

Atento
el despliegue de los gradientes o la aplicacin de las sombras. Esto es
lo contrario de drawImage(), la cual si es afectada por todas estas
cosas.

putImageData(): necesita tanto los pixeles de dispositivo como los


pixeles CSS

Cuando tu llamas al mtodo putImageData() con sus siete


argumentos, tu especificas una impresin dentro del canvas (con el
segundo y tercer argumento) y un rectngulo sucio dentro de los datos
de la imagen que tu quieres copiar dentro del canvas (los ltimos
cuatro argumentos).

Atento

Tu especificas la impresin del canvas en pixeles CSS, mientras que el


rectngulo sucio de los datos de la imagen lo especificas en pixeles de
dispositivo. Si tu inadvertidamente usas las mismas unidades para
ambos casos, putImageData() podra no trabajar como tu lo
esperas.

createImageData(number width, number height)


Descripcin Este mtodo puede tomar dos set de argumentos:
ImageData createImageData(width, height)
ImageData createImageData(ImageData data) Para
el primero de estos, los argumentos width y height representan el
ancho y alto en pixeles de CSS del objeto ImageData que se
quiere. Mientras que en el segundo, el argumento data es un objeto
ImageData ya existente del cual se toma el tamao para el nuevo
objeto ImageData a ser creado.
Este mtodo devuelve un objeto ImageData creado nuevamente
que tiene el ancho y alto especiicado o el mismo tamao del argumento
data. Todos los pixeles dentro de este nuevo objeto ImageData
estn inicializados como negro transparentes (todos los componentes
de color y el alpha estn en 0). Los valores de las propiedades
width y height devueltos por el objeto ImageData no siempre
coinciden con las propiedades width y height pasados en los
argumentos.

Ejemplo de aplicacin de los mtodos de manipulacin de imagenes

nombre del archivo - imageData.html


<!DOCTYPE html>
<html>

<head>
<title>
Aplicaci&oacute;nde los m&eacute;todos
getImageData(), putImageData() y
createIamgeData()
</title>
<style>
body {
background: #eaeaea; }

#contenedor{
width:800px;
margin:0px auto;
padding-top:50px;
}
#canvas {
margin-left: 20px;
margin-right: 0;
margin-bottom: 20px;
border: thin solid #aaaaaa;
cursor: crosshair;
}
#controles {
position:relative;
top:60px;
left:20px;
margin: 20px 0px 20px 20px; }

</style> </head>

<body>
<div id=contenedor>
<div id=controles>

<input type=button id=botonResetear


value=Resetear/>
</div>
<canvas id=canvas width=800 height=520>

Canvas not supported


</canvas>
</div>

<script src=imageData.js></script> </body>


</html>

nombre del archivo


- imageData.js
var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d), botonResetear =
document.getElementById(botonResetear),

imagen = new Image(),


imageData,
copiaImageData =
context.createImageData(canvas.width,

canvas.height),

mousedown = {},
bandasRectangulares = {}, arrastrar = false;

//
Funciones....................................
function windowToCanvas(canvas, x, y) {
var rectanguloCanvas =
canvas.getBoundingClientRect();

return { x: x - rectanguloCanvas.left, y: y -
rectanguloCanvas.top };

}
function copiarPixelesCanvas() { var i=0;
// copia los componentes rojo, verde y azul
del primer pixel

for (i=0; i < 3; i++) {


copiaImageData.data[i] = imageData.data[i];
}

// inicia con los componentes alpha del


primer pixel, // copia imagedata, y hace la
copia mas transparente
for (i=3; i < imageData.data.length - 4;
i+=4) {
copiaImageData.data[i] = imageData.data[i] /
2; // Alpha: mas transparente

copiaImageData.data[i+1] =
imageData.data[i+1]; // Rojo
copiaImageData.data[i+2] =
imageData.data[i+2]; // Verde
copiaImageData.data[i+3] =
imageData.data[i+3]; // Azul

}
}

function capturarPixelesCanvas() {
imageData = context.getImageData(0, 0,
canvas.width, canvas.
height);
copiarPixelesCanvas();
}

function restaurarPixelBandas() {
var anchoDispositivoSobreCSSPixeles =
imageData.width / canvas.
width,
altoDispositivoSobreCssPixeles =
imageData.height / canvas.height;

// restaura el canvas al ultimo estado del


evento maose down
context.putImageData(imageData, 0, 0);
// coloca los datos de la imagen mas
transparentes dentro del rectangulo de la
banda

context.putImageData(copiaImageData, 0, 0,
(bandasRectangulares.left +
context.lineWidth), (bandasRectangulares.top
+ context.lineWidth),
(bandasRectangulares.width -
2*context.lineWidth) *
anchoDispositivoSobreCSSPixeles,

(bandasRectangulares.height -
2*context.lineWidth) *
altoDispositivoSobreCssPixeles);
}

bandasRectangulares.left = Math.min(x,
mousedown.x); bandasRectangulares.top =
Math.min(y, mousedown.y);
bandasRectangulares.width = Math.abs(x -
mousedown.x), bandasRectangulares.height =
Math.abs(y - mousedown.y);
}

function dibujarBanda() {
var anchoDispositivoSobreCSSPixeles =
imageData.width / canvas.
width,
altoDispositivoSobreCssPixeles =
imageData.height / canvas.height;

context.strokeRect(bandasRectangulares.left +
context.lineWidth, bandasRectangulares.top +
context.lineWidth, bandasRectangulares.width
- 2*context.lineWidth,
bandasRectangulares.height -
2*context.lineWidth);

function inicioBanda(x, y) { mousedown.x = x;


mousedown.y = y;

bandasRectangulares.left = mousedown.x;
bandasRectangulares.top = mousedown.y;
bandasRectangulares.width = 0;
bandasRectangulares.height = 0;

arrastrar = true;
capturarPixelesCanvas(); }
function ajustarBanda(x, y) {
if (bandasRectangulares.width >
2*context.lineWidth &&
bandasRectangulares.height >
2*context.lineWidth) {
restaurarPixelBandas(); }
}
if (bandasRectangulares.width >
2*context.lineWidth &&
bandasRectangulares.height >
2*context.lineWidth) { dibujarBanda();
}
};
context.putImageData(imageData, 0, 0);
// Draw the canvas back into itself, scaling
along the way

context.drawImage(canvas,
bandasRectangulares.left +
context.lineWidth*2, bandasRectangulares.top
+ context.lineWidth*2,
bandasRectangulares.width -
4*context.lineWidth,
bandasRectangulares.height -
4*context.lineWidth,

0, 0, canvas.width, canvas.height);
arrastrar = false;
}
// Manejadores de
eventos......................................
canvas.onmousedown = function (e) {
e.preventDefault();
inicioBanda(loc.x, loc.y); };
canvas.onmousemove = function (e) { var loc;
if (arrastrar) {
ajustarBanda(loc.x, loc.y); }
};
canvas.onmouseup = function (e) {
imagen 2.27 - aplicacin del mtodo imageData().

getImageDataHD(number x, number y, number width,


number height)

Descripcin Devuelve un objeto imageData que contiene una matriz


de datos enteros 4xwxh, donde w y h representan el ancho y alto de
la imagen en pixeles de dispositivo. Se puede extraer el ancho y el alto
con los atributos width y height del objeto imageData.
Este mtodo devuelve los datos con la misma resolucin que el canvas.
Como se habr dado cuenta el objeto imagedata devuelto por este
mtodo tiene tres propiedades, las cuales son:
width: el ancho de los datos de la imagen en pixeles de dispositivo.
height: el alto de los datos de la imagen, tambin en pixeles de
dispositivo. data: una matriz de valores que representan los pixeles
del dispositivo. Las propiedades width y height son solo de
lecturas, de tipo long y sin signo.
Una matriz de datos del objeto imageData contiene cuatro enteros
por pixel, cada uno de los cuales pertenece al rojo, verde, azul y la
transparencia de cada pixel, estos valores son conocidos como los
valores alpha.
Una vez hecho esto, el ancho (width) de el objeto imageData
devuelto por el mtodo getImageData() no es necesariamente el
mismo ancho (width) que tu pasaste como argumento al mtodo
getImageData(). Esto es porque el primero representa los
pixeles del dispositivo, mientras que el ltimo representa los pixeles
CSS.
putImageDataHD(ImageData imagedata, float x, float y,
[float dirtyX, float dirtyY, float dirtyWidth, float
dirtyHeight])

Descripcin Coloca los datos de la imageno el objeto Im,ageData


dentro del canvas en las coordenadas (x, y), donde (x, y), con la
misma densidad de pixeles del canvas (independientemente del valor
del atributo resolution del objeto ImageData), son expresados en
pixeles de CSS. El rectngulo sucio representa los datos de la regin
de la imagen que el navegador copiar en la vista activa de el canvas.
Tu especiicas ese rectngulo en pixeles de dispositivo.
Este mtodo acepta siete argumentos, estos son:
El argumento imageData que representa un objeto imageData.
Los argumentos x e y que representan las coordenadas de un punto
de destino en el canvas. Los pixeles desde los datos de la imagen
sern copiados al inicio del canvas en este punto. Estos argumentos no
son transformados por la matrix de transformacin actual.
Los argumentos dirtyX y dirtyY que representan la ubicacin
horizontal y vertical desde la esquina superior izquierda de los datos
de la imagen, expresados en pixeles de dispositivos. Sus valores por
defecto son 0. Y por ltimo los argumentos dirtyWidth y
dirtyHeight que representan el ancho y alto del rectngulo sucio,
expresados en pixeles de dispositivo. Sus valores por defecto son el
ancho y el alto de los datos de la imagen. Los atributos globalAlpha y
globalCompositeOperation, as como los atributos de sombra, son
ignorados a los efectos de llamado de este mtodo. Los pixeles en el
canvas son reemplazados en su mayora sin composicin, mezclas
alpha, ni sombras, etc.
Una excepcin NotSupportedError es lamnzada si alguno de los
argumentos son valores ininitos.

createImageDataHD(number width, number height)

Descripcin
Este mtodo puede tomar solo un set de argumentos:

ImageData createImageDataHD(width, height) Los


argumentos width y height representan el ancho y alto en pixeles
de CSS del objeto ImageData que se quiere.
Este mtodo devuelve un objeto ImageData creado nuevamente
cuyas dimensiones son iguales a las dimensiones pasadas con los
argumentos, multiplicado por el nmero de pixeles en el canvas que a
su vez corresponden a cada unidad de espacio de coordenadas.
Todos los pixeles dentro de este nuevo objeto ImageData estn
inicializados como negro transparentes (todos los componentes de
color y el alpha estn en 0). Los valores de las propiedades width y
height devueltos por el objeto ImageData no siempre coinciden
con las propiedades width y height pasados en los argumentos.

Ejemplo de aplicacin de los mtodos de manipulacin de imagenes


HD

nombre del archivo - getImageDataHD.html


<!DOCTYPE HTML>
<html>

<head>
<title>Ejemplo de los m&eacute;todos de
ImageDataHD</title> <style>

body {
background: #eaeaea;
}
#contenedor{
width:800px;
margin:0px auto;
padding-top:50px;
}
#canvas {

}
</style>
</head>
<body onload=init()>

<div id=contenedor>
<canvas id=canvas width=800 height=400>
Tu navegador no soporta canvas de HTML5

</canvas>
</div>
<script src=javascript/getImageDataHD.js>
</script> </body>
</html>

nombre del archivo - getImageDataHD.js


var image = new Image();
function init() {

image.onload = demo;
image.src = images/slider-img2.jpg;
}
function demo() {
var canvas =
document.getElementsByTagName(canvas)[0];
var context = canvas.getContext(2d);

// dibujamos la imagen dentro del canvas


context.drawImage(image, 0, 0);
// tomamos los datos de la imagen para
manipularlas var input =
context.getImageDataHD(0, 0, canvas.width,
canvas. height);
// Tomamos un lugar vacio para colocar los
datos var output =
context.createImageDataHD(canvas.width,
canvas. height);

// alias algunas variables por conveniencia


// note que estamos usando input.width e
input.height aqu // ya que podran no ser lo
mismo que canvas.width y //canvas.height
// (en particular, puede ser diferente en las
pantallas de alta //resolucin)
var w = input.width, h = input.height;
var inputData = input.data;
var outputData = output.data;

// deteccin de bordes
for (var y = 1; y < h-1; y += 1) {
for (var x = 1; x < w-1; x += 1) {

for (var c = 0; c < 3; c += 1) {


var i = (y*w + x)*4 + c;
outputData[i] = 127 + -inputData[i - w*4 - 4]
inputData[i - w*4] - inputData[i - w*4 + 4] +

-inputData[i - 4] + 8*input

Data[i] - inputData[i + 4] +
-inputData[i + w*4 - 4] input
Data[i + w*4] - inputData[i + w*4 + 4];
}
outputData[(y*w + x)*4 + 3] = 255; // alpha
}
}
// poner los datos de la imagen de nuevo
despus de //la manipulacin
context.putImageDataHD(output, 0, 0);
}

El resultado se mostrar mas o menos de esta manera:


caretBlinkRate()

Descripcin Devuelve un objeto imageData que contiene una matriz


de datos enteros 4xwxh, donde w y h representan el ancho y alto de
la imagen en pixeles de dispositivo. Se puede extraer el ancho y el alto
con los atributos width y height del objeto imageData.

drawSystemFocusRing(path, element)

Descripcin Dibuja un anillo de enfoque del estilo apropiado a lo largo


de la ruta prevista, siguiendo las convenciones de la plataforma.
Cuando este mtodo es invocado se deben seguir los siguientes
pasos: 1. S el elemento no esta enfocado o no es un descendiente del
elemento con cuyo contexto ha sido asociao, entonces aborta estos
pasos. 2. S el usuario ha solicitado el uso de anillos de enfoque
particulares (por ejemplo: anillos de enfoque de alto contraste), o si el
elemento tendra un anillo de seleccin alrededor de l, entonces
dibuje un anillo de enfoque del estilo apropiado a lo largo del path
previsto, siguiendo las convenciones de la plataforma. El anillo de
enfoque no debe estar sujeta a los efectos de sombra, transparencias
o a los operadores de globalComposite, pero debe estar sujeta a la
regin clipping.
3. Opcionalmente informar al usuario de que el foco est en el lugar
determinado por la trayectoria deseada. Los user agents pueden
esperar hasta la prxima vez que el ciclo de eventos alcance su paso
actualizar la representacion de informar opcionalmente al usuario.
Este mtodo acepta dos parmetros:
path: La ruta en la cual el anillo de enfoque se va a dibujar, tambien
acepta un objeto path, la cual puede ser un path svg.
element: El elemento en la cual el anillo de enfoque se va a dibujar.
Este mtodo devuelve un objeto de tipo DOM nodo.

Nota destacada!

Algunas plataformas solo dibujan anillos de enfoques en torno a


elementos que se han centrado en el teclado y no los que se centran
en el ratn. Otras plataformas simplemente no llaman a los anillos de
enfoque en torno a ningn elemento en absoluto a menos que las
caractersticas de accesibilidad pertinentes estn habilitadas. Es por
eso

Atento

que este mtodo se centrar en seguir estas convenciones. Los user


agent que implementen distinciones basadas en la manera en que el
elemento estuvo enfocado estn animando a clasificar un enfoque
impulsado por el mtodo focus() basado en el tipo de evento de la
interaccin del usuario desde que se dispara la llamada (si la hay).

drawCustomFocusRing(path, element)

Descripcin Dibuja un anillo de enfoque a lo largo de la ruta prevista y


conjunto de resultados false.
Cuando este mtodo es invocado se deben seguir los siguientes
pasos: 1. S el elemento no esta enfocado o no es un descendiente del
elemento con cuyo contexto ha sido asociao, entonces devuelve false y
aborta estos pasos. 2. Deja que el resultado sea true.
3. S el usuario ha solicitado el uso de anillos de enfoque particulares
(por ejemplo: anillos de enfoque de alto contraste), entonces dibuje un
anillo de enfoque del estilo apropiado a lo largo del trazo previsto y del
conjunto de resultados en false.
El anillo de enfoque no debe estar sujeta a los efectos de sombra,
transparencias o a los operadores de globalComposite, pero
debe estar sujeta a la regin clipping.
4. Opcionalmente informar al usuario de que el foco est en el lugar
determinado por la trayectoria deseada. Los user agents pueden
esperar hasta la prxima vez que el ciclo de eventos alcance su paso
actualizar la representacion de informar opcionalmente al usuario.
5. devuelve resultados.

Este mtodo acepta dos parmetros:


path: El trazado en la cual el anillo de enfoque se va a dibujar, tambien
acepta un objeto path, la cual puede ser un path svg.
element: El elemento en la cual el anillo de enfoque se va a dibujar.
Este mtodo devuelve un objeto de tipo DOM nodo.

La regin Clipping

Combinar los mtodos save() y restore() con la regin clip de


canvas, nos permite limitar el rea para dibujar de un path y sus
subpaths. Podemos hacer esto la primera vez usando el mtodo
rect() para dibujar un rectngulo o un rea en la que nos gustara
dibujar, sin que podamos correr el riesgo de invadir la parte exterior de
esta regin, es decir, limitando esta rea a mi dibujo en particular,
entonces llamamos al mtodo clip(). Esto deine el rea que
coniguramos con el mtodo rect() como la regin clip. Ahora, lo que
pasar en el contexto actual, ser que nicamente se mostrar lo que
dibujemos en la porcin que hemos deinido anteriormente, es decir, se
mostrar solo lo que este dentro de la regin clipping. Piensa en esto
como una mascara que tu puedes usar en tus operaciones de dibujo.
Por defecto la regin clipping es del mismo tamao que el elemento
canvas. A continuacin vamos a ver un ejemplo que nos ayudar a
comprender de forma visual, lo que podemos hacer con un rea
clipada.

Ejemplo de aplicacin de la regin clipping:

nombre del archivo - regionClipping.html <!DOCTYPE html>


<html>

<head> <title>Ejemplo de sintaxis


canvas</title> <style>
#contenedor{

width:600px;
margin:0px auto;
padding-top:50px;

#canvas {
background: #eaeaea;
}
</style>
</head>
<body>
<div id=contenedor>
<canvas id=canvas width=600 height=400>
Tu navegador no soporta canvas de HTML 5
</canvas>
<script src=regionClipping.js></script>
</div>
</body>
</html>

nombre del archivo - regionClipping.js


var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d);

function dibujarCuadricula(context, color,


stepx, stepy) { context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepx + 0.5; i <
context.canvas.width; i +=

stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();

}
for (var i = stepy + 0.5; i <
context.canvas.height; i += stepy) {

context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}
}
function drawScreen() {
context.save();
context.beginPath();

//establecemos una region clipping en 5050


comenzando 200,100 context.rect(200, 100, 70,
70);
context.clip();

//creamos un circulo negro


context.beginPath();
context.strokeStyle = black;
context.lineWidth = 5;
context.arc(300, 200, 100, (Math.PI/180)*0,
(Math.PI/180)*360,

false);

//circulo full
context.stroke(); context.closePath();
context.restore();

//reclipamos el canvas completamente


context.beginPath();
context.rect(0, 0, 600, 400); context.clip();

//creamos una linea naranja


context.beginPath();
context.strokeStyle = orange;
context.lineWidth = 5;
context.arc(300, 200, 150, (Math.PI/180)*0,
(Math.PI/180)*360,
Descripcin Se reiere al contexto del elemento canvas. El uso mas
comn del atributo canvas es para acceder a los atributos ancho y alto
del elemento canvas: context. canvas.width y
context.canvas.height respectivamente.

fillStyle

Descripcin
Tipo
Valor por defecto

Especiica un color, gradiente o un patrn que subsecuentemente usa


el contexto para rellenar formas. Los valores vlidos son: una cadena
que contiene un color CSS, un canvasGradient object y un
canvasPattern Object. cualquiera
#000000

font

Descripcin
Tipo
Valor por defecto

Especiica la fuente que el contexto usa cuando llamas a los mtodos


illText() o strokeText(). Debe ser una fuente vlida CSS conigurada.
String
10px sans-serif.

Atento
Configurar las propiedades de la fuente.

Se puede configurar cualquier fuente del texto que se dibuja con la


propiedad font del contexto, la cual consiste en una cadena con los
componentes de una fuente css3 vlida. En la tabla 2 se listan los
componentes de estas fuentes en el orden que deben usarse para
esta propiedad. Una vez configurada la cadena de esta propiedad,
esta es impresa haciendo uso del mtodo

propiedad font-style
font-variant
font-weight

valores permitidos
Tres valores son permitidos: normal, italic y oblique Dos
valores son permitidos: normal y small-caps Determina el grosor
del carcter de una fuente: normal, bold, bolder (una fuente
mas resaltada que la fuente base), lighter (una fuente menos
resaltada que la fuente base), 100, 200, 300,,900. una fuente de 400
es normal, 700 es bold

propiedad font-size
line-height
font-family

valores permitidos
Valores para el tamao de la fuente: xx-small, x-small,
medium, large, x-large, xx-larger, smaller, larger,
length, %.
El navegador siempre lleva esta propiedad a su valor por defecto, la
cual es normal. Si tu coniguras esta propiedad, el navegador ignorar
tu coniguracin.
Dos tipos de nombres de familias de fuentes son permitidas: family-
name, tal como helvtica, verdana, palatino, etc. Y nombres
de generic-family: serif, sans-serif, monospace, cursive
y fantasy. Tu puedes usar family-name, generic-family o ambos para
el componente font-family de la fuente.

Tabla 2 - componentes y valores vlidos de las fuentes


Ejemplo de aplicacin de la propiedad font y sus valores:

nombre del archivo - font.html


<!DOCTYPE html>
<html>

<head>
<title>La propiedad font y sus
valores</title> <style>

body {
background: #eaeaea;
}
#contenedor{
width:500px;
margin:0px auto;
padding-top:50px;
}
#canvas {
}
</style> </head>

<body> <div id=contenedor>


<canvas id=canvas width=500 height=700>

Tu navegador no soporta canvas de HTML5


</canvas>
</div>

<script src=javascript/font.js></script>
</body>
</html>

nombre del archivo


- font.js
var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d),

FUENTES_A = [
normal 2em palatino,bolder 2em palatino,
lighter 2em palatino, italic 2em
palatino, oblique small-caps 30px
palatino,bold 18pt palatino, xx-large
palatino, italic xx-large palatino,
oblique 1.5em lucida console, x-large
fantasy, italic 28px monaco, italic large
copperplate, 36px century, 28px tahoma,
28px impact, 1.7em verdana

],
DELTA_Y = 40, TOP_Y = 50, y = 40;

function dibujarFondo() {
var DISTANCIA_Y = 12,
i = context.canvas.height;
context.strokeStyle = rgba(0,0,0,0.5);
context.lineWidth = 0.5;
context.save(); context.restore();

while(i > DISTANCIA_Y*4) {


context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
i -= DISTANCIA_Y;

}
context.save();
context.strokeStyle = rgb(0,0,0);
context.lineWidth = 1;
context.beginPath();
context.moveTo(35,0);
context.lineTo(35,context.canvas.height);
context.stroke(); context.restore(); }
dibujarFondo();
FUENTES_A.forEach( function (fuentes) {
context.font = fuentes;
});

El resultado se mostrar mas o menos de esta manera:


Atento
Composicin del Canvas

Se refiere a como finalmente podemos controlar los efectos de


transparencia y las capas de los objetos cuando dibujamos en el
canvas. Para operaciones de composicin del canvas podemos
disponer de dos funciones: globalAlpha y globalCompositeOperation.

globalAlpha

Descripcin
Tipo
Valor por defecto

Especiica la coniguracin global del alpha, la cual debe ser un nmero


entre 0 (transparente) y 1.0 (totalmente opaco). El buscador multiplica
el valor de cada pixel dibujado por la propiedad globalAlpha,
incluyendo cuando dibujas imgenes.
numbers.
1.0

Atento

Nota destacada!

Ademas de los colores especificados como semi transparentes con el


componente alpha de los sistemas de colores rgba() o hsla(), tambin
es posible usar la propiedad globalAlpha, la cual es aplicado por
el navegador a toda forma o imagen que hayas dibujado. El valor para
esta propiedad debe estar entre 0.0 lo cual significa que es totalmente
transparente y 1.0 que es totalmente opaco.

globalComposite-Operation

Descripcin Determina como el navegador dispone un objeto sobre


otro. Tipo String.
Valor por defecto
source-over

Por defecto cuando dibujas un objeto (source) encima de otro


(destination) en un canvas, el navegador simplemente dibuja el
recurso (source) sobre el destino (destination). Esta manera de
componer los objetos que dibujas, no debe causarte ninguna
sorpresa, ya que despus de todo, eso es exactamente lo que pasa si
tu dibujas en un papel, una cosa sobre otra.
Ahora bien, si tu coniguras la propiedad
globalCompositeOperation del contexto de canvas, tu
puedes cambiar el valor por defecto de una composicin por
cualquiera de los valores listados en la siguiente tabla. Estos valores
son conocidos como operadores porter-duf, los cuales fueron descritos
por homas Porter y Tom Duf para Lucas Films ltd., en un articulo
publicado en la revista computer graphics de julio de 1984. Puedes
leer este artculo en: http://keithp.com/~keithp/porterduf/ p253-
porter.pdf.
En la tabla 3 se muestran todos los valores vlidos para la propiedad
globalCompositeOperation, tambin muestra como el objeto
recurso (source), mostrado como un circulo, se compone sobre un
objeto destino (destination), mostrado como un cuadrado. El valor por
defecto, source-over, esta resaltado en la tabla.

Resultado Valor
source-atop
source-in
Descripcin
Renderiza A en la propiedad top de B solo donde B no es
transparente
Renderiza solo A y solo donde B no es transparente
source-out Renderiza solo A y solo donde B es transparente
source-over
destination-atop
destination-in

destination-out Renderiza A en la propiedad top de B donde A no es


transparente

Renderiza B en la propiedad top de A pero solo donde B no es


transparente
Renderiza solo B y solo donde A no es transparente
Renderiza solo B y solo donde A es transparente

destination-over Renderiza B en la propiedad top de A donde A no


es transparente

lighter Renderiza la suma de A y B


copy Se olvida de B y renderiza solo A

xor Renderiza A donde B es transparente. Renderiza transparente


donde ni A ni B son transparentes

Tabla 3 - valores para la propiedad globalComposite-Operation


Ejemplo de aplicacin de algunas de las propiedades de composicin
del canvas:

nombre del archivo - composicionCanvas.html


<!DOCTYPE html>
<html>

<head> <title>Ejemplo de composici&oacute;n


canvas</title> <style>
#contenedor{

width:600px;
margin: 0px auto; padding-top:50px;

#canvas {
background: #eaeaea;
}
</style>
</head>
<body>
<divid=contenedor>
<canvas id=canvas width=600 height=400>
Tu navegador no soporta canvas de HTML 5
</canvas>
<script src=composicionCanvas.js></script>
</div>
</body>
</html>

nombre del archivo - composicionCanvas.js


var canvas =
document.getElementById(canvas); var
context = canvas.getContext(2d);

dibujarCuadricula(context, lightgrey, 10,


10);
//creamos un area para mostrar el ejemplo
//dibujamos un cuadro rojo
context.globalCompositeOperation = source-
over; //draw a red square next to the other
one
context.globalCompositeOperation =
destination-out; context.globalAlpha = .5;
context.globalCompositeOperation = source-
atop;

//Funciones..................................
function dibujarCuadricula(context, color,
stepx, stepy) { context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepx + 0.5; i <
context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i,context.canvas.height);
context.stroke();
}
for (var i = stepy + 0.5; i <
context.canvas.height; i += stepy) {
context.beginPath();
puedes especiicar algunos de los siguientes tres valores: butt,
round y square. String.
butt
Atento
butt round square
imagen 2.31 - diferentes valores para las terminaciones de las
lineas
lineCap

Cuando dibujas en el canvas tu puedes controlar que la terminacin


de la linea sea igual a una de las mostradas en la imagen anterior -
conocidas como lineCap . Los finales de linea son controladas por la
propiedad lineCap del contexto de canvas.
En el contexto canvas la terminacin de la linea por defecto es butt,
la cual da salida a la linea como si fuera cortada de tajo en ese mismo
punto. Pero round y square agregan un remate al final de la linea;
round agrega un semicirculo al final de la linea con un diametro igual
a la mitad del ancho de la linea; square agrega un rectangulo al final
de la linea equivalente a la mitad del ancho de la linea.

lineWidth

Descripcin
Tipo
Valor por defecto
Determina el ancho, en pixel de pantalla o screen, de lo que tu dibujas
en el elemento canvas. El valor debe ser un double no negativo y no
ininito. Numbers
1.0

lineJoin

Descripcin
Tipo
Valor por defecto

Especiica como son unidas las lneas cuando se encuentran los puntos
inales. Tu puedes especiicar algunos de los siguientes tres valores:
bevel, round y miter.
String
miter

miter round bevel

imagen 2.32 - valores de la propiedad lineJoin para los encuentros


de lineas
lineJoin

lineas cuando estas coincidan, esto es conocido como unin de lineas


(line join en en ingls). Las uniones de lineas son controladas por la
propiedad lineJoin del contexto.
Un valor bevel para la propiedad lineJoin es el resultado de
formar un triangulo en la esquina opues

Atento

ta de las dos lineas con una linea recta. miter, la cual es el valor por
defecto para esta propiedad, es lo mismo que bevel con la diferencia
que miter agrega un triangulo extra al cuadrado de las esquinas.
Finalmente, un valor round para esta propiedad resulta de crear un
arco en las dos esquinas.

miterLimit

Descripcin
Tipo
Valor por defecto

Especiica como son unidas las lneas cuando se encuentran los puntos
inales. Tu puedes especiicar algunos de los siguientes tres valores:
bevel, round y miter.
String
miter

Ancho linea larg


Ancho linea largo m i te r
imagen 2.33 - formato del miter para los encuentros de lineas
miterLimit
Tu puedes controlar el largo del valor miter de la propiedad lineJoin,
cuando este es usado en tus dibujos, puedes especificar un limite a
este valor con la propiedad miterLimit, la cual es el largo del miter
dividido entre la mitad Atento del ancho de la linea.

Al dibujar o trabajar con formas, textos o imgenes dentro del elemento


canvas, quizs tu desees tambin aadirle una sombra a tus diseos,
el contexto de canvas posee cuatro atributos ideales para tal in.

shadowBlur

Descripcin
Tipo
Valor por defecto

Determina como el navegador extiende la sombra exterior; el nmero


ms alto es el mas extendido fuera de la sombra. El valor shadowBlur
no es un valor pixel pero si un valor usado en una ecuacin de
desenfoque gaussiano. Debe ser un valor no negativo.

Numbers
0.0

shadowColor

Descripcin
Tipo
Valor por defecto

Especiica el color a usar por el navegador al dibujar la sombra. El valor


para esta propiedad es a menudo especiicada como parcialmente
transparente para que se vea el fondo a travs de ella. Debe ser un
color CSS vlido. String
transparent black

Valores permitidos
#F444

#44FF44
rgb(60,60,255)
rgb(100%,25%,100%) rgba(0,0,0,0)
hsl(60, 100%, 50%) hsla(60,100%,50%,0.5) magenta

Comentario
Color RGB Hexadecimal: red (rojo)

RRGGBB :Green (verde)


rgb expresados como enteros
rgb expresados como porcentaje: purple (prpura) Negro
transparente
Expresa un valor amarillo saturado
Expresa un valor amarillo al 50% de opacidad Como un string con
un color css vlido

Tabla 4 - ejemplos de cadenas para expresar colores con la


propiedad shadowColor.

shadowOffsetX

Descripcin
Tipo
Valor por defecto
Determina la impresin horizontal, en pixeles de pantalla, para
sombrados. Numbers
0.0
shadowOffsetY

Descripcin
Tipo
Valor por defecto
Determina la impresin vertical, en pixeles de pantalla, para
sombreados. Numbers
0.0
Atento
Las sombras

De acuerdo con las especificaciones del canvas, los navegadores


deben dibujar las sombras solo si: a. has especificado un color con la
propiedad shadowColor, lo cual indicar que no es completamente
transparente.
b. Has indicado un valor diferente de 0 en alguna de las tres
propiedades del contexto de canvas para las sombras:
shadowBlur, o . Otra manera sencilla para no mostrar las sombras
es establecer shadowColor como indefinido. Sin embargo, hay que
tomar en cuenta que al configurar esta propiedad como indefinida, no
trabajar en todos los navegadores, al momento de escribir esta gua
de referencia solo trabajaba en los navegadores basados en webKit,
en los navegadores tales como Firefox u Opera no funciona. Para estar
seguro de que tus sombras se dibujarn o no en todos los
navegadores, deberas darle algn valor a las propiedades de
sombras, esto lo puedes hacer de forma manual o usando los mtodos
del contexto save() o restore().
strokeStyle

Descripcin
Tipo
Valor por defecto

Especiica estilo usado para el dibujado de las lneas. Este valor puede
ser un color, gradiente o patrn. Los valores vlidos son: una cadena
que contiene un color CSS, un canvasGradient Object y un
canvasPattern Object. cualquiera
#000000

Atento

Posicionar horizontal y verticalmente los textos

Cuando dibujas textos en un canvas con los mtodos strokeText() y


fillText(), estas especificando las coordenadas x e y donde deben
dibujarse los textos dentro del canvas; sin embargo, exactamente
donde el navegador dibuja los textos depende de dos propiedades
del contexto: textAlign y textBaseline.

textAlign

Descripcin Determina la colocacin horizontal del texto dibujado con


los mtodos - Text() o strokeText().Valores vlidos son:
start, end, left y right.

Tipo String
Valor por defecto start
La propiedad textAlign
El valor por defecto para la propiedad textAlign es start y cuando el
navegador muestra el texto desde la izquierda a la derecha, significa
que el atributo dir del elemento canvas es ltr, left es lo mismo
que
Atento

start y right es lo mismo que end. De igual manera, cuando el


navegador muestra los textos de derecha a izquierda, significa que el
valor para el atributo dir esrtl, right es lo mismo que start y
left es lo mismo que end.

textBaseLine

Descripcin Determina la colocacin vertical del texto dibujado con los


mtodos - Text() o strokeText(). Los valores vlidos para
esta propiedad son: top, hanging, middle, alphabetic,
ideographic y bottom.

Tipo String
Valor por defecto alphabetic
La propiedad textBaseline
El valor por defecto para la propiedad textBaseline es alphabetic,
la cual es usado para lenguajes base latin, ideographic es usado
para lenguajes tales como japons y chino, mientras que hanging es
Atento

usado para muchos de los lenguajes de India. Los valores top,


}
#canvas {

border:2px solid #666; margin-top:5px;


}
p{
display:inline; margin-left:60px; margin-
right:130px; font-size:16px;
color:red;
}
p#last{
margin-right:0px; color:red;
}
</style>
</head>

<body> <div id=contenedor>


<p>izquierda a derecha</p>
<p>centrado</p>
<p id=last>derecha a izquierda</p>

<canvas id=canvas width=800 height=500>

Tu navegador no soporta canvas de HTML5


</canvas>
</div>

<script src=javascript/posicionTextos.js>
</script> </body> </html>

nombre del archivo - composicionCanvas.js


var canvas =
document.getElementById(canvas),
context = canvas.getContext(2d),
tamFuente = 24,
valoresTextAlign = [start, center,
end],
valoresTextBaseline = [top, middle,
bottom, alphabetic, ideographic,
hanging],
x, y;

//
Funciones....................................
function dibujarCuadricula(context, color,
stepx, stepy) { context.save();
context.strokeStyle = color;
context.lineWidth = 0.5;
height);

for (var i = stepx + 0.5; i <


context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();

for (var i = stepy + 0.5; i <


context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}
context.restore(); }
function dibujarIndicadorPosicion() {
context.strokeRect(x, y, 7, 7); }
function dibujarTextos(texto, textAlign,
textBaseline) { if(textAlign)
context.textAlign = textAlign;
if(textBaseline)
context.textBaseline = textBaseline;
}
function dibujarLineaTexto() {
context.strokeStyle = red;

context.beginPath();
context.moveTo(x, y); context.lineTo(x + 728,
y); context.stroke();

}
//
Initialization...............................
context.font = normal bold 18px palatino;
dibujarCuadricula(context, #ccc, 10, 10);

for (var align=0; align <


valoresTextAlign.length; ++align) { for (var
baseline=0; baseline <
valoresTextBaseline.length;
++baseline) {
x = 40 + align*tamFuente*15;
y = 40 + baseline*tamFuente*3.3;

dibujarTextos(posicion: +
valoresTextAlign[align] + / +
mtodos y strokeText(). Valores vlidos son: ltr, rtl e
inherit
Tipo String
Valor por defecto inherit

La propiedad direction
El valor por defecto para la propiedad direction es inherit, lo cual
sigue la direccionalidad del elemento canvas o documento en su caso,
ltr es usado para indicar al canvas que deseamos que los textos se
dibujen
Atento

desde la izquierda hacia la derecha, mientras que rtl es usado para


indicarle al canvas que los textos se deben dibujar desde la derecha
hacia la izquierda. Este mtodo devuelve el valor actual, que si no se
ha indicado ningn otro, se establece inicialmente en inherit,
pero al cambiarsele el valor, este toma inmediatamente el nuevo valor
asignado.

lineDashOffset

Descripcin
Tipo
Valor por defecto

Esta coniguracin puede ser usada para estipular cun lejos dentro de
la secuencia de la linea dash se dibuja al inicio de la misma. es decir, si
coniguras una linea dash segn esta matriz de nmeros ([5,5,2,2]) y
coniguras la propiedad lineDashOfset igual a 10, entonces, el primer
trazo que es dibujado ser de 2 pixeles de tamao seguido de un
espacio de 2 pixeles, para luego repetir el ciclo indicado en la matriz
de nmeros , una y otra vez, hasta que inalice la linea a la cual se le
aplica el mtodo dash.
Number
0

Ejemplo de aplicacin de la propiedade lineDashOffset:

nombre del archivo - dash.html


<!DOCTYPE html>
<html>

<head>
</title>
<style>
body {
background: #eaeaea; }

#contenedor{
width:500px; margin:0px auto; padding-
top:50px;

}
#canvas {
}
</style> </head>
<body>
<div id=contenedor>
<canvas id=canvas width=500 height=300>

Tu navegador no soporta canvas de HTML5


</canvas>
<button onclick=incrementarDash()>A
marchar!</button>

</div>
<script src=javascript/dash.js></script>
</body>
</html>

nombre del archivo


- dash.js
window.onload = function () {
contexto =
document.getElementById(canvas).getContext(
contexto.translate(0.5,0.5);

//Agregar una funcin de marcador de posicin


para //los navegadores que no tienen
setLineDash() if (!contexto.setLineDash) {

contexto.setLineDash = function () {}; }

// La primera linea dashed


contexto.setLineDash([1,2]); contexto.mozDash
= [5]; contexto.beginPath();
contexto.moveTo(15,45);
contexto.lineTo(485,45); contexto.stroke();

// La segunda linea dashed


contexto.setLineDash([2,4]); contexto.mozDash
= [5]; contexto.beginPath();
contexto.moveTo(15,70);
contexto.lineTo(485,70); contexto.stroke();
// La tercera linea dashed
contexto.setLineDash([5]); contexto.mozDash =
[5]; contexto.beginPath();
contexto.moveTo(15,95);
contexto.lineTo(485,95); contexto.stroke();

// la cuarta linea dashed


contexto.setLineDash([10]); contexto.mozDash
= [5]; contexto.beginPath();
contexto.moveTo(15,120);
contexto.lineTo(485,120); contexto.stroke();

// El circulo
contexto.setLineDash([5]);
contexto.mozDash = [5];
contexto.beginPath();
contexto.arc(55,215,40,0,2 * Math.PI,false);
contexto.stroke();

// El cuadrado
contexto.setLineDash([1,2]); contexto.mozDash
= [5];
contexto.beginPath();
contexto.strokeStyle = red;
contexto.rect(130,175,80,80);
contexto.stroke();

// la linea curva
contexto.setLineDash([5]);
contexto.mozDash = [5];
contexto.beginPath();
contexto.strokeStyle = blue;
contexto.moveTo(255,175);
contexto.quadraticCurveTo(295,325,345,175);
contexto.stroke();

// La forma irregular
contexto.setLineDash([5,5,2,2]);
contexto.mozDash = [5];
contexto.beginPath();
contexto.strokeStyle = green;
contexto.moveTo(415,175);
contexto.lineTo(385,215);
contexto.lineTo(405,255);
contexto.lineTo(455,255);
contexto.lineTo(435,225);
contexto.lineTo(455,175);
contexto.closePath();
contexto.stroke();

};

/** */
function incrementarDash () {

if (typeof(interval_reference) != number) {
interval_reference = setTimeout(foo =
function () {
contexto.canvas.width =
contexto.canvas.width;
// Dibujar las lineas/formas window.onload();
setTimeout(foo, 50);
}, 50);
location.href = #introduction; }
}
Los objetos dentros del canvas
textMetrics

Descripcin
Atributos

Este es un objeto devuelto por el mtodo measureText() del


canvasRenderingContext2d. Las medidas devueltas en este
objeto viene dada en pixeles CSS

width, actualBoundingBoxLeft,
actualBoundingBoxRight,
fontBoundingBoxAscent,
fontBoundingBoxDescent,
actualBoundingBoxAscent,
actualBoundingBoxDescent, emHeightAscent,
emHeightDescent, hangingBaseline,
alphabeticBaseline, ideographicBaseline

Atributos del objeto textMetrics

Direccion horizontal X

width

Descripcin
Representa el ancho del texto dado. viene expresado en pixeles CSS

actualBoundingBoxLeft
Descripcin

Representa la distancia paralela a la linea base desde el punto de


alineacin

dado por el atributo textAlign al lado izquierdo del rectngulo


delimitador en el texto dado, en pixeles CSS; valores positivos indican
una distancia que va desde la izquierda al punto de alineacin dado.

actualBoundingBoxLeft y actualBoundingBoxRight
la suma de estos valores puede ser ms ancho que el ancho de la
linea de caja (anchura), en particular con las fuentes inclinadas donde
los caracteres sobresalen de su anchura normal.
Atento

actualBoundingBoxRight

Descripcin Representa la distancia paralela a la linea base desde el


punto de alineacin dado por el atributo textAlign al lado
derecho del rectngulo delimitador en el texto dado, en pixeles CSS;
valores positivos indican una distancia que va desde la derecha al
punto de alineacin dado.

Direccion vertical Y

fontBoundingBoxAscent

Descripcin Representa la distancia desde la linea horizontal indicada


por el atributo textBaseline a la parte superior del rectngulo
delimitador ms alto de todas las fuentes usadas para renderizar el
texto, en pixeles CSS; valores positivos indican una distancia que va
desde la parte superior a la linea base dada.

fontBoundingBoxAscent y fontBoundingBox Descent


Estos valores son tiles cuando se representa un fondo(background)
que debe tener una altura constante, incluso si el texto exacto
renderiza cambios El atributo actualBoundingBoxAscent (y su
corresponAtento diente atributo para el descenso) son tiles cuando
dibujas una caja limitadora de un texto especifico.

fontBoundingBoxDescent

Descripcin Representa la distancia desde la linea horizontal indicada


por el atributo textBaseline a la parte inferior del rectngulo
delimitador ms alto de todas las fuentes usadas para renderizar el
texto, en pixeles CSS; valores positivos indican una distancia que va
desde la parte inferior a la linea base dada.

actualBoundingBoxAscent

Descripcin

Representa la distancia desde la linea horizontal indicada por el


atributo

textBaseline a la parte superior del rectngulo delimitador del


texto dado, en pixeles CSS; valores positivos indican una distancia que
va desde la parte superior a la linea base dada.
Nota destacada!
Este nmero puede variar en gran medida basado en el texto de
entrada, incluso si la primera fuente especificada cubre todos los
caracteres de la entrada. Por ejemplo, el actualBoundingBoxAscent de
una letra minuscula o
Atento

desde una propiedad alphabetic del atributo textBaseline sera


menor que la de una F mayuscula. El valor fcilmente debe ser
negativo; por ejemplo, la distancia desde la parte superior de la caja
em(textBaseline valor top) a la parte superior del rectngulo
delimitador cuando el texto dado es solo una coma , probablemente
(a menos que la fuente sea bastante inusual) ser negativo.

actualBoundingBoxDescent

Descripcin Representa la distancia desde la linea horizontal indicada


por el atributo textBaseline a la parte inferior del rectngulo
delimitador del texto dado, en pixeles CSS; valores positivos indican
una distancia que va desde la parte baja a la linea base dada.

emHeightAscent

Descripcin Representa la distancia desde la linea horizontal indicada


por el atributo textBaseline a la parte superior del cuadro em
(em square) en la linea de caja, en pixeles CSS, valores positivos
indican que la linea base dada esta por debajo de la parte superior
del cuadro em (por lo que este valor, usualmente ser positivo). (Cero
si la linea base dada esta en la parte superior de el cuadro em; la mitad
del tamao de la fuente si la linea base dada esta en el medio del
cuadro em).

emHeightDescent

Descripcin Representa la distancia desde la linea horizontal indicada


por el atributo textBaseline a la parte inferior del cuadro em (em
square) en la linea de caja, en pixeles CSS, valores positivos indican
que la linea base dada esta detrs de la parte inferior del cuadro em
(por lo que este valor, usualmente ser negativo). (Cero si la linea base
dada esta en la parte superior de el cuadro em).

hangingBaseline

Descripcin Representa la distancia desde la linea horizontal indicada


por el atributo textBaseline al punto hanging a la linea base
de la linea de caja, en pixeles CSS; valores positivos indican que la
linea base dada est detrs del valor hanging de la linea base.
(Cero si la linea base dada esta en el punto hanging de la linea
base).

alphabeticBaseline

Descripcin Representa la distancia desde la linea horizontal indicada


por el atributo textBaseline al valor alphabetic a la linea
base de la linea de caja, en pixeles CSS; valores positivos indican que
la linea base dada est detrs del valor alphabetic de la linea
base. (Cero si la linea base dada esta en el punto alphabetic de
la linea base).

ideographicBaseline

Descripcin Representa la distancia desde la linea horizontal indicada


por el atributo textBaseline al valor ideographic a la linea
base de la linea de caja, en pixeles CSS; valores positivos indican que
la linea base dada est detrs del valorideographic de la linea
base. (Cero si la linea base dada esta en el punto ideographic de
la linea base).

Nota destacada!
Los grficos usando los mtodos y strokeText() pueden
sobresalir de la caja propuesta por el tamao de la fuente (el tamao
del cuadro em) y la anchura devuelta por el mtodo mea
Atento
sureText() (el ancho del texto). Los autores pueden utilizar los
valores del cuadro delimitador descritos anteriormente si esto es un
problema.

El Objeto canvasGradient

Descripcin Un objeto canvasGradient representa a un color gradiente


que puede ser asignado por las propiedades strokeStyle y illStyle de
un objeto canvasRenderingContext2d. Los mtodos
createLinearGradient() y createRadialGradient() del
canvasRenderingContext2d devuelven objetos canvasGradient. Una
vez que se haya creado un objeto canvasGradient, use el mtodo
addColorStop() para especiicar que color debe aparecer en que
posiciones dentro del gradiente. Entre las posiciones que usted
especiique, los colores se interpolan para crear un degradado suave o
desvanecimiento. Si se especiica sin escalas de color, el gradiente ser
negro transparente uniforme.

Mtodos del objeto canvasGradient addColorStop(number


offset, string color)

Descripcin
Especiica colores ijos dentro de un gradiente. Si tu especicas 2 o mas
para

das de color, el gradiente interpolar suavemente los colores entre las


paradas. Antes de la primera parada, el gradiente mostrar el color de
la primera parada. Despus de la ltima parada, el gradiente mostrara
el color de la ltima parada. Si tu especiicas solo un color, el gradiente
ser un color slido. Si tu no especicas paradas de colores, el
gradiente ser un negro transparente uniforme. Este mtodo acepta
dos argumentos, el primero ofset representa la posicion del color
especiicado por el segundo argumento, este es un valor de coma
lotante dentro de un rango de 0.0 a 1.0 que representa una fraccin
entre el comienzo y el punto inal del gradiente.Un ofset de 0
representa el punto de inicio y 1 representa el punto inal. El segundo
argumento representa el color a ser mostrado en la posicin del primer
argumento, este debe ser una cadena vlida para un color CSS.
Colores en otros puntos a lo largo del gradiente son interpolados
basados en esta y otras paradas de color

El Objeto ImageData

Descripcin Un objeto ImageData contiene los componentes rojo,


verde, azul y alpha de una regin rectangular de pixeles. Obtienes un
objeto ImageData con los mtodos createImageData() o
getImageData(), ambos objetos
CanvasRenderingContext2D.
Los nuevos objetos ImageData deben inicializarse de manera que
su atributo de anchura se establece en el nmero de pixeles por ila en
los datos de la imagen, su atributo de altura se establece en el nmero
de ilas de los datos de la imagen, su resolucin se ajusta a la densidad
de pixeles del objeto y su atributo data se inicializa con un objeto
Uint8ClampedArray. El objeto Uint8ClampedArray de be
utilizar un pixel del canvas para su almacenamiento y debe tener un
comienzo en cero y una longitud igual a la longitud de su
almacenamiento, en bytes. El pixel del Canvas debe contener los datos
de la imagen. Por lo menos el valor de un pixel debe ser devuelto con
los datos de la imagen.
Un pixel del Canvas es un cuyos datos se representan ordenados de
izquierda-a-derecha, ila por ila de arriba-a-abajo, comenzando por la
parte superior izquierda, con cada pixel son dado los componentes
rojo (R), verde(G), azul (B) y alpha (A), cada uno de ellos en este mismo
orden. Cada componente de cada pixel representado en esta matriz
debe estar dentro de un rango de 0 y 255, que representa el valor de
8 bits para ese componente. A los componentes le son asignados los
indices consecutivos comenzando con 0 para el componente rojo del
pixel superior izquierdo. As el componente color de un pixel en (x,
y) dentro de un objeto ImageData imagen puede ser accesado
como sigue:

Los elementos son de lectura/escritura, pero la longitud de la matriz es


ija. Para cualquier objeto ImageData i,i.data.lenght siempre
ser igual a i.width*i.height*4.

Propiedades del objeto ImageData width

Descripcin Devuelve el componente de anchura real de los datos en


el objeto ImageData, en pixeles. Para los objetos devueltos por las
variantes no HD de los mtodos en esta API, esto corresponder a la
anchura dada por los mtodos. Para las variantes de alta deinicin
(HD), el nmero de pixeles puede ser diferente que el nmero de
unidades correspondiente de espacio de coordenadas.

height

Descripcin
Devuelve el componente de altura real de los datos en el objeto
ImageData,

en pixeles. Para los objetos devueltos por las variantes no HD de los


mtodos en esta API, esto corresponder a la altura dada por los
mtodos. Para las variantes de alta deinicin (HD), el nmero de
pixeles puede ser diferente que el nmero de unidades
correspondiente de espacio de coordenadas.
resolution

Descripcin
Devuelve el nmero terico de pixeles en los datos del objeto
ImageData

por unidad de espacio coordenadas correspondiente. Este valor se


determina de forma automtica a partir de la imagen de la fuente
cuando se crea el objetoImageData, solo se utiliza para asegurar
que los objetos ImageBitmap tienen la densidad de pixeles
correcta a partir de objetos ImageData.

data

Descripcin Devuelve una matriz unidireccional que contiene los datos


rgba, como enteros a partir de 0 a 255.

El Objeto CanvasPatternCanvasPattern es devuelto por

el mtodo createPattern()Descripcin Un objeto

del objeto CanvasRenderingContext2D. Un objeto


CanvasPattern puede ser usado como el valor de las
propiedades strokeStyle y fillStyle del objeto
CanvasRenderingContext2D.
Un objeto CanvasPattern no tiene propiedades o mtodos
propios.

El Objeto CanvasProxy CanvasProxy puede ser


neutralizado (como cualquier objeto Descripcin Un
objeto

transferible), lo que signiica que ya no puede ser transferida, y puede


ser desactivada, lo que signiica que ya no puede ser obligado a
contextos renderizados. Cuando es creado por primera vez, un objeto
CanvasProxy debe ser nulo. Un objeto CanvasProxy se crea
con un enlace a un elemento canvas. Un objeto CanvasProxy que
no ha sido deshabilitado debe tener una fuerte referencia a su
elemento canvas.
Para transferir un objeto CanvasProxy antiguo a uno nuevo, un
user agent debe crear un nuevo objeto CanvasProxy
referenciando al mismo elemento canvas, de forma que, obtendra uno
nuevo, que debe neutralizar y desactivar al anterior objeto para
inalmente devolver uno completamente nuevo.

Mtodos del objeto CanvasProxy setContext(context)

Descripcin Establece un contexto de renderizado del elemento


canvas del objeto CanvasProxy al objeto dado.
Lanza una excepcin InvalidStateError si el objeto CanvasProxy se
ha transferido.

El Objeto Path

Descripcin
Junto con las regiones Hit, los objetos Path son una de las adiciones
ms signif
icativas de la especiicacin canvas. Actualmente el canvas tiene solo
un path que se puede manipular, delinear y/o rellenar. Una vez que
hayamos creado un n uevo path, el primer path se pierde. Los objetos
paths le permiten conservar los paths y reproducirlos, ajustarlos y
ponerlos a prueba mediante el mtodo isPointInPath(). Esta ltima
caracterstica, la prueba de posicionamiento del mtodo isPointInPath(),
hara que se pruebe la deteccin de colisiones en el canvas de una
forma ms rapida y sencilla. Actualmente si usted desea probar si un
par de coordenadas estn dentro de un cuadrado, tu tienes que
probar que esas coordenadas esten dentro de los lmites X/Y/W/H del
cuadrado. Con el mtodo isPointInPath(), se realiza con slo una
simple llamada a la funcin y pasar los parametros para comoprobar el
resultado (que ser true o false). Tambin tiene el potencial de eliminar
las porciones de cdigo, en partcular cuando se trata de formas mucho
ms complejas.
Al momento de escribir este libro, ningn navegador soporta an las
funciones del objeto path y el objeto en si mismo.

Crear un objeto Path

Para crear un nuevo objeto path existen tres variantes:


path = new Path() Cuando no son pasados argumentos al mtodo este
crea un nuevo objeto path path = new Path(path)
Pasando un path existente, el mtodo crear una copia del path
pasado en los argumentos
path = new Path(SVGpath) Pasando una cadena que representa un
objeto Path SVG, este crear un objeto Path que consiste en el path
SVG pasado en los argum,entos. Ejemplo de creacin de un objeto
path

nombre del archivo - path.js


<script>
// Un cuadrado
path1 = new Path();
path1.rect(5,5,90,90);
// Un rectangulo con esquinas redondeadas
path2 = new Path();
path2.arc(50,50,45,Math.PI / 2,Math.PI *
1.5,false); path2.lineTo(200,5);
path2.arc(200,50,45,Math.PI * 1.5,Math.PI /
2,false); path2.closePath();
context.stroke(path1);
context.stroke(path2);
canvas.onclick = function (e)
{
var context = e.target.getContext(2d);

var coordY = coords[1];


// Test de clicks para el cuadrado
// ... }
// ... }
}
<script>

Mtodos del objeto Path addPath(path, transform)

Descripcin Agrega al path el path dado por el primer argumento


pasado al mtodo. El segundo argumento es representado por alguno
de los mtodos de transformacin.
Ejemplo de aplicacin del mtodo addPath()

nombre del archivo - addPath.js


var canvas =
document.getElementById(canvas);
var context = canvas.getContext(2d);
// transformar un path cuando se agrega a
otra path
var duck = new Path(M 0 0 c 40 48 120 -32
160 -6 c 0 0 5 4 10 + -3 c 10 -103 50 -83
90 -42 c 0 0 20 12 30 7 c +
-2 12 -18 17 -40 17 c -55 -2 -40 25 -20 35 c
+
30 20 35 65 -30 71 c -50 4 -170 4 -200
-79z);
var identity = new SVGMatrix();

var threeDucks = new Path();


threeDucks.addPath(duck,
identity.translate(0,0));
threeDucks.addPath(duck,
identity.translate(100,0));
threeDucks.addPath(duck,
identity.translate(200,0));

addPathByStrokingPath(path, styles, transform)

Descripcin Agrega al path elpath dado por el primer argumento


pasado al mtodo, en el caso del estilo de lineas, estas son tomadas
del segundo argumento styles, la cul puede ser un objeto
DrawingStyle o un objeto CanvasRenderingContext2d.
El tercer y ltimo argumento es representado por alguno de los
mtodos de transformacin.

addText(text, styles, transform, x, y [, maxWidth])

Descripcin Agrega el texto pasado como primer argumento al path


o al canvas. Este mtodo posee dos variantes, las cuales son:
addText(text, styles, transform, x, y [,
maxWidth]) y addText(text, styles, transform,
path [, maxWidth]). La diferencia entre estas dos variantes,
es que en lugar de unas coordenadas, se pasa otro objeto Path como
argumento.
La primera variante de este mtodo acepta 6 argumentos, de los cuales
el ltimo es opcional. El primer argumento representa el texto a ser
dibujado, el segundo representa el estilo del delineado que puede ser
un objeto DrawingStyle o un objeto CanvasRenderingContext2d; el
tercer argumento representa una transformacin representada por
cualesquiera de los mtodos de transformacin del objeto
CanvasRenderingContext2d, el cuarto y quinto argumentos
representan las coordenadas de donde se dibujar el texto, si fuera
esta la variante usada, el texto se dibujara horizontalmente en las
coordenadas dadas, y por ltimo de manera opcional un argumento
que representa el ancho mximo a ocupar por el texto que se dibujara,
si es pasado este argumento, el texto se escalar, si fuera necesario,
hasta ocupar el ancho suministrado por este argumento. Para la
segunda variante los argumentos son solo cinco en lugar de seis
pasados a la primera variante, estos son iguales con la diferencia de
que el cuarto y quinto argumentos que representan las coordenadas,
son sustituidos por un objeto path en donde se dibujar los textos
pasados por el primer argumento. Si fuera este el caso usado,
entonces el texto se dibujara a lo largo del path dado.

Ejemplo de aplicacin del mtodo addText()

nombre del archivo - addText.js


var canvas =
document.getElementById(canvas); var
context = canvas.getContext(2d);
var p1 = new Path(M 100 350 q 150 -300 300
0); var p2 = new Path();
var styles = new DrawingStyle();
styles.font = 20px sans-serif;
p2.addText(Hello World, styles, null, p1);

addPathByStrokingText(text, styles, transform, x, y [,


maxWidth])

Descripcin Agrega el texto pasado como primer argumento al path


o al canvas. Este mtodo posee dos variantes, las cuales son:
addPathByStrokingText(text, styles,
transform, x, y [, maxWidth]) y
addPathByStrokingText(text, styles,
transform, path [, maxWidth]).
La diferencia entre estas dos variantes, es que en lugar de unas
coordenadas, se pasa otro objeto Path como argumento.
La primera variante de este mtodo acepta 6 argumentos, de los cuales
el ltimo es opcional. El primer argumento representa el texto a ser
dibujado, el segundo representa el estilo del delineado que puede ser
un objeto DrawingStyle o un objeto CanvasRenderingContext2d; el
tercer argumento representa una transformacin representada por
cualesquiera de los mtodos de transformacin del objeto
CanvasRenderingContext2d, el cuarto y quinto argumentos
representan las coordenadas de donde se dibujar el texto, si fuera
esta la variante usada, el texto se dibujara horizontalmente en las
coordenadas dadas, y por ltimo de manera opcional un argumento
que representa el ancho mximo a ocupar por el texto que se dibujara,
si es pasado este argumento, el texto se escalar, si fuera necesario,
hasta ocupar el ancho suministrado por este argumento. Para la
segunda variante los argumentos son solo cinco en lugar de seis
pasados a la primera variante, estos son iguales con la diferencia de
que el cuarto y quinto argumentos que representan las coordenadas,
son sustituidos por un objeto path en donde se dibujar los textos
pasados por el primer argumento. Si fuera este el caso usado,
entonces el texto se dibujara a lo largo del path dado.

moveTo(float x, float y)

Descripcin Agrega un nuevo subpath al actual path con el punto que


has especiicado como el nico punto de ese subpath. Este mtodo no
limpia ninguno de los subpaths que estn en el path actual.

closePath()

Descripcin
Explcitamente cierra un path abierto. Este mtodo es para abrir paths
de arcos y paths creados con lneas o curvas.
lineTo(float x, float y)

Descripcin Si estos no son subpaths en el path actual, este mtodo


hace parcialmente lo mismo que moveTo(): crea un subpath en el punto
que has especiicado. Ahora bien, si estos son subpaths en el path
actual, este mtodo agrega el punto que has especiicado a este
subpath.

quadraticCurveTo(float cpx, float cpy, float x, float y)

Descripcin
Crea un path para una curva Bzier cuadrtica. Este mtodo acepta
cuatro (4)

argumentos. Los argumentos cpx y cpy representan las


coordenadas del punto de control y los argumentos x e y representan
el punto inal de la curva. Este mtodo agrega un segmento de curva
Bzier cuadrtica al subpath actual. La curva se inicia en el punto
actual y termina en las coordenadas x e y dada por los argumentos. El
punto de control (cpx, cpy) determina la forma de la curva entre estos
dos puntos.
Cuando este mtodo inaliza devuelve el punto actual como las
coordenadas x e y.

bezierCurveTo(float cpX1, float cpY1, float cpX2, float


cpY2, float x, float y)

Descripcin
Agrega una curva bezier cubica al actual subpath. Este mtodo acepta
seis (6)

argumentos: cpX1 y cpY1 representan las coordenadas del punto de


control asociadas al punto inicial de las curvas (la posicin actual),
cpX2 y cpY2 representan las coordenadas del punto de control
asociadas al punto inal de las curvas y por ltimo x e y representan las
coordenadas del punto inal de las curvas.
El punto de inicio de la curva, es el punto actual del canvas y el punto
inal est representados en las coordenadas x e y de los argumentos.
Los dos puntos de control Bzier (cpX1, cpY1) y (cpX2, cpY2)
deinen la forma de la curva.

arcTo(float x0, float y0, float x1, float y1, float radius)

Descripcin Este mtodo acepta cinco (5) argumentos: los dos primeros
representan las coordenadas del punto P1, los dos siguientes
representan las cordenadas del punto P2 y el ltimo argumento
representa el radio del crculo que deine el arco. Este mtodo agrega
una lnea recta y un arco al actual subpath y describe un arco que lo
hace particularmente til para dar esquineas redondeadas a los
poligonos. El arco que es agregado al path es una porcin de un
crculo con el radio especiicado. El arco tiene un punto que es
tangente a la lnea desde la posicin actual a P1 y un punto que es
tangente a la lnea desde P1 a P2. El arco comienza y termina en esos
dos puntos tangentes y es dibujado en la posicin que conecta estos
dos puntos con el arco mas pequeo. Despues agrega el arco al path,
este mtodo agrega una lnea recta desde el punto actual al inicio del
punto del arco. Despues de llamar a este mtodo, el punto actual es el
ltimo punto del arco, la cual reside entre los puntos P1 y P2.

arc(float x, float y, radius, starAngle, endAngle,boolean


anticlockwise)

Descripcin Agrega los subpaths que vienen a representar un arco o


un crculo al actual path. T puedes controlar la direccin en que se
dibujarn los subpaths (a diferencia del mtodo rect()), con una
variable booleana. S existe un subpath cuando el mtodo es llamado,
este dibujar una lnea desde el ltimo punto en el subpath existente
hasta el primer punto delante del arco del path. Este mtodo toma 6
parmetros, los primeros dos parmetros representan un punto en el
centro de un crculo; el tercer parmetro representa el radio del crculo,
el cuarto y quinto parmetros representan el angulo inicial y el angulo
inal, respectivamente del crculo que el navegador dibujar. El ltimo
argumento es opcional y representa la direccin en la cual el
navegador dibujara el arco. Si el valor se establece en false, como
viene por defecto, el navegador dibujar el arco en direccin al
sentido de las agujas del reloj, si por el contrario se establece en true,
el navegador dibujar el arco en la direccin contraria al sentido de
las agujas del reloj.

rect(float x, float y, float width, float height)

Descripcin
Este mtodo agrega un rectngulo al path, es un subpath de si mismo y
no
esta conectado a otro subpath en el path, es decir, el subpath es
implcitamente cerrado y siempre en direccin al sentido de las agujas
del reloj. Este mtodo devuelve la posicin actual en sus coordenadas
x e y.
Acepta 4 argumentos, x e y representan las coordenadas de la
esquina superior izquierda del rectngulo, mientras que width y
height representan las dimensiones del ancho y alto del rectngulo.
Un llamado a este mtodo es equivalente a una secuencia de llamado
de los siguientes mtodos:

styles.moveTo(x, y);
styles.lineTo(x + w, y);
styles.lineTo(x + w, y + h);
styles.lineTo(x, y + h);
styles.closePath();

ellipse(float x, float y, float radiusX, float radiusY, float


rotation, float startAngle, float endAngle,boolean
anticlockwise)

Descripcin Dibuja una elipse segn los argumentos especicados. Si


la trayectoria del objeto no posee un subpath, este mtodo aade una
lnea recta desde el ltimo punto del subpath al punto de inicio del
arco. Luego aadir los puntos de inicio y inal de la circunferencia y
las conecta con un arco.
Este mtodo posee 8 argumentos:
x e y representan las coordenadas, en pixeles, del centro de el arco
en relacin con la esquina superior izquierda del canvas.
radiusX y radiusY representan las coordenadas, en pixeles, de
la ruta a seguir por el arco.

El Objeto DrawingStyle

Descripcin
Todos los estilos de linea (line Width, caps, join y patrones dash) y
estilos de

textos (fonts) son cubiertos por este objeto. En esta seccin se deine el
constructor usado para obtener un objeto DrawingStyle. Este objeto es
usado por los mtodos en objetos path para controlar como los textos y
los trazos son rasterizados y delineados.

Crear un objeto DrawingStyle

Para crear un nuevo objeto DrawingStyle hay que invocar al


constructor
style = new DrawingStyle([element])

Descripcin Este constructor crea un nuevo objeto DrawingStyle,


opcionalmente usa un elemento como argumento especiico para la
resolucin de palabras claves y los tamaos relativos de las
especiicaciones de las fuentes

Propiedades del objeto DrawingStyle lineWidth

Descripcin Determina el ancho, en pixel de pantalla o screen, de lo


que tu dibujas en el elemento canvas. El valor debe ser un double no
negativo y no ininito.
lineCap

Descripcin
Especiica como el buscador dibuja los puntos inales de una lnea. Tu
puedes especiicar algunos de los siguientes tres valores: butt,
round y square.
butt round square imagen 2.31 - diferentes valores para las
terminaciones de las lineas

lineJoin

Descripcin
Especiica como son unidas las lneas cuando se encuentran los puntos
inales. Tu puedes especiicar algunos de los siguientes tres valores:
bevel, round y miter.

miter round bevel

imagen 2.32 - valores de la propiedad lineJoin para los encuentros


de lineas

miterLimit

Descripcin Especiica como son unidas las lneas cuando se


encuentran los puntos inales. Tu puedes especiicar algunos de los
siguientes tres valores: bevel, round y miter.
Ancho linealarg Ancho linea largo m i te r imagen 2.33 - formato
del miter para los encuentros de lineas

lineDashOffset

Descripcin Devuelve la coniguracin de la actual linea dash, con las


mismas unidades que el patrn linea dash. Puede ser conigurado para
cambiar los valores del patrn linea dash. El valor debe ser un double
no ininito.

font

Descripcin
Especiica la fuente usada por el objeto DrawingStyle. La sintaxis es la
misma

que para la propiedad font de CSS, se ignoran los valores que no se


pueden analizarse como valores de fuente CSS vlidas. Palabras clave
y las longitudes relativas se calculan en relacin con el tipo de letra del
elemento canvas.

propiedad font-style
font-variant
font-weight

font-size
line-height
font-family

valores permitidos
Tres valores son permitidos: normal, italic y oblique Dos
valores son permitidos: normal y small-caps Determina el grosor
del carcter de una fuente: normal, bold, bolder (una fuente
mas resaltada que la fuente base), lighter (una fuente menos
resaltada que la fuente base), 100, 200, 300,,900. una fuente de 400
es normal, 700 es bold Valores para el tamao de la fuente: xx-
small, x-small, medium, large, x-large, xx-larger,
smaller, larger, length, %.
El navegador siempre lleva esta propiedad a su valor por defecto, la
cual es normal. Si tu coniguras esta propiedad, el navegador ignorar
tu coniguracin.
Dos tipos de nombres de familias de fuentes son permitidas: family-
name, tal como helvtica, verdana, palatino, etc. Y nombres
de generic-family: serif, sans-serif, monospace, cursive
y fantasy. Tu puedes usar family-name, generic-family o ambos para
el componente font-family de la fuente.

Tabla 2 - componentes y valores vlidos de las fuentes

textAlign

Descripcin Determina la colocacin horizontal del texto dibujado.


Valores vlidos son: start, end, left y right. El valor por
defecto es start.

textBaseLine

Descripcin
Determina la colocacin vertical del texto dibujado. Los valores vlidos
para esta propiedad son: top, hanging, middle, alphabetic,
ideographic y bottom. El valor por defecto es alphabetic.

direction

Descripcin
Determina la direccin de como se dibujarn los textos en el canvas.
Valores vlidos son: ltr, rtl e inherit. El valor por defecto es
inherit.

Mtodos del objeto DrawingStyle


setLineDash(segments)

Descripcin Este mtodo establece la coniguracin de los trazos y


espacios de las lineas dash. Acepta un argumento y es una matriz de
nmeros que especiican una secuencia trazo/espacio/trazo/espacio,
etc. Cuando se haya terminado la secuencia, se repite hasta que
inalice la linea donde es aplicada la funcin.

getLineDash(segments)

Descripcin Este mtodo devuelve la actual coniguracin de los trazos


y espacios de las lineas dash.
Ej.segments = styles.getLineDash();

Ejemplo objeto DrawingStyle

nombre del archivo - drawingStyle.js


var canvas =
document.getElementById(canvas); var
context = canvas.getContext(2d);
var p1 = new Path(M 100 350 q 150 -300 300
0); var p2 = new Path();
var styles = new DrawingStyle();
styles.font = 20px sans-serif;
p2.addText(Hello World, styles, null, p1);

La regin Hit

La regin hit es posiblemente la ms excitante de todas las


caractersticas agregadas a principios del 2012 por la especiicacin
canvas.
Cada elemento canvas cuyo contexto primario es un objeto
CanvasRenderingContext2D debe tener una lista de regiones
Hit asociadas a este mapa de bits.
Las regiones Hit se asocian en una lista denominada: Lista de
Regiones Hit y cada regin Hit consiste de la siguiente informacin:
Un Conjunto de pixeles
Es un conjunto de pixeles contenidos dentro del elemento canvas por
la que esta regin es responsable.

Una circunferencia limitadora


Un conjunto de pixeles dentro de un area limitada por una
circunferencia dentro del elemento canvas y que rodea a la region Hit y
cuyo conjunto de pixeles ya se encontraban alli cuando esta fue
creada.
Una especiicacin del cursor
Viene expresado ya sea en un valor de cursor CSS o la cadena
inherit , que signiica que el cursor de la regin Hit padre, s este
existe, o del elemento canvas, si no, se va a usar en su lugar.

Y opcionalmente por
Una cadena no vaca que representa un identiicador para distinguir
dicha regin de las dems. Una referencia a otra regin que acta
como el padre de esta.
Un nmero de regiones que tiene a este como su padre, conocido
como la cantidad de hijos de las regiones Hit.

addHitRegion(options)

Descripcin Este mtodo agrega una regin Hit al canvas. El


argumento es un objeto con los siguientes miembros:
Path (por defecto null)
Un objeto path que describe los pixeles que forman parte de la regin.
Si este miembro no se suministra o se establece en null, entonces se
usa la ruta predeterminada actual en su lugar.
ID (por defecto una cadena vaca)
La D a usar para esta regin. Esta es usada en eventos mouseEvent
dentro del canvas (event.region) y una manera de hacer referencia a
esta regin en futuras llamadas a addRegionHit().
parent D (por defecto null)
El D de la regin padre, para propositos de navegacin por
herramioenteas de accesibilidad y para el despliegue del cursor.
Cursor (por defecto inherit )
El cursor a usar cuando el mouse esta sobre esta regin. El valor
inherit signiica que usa el cursor para la regin padre (como ha sido
especiicao por el miembro parentID), si existe, o que usa el cursor del
elemento canvas si la region no tiene padre.
Control (por defecto null)
Un elemento (que es un descendiente del canvas) a la cual los eventos
han de ser enviados y que la herramientas de accesibilidad son
usadas como un sustituto para la descripcin e interaccin con esta
regin.
Label (por defecto null)
Una etiqueta de texto para las herramientas de accesibilidad usado
como una descripcin de esta regin, si no hay control.
Role (por defecto null)
Un role-ARIA para las herramientas de accesibilidad usado para
determinar como se representa esta regin, si no hay control.

La regin Hit puede ser usada para una gran variedad de propsitos!

Con un ID, ellos podran detectar la coalisin de objetos, ya el user


agent tendr que comprobar que regin del mouse esta sobre e incluir
el id de los eventos del mouse.
Con un control, podran dirigir de forma automtica los eventos al
elemento DOM permitiendo por ejemplo: hacer

Atento
click en un canvas y enviar automticamente un formulario via un
elemento button .
Con una etiqueta (label), pueden hacer que sea ms fcil para las
diferentes regiones del canvas tener diferentes cursores, el user agent
automticamente cambiara entre ellos.

removeHitRegion(options)

Descripcin Remueve una regin Hit (y todos sus ascendientes) desde


el canvas. Los argumentos son el D agregado al crearlo con el mtodo
addHitRegion(). Los pixeles que estaban cubiertos por esta regin y
sus descendientes son efectivamente eliminados por esta operacin,
dejando la regin no interactiva. En particular, las regiones que
ocuparon los mismos pixeles antes de las regiones removidas, se
solapan y no vuelven a su funcin anterior.

Ejemplo de aplicacin de la regin Hit

nombre del archivo - regionHit.html


<!DOCTYPE html>
<html>

<head>
<title>Aplicaci&oacute;n de La Region
Hit</title> <style>

body {
background: #eaeaea;
}
#contenedor{
width:500px; margin:0px auto; padding-
top:50px; }
#canvas {

}
</style> </head>

<body> <div id=contenedor>


<canvas id=canvas width=500 height=300>

Tu navegador no soporta canvas de HTML5


</canvas>
</div>

<script src=javascript/regionHit.js>
</script> </body>
</html>

nombre del archivo - composicionCanvas.js


var canvas =
document.getElementById(canvas), context =
canvas.getContext(2d);
context.beginPath();
context.rect(10,10,100,100);
context.addHitRegion({ id: The First Button
});
context.beginPath();
context.rect(120,10,100,100);
context.addHitRegion({ id: The Second
Button });
canvas.onclick = function (event) {
if (event.region) {
alert(You clicked + event.region); }
};

Las reglas de la API de canvas


Los paths son un elemento bsico de cualquier biblioteca de gricos.
Cada vez que se dibuja un path, el navegador tiene que determinar si
un punto del canvas est dentro de la curva cerrada. Cuando el path
es un simple crculo o un rectngulo, esto es obvio, pero cuando la
trayectoria se corta a s misma o esta tiene paths anidados, la cosa no
siempre es tan clara.
Existen dos formas comunes para calcular si un punto en un path debe
ser rellenado, estas son: nonzero y evenOdd.

Nonzero Winding Rule

Descripcin
Para probar si un punto P esta dentro de un path, utilizando la regla
nonzeron

winding rule, imagina un rayo dibujado desde P, en cualquier


direccin, hasta el ininito (o mejor an, hasta cierto punto fuera de la
caja delimitadora de los path). Ahora inicializamos un contador en cero
y enumeramos todos los lugares donde el path cruza el rayo. Cada vez
que el path cruza el rayo en direccin al sentido de las agujas del reloj,
agregamos uno al contador. Cada vez que el path cruza el rayo en el
sentido contrario a la direccin de las agujas del reloj, restamos uno a
nuestro contador. Si despues de que todos los pasos han sido
enumerados, el contador es distinto de cero, entonces el punto P esta
dentro del path. Si por el contrario, el recuento es igual a cero,
entonces el punto esta fuera del path.

imagen 2.36 - aplicacin de la regla nonzero


Este es un path que consiste en 2 crculos. El crculo exterior se ejecuta
a la izquierda en direccin contraria al sentido de las agujas del reloj y
el crculo interior se ejecuta en direccin del sentido de las agujas del
reloj.
Tenemos 3 puntos y queremos determinar si estn dentro del trazado.
La lnea imaginaria que en este ejemplo, va desde la parte inferior
izquierda hacia la parte superior derecha, pero se puede dibujar la
forma que desee.
el punto 1. Total = 1 para el interior y pintado
el punto 2. Total = 1 - 1 = 0 por lo exterior y no pintada
punto 3. Total = 1 - 1 + 1 = 1 para el interior y pintado
Ahora, vamos a cambiar la direccin del crculo ms cercano:

imagen 2.37
- aplicacin de la regla nonzero

el punto 1. Total = 1 para el interior y pintado el punto 2. Total = 1 + 1 =


2 para el interior y pintado el punto 3. Total = 1 + 1 + 1 = 3 para el
interior y pintado

EvenOdd Rule

Descripcin
El valor EvenOdd indica la regla par-impar, en el que un punto se
considerar

como fuera de la igura o la forma, si el nmero de veces que una lnea


recta semi-ininita dibujada desde ese punto cruza el trazo de la igura o
la forma entonces este ser par.
Para determinar si un punto cae dentro del path, una vez ms, dibuja
una lnea que pasa por ese punto. Esta vez, le basta con aadir el
nmero de veces que se cruza el path Si el total es par, el punto est
fuera, y si es impar, el punto est dentro. El sentido o direccin del path
se pasa por alto. por ejemplo: el punto 1. Total = 1 para el interior y
pintado.
el punto 2. Total = 1 + 1 = 2, de modo exterior y no pintado. punto 3.
Total = 1 + 1 + 1 = 3 para el interior y pintado.

imagen 2.38 - aplicacin de la regla evenOdd

La regla de liquidacin evenOdd es ms fcil de entender para un


autor experimentado. Por ejemplo, si usted quiere hacer un donuts con
dos crculos, uno grande y otro pequeo, con la regla de liquidacin
nonzero, tu tendras que aplicar un pequeo truco y cambiar la
direccin del crculo pequeo en el sentido contrario al grande, con la
regla evenOdd, es ms sencillo, basta trazar una linea y rellenar los
circulos con la regla de liquidacin evenOdd.

Adicional al canvas

Como el contexto del canvas 2d no tiene soporte para la alineacin


evenOdd, mozilla implementa una propiedad con un preijo
mozFillRule que establece la regla de rellenos en el estado de los
gricos. Esto tuvo algunos inconvenientes:

1. Arreglando esto se obliga al usuario a comprobar siempre la regla


de liquidacin antes de cada relleno o clip, o tiene una convencin
para establecer y restablecer la regla de liquidacin que no es tan
comn su uso.

2. Las regiones Clipping y la deteccin de colisiones tambin se ven


afectadas por esta regla, por lo que el nombre de illRule es confuso.
3. Agregar ms parmetros al estado de los gricos crea algo de
sobrecarga.
4. Es ms trabajo para el autor y el entorno, ya que tiene que hacer
una llamada adicional a travs del lmite javascript.
5. Casi todos los dems lenguajes gricos (como PDF y SVG) y las
bibliotecas (como coreGraphics, direct2D y Skia) establecen la
liquidacin en tiempos de uso.

Uno de las recopilaciones hechas alrededor del tema son las


siguientes:
enum CanvasWindingRule { nonzero, evenodd
};
void clip(optional CanvasWindingRule w =
nonzero);
boolean isPointInPath(unrestricted double x,
unrestricted double y, optional
CanvasWindingRule w = nonzero);

ill, clip y isPointInPath ahora tendrn un parmetro opcional que


especiica qu norma de liquidacin se va a aplicar. Si no lo especiica,
se obtiene el comportamiento antiguo que es la nonzero winding rule.

El siguiente es un ejemplo que muestra esta caracterstica en accin:

Ejemplo de aplicacin de las reglas de la API de canvas


nombre del archivo - evenodd.js
var canvas =
document.getElementById(canvas); var ctx =
canvas.getContext(2d);

ctx.beginPath();
ctx.arc(75, 75, 75, 0, Math.PI*2, true);
ctx.arc(75, 75, 25, 0, Math.PI*2, true);

El resultado se mostrar mas o menos de esta manera: imagen 2.39


- ejemplo de aplicacin de la regla evenodd
Los proyectos
Juegos

Los juegos son la razn por la que muchos de nosotros, en principio,


nos interesamos por las computadoras, hoy en da los juegos siguen
siendo la fuerza motriz que impulsa la tecnologa informatica a nuevas
alturas. En este apartado, examinaremos como crear un framework
para mini-juego, que se podr usar como base para crear juegos en el
canvas de HTML5. Vamos a explorar muchos de los bloques de
construccin bsicos asociados con el desarrollo de juegos y
aplicarlos al canvas de HTML5 con la API de javascript.

No tenemos espacio, ni tampoco es el objetivo de este libro, para cubrir


cada tipo de juego que tu quieras crear, pero vamos a discutir muchos
temas elementales y algunos otros no tanto, necesarios para la gran
mayora de los juegos. Al inal del ejercicio vamos a tener una copia
bsica del clsico juego de Atari Asteroids. Vamos a pasar a travs
de la creacin de este juego, aplicando en primer lugar algunas de las
tcnicas de dibujo y transformaciones especicas de los objetos
visuales de nuestro juego. Esto le ayudar a conseguir una base
gracias a la puesta en practica de todas los conceptos elementales
vistos en el capitulo 2 - La referencia, y aplicarlos a la creacin de
juegos de arcade. Seguidamente vamos a crear como base un
framework de juego que pueda ser fcilmente aplicable a cualquier
juego de arcade que te propongas hacer en el canvas de HTML5.
Despus nos sumergiremos en algunas tcnicas de juegos y en el
estudio de varios algoritmos propios de la ocasin, y, para inalmente
aplicar todo lo que hemos tratado de crear al producto inal.

Juegos bidimensionales viajando en el espacio y disparando a los


enemigos, son solo el comienzo de lo que puede conseguirse en un
canvas de HTML5. Mientras desarrollamos este tutorial,
profundizaremos ms en el uso y conocimientos de las principales
herramientas y tcnicas que provee la API del canvas de HTML5.

Porque juegos en HTML5?

Jugar en el navegador se ha convertido en una de las actividades ms


populares para los usuarios de internet. El canvas de HTML5 ofrece a
los desarrolladores una API web para gestionar directamente la
elaboracin de un rea especica del navegador. Esta funcionalidad
permite que el desarrollo del juegos en javascript sea mucho mas
potente que nunca.

El canvas comparado con flash

Usted encontrar que el canvas de HTML5 ofrece una funcionalidad


similar al Flash de Adobe en ciertas areas, pero, carece de algunas
de las caractersticas mas reinadas de Flash.
Sin lmite de tiempo

No hay linea de tiempo basadas en fotogramas para la animacin


intrnseca en canvas. Esto signiica que necesitaremos codiicar todas
nuestras animaciones a partir de imgenes o trazados, y aplicar
nuestras propias actualizaciones basadas en fotogramas.
Sin lista de visualizacin

ActionScript 3 de Flash ofrece la idea muy potente de una lista de


visualizacin de objetos, un desarrollador puede agregar cientos de
objetos fsicos individuales desde la lista de visualizacin a la pantalla
de juego. El canvas de HTML5 slo tiene un nico objeto de
visualizacin (el propio canvas).

Que ofrece el canvas de HTML5?

A pesar de que el canvas de HTML5 carece de algunas de las


caractersticas que hacen de la plataforma Flash un excelente medio
para el desarrollo de juegos, tambin es verdad que este tiene
algunos puntos fuertes.

Un potente escenario

El canvas de HTML5 es muy semejante al escenario de Flash. Es una


pieza rectangular de espacio en pantalla, que se puede manipular
mediante programacin. Desarrolladores avanzados de Flash
pueden reconocer al canvas como un primo cercano, tanto a la
BitmapData como a los objetos Shape de actionScript. Podemos dibujar
directamente en el canvas con trazados e imgenes y transformarlos
sobre la marcha.

Objetos de visualizacin lgicos

Canvas de HTML5 nos d solo un objeto de visualizacin fsico, pero


podemos crear cualquier nmero de objetos de visualizacin lgicos.
Vamos a usar los objetos javascript para almacenar todos los datos
lgicos y mtodos necesarios para dibujar y transformar nuestros
objetos de juego lgicos al canvas fsico.

Archivo bsico para el juego

Antes de comenzar a desarrollar nuestro juego de arcade, vamos a


crear un archivo bsico de HTML y otro de javascript. Ambos los
usaremos para nuestros propositos.
Archivo base HTML para el juego

nombre del archivo - defensaEspacial.html


<!DOCTYPE html>
<html>

<head>
<title>
Tutorial juego de arcade </title>
<style>
body {
background: #eaeaea; }

#contenedor{
width:400px;
margin:0px auto;
padding-top:20px;
}
#canvas {
margin-left: 20px;
margin-right: 0;
margin-bottom: 20px;
border: thin solid #aaaaaa; cursor:
crosshair; }
</style>
</head>

<body>
<div id=contenedor>
<canvas id=canvas width=400 height=600>

Tu navegador no soporta canvas de HTML5


</canvas>
</div>

<script src=defensaEspacial.js></script>
</body>
</html>

nombre del archivo - defensaEspacial.js


window.addEventListener(load,
eventWindowLoaded, false); function
eventWindowLoaded() {

canvasApp();
}

function canvasApp(){
var canvas =
document.getElementById(canvas); if
(!canvas || !canvas.getContext) {

return;
}
var context = canvas.getContext(2d);
if (!context) { return;
}
crearDibujo();

function crearDibujo() {
context.font = 30px sans-serif;
context.textBaseline = top;
}
}

El resultado se mostrar mas o menos de esta manera:


imagen 3.1 - base para el juego de arcade
Vamos a comenzar nuestro juego de forma similar a Asteroids de Atari,
al cul llamaremos Defensa Espacial.

El diseo de nuestro juego

No vamos a asumir que todo el que lea este tutorial conoce o entiende
el clsico juego de arcade de Atari Asteroids. Asteroids fue diseado
por Ed Logg y Lile Rains, este fu lanzado por Atari en 1979. El juego
enfrenta a una pequea nave espacial de forma triangular
bidimensional vectorizada (jugador) contra un grupo de asteroides
que se va multiplicando a medida que avanza y que a su vez necesitan
ser destruidos o esquivados por el jugador. De vez en cuando aparece
un platillo volador que intentar destruir la nave del jugador con sus
misiles.

Todos los asteroides comienzan el juego como grandes e inmensas


rocas, pero cuando son alcanzados por los misiles del jugador esta se
dividen y forman dos rocas de tamao mediano, asimismo, cuando
estas rocas medianas son alcanzadas por los misiles del jugador,
nuevamente se dividen y crean dos rocas de menor tamao, es decir
pequeas, para luego ser totalmente destruidas una vez sea
alcanzadas por los misiles del jugador.

Cuando el jugador destruye todos los asteroides, avanza de nivel, el


cual consiste en una nueva tanda de asteroides pero ahora con mayor
velocidad. Esto continuar hasta que el jugador agote sus tres naves
espaciales. El jugador sin embargo cada vez que le sume 10000
puntos a la puntuacin obtenida, recibir una nave espacial adicional.

Todos los objetos del juego se mueven (empujar, rotar y/o lotar)
libremente por toda la pantalla de juego, lo que representa una
porcin del plano espacial. Cuando uno de estos objetos sale de la
pantalla, este vuelve a aparecer por el extremo contrario, as se da la
impresin de un espacio ininito.

Grficos del Juego - Dibujar con paths

Entremos de lleno al desarrollo del juego en el canvas, primero


echaremos un vistazo a algunos de los gricos que utilizaremos en
nuestro juego. Esto nos ayudar a tener una sensacin visual del tipo
de cdigo que tendremos que poner en prctica.

Que necesitaremos

Para la simulacin del juego de Asteroids, que nosotros hemos llamado


Defensa Espacial, vamos a necesitar algunos gricos muy simples ,
tales como:
Un fondo negro slido.
Una nave espacial para el jugador que pueda girar y avanzar en la
pantalla del juego. Habr que hacer

dos fotogramas para la animacin de la nave espacial, un fotograma


para representar la nave estatica y un fotograma para representar la
nave en avance.
Un platillo volador que vuele a traves de la pantalla y le dispare al
jugador.
Algunas piedras o rocas que representen los asteroides y que el
jugador pueda dispararles. Para ello usaremos cuadrados simples.
Existen dos mtodos diferentes que podemos emplear para dibujar los
gricos de nuestro juego: imgenes
de mapa de bits o paths (trazados). Para el juego en esta seccin, nos
centraremos en el uso de los paths.
En el apndice B de este libro podr ver como manipular las imagenes
de mapa de bits para los gricos de
este juego.

Usar paths para dibujar la figura principal del juego

Los paths nos ofrecen una manera muy simple pero de gran alcance
para imitar el aspecto vectorial del clsico juego de asteroides.
Podramos utilizar las imgenes de mapa de bits para este propsito,
pero en esta seccin nos vamos a centrar en la creacin de nuestro
juego en el cdigo sin activos externos. Vamos a comenzar a realizar
los dos fotogramas de animacin necesarios para nuestra nave
espacial del jugador.

La nave espacial esttica (fotograma 1)


El fotograma principal que representar la nave del jugador ser
dibujado con paths en una cuadrcula de 30 20. Como se muestra en
la siguiente imagen:

imagen 3.2 - Trazado que representa la nave espacial


Dibujar la nave espacial esttica(jugador)
nombre del archivo
- defensaEspacial.js
//dibujar la nave espacial (jugador)
context.strokeStyle = red;

context.beginPath(); context.moveTo(16,0);
context.lineTo(30,19); context.lineTo(16,14);
context.moveTo(16,14); context.lineTo(0,19);
context.lineTo(16,0); context.stroke();

context.closePath();

Dibujar con paths


Recordemos como dibujar con paths, revise los siguientes pasos:
1. Siempre empezar un nuevo path con la llamada al mtodo beginPath
().
Atento

2. Establecer strokeStyle () antes de empezar a dibujar el trazado.


2. Establecer fillStyle () antes de empezar a dibujar el trazado.
3. Use una combinacin de los mtodos context moveTo () y
context.drawTo () para comenzar a trazar las lneas de la trayectoria.
4. Terminar el dibujo con la llamada a los mtodos stroke () y fill(), y
cerca del path con closePath ().

La nave espacial de avance (fotograma 2)


Ahora dibujaremos el segundo fotograma que representar la nave
espacial (jugador) cuando este avance. Puede verlo en la imagen 3.3
Dibujar la nave espacial de avance(jugador)

nombre del archivo - defensaEspacial.js


//dibujar la nave espacial de avance
(jugador) context.moveTo(16,16);
context.lineTo(17,20);
context.moveTo(16,16);
context.lineTo(16,22);
context.moveTo(17,16);
context.lineTo(16,22);

context.stroke();

context.closePath(); imagen 3.3 - Trazado que


representa la nave espacial en avance

Animacin en el canvas

La nave espacial del jugadior que acabamos de crear, tiene dos


fotogramas (esttico y avance), pero solo podemos mostrar un
fotograma a la vez. Nuestro juego tendr que cambiar el fotograma de
animacin basado en el estado de la nave espacial del jugador y
debera ejecutarse en un temporizador para que se produzca esta
animacin. Vamos a escribir el cdigo que dar vida a nuestro
cronometro de juego.

Bucle para controlar nuestro juego

Los juegos en HTML5 Canvas requieren el uso repetido de un bucle


de actualizacin/renderizado para simular la animacin. Hacemos esto
mediante el uso de la funcin JavaScript setTimeout(), que llama
repetidamente a la funcin de nuestra eleccin en intervalos de
milisegundos. Cada segundo de tiempo de juego/animacin se
compone de 1.000 milisegundos. Si queremos que nuestro juego se
ejecute en 30 ciclos por segundo de actualizacin/renderizado,
llamamos esto a 30 fotogramas por segundo (FPS) promedio. Para
ejecutar nuestro intervalo a 30 FPS, en primer lugar hay que dividir
1.000 por 30. El resultado es el nmero de milisegundos en cada
intervalo:

const PROM_FOTOGRAMA = 30;


var intervaloTiempo = 1000/PROM_FOTOGRAMA;
gameLoop()
function gameLoop() {

crearDibujo();
window.setTimeout(gameLoop, intervaloTiempo);
}

Al llamar a la funcin crearDibujo() varias veces en cada intervalo de


tiempo de espera, se puede simular la animacin.

Cambio de estado en la nave espacial (jugador)

Simplemente tenemos que cambiar los estados esttico y de avance


para simular la animacin. Vamos a escribir el cdigo para poder hacer
esto. En el siguiente trozo de cdigo, vamos a empezar a colocar las
variables de nivel de la clase canvasApp en una nueva seccin justo
por encima de la funcin crearDibujo(). Este ser el lugar en el futuro
de todas las variables que requieren un alcance global dentro del
objeto canvasApp ().
Dado que hemos realizado algunos cambios importantes en nuestro
codigo, a continuacin mostraremos el archivo javascript completo para
poder visualizar estos pequeos cambios realizados.

nombre del archivo - defensaEspacial.js


window.addEventListener(load,
eventWindowLoaded, false); function
eventWindowLoaded() {

canvasApp();
}

function canvasApp(){
var canvas =
document.getElementById(canvas); if
(!canvas || !canvas.getContext) {

return;
}
var context = canvas.getContext(2d);

if (!context) {
return;
}
crearDibujo();
//variables de nivel del objeto canvasApp

function crearDibujo() {
//actualizar estado de la nave espacial
estadoNave++;
if (estadoNave >1) {

estadoNave=0;
}
context.font = 30px sans-serif;
context.textBaseline = top;
//dibujar la nave espacial estatica (jugador)
context.strokeStyle = red;

context.beginPath();
context.moveTo(16,0);
context.lineTo(30,19);
context.lineTo(16,14);
context.moveTo(16,14);
context.lineTo(0,19);
context.lineTo(16,0);
//dibujar la nave espacial de avance
(jugador) if (estadoNave==1) {

context.moveTo(16,16); context.lineTo(17,20);
context.moveTo(16,16); context.lineTo(16,22);
context.moveTo(17,16); context.lineTo(16,22);

}
context.stroke();

context.closePath();
}
const PROM_FOTOGRAMA = 30;
var intervaloTiempo = 1000/PROM_FOTOGRAMA;
temporizador();
function temporizador(){

crearDibujo();
window.setTimeout(temporizador,intervaloTiempo
}
}
Aplicando transformaciones a los grficos del juego

Nuestro juego probablemente tendr muchos objetos de visualizacin


lgicas individuales que necesitan ser actualizados en un solo
fotograma. Podemos hacer uso de los mtodos save() y restore() y el
uso de la matriz de transformacin para garantizar que el resultado inal
slo afecte al objeto actual que estamos trabajando, y no todo el
canvas.

La pila del canvas


El estado del canvas se puede guardar en una pila y recuperarse
luego. Esto es importante cuando estamos transformando y animando
los objetos del juego, porque queremos que nuestros transformaciones
afecten slo el objeto del juego actual y no a todo el canvas. El lujo de
trabajo bsico para el uso de la pila del canvas en un juego se parece
a esto:
1. Guardar el canvas actual en la pila.
2. Transformar y dibujar el objeto del juego.
3. Recuperar el canvas salvado de la pila.

Como ejemplo, vamos a conigurar el giro bsico para nuestra nave


espacial (jugador). Vamos a girar en 1 grado en cada fotograma.
Debido a que estamos elaborando en la actualidad la nave espacial
(jugador) en la esquina superior izquierda del canvas, vamos a
moverlo a una nueva ubicacin. Hacemos esto porque el giro bsico
utilizar la esquina superior izquierda de la nave espacial como el
punto de registro: la ubicacin del eje utilizado para las operaciones
de rotacin y la escala. Por lo tanto, si seguimos con la nave espacial
en las coordenadas 0,0 y se hace girar por la esquina superior
izquierda, usted no ver la nave espacial la mitad del tiempo, ya que su
ubicacin sera en los bordes superior e izquierdo del canvas. En su
lugar, colocaremos la nave espacial en las nuevas coordenadas 50,50.
Nosotros vamos a usar el mismo cdigo javascript que en el ejemplo
anterior, cambiando slo la funcin crearDibujo(). Para simpliicar este
ejemplo, vamos a eliminar la variable estadoNave y nos
concentraremos en el estado esttico solamente. Agregaremos tres
nuevas variables arriba de la funcin crearDibujo():

var rotacion=0;-mantiene la rotacin actual


de la nave (jugador) var x=50; -ocupa la
posicin x para empezar a dibujar la nave
(jugador) var y=50; - ocupa la posicin y
para empezar a dibujar ela nave (jugador)

A continuacin nuevamente el cdigo completo de nuestro archivo


javascript:

nombre del archivo - defensaEspacial.js


window.addEventListener(load,
eventWindowLoaded, false); function
eventWindowLoaded() {

canvasApp();
}
function canvasApp(){

var canvas =
document.getElementById(canvas); if
(!canvas || !canvas.getContext) {
return;

}
var context = canvas.getContext(2d);
if (!context) {

return;
}
crearDibujo();
//variables de nivel del objeto canvasApp var
rotacion = 0;
var x = 50;
var y = 50;
function crearDibujo() {

context.font = 20px sans-serif;


context.textBaseline = top;

//transformacin
var anguloEnRadianes = rotacion * Math.PI /
180; context.save(); //salvar el actual
estado de la pila // reestablecer la
identidad
context.setTransform(1,0,0,1,0,0);
//Trasladar el canvas original al centro del
jugador context.translate(x,y);
context.rotate(anguloEnRadianes);
//dibujar la nave espacial estatica (jugador)
context.strokeStyle = red;

context.beginPath(); context.moveTo(16,0);
context.lineTo(30,19); context.lineTo(16,14);
context.moveTo(16,14); context.lineTo(0,19);
context.lineTo(16,0);

context.stroke();
context.closePath();

//restaurar el contexto
//antiguo estado emergente a la pantalla
context.restore();
//agregar la rotacin
rotacion++;

const PROM_FOTOGRAMA = 40;


var intervaloTiempo = 1000/PROM_FOTOGRAMA;
temporizador();

function temporizador(){
crearDibujo();
window.setTimeout(temporizador,
intervaloTiempo);

}
}

Como puede ver, la nave del jugador gira en sentido horario un grado
a la vez. Como hemos mencionado anteriormente, debemos convertir
los grados a radianes para las transformaciones del mtodo
context rotate(), que usan radianes para los clculos. En la siguiente
parte de nuestro tutorial, veremos algunas transformaciones mas
complejas que usaremos en nuestro juego bsico Defensa Espacial.
Transformaciones grafica del juego

Como vimos anteriormente, podemos girar fcilmente los gricos del


juego en la esquina superior izquierda utilizando el mtodo de
transformacin context.rotate(). Sin embargo, nuestro juego tendr que
rotar los objetos en el centro en lugar de la esquina superior izquierda.
Para ello, tenemos que cambiar el punto de transformacin en el centro
de nuestro juego para los objetos gricos.

Rotando la nave espacial desde el centro

El cdigo para girar la nave espacial (jugador) desde su punto central


es casi exactamente igual que el cdigo utilizado para girarlo desde la
esquina superior izquierda. Lo que tenemos que hacer es modiicar el
punto desde donde se hace el movimiento de traslacin. En el cdigo
anterior, colocamos el contexto de dibujo de modo inmediato a las
coordenadas x e y de nuestro objeto juego (50,50). Esto tuvo el
efecto de hacer girar el objeto desde la esquina superior izquierda.
Ahora hay que llevar el movimiento de traslacin al centro de nuestro
objeto:

context.translate (x + 0,5 * width, y + 0,5 *


height);

Nota destacada!
Las variables width y height representan los atributos ancho y alto de
nuestro nave espacial (jugador) dibujada. Vamos a crear estos
atributos en elas siguientes lineas.
Atento
Este no es el nico cambio que tenemos que hacer, tambin tenemos
que dibujar nuestra nave espacial como si pensamos que es el punto
central. Para realizar esto, vamos a restar la mitad del ancho de cada
atributo x en nuestra secuencia de trazos de dibujo, y restar la mitad
de la altura de cada atributo y:

context.moveTo (16 - 0.5 * width, 0 - 0.5 *


height); context.lineTo (30 - 0.5 * width, 19
- 0.5 * height);

Como puede ver, puede ser un poco confuso tratando de dibujar las
coordenadas de esta manera. Tambin es ligeramente menos intenso
para el procesador que utilizar constantes. En ese caso, podramos
simplemente codiicar los valores necesarios. Recuerde que los
atributos de anchura y altura de nuestra nave espacial son ambos 30 y
20. La versin codiicada sera algo como esto:

context.moveTo (6, -10) / / 16-10, 0-10


context.lineTo (20,9) / / 30-10, 19-10

El mtodo en el que se usan los valores calculados (usando la anchura


y la altura de las variables) es mucho ms lexible, mientras que el
mtodo codiicado es mucho menos intenso para el procesador. Con la
versin calculada nuestro cdigo quedara de la siguiente manera:

nombre del archivo - defensaEspacial.js


window.addEventListener(load,
eventWindowLoaded, false); function
eventWindowLoaded() {
canvasApp();
}
function canvasApp(){

var canvas =
document.getElementById(canvas);
if (!canvas || !canvas.getContext) {
return;

}
var context = canvas.getContext(2d); if
(!context) {

return;
}
crearDibujo();
//variables de nivel del objeto canvasApp var
rotacion = 0;
var x = 50;
var y = 50;
var width=30;
var height=20;
function crearDibujo() {

context.font = 20px sans-serif;


context.textBaseline = top;

//transformacin
var anguloEnRadianes = rotacion * Math.PI /
180; context.save(); //salvar el actual
estado de la pila
context.setTransform(1,0,0,1,0,0);//reestable
la identidad //Trasladar el canvas original
al centro del jugador
context.translate(x+.5*width,y+.5*height);
context.rotate(anguloEnRadianes);

//dibujar la nave espacial estatica (jugador)


context.strokeStyle = red;

context.beginPath();
context.moveTo(16-.5*width,0-.5*height);
context.lineTo(30-.5*width,19-.5*height);
context.lineTo(16-.5*width,14-.5*height);
context.moveTo(16-.5*width,14-.5*height);
context.lineTo(0-.5*width,19-.5*height);
context.lineTo(16-.5*width,0-.5*height);

context.stroke();
context.closePath();
//restaurar el contexto context.restore();
//antiguo estado emergente a la pantalla

//agregar la rotacin
rotacion++;
}
const PROM_FOTOGRAMA = 45;
var intervaloTiempo = 1000/PROM_FOTOGRAMA;
temporizador();

function temporizador(){
crearDibujo();
window.setTimeout(temporizador,
intervaloTiempo);

}
}

Desvanecimiento gradual de la nave espacial (jugador)

Cuando una nave espacial entra en la pantalla de nuestro juego


Defensa Espacial, vamos a tener que crear un desvanecimiento desde
opaco a transparente, igual ocurre si nuestra nave es alcanzada por
cualquier objeto enemigo, el desvanecimiento se hara al contrario. En
la siguiente muestra de cdigo, mostraremos como vamos a crear esta
transformacin en nuestro juego.
Para usar el atributo context.globalAlpha del canvas, simplemente
tenemos que conigurar un nmero entre 0 y 1 antes de dibujar los
gricos del juego. Vamos a crear una nueva variable en nuestro
cdigo, a la cual, llamaremos transparencia, que contendr el valor
alpha actual de nuestra nave espacial. Vamos a aumentar este valor
gradualmente en 0.01 hasta llegar a 1. Cuando realmente creemos
nuestro juego, lo detendremos en 1 y comenzaremos nuestro nivel de
juego. Sin embargo, aclaremos que para efectos de esta demo solo nos
limitaremos a repetir el mismo nivel una y otra vez.

nombre del archivo - defensaEspacial.js


window.addEventListener(load,
eventWindowLoaded, false); function
eventWindowLoaded() {

canvasApp();
}
function canvasApp(){

var canvas =
document.getElementById(canvas); if
(!canvas || !canvas.getContext) {
return;

}
var context = canvas.getContext(2d);
if (!context) {

return;
}
crearDibujo();
//variables de nivel del objeto canvasApp var
rotacion = 0;
var x = 50;
var y = 50;
var width=30;
var height=20;
var transparencia=0;
context.globalAlpha = 1;

function crearDibujo() {
context.globalAlpha = 1;
context.font = 20px sans-serif;
context.textBaseline = top;
180);
context.globalAlpha = transparencia;

//transformacin
var anguloEnRadianes = rotacion * Math.PI /
180; context.save(); //salvar el actual
estado de la pila
context.setTransform(1,0,0,1,0,0);//reestable
la identidad
//Trasladar el canvas original al centro del
jugador
context.translate(x+.5*width,y+.5*height);
context.rotate(anguloEnRadianes);

//dibujar la nave espacial estatica (jugador)


context.strokeStyle = red;

context.beginPath();
context.moveTo(16-.5*width,0-.5*height);
context.lineTo(30-.5*width,19-.5*height);
context.lineTo(16-.5*width,14-.5*height);
context.moveTo(16-.5*width,14-.5*height);
context.lineTo(0-.5*width,19-.5*height);
context.lineTo(16-.5*width,0-.5*height);
context.stroke();

context.closePath();
//restaurar el contexto
context.restore(); //antiguo estado emergente
a la pantalla

//agregar la rotacin transparencia+=.01;


if (transparencia > 1) {

transparencia=0; }
}

const PROM_FOTOGRAMA = 45;


var intervaloTiempo = 1000/PROM_FOTOGRAMA;
temporizador();

function temporizador(){
crearDibujo();
window.setTimeout(temporizador,
intervaloTiempo);

}
}

Fsica y animacin de los objetos del juego

Todos los objetos del juego se mover en un plano de dos


dimensiones. Vamos a utilizar los vectores bsicos de movimiento
direccional para calcular el cambio en las coordenadas x e y para
cada objeto del juego. En su nivel ms bsico, estaremos actualizando
la coordenada x (dx) y la coordenada y (dy) de cada uno de los
objetos del juego en cada fotograma para simular el movimiento. Estos
valores dx y dy se basarn en el ngulo y la direccin en la que
queremos que el objeto se mueva. Todos nuestros objetos de
visualizacin lgicos sumarn sus respectivos valores de dx y dy a su
valores x e y en cada fotograma de la animacin. la nave del jugador
no usar dx ni dy estricto, porque tiene que ser capaz de lotar y girar
de forma independiente. Vamos a analizar en mayor profundidad el
movimiento de la nave del jugador ahora.

Como se mover la nave del jugador


Nuestra nave cambiar su angulo desde el centro del eje de rotacin
cuando el jugador presione las teclas izquierda o derecha del teclado.
Cuando el jugador presione la tecla arriba, la nave acelerar (avanza)
en direccin al angulo que se encuentre actualmente. Porque no hay
friccin aplicada a la nave, esta continuar lotando en direccin del
angulo de aceleracin actual, hasta que sea aplicado un angulo
diferente de aceleracin. Esto sucede cuando el jugador gira la nave a
un nuevo angulo presionando las teclas derecha o izquierda y luego
presione la tecla arriba para avanzar una vez mas.

La diferencia entre avanzar y moverse

Nuestra nave puede girar en la direccin que desee mientras se este


moviendo en una direccin diferente. Por esta razn, no podemos
simplemente usar los valores clsicos dx y dy para representar el
valor de movimiento en los ejes x e y. Hay que mantener los dos
conjuntos de valores para la nave en cada momento. Cuando el
jugador hace girar la nave pero no avanza, necesitamos dibujar la
nave en el nuevo angulo rotado. Todos los misiles que la nave dispare,
deben tambin moverse en la misma direccin de la nave. En el eje x
nombraremos este valor avanceX y en el eje y lo llamaremos
avanceY. Los valores moverX y moverY manejarn el movimiento
de la nave en la direccin que se indique cuando el avance sea
aplicado. Se necesitarn los 4 valores para mover la nave hacia una
nueva direccin.

Avanzar en la direccin rotada

Despus que la nave ha girado en la direccin deseada, el jugador


puede avanzar hacia adelante al presionar la tecla hacia arriba del
teclado, esta tecla acelera la nave del jugador, solo mientras la tecla se
encuentre presionada. Y gracias a que conocemos la rotacin de la
nave, podemos calcular facilmente el angulo de rotacin. Solo
entonces podemos aadir los atributos x e y de la nave para hacerla
avanzar.

En primer lugar debemos cambiar los valores de rotacin de grados a


radianes.
var anguloEnRadianes = rotacion * Math.PI /
180;
Ustedes han visto esto antes, es exactamente igual a la forma en que
se calcul la transformacin de rotacin antes de que fuera aplicada a
la nave del jugador.

Cuando tenemos el ngulo de rotacin de la nave, debemos calcular


los valores avanceX y avanceY de la direccin actual. Lo hacemos
solo cuando vamos a avanzar, porque es un clculo costoso, en lo que
se reiere al procesador, ya que consume muchos recursos del sistema.
Nosotros podramos calcular stos cada vez que el jugador cambia la
rotacin de la nave, pero hacerlo sera una sobrecarga innecesaria
del procesador:

avanceX = Math.cos(angleInRadians); avanceY =


Math.sin(angleInRadians);
Cuando tenemos los valores de los ejes x e y, que representan el
sentido de la direccin actual de la nave del jugador, podemos calcular
los nuevos valores moverX y moverY para la nave del jugador:
moverX = moverX+aceleracionAvance*avanceX;
moverY = moverY+aceleracionAvance*avanceY;

Para aplicar estos nuevos valores a la posicin actual de la nave del


jugador, necesitaremos aadirselas a sus actuales posiciones x e y.
Esto no ocurre slo cuando el jugador presiona la tecla hacia arriba. Si
lo hiciera, la nave del jugador no lotara, sino que se movera slo
cuando se presiona la tecla. Debemos modiicar los valores x e y en
cada fotograma con los valores moverX y moverY:

x = x+moverX; y = y+moverY;

Redibujar la nave del jugador para comenzar en un angulo 0.

Como recordarn, cuando dibujamos por primera vez la nave del


jugador, tuvimos la punta de la nave (la parte superior) hacia arriba.
Hicimos esto para facilitar el dibujo, pero no es realmente la mejor
direccin para dibujar nuestra nave cuando lo que intentamos es
realizar calculos de comprensin rotatoria. Cuando la nave apunta
hacia arriba en realidad lo que tenemos es un angulo de -90 grados (o
270). Si queremos dejar todo como esta actualmente, tendremos que
modiicar el calculo de nuestra variable anguloEnRadianes a algo
parecido a esto:

Esto es un cdigo algo feo, pero funciona muy bien si queremos que
nuestra nave del jugador este apuntando hacia arriba antes de aplicar
las transformaciones de rotacin. Un mtodo mejor es dejar a la
variable anguloEnRadianes tal como esta, pero dibujando la
nave del jugador apuntando hacia la direccin del ngulo 0 (a la
derecha). La siguiente imagen muestra cmo bamos a sacar esto.

imagen 3.4
- Trazado que representa la nave espacial apuntando a un angulo
0
El cdigo para dibujar la nave se modiicara de la siguiente manera:

//dibujar la nave espacial del jugador


context.moveTo(-10,-15);
context.lineTo(15,0);
context.lineTo(-10,15);
context.lineTo(0,0);
context.moveTo(0,0);
context.lineTo(-10,-15);
context.moveTo(-10,-15);

Controlar la nave del jugador con el teclado

Vamos a aadir dos eventos de teclado y una matriz de objetos que va


a mantener el estado cada vez que se presione una tecla. Esto
permitir que el jugador mantenga pulsada una tecla y que se repita
sin pausa. Los juegos de arcade requieren este tipo de respuesta al
presionar las teclas.
Una matriz que guarda las pulsaciones de las teclas
Una matriz contendr el valor verdadero o falso para cada keyCode
asociado con eventos de teclado. El keyCode ser el ndice de la matriz
que va a recibir el valor verdadero o falso:

var listaTeclasPres = [];

Los Eventos de teclado


Usaremos eventos separados para la tecla de arriba y la tecla de
aabajo. El evento de tecla pulsada (keyDown Event) pondr un valor
true en la matriz listaTeclasPres en el ndice asociado al
keyCode del evento. De lo contrario, el evento de tecla arriba colocar
un valor falso a dicho ndice en la matriz:

document.onkeydown = function(e){
e=e?e:window.event;
//ConsoleLog.log(e.keyCode + down);
listaTeclasPres[e.keyCode] = true;

}
document.onkeyup = function(e){
e = e?e:window.event;
//ConsoleLog.log(e.keyCode + up);
listaTeclasPres[e.keyCode] = false; };

Evaluando las teclas pulsadas


Nuestro juego necesitar incluir el cdigo para buscar valores true (o
false) en la matriz listaTeclasPres y utilizar esos valores para
aplicar la lgica del juego:

if ( listaTeclasPres[38]==true){
//thrust
var anguloEnRadianes = jugador.rotacion * Math PI / 180; avanceX =
Math.cos(anguloEnRadianes);
avanceY = Math sin(anguloEnRadianes);
moverX = moverX+aceleracionAvance*avanceX; moverY =
moverY+aceleracionAvance*avanceY;

}
if ( listaTeclasPres[37]==true) {
//rotar en sentido contrario a las agujas del reloj rotacion-
=velocidadDeRotacion;

if ( listaTeclasPres[39]==true) {
//rotar en el sentido de las agujas del reloj
rotacion+=velocidadDeRotacion;

}
Una vez ms vamos a escribir todo el archivo javascript completo
debido a que se han sucedido cambios muy importantes y es una
buena practica chequear que hasta ahora estemos haciendo bien los
deberes.

nombre del archivo - defensaEspacial.js


window.addEventListener(load,
eventWindowLoaded, false); function
eventWindowLoaded() {

canvasApp();
}

function canvasApp(){
var canvas =
document.getElementById(canvas); if
(!canvas || !canvas.getContext) {

return;
}
var context = canvas.getContext(2d);

if (!context) { return;
}

//variables de nivel del objeto canvasApp var


rotacion=0;
var x=50;
var y=50;

var avanceY=0;

var moverY=0;
var width=30;
var height=20;
var velocidadDeRotacion=5; //grados que gira
la nave var aceleracionAvance=.03;
var listaTeclasPres=[];

function crearDibujo() {
if (listaTeclasPres[38]==true){
//avance
var anguloEnRadianes = rotacion * Math.PI /
180; avanceY=Math.sin(anguloEnRadianes);
moverY=moverY+aceleracionAvance*avanceY;
}

if (listaTeclasPres[37]==true) {
//rotar en direccion contraria al sentido
//de las agujas del reloj
rotacion-=velocidadDeRotacion;

}
if (listaTeclasPres[39]==true) {
//rotar en direccion al sentido de las agujas
del reloj rotacion+=velocidadDeRotacion;

}
y=y+moverY;
context.font = 20px sans-serif;
context.textBaseline = top;

//transformacin
var anguloEnRadianes = rotacion * Math.PI /
180; context.save(); //salvar el actual
estado de la pila
context.setTransform(1,0,0,1,0,0);

//Trasladar el canvas original al centro del


jugador
context.translate(x+.5*width,y+.5*height);
context.rotate(anguloEnRadianes);

//dibujar la nave espacial estatica (jugador)


context.strokeStyle = red;

context.beginPath(); context.moveTo(-10,-15);
context.lineTo(15,0); context.lineTo(-10,15);
context.lineTo(0,0); context.moveTo(0,0);
context.lineTo(-10,-15);
context.moveTo(-10,-15);

context.stroke();
context.closePath();
//restaurar el contexto
context.restore();//antiguo estado emergente
a la pantalla }
const PROM_FOTOGRAMA = 45;
var intervaloTiempo = 1000/PROM_FOTOGRAMA;
temporizador();

function temporizador(){
crearDibujo();
window.setTimeout(temporizador,
intervaloTiempo);

}
document.onkeydown=function(e){

e=e?e:window.event;
//ConsoleLog.log(e.keyCode + down);
listaTeclasPres[e.keyCode]=true;

}
document.onkeyup=function(e){
//document.body.onkeyup=function(e){

e=e?e:window.event;
//ConsoleLog.log(e.keyCode + up);
listaTeclasPres[e.keyCode]=false;

};
}

Cuando se ejecuta este archivo en un navegador, la aplicacin ser


capaz de responder cuando tu oprimas las teclas derecha e izquierda
y la nave girar sobre su eje central. Si pulsa la tecla de arriba, la nave
se mover en la direccin en la que se enfrenta.
Dar a la nave del jugador mxima velocidad

Si has probado el cdigo escrito anteriormente, te dars cuenta de dos


pequeos problemas:
1. La nave del jugador puede ir fuera de los lados de la pantalla y
perderse.
2. La nave del jugador no tiene la velocidad mxima.

Vamos a resolver el primer problema cuando empezemos a codiicar el


juego completo, pero por ahora, vamos a ver cmo aplicar una mxima
velocidad con el codigo de movimiento actual. Supongamos que le
damos a la nave del jugador una aceleracin mxima de dos pxeles
por fotograma. Es fcil calcular la velocidad actual, si nos movemos slo
en las cuatro direcciones principales: arriba, abajo, derecha, izquierda.
Cuando nos estamos moviendo hacia la izquierda o la derecha, el
valor moverY siempre ser 0. Si nos movemos hacia arriba o hacia
abajo, el valor moverX siempre ser 0. La velocidad actual en la que
nos estamos moviendo en un eje sera fcil comparar a la velocidad
mxima.
Pero en nuestro juego, estamos casi siempre avanzando en las
direcciones x e y al mismo tiempo. Para calcular la velocidad actual y
compararlo con una velocidad mxima, debemos usar un poco ms de
matemticas.

En primer lugar, supongamos que vamos a aadir una variable de


velocidad mxima a nuestro juego:
var velocidadMax = 2;

Lo siguiente, es que debemos asegurarnos de calcular y comparar el


valor de la variable velocidadMax a la velocidad actual, antes de
calcular los nuevos valores para moverX y moverY. Haremos esto
con variables locales usadas para almacenar los nuevos valores para
las variables moverX y moverY antes de que sean aplicados.

var moverXNuevo =
moverX+aceleracionAvance*avanceX; var
moverYNuevo =
moverY+aceleracionAvance*avanceY;
La velocidad actual de nuestra nave es la raz cuadrada de
moverXNuevo * 2 + moverYNuevo * 2
var velocidadActual = Math.sqrt
((moverXNuevo*moverXNuevo) +
(moverYNuevo*moverYNuevo));
Si la variable velocidadActual es menor que la variable velocidadMax,
coniguramos los valores moverX y moverY:

if (velocidadActual < velocidadMax) { moverX


= moverXNuevo;
moverY = moverYNuevo;

Un framework para juegos bsico

Ahora que hemos conseguido mojarnos los pies (por as decirlo),


gracias a que ya tenemos la primera impresin de lo que sern los
gricos de juego, las transformaciones y la fsica bsica que vamos a
usar en nuestro juego, vamos a ver como podemos estructurar un
framework simple que sirva de base para todos los juegos que
querramos crear en un canvas de HTML5. Empezaremos por crear un
grupo esttico usando para ellos las constantes, seguidamente
introduciremos nuestra funcin temporizador de intervalos a nuestra
estructura, para inalmente crear un objeto simple reusable que muestre
la cantidad de fotogramas actuales que hay en nuestro juego para
saber que esta funcionando. Dicho esto, es hora de ponernos manos a
la obra.

El grupo esttico del juego

Lo que llamo grupo esttico del juego, no es ms que la construccin


de un pequeo programa que permite a nuestro juego estar en un solo
estado de la aplicacin en cualquier momento. Vamos a crear un grupo
esttico para nuestro juego, llamado estado de la aplicacin, que
incluir siete estados bsicos (vamos a usar constantes para referirnos
a estos estados):

ESTADO_TITULO_DEL_JUEGO
ESTADO_NUEVO_JUEGO
ESTADO_NUEVO_NIVEL
ESTADO_JUGADOR_INICIAL
ESTADO_NIVEL_DEL_JUEGO
ESTADO_JUGADOR_MUERTO
ESTADO_JUEGO_TERMINADO

Vamos a crear una funcin para cada estado, dicha funcin va a


contener la lgica del juego necesarias para cada estado y para
cambiar a un nuevo estado cuando sea apropiado. Al hacer esto,
podemos usar la misma estructura para cada juego que creemos,
simplemente cambiando el contenido de cada funcin de estado (como
nos referiremos a ellos).
Echemos un vistazo a una versin muy bsica de esto en accin. Vamos
a utilizar una variable de referencia a una funcin llamada
funcionActualEstadoDeJuego, as como una variable
llamada estadoActualDeJuego que almacenar un valor
constante: el estado actual de la aplicacin.

var estadoActualDeJuego = 0;
var funcionActualEstadoDeJuego = null;
Vamos a crear una funcin llamada cambioEstadoApp() que
ser llamada slo cuando queremos cambiar a un nuevo estado:

function cambioEstadoApp(nuevoEstado) {
estadoActualDeJuego = nuevoEstado;
switch (estadoActualDeJuego) {

case ESTADO_TITULO_DEL_JUEGO:
funcionActualEstadoDeJuego =
estadoTituloJuego; break;

case ESTADO_NIVEL_DEL_JUEGO:
funcionActualEstadoDeJuego =
estadoNivelJuegoApp; break;

case ESTADO_JUEGO_TERMINADO:
funcionActualEstadoDeJuego =
estadoJuegoTerminado; break;

}
}
El llamado a la funcion temporizador() inicia la aplicacin mediante la
activacin de la iteracin de la funcin iniciarJuego(), mediante el uso
del mtodo setTimeout(). Vamos a llamar a la funcin iniciarJuego()
repetidamente en este mtodo setTimeout(). la funcin iniciarJuego()
llamar a la variable de referencia
funcionActualEstadoDeJuego en cada fotograma. Esto nos
permite cambiar fcilmente la funcin llamada por iniciarJuego() sobre
la base de los cambios de estado de la aplicacin:

temporizador();
function temporizador() {
iniciarJuego();
window.setTimeout(temporizador,
intervaloTiempo); }

function iniciarJuego(){
funcionActualEstadoDeJuego();
}

Veamos el cdigo completo. Vamos a crear algunas funciones shell


para los diferentes estados de la aplicacin. Antes de que se inicie la
aplicacin, vamos a llamar a la funcin cambioEstadoApp()y le
pasaremos el valor constante para la nueva funcin que queremos que
es la funcionActualEstadoDeJuego:

//*** inicio de la aplicacin


cambioEstadoApp(ESTADO_TITULO_DEL_JUEGO);
A continuacin actualizaremos nuestro cdigo, vamos a utilizar el
estado ESTADO_TITULO_DEL_JUEGO para dibujar una pantalla de
ttulo simple que volvera a dibujarse en cada fotograma.
nombre del archivo - defensaEspacial.js
window.addEventListener(load,
eventWindowLoaded, false); function
eventWindowLoaded() {

canvasApp();

}
function canvasApp(){
var canvas =
document.getElementById(canvas);
if (!canvas || !canvas.getContext) {
return;
}

var context = canvas.getContext(2d);

if (!context) { return;
}

//estados de la aplicacin

const ESTADO_TITULO_DEL_JUEGO=0; const


ESTADO_NUEVO_NIVEL=1; const
ESTADO_JUEGO_TERMINADO=2;

var estadoActualDeJuego=0;
var funcionActualEstadoDeJuego=null;

function cambioEstadoApp(newState) {
estadoActualDeJuego=newState;
switch (estadoActualDeJuego) {

case ESTADO_TITULO_DEL_JUEGO:
funcionActualEstadoDeJuego =
estadoTituloJuego; break;
case ESTADO_NIVEL_DEL_JUEGO:
funcionActualEstadoDeJuego =
estadoNivelJuegoApp; break;
case ESTADO_JUEGO_TERMINADO:
funcionActualEstadoDeJuego=estadoJuegoTerminad
break;

}
}
function estadoTituloJuego() {

ConsoleLog.log(estadoTituloApp); // dibujar
el fondo y los textos
context.font = 20px sans-serif;
context.textBaseline = top;
}
function estadoNivelJuegoApp() {
ConsoleLog.log(estadoNivelJuegoApp); }
function estadoJuegoTerminadoApp() {
ConsoleLog.log(estadoJuegoTerminadoApp); }

function iniciarJuego(){
funcionActualEstadoDeJuego();
}

//*** inicio de la aplicacin


cambioEstadoApp(ESTADO_TITULO_DEL_JUEGO);

//**** aplicacin temporizador


const PROM_FOTOGRAMA = 45;
var intervaloTiempo = 1000/PROM_FOTOGRAMA;
temporizador();

function temporizador() {
iniciarJuego();
window.setTimeout(temporizador,intervaloTiempo

}
}
//***** objecto prototypes *****

//*** objeto consoleLog


//llamamos al constructor de la clase
function ConsoleLog(){

}
console_log=function(message) {

console.log(message);
}
}
//agregar la funcin clase/estatica para la
clase por asignacin
ConsoleLog.log=console_log;

Nota destacada!
hemos aadido el objeto ConsoleLog para usar esta utilidad para
crear mensajes de depuracin tiles en la ventana de registro
JavaScript del navegador. Esto se aadi para los navegadores que
chocaban cuando ninguna consola
Atento
estaba encendida. Sin embargo, este es un fenmeno poco frecuente
en la mayora de los navegadores que soportan Canvas.
El ciclo actualizar/renderizar

En cualquiera de los estados de la aplicacin, es posible que


necesitemos actualizar la animacin y la pantalla de juego. Ahora bien,
nosotros nos encargaremos de estos cambios, agregando al cdigo
dos mtodos diferentes para ello: actualizar() y
renderizar(). Por ejemplo, como podemos recordar, la nave del
jugador puede moverse alrededor de la pantalla de juego, y cuando el
jugador pulsa la tecla hacia arriba(avance), el fotograma debera
mostrar la nave de jugador avanzando en lugar de la nave esttica. En
los ejemplos anteriores, teniamos todo el cdigo que actualiza las
propiedades de la nave, as como el cdigo que construye la nave, en
una nica funcin llamada crearDibujo(). Vamos a revisar a
fondo el cdigo anterior, y vamos a deshacernos de esta funcin
llamada crearDibujo() y en su lugar usaremos las funciones
separadas: actualizar() y renderizar(). Tambin vamos a
separar el cdigo que comprueba cuando una determinada tecla
especiica ha sido pulsada en el juego agregando a nuestro cdigo
otra funcin llamada chequearTeclas().

Vamos a reexaminar el contenido de la funcin crearDibujo(),


pero esta vez, vamos a disolver la funcin en funciones separadas
para cada conjunto de tareas, como se muestra en el cdigo siguiente.

nombre del archivo - defensaEspacial.js


window.addEventListener(load,
eventWindowLoaded, false); function
eventWindowLoaded() {
canvasApp();

}
function canvasApp(){
var canvas =
document.getElementById(canvas);
if (!canvas || !canvas.getContext) {
return;
}
var context = canvas.getContext(2d);

if (!context) {
return;
}
//variables de nivel del objeto canvasApp
var rotacion=0;
var x=50;
var y=50;
var avanceY=0;

var moverY=0;
var width=30;
var height=20;
var velocidadDeRotacion=5; //grados que gira
la nave var aceleracionAvance=.03;
var listaTeclasPres=[];

function estadoNivelJuegoApp() {
chequearTeclas();
actualizar();
renderizar();

}
function chequearTeclas() {
//chequeamos las teclas pulsadas
if (listaTeclasPres[38]==true){

//avance
var anguloEnRadianes = rotacion * Math.PI /
180;
avanceY=Math.sin(anguloEnRadianes);
moverY=moverY+aceleracionAvance*avanceY;

}
if (listaTeclasPres[37]==true) {
//rotar en contra del sentido de las agujas
del reloj

rotacion-=velocidadDeRotacion;
}
if (listaTeclasPres[39]==true) {

//rotar en direccion de las agujas del reloj


rotacion+=velocidadDeRotacion;
}
}
function actualizar() {

y=y+moverY;
}
function renderizar() {

// dibujar el fondo y el texto context.font =


20px sans-serif; context.textBaseline =
top;

//transformacin
var anguloEnRadianes = rotacion * Math.PI /
180; context.save(); //salvar el actual
estado de la pila
context.setTransform(1,0,0,1,0,0);//reestable
la identidad

//Trasladar el canvas original al centro del


jugador
context.translate(x+.5*width,y+.5*height);
context.rotate(anguloEnRadianes);

//dibujar la nave espacial estatica (jugador)


context.strokeStyle = red;

context.beginPath(); context.moveTo(-10,-15);
context.lineTo(15,0); context.lineTo(-10,15);
context.lineTo(0,0); context.moveTo(0,0);
context.lineTo(-10,-15);
context.moveTo(-10,-15);

context.stroke();
context.closePath();
//restaurar el contexto
context.restore(); //antiguo estado emergente
a la pantalla }

function iniciarJuego() {
estadoNivelJuegoApp();
}
const PROM_FOTOGRAMA = 45;
var intervaloTiempo = 1000/PROM_FOTOGRAMA;
temporizador();

function temporizador(){ iniciarJuego();


window.setTimeout(temporizador,
intervaloTiempo); }
document.onkeydown=function(e){

e=e?e:window.event;
//ConsoleLog.log(e.keyCode + down);
listaTeclasPres[e.keyCode]=true;

document.onkeyup=function(e){
//document.body.onkeyup=function(e){ e=e?
e:window.event;
//ConsoleLog.log(e.keyCode + up);
listaTeclasPres[e.keyCode]=false;
};
}

Dejamos fuera todos los estados de la aplicacin solo para ahorrar


espacio, simplemente estamos mostrando lo que la funcin
estadoNivelJuegoApp() puede hacer.

Profundizaremos mas en los detalles importantes a medida que


comencemos a construir la aplicacin completa, mientras tanto es
importante que vayamos concentrandonos en saber de donde
proviene cada funcin y en el anlisis que se hace para crearlas.

El objeto prototype contadorDeFotogramas

Los juegos arcade tales como Asteroids y Defensa Espacial se basan


en el procesado rpido y actualizacin de la pantalla de juego para
asegurarse de que toda el renderizado del objeto-juego y la lgica de
juego se entregan al jugador a una velocidad segura. Una forma de
saber si su juego est llevando a cabo este trabajo es emplear el uso
de un contador de fotogramas por segundo (FPS). A continuacin se
muestra una sencilla funcin que nos ser til para este in y adems
puede ser reutilizado en cualquier juego que se crea en el canvas de
HTML5:

//*** objecto prototype contadorDeFotogramas


function contadorDeFotogramas() {
this.ultimoContadorDeFotogramas = 0;
var tiempo = new Date();
this.ultimoFotograma = tiempo.getTime();
delete tiempo;
this.contadorF = 0;
}
contadorDeFotogramas.prototype.cuentaFotograma
{
var tiempo = new Date();
this.contadorF++;
if (tiempo.getTime()
>=this.ultimoFotograma+1000) {
ConsoleLog.log(evento fotograma);
this.ultimoContadorDeFotogramas =
this.contadorF;
this.ultimoFotograma = tiempo.getTime();
this.contadorF = 0;
}
delete tiempo;
}
Nuestro juego va a crear una instancia de este objeto y nuestra funcin
actualizar() llamar a la funcin cuentaFotogramas() en cada
fotograma. Vamos a escribir la cantidad de fotogramas actuales en
nuestra funcin renderizar().
En el siguiente cdigo se muestra estas funciones agregadas al
cdigo. Como alternativa, usted puede colocar este cdigo dentro de
sus propias etiquetas <script> o tambin puede crear un archivo
javascript separado y hacer referencia a este en el documento
principal. Para simpliicar, nosotros vamos a mantener todo nuestro
cdigo en un solo archivo.

nombre del archivo - defensaEspacial.js


window.addEventListener(load,
eventWindowLoaded, false); function
eventWindowLoaded() {

canvasApp();
}
function canvasApp(){

var canvas =
document.getElementById(canvas); if
(!canvas || !canvas.getContext) {
return;
}
var context = canvas.getContext(2d);

if (!context) {
return;
}
//variables de nivel del objeto canvasApp
var rotacion=0;
var x=50;
var y=50;

var avanceY=0;

var moverY=0;
var width=30;
var height=20;
var velocidadDeRotacion=5; //grados que gira
la nave var aceleracionAvance=.03; var
listaTeclasPres=[];

function estadoNivelJuegoApp() {
chequearTeclas();
actualizar();
renderizar();

}
function chequearTeclas() {
//chequeamos las teclas pulsadas

if(listaTeclasPres[38]==true){
//avance
var anguloEnRadianes = rotacion * Math.PI /
180;

avanceY=Math.sin(anguloEnRadianes);
moverY=moverY+aceleracionAvance*avanceY;
}

if (listaTeclasPres[37]==true) {
//rotar en contra de las agujas del reloj
rotacion-=velocidadDeRotacion;
}

if (listaTeclasPres[39]==true) {
//rotar en direccion a las agujas del reloj
rotacion+=velocidadDeRotacion;

}
}
function actualizar() {

y=y+moverY;
contadorDeFotogramas.cuentaFotogramas(); }
function renderizar() {
// dibujar el fondo y el texto
context.font = 20px sans-serif;
context.textBaseline = top;

contadorDeFotogramas.ultimoContadorDeFotograma
20, 570);

//transformacin
var anguloEnRadianes = rotacion * Math.PI /
180; context.save(); //salvar el actual
estado de la pila
context.setTransform(1,0,0,1,0,0);//reestable
la identidad

//Trasladar el canvas original al centro del


jugador
context.translate(x+.5*width,y+.5*height);
context.rotate(anguloEnRadianes);

//dibujar la nave espacial estatica (jugador)


context.strokeStyle = red;

context.beginPath(); context.moveTo(-10,-15);
context.lineTo(15,0); context.lineTo(-10,15);
context.lineTo(0,0); context.moveTo(0,0);
context.lineTo(-10,-15);
context.moveTo(-10,-15);

context.stroke();
context.closePath();
//restaurar el contexto
context.restore(); //antiguo estado emergente
a la pantalla }

function iniciarJuego() {
estadoNivelJuegoApp();
}

contadorDeFotogramas = new
ContadorDeFotogramas(); const PROM_FOTOGRAMA
= 45;
var intervaloTiempo = 1000/PROM_FOTOGRAMA;
temporizador();
function temporizador(){

iniciarJuego();
window.setTimeout(temporizador,
intervaloTiempo); }

document.onkeydown=function(e){
e=e?e:window.event;
//ConsoleLog.log(e.keyCode + down);
listaTeclasPres[e.keyCode]=true;
}
document.onkeyup=function(e){
//document.body.onkeyup=function(e){

e=e?e:window.event;
//ConsoleLog.log(e.keyCode + up);
listaTeclasPres[e.keyCode]=false;

};
}

//*** objecto prototype contadorDeFotogramas


function ContadorDeFotogramas() {
this.ultimoContadorDeFotogramas = 0;
var tiempo = new Date();
this.ultimoFotograma = tiempo.getTime();
delete tiempo;
this.contadorF = 0;
}
ContadorDeFotogramas.prototype.cuentaFotograma
{
var tiempo = new Date();
this.contadorF++;
if (tiempo.getTime()
>=this.ultimoFotograma+1000) {
ConsoleLog.log(evento fotograma);
this.ultimoContadorDeFotogramas =
this.contadorF; this.ultimoFotograma =
tiempo.getTime(); this.contadorF = 0;
}
delete tiempo;
}

//***** objecto prototypes *****

//*** objeto consoleLog


//llamamos al constructor de la clase
function ConsoleLog(){
}
//crear la funcin que se agregar a la clase
console_log=function(message) {

console.log(message);
}
}
//agregar la funcin clase/estatica para la
clase por asignacin
ConsoleLog.log=console_log;

Crear nuestro juego aplicando todo lo anterior

Ahora estamos listos para empezar a programar nuestro juego. En


primer lugar, vamos a ver la estructura del juego y algunas de las ideas
que sustentan los diversos algoritmos que se emplean para crearlo.
Despus de eso, vamos a presentar el cdigo fuente completo de
nuestro juego Defensa Espacial.

La estructura de nuestro juego: Defensa Espacial

La estructura de la aplicacin del juego es muy similar a la estructura


que hemos empezamos a construir en este mismo tutorial. Vamos a
echar un vistazo a las funciones de cada uno de los estados de la
aplicacin y ver cmo van a trabajar juntas.

Aplicando los estados de juego


Como lo habiamos visto anteriormente el juego contar con siete
estados distintos para la aplicacin. Vamos a almacenar estos en
constantes de la siguiente manera:

const ESTADO_TITULO_DEL_JUEGO = 0; const


ESTADO_NUEVO_JUEGO = 1; const
ESTADO_NUEVO_NIVEL = 2; const
ESTADO_JUGADOR_INICIAL = 3; const
ESTADO_NIVEL_DEL_JUEGO = 4; const
ESTADO_JUGADOR_MUERTO = 5; const
ESTADO_JUEGO_TERMINADO = 6;

Las funciones de los estados de la aplicacin

Cada estado individual tendr una funcin asociada que se llamar en


cada fotograma. vamos a deinir terica y practicamente cada una de
estas funciones, no se sorprendan si ven algunas variables y funciones
no declaradas, ya que sern declaradas en el transcurso de las
siguientes pginas.

estadoTituloJuego()
muestra los textos del titulo en la pantalla de inicio del juego y espera
que la barra de espacio sea pulsada antes de iniciar el nuevo juego.

function estadoTituloJuego() { if
(titulosIniciales !=true){ rellenarFondo();
140); titulosIniciales=true;

}else{
//esperando click en la barra de espacio if
(listaTeclasPres[32]==true){

ConsoleLog.log(espacio presionado);
cambioEstadoApp(ESTADO_NUEVO_JUEGO);
titulosIniciales=false;

}
}
}

estadoNuevoJuego()
conigura todos los valores predeterminados para un nuevo juego.
Todas las matrices que almacenan objetos de visualizacin se reinician
- el nivel de juego se resetea a 0 y la puntuacin del juego vuelve a 0.

function estadoNuevoJuego(){
ConsoleLog.log(estadoNuevoJuego);

nivel=0;
puntuacion=0;
navesJugador=3;
jugador.velocidadMax=5;
jugador.width=30;
jugador.height=20;
jugador.widthMedio=15;
jugador.heightMedio=10;
jugador.velocidadDeRotacion=5; //cuantos
grados gira la nave
jugador.aceleracionAvance= .05;
jugador.retrasoMisilFotograma = 5;
jugador.avance = false;

rellenarFondo();
renderizarTableroPuntuacion();
cambioEstadoApp(ESTADO_NUEVO_NIVEL);

estadoNuevoNivel()
aumenta el valor del nivel en 1 y conigura los valores de mando del
juego para controlar el nivel de diicultad de nuestro juego.

function estadoNuevoNivel(){
piedras=[];
platillos=[];
misilesDelJugador=[];
particulas=[];
misilesDelPlatillo=[];
nivel++;
nivelAjusteVelocidadMaxPiedra = nivel * .25;
if (nivelAjusteVelocidadMaxPiedra > 3){

nivelAjusteVelocidadMaxPiedra = 3; }

if (nivelPlatilloMax > 5){


nivelPlatilloMax = 5;
}
nivelPromedioAparicionPlatillo = 10 + 3 *
nivel;
if (nivelPromedioAparicionPlatillo > 35){
nivelPromedioAparicionPlatillo=35;
}
nivelVelocidadPlatillo = 1 + .5 * nivel;
if (nivelVelocidadPlatillo > 5){
nivelVelocidadPlatillo = 5;
}
nivelRetrasoDisparoPlatillo = 120 - 10 *
nivel;
if (nivelRetrasoDisparoPlatillo < 20) {
nivelRetrasoDisparoPlatillo = 20;
}

nivelPromedioDisparoPlatillo = 20 + 3 *
nivel; if (nivelPromedioDisparoPlatillo < 50)
{ nivelPromedioDisparoPlatillo = 50;

}
nivelVelocidadMisilPlatillo = 1 + .2*nivel;
if (nivelVelocidadMisilPlatillo > 4){
nivelVelocidadMisilPlatillo = 4;

}
//crear el nivel de las piedras
for (var contarNuevaPiedra = 0;
contarNuevaPiedra < nivel+3;

contarNuevaPiedra++){
var nuevaPiedra={};
nuevaPiedra.scale=1; nuevaPiedra.width=50;
nuevaPiedra.height=50;
nuevaPiedra.widthMedio=25;
nuevaPiedra.heightMedio=25;

//nuevas piedras se inician en la esquina


superior izquierda //para seguridad de la
nave del jugador
//ConsoleLog.log(nuevaPiedra.x= +
nuevaPiedra.x);

//ConsoleLog.log(nuevaPiedra.y= +
nuevaPiedra.y); nuevaPiedra.dx=
(Math.random()*2)+nivelAjusteVelocidadMaxPiedr
if (Math.random() < .5){

nuevaPiedra.dx *= -1;
}
nuevaPiedra.dy=
(Math.random()*2)+nivelAjusteVelocidadMaxPiedr
if (Math.random()<.5){

nuevaPiedra.dy*=-1;
}
//velocidad de rotacin y direccin
nuevaPiedra.rotacionInc=(Math.random()*5)+1;
if (Math.random()<.5){

nuevaPiedra.rotacionInc *= -1;
}
nuevaPiedra.valorPuntuacion =
puntosPiedrasGrandes; nuevaPiedra.rotacion =
0;

piedras.push(nuevaPiedra);
//ConsoleLog.log(piedras creadas
rotacionInc= + //nuevaPiedra.rotacionInc);

}
resetearJugador();
cambioEstadoApp(ESTADO_JUGADOR_INICIAL);

estadoJugadorInicial()
los gricos correspondientes al jugador desaparecen en un alpha con
valores de 0 a 1. Cuando se ha completado, el juego iniciar el nivel.

function estadoJugadorInicial(){

rellenarFondo();
renderizarTableroPuntuacion();
if (jugador.alpha < 1){

jugador.alpha += .02;
context.globalAlpha = jugador.alpha; }else{
cambioEstadoApp(ESTADO_NIVEL_DEL_JUEGO); }

renderizarNaveJugador(jugador.x, jugador.y,
270, 1); context.globalAlpha=1;
actualizarPiedras();
renderizarPiedras();
}

estadoNivelDelJuego()
controla el nivel en la cual se desarrolla el juego. Esta funcin llama a
las funciones actualizar() y renderizar(), as como a las funciones que
evaluan los eventos y entradas del teclado para el control de la nave
del jugador.

function estadoNivelDelJuego(){
chequearTeclas();
actualizar();
renderizar();
chequearColisiones();
chequearParaNaveExtra();
chequearFinDeNivel();
contadorDeFotogramas.cuentaFotogramas();

estadoJugadorMuerto()
inicia una explosin en el lugar donde la nave del jugador ha
colisionado con una roca, un platillo volador o un misil del platillo
volador. Cuando la explosin termine (todas las partculas de la
explosin han agotado sus valores de vida individuales), da paso al
estado ESTADO_JUGADOR_ NICIAL.

function estadoJugadorMuerto(){
if (particulas.length > 0 ||
misilesDelJugador.length > 0) {
rellenarFondo();
renderizarTableroPuntuacion();
actualizarPiedras();
actualizarPlatillos();
actualizarParticulas();
actualizarMisilesDelPlatillo();
actualizarMisilesDelJugador();
renderizarPiedras();
renderizarPlatillos();
renderizarParticulas();
renderizarMisilesDelPlatillo();
renderizarMisilesJugador();
contadorDeFotogramas.cuentaFotogramas();

}else{
navesJugador--; if (navesJugador < 1) {

cambioEstadoApp(ESTADO_JUEGO_TERMINADO);
}else{
resetearJugador();
cambioEstadoApp(ESTADO_JUGADOR_INICIAL); }
}
}

estadoJuegoTerminado()

muestra la pantalla juego terminado e inicia un nuevo juego al pulsar


la barra de espacio.
function estadoJuegoTerminado() {
ConsoleLog.log(Estado juego terminado);
rellenarFondo();
renderizarTableroPuntuacion();
70, 180);

}else{ //esperar por click en la barra de


espacio if (listaTeclasPres[32] == true){

ConsoleLog.log(espacio presionado);
cambioEstadoApp(ESTADO_TITULO_DEL_JUEGO);
} }
}

Funciones de la aplicacin

Tal cual lo dijimos con anterioridad, hay una cantidad de funciones que
son llamadas por estas funciones estadales que no han sido
declaradas, y tampoco sabemos cual es su funcionamiento y utilidad.
En la siguiente seccin vamos a deinir, de la misma forma que lo hemos
hecho en la seccin anterior con las funciones de estado de la
aplicacin, cada una de estas funciones complementarias necesarias
para el funcionamiento de nuestra aplicacin.

resetearJugador()
resetea la nave del jugador y lo traslada al centro de la pantalla de
juego preparandolo para que continue jugando.

function resetearJugador() { jugador.rotacion


= 270;
jugador.x = .5 * xMax;
jugador.y = .5 * yMax;
jugador.avanceX = 0;
jugador.avanceY = 0;
jugador.moverX = 0;
jugador.moverY = 0;
jugador.alpha = 0;
jugador.cuentaMisilesPorFotograma=0;

chequearParaNaveExtra()
Comprueba si al jugador debe o no otorgarsele una nueva nave
adicional. Consulte ms adelante en la seccin concesin de naves
adicionales a los jugadores para obtener ms informacin acerca de
este algoritmo.

function chequearParaNaveExtra() {

{ navesJugador++; naveExtraGanada++;

}
}

chequearFinDeNivel()
Comprueba si todas las piedras han sido destruidas en un
determinado nivel y, si es as, inaliza el nivel actual y da comienzo a un
nuevo nivel. Consulta mas adelante la seccin nivel y in de juego para
obtener mas informacin sobre este algoritmo.

function chequearFinDeNivel(){
if (piedras.length==0) {
cambioEstadoApp(ESTADO_NUEVO_NIVEL); }
}
rellenarFondo()
Rellena el canvas con el color del fondo en cada uno de los
fotogramas.
function rellenarFondo() {
// dibujar el fondo y los textos
}
Conigura la base del estilo del texto antes de que este sea dibujado
en la pantalla del juego.
context.font = 15px sans-serif;
context.textBaseline = top;
}

RenderizarTableroPuntuacion()
Esta funcin es llamada en cada uno de los fotogramas de la
aplicacin. Su funcin es mostrar el tablero con los indicadores que
interesan al jugador, como la puntuacin actualizada, el nmero de
naves disponibles y por ltimo la cantidad de fotogramas por segundo
(FPS) actuales de la aplicacin.

function renderizarTableroPuntuacion() {
renderizarNaveJugador(200,10,270,0.5);

- Fotogramas, 330,10);
}

chequearTeclas()
Comprueba la matriz listaTeclasPres y luego modiica el
comportamiento de la nave del jugador basada en los valores que
resulten en true como resultado de dicha comprobacin.
function chequearTeclas() {
//chequear las teclas pulsadas

if (listaTeclasPres[38]==true){
//avance
var angulosEnRadianes = jugador.rotacion *
Math.PI / 180; jugador.avanceX =
Math.cos(angulosEnRadianes); jugador.avanceY
= Math.sin(angulosEnRadianes);

var moverXNuevo = jugador.moverX +


jugador.aceleracionAvance * jugador.avanceX;
var moverYNuevo = jugador.moverY +
jugador.aceleracionAvance * jugador.avanceY;

var velocidadActual= Math.sqrt


((moverXNuevo*moverXNuevo) +
(moverYNuevo*moverYNuevo));

if (velocidadActual < jugador.velocidadMax) {


jugador.moverX = moverXNuevo;
jugador.moverY = moverYNuevo;

}
jugador.avance = true;

}else{ jugador.avance = false;


}

if (listaTeclasPres[37]==true) {
//rotar direccion contraria a las agujas del
reloj jugador.rotacion -=
jugador.velocidadDeRotacion;

if (listaTeclasPres[39]==true) {
//rotar direccion a las agujas del reloj
jugador.rotacion +=
jugador.velocidadDeRotacion;

if (listaTeclasPres[32]==true) {
//ConsoleLog.log(jugador.cuentaMisilesPorFoto
= // + jugador.cuentaMisilesPorFotograma);
//ConsoleLog.log(jugador.retrasoMisilFotogram
= // + jugador.retrasoMisilFotograma);
if (jugador.cuentaMisilesPorFotograma >

jugador.retrasoMisilFotograma){
misilDisparadoPorJugador();
jugador.cuentaMisilesPorFotograma = 0;

}
}
}

actualizar()
Esta funcin es llamada desde el ESTADO_NIVEL_DEL_JUEGO,
quien a su vez llama a cada una de las funciones actualizar()
para cada matriz de objeto mostrado en la pantalla de juego. funcion
actualizar() por cada objeto mostrado de forma individual
Cada una de las funciones que iguran a continuacin actualiza a cada
uno de los objetos mostrados en la pantalla de juego. Estas funciones
(excepto actualizarJugador()) se repetir a travs de la
matriz respectiva de los objetos asociados al tipo de objeto mostrado y
actualiza los valores x e y con los valores dx y dy. La funcin
actualizarPlatillo() contiene la logica necesaria para
comprobar si se debe o no crear otro platillo, a la vez que chequea si
actualmente existe un platillo en la pantalla de juego, para comprobar
si el mismo debe o no disparar un misil al jugador.

actualizarJugador()
actualizarMisilesDelJugador()
actualizarPiedras()
actualizarPlatillos()
uactualizarMisilesDelPlatillo()
actualizarParticulas()

function actualizar() {
actualizarJugador();
actualizarMisilesDelJugador();
actualizarPiedras();
actualizarPlatillos();
actualizarMisilesDelPlatillo();
actualizarParticulas();

renderizar()
Esta funcin es llamada desde el ESTADO_NIVEL_DEL_JUEGO,
quien a su vez llama a la funcin renderizar() para cada matriz
de objeto mostrado en la pantalla de juego.
funcion actualizar() por cada objeto mostrado de forma individual
Al igual que las funciones actualizar() cada una de las
funciones que iguran a continuacin, renderizan a cada uno de los
diferentes objetos mostrados en la pantalla de juego. Nuevamente con
la excepcin de la funcin renderizarJugador() (porque solo
existe una nave del jugador), cada una de esas funciones pasar un
bucle a traves de las matrices de los objetos asociados a su tipo, y los
dibujar en la pantalla de juego. Como vimos en la elaboracin de la
nave del jugador al principio de este tutorial, dibujaremos cada objeto
mediante el movimiento y el traslado del canvas al punto en la cual
queremos dibujar nuestros objetos lgicos, luego transformaremos
nuestros objetos (si es necesario) y dibujaremos los trazos en la
pantalla del juego.

renderizarNaveJugador()
renderizarMisilesJugador()
renderizarPiedras()
renderizarPlatillos()
renderizarMisilesDelPlatillo()
renderizarParticulas()

function renderizar() {
rellenarFondo();
renderizarTableroPuntuacion();
renderizarNaveJugador(jugador.x,jugador.y,juga
renderizarMisilesJugador();
renderizarPiedras();
renderizarPlatillos();
renderizarMisilesDelPlatillo();
renderizarParticulas();

chequearColisiones()
Pasa un bucle a traves de cada uno de los diferentes objetos
mostrados en pantalla y chequea si ha colisionado o no con otros
objetos mostrados en la pantalla de juego. Para una informacin mas
detallada sobre este tema, lea la seccin aplicacin de deteccin de
colisiones en las paginas siguientes de este tutorial. A continuacin el
cdigo de esta funcin, no se sorprenda si es un poco largo, en
realidad es muy sencillo, pero muy potente.

function chequearColisiones() {
//Pasar un bucle a traves de las piedras y
luego a los misilies. //Siempre habr piedras
y una nave,pero no siempre habr misiles var
piedrasTemporales={};
var cantidadPiedras = piedras.length-1;
var misilesJugadorTemp = {};
var cantidadMisilesJugador =
misilesDelJugador.length-1; var
cantidadPlatillos = platillos.length-1;
var platillosTemp = {};
var cantidadMisilesPlatillo =
misilesDelPlatillo.length-1;

piedras:for(var
cuentaPiedras=cantidadPiedras; cuentaPiedras
>= 0; cuentaPiedras--){
piedrasTemporales = piedras[cuentaPiedras];

misiles:for (var cuentaMisilesJugador =


cantidadMisilesJugador; cuentaMisilesJugador
>= 0;
cuentaMisilesJugador--){
misilesJugadorTemp =
misilesDelJugador[cuentaMisilesJugador];

if
(colisionCuadroDelimitador(piedrasTemporales,
misilesJugadorTemp)){
//ConsoleLog.log(colision con piedra);
crearExplosion(piedrasTemporales.x +

piedrasTemporales.widthMedio,
piedrasTemporales.y +
piedrasTemporales.heightMedio, 10);
if (piedrasTemporales.scale < 3) {

dividirPiedras(piedrasTemporales.scale+1,
piedrasTemporales.x,
piedrasTemporales.y);
}
agregarAPuntuacion(piedrasTemporales.valorPun
misilesDelJugador.splice(cuentaMisilesJugador
misilesJugadorTemp = null;

piedras.splice(cuentaPiedras,1);
piedrasTemporales=null;
break piedras; break misiles; }
}
platillos:for (var cuentaPlatillos =
cantidadPlatillos; cuentaPlatillos >= 0;
cuentaPlatillos--){
platillosTemp=platillos[cuentaPlatillos];

if
(colisionCuadroDelimitador(piedrasTemporales,p
{ ConsoleLog.log(colision con roca);
crearExplosion(platillosTemp.x +
platillosTemp.widthMedio,

platillosTemp.y + platillosTemp.heightMedio,
10); crearExplosion(piedrasTemporales.x +
piedrasTemporales.widthMedio,
piedrasTemporales.y +
piedrasTemporales.heightMedio, 10);

if (piedrasTemporales.scale < 3) {
dividirPiedras(piedrasTemporales.scale+1,
piedras

Temporales.x, piedrasTemporales.y); }
platillos.splice(cuentaPlatillos, 1);
platillosTemp = null;

piedras.splice(cuentaPiedras, 1);
piedrasTemporales = null;
break piedras;
break platillos;
}
}
//misiles del platillo contra las piedras
//esto se hace aqu, as que no tenemos que
recorrer las rocas de //nuevo ya que
probablemente la matriz seria mayor
misilesPlatillos:for (var
cuentaMisilesPlatillo =

cantidadMisilesPlatillo;
cuentaMisilesPlatillo >= 0;
cuentaMisilesPlatillo--){
misilesPlatilloTemp =
misilesDelPlatillo[cuentaMisilesPlatillo];
if
(colisionCuadroDelimitador(piedrasTemporales,
misilesPlatilloTemp)){
ConsoleLog.log(colision con piedra);

crearExplosion(piedrasTemporales.x +
piedrasTemporales.widthMedio,
piedrasTemporales.y +
piedrasTemporales.heightMedio, 10);
if (piedrasTemporales.scale < 3) {

dividirPiedras(piedrasTemporales.scale + 1,
piedrasTemporales.x, piedrasTemporales.y); }

misilesDelPlatillo.splice(cuentaPlatillos,
1); misilesPlatilloTemp=null;
piedras.splice(cuentaPiedras, 1);
piedrasTemporales=null;

break piedras;
break misilesPlatillos;

}
}
//chequear jugador contra las rocas
if
(colisionCuadroDelimitador(piedrasTemporales,
jugador)){

ConsoleLog.log(colision jugador);
crearExplosion(piedrasTemporales.x +
piedrasTemporales.widthMedio,
piedrasTemporales.heightMedio, 10);
agregarAPuntuacion(piedrasTemporales.valorPun
if (piedrasTemporales.scale < 3) {
dividirPiedras(piedrasTemporales.scale + 1,
piedrasTemporales.x, piedrasTemporales.y);
}
piedras.splice(cuentaPiedras, 1);
piedrasTemporales = null;

jugadorMuerto(); }
}

//Ahora compruebe jugador contra platillos y


luego platillos contra //los misiles de
jugadores y por ltimo jugador contra misiles
platillo
cantidadMisilesJugador =
misilesDelJugador.length-1;
cantidadPlatillos = platillos.length-1;
platillos:for (var cuentaPlatillos =
cantidadPlatillos; cuentaPlatillos >= 0;
cuentaPlatillos--){
platillosTemp=platillos[cuentaPlatillos];

misiles:for(var
cuentaMisilesJugador=cantidadMisilesJugador;
cuentaMisilesJugador>=0;cuentaMisilesJugador-
-){
misilesJugadorTemp=misilesDelJugador[cuentaMi

if (colisionCuadroDelimitador(platillosTemp,
misilesJugadorTemp)){
ConsoleLog.log(colision con piedras);
crearExplosion(platillosTemp.x +
platillosTemp.widthMedio,

platillosTemp.y + platillosTemp.heightMedio,
10);
agregarAPuntuacion(platillosTemp.valorPuntuaci
misilesDelJugador.splice(cuentaMisilesJugador
misilesJugadorTemp = null;
platillos.splice(cuentaPlatillos, 1);
platillosTemp = null;
break platillos; break misiles; }
}

//jugador contra platillo


if (colisionCuadroDelimitador(platillosTemp,
jugador)){ ConsoleLog.log(colision
jugador);
crearExplosion(platillosTemp.x + 16,
platillosTemp.y + 16, 10);
agregarAPuntuacion(platillosTemp.valorPuntuaci

platillos.splice(cuentaPiedras, 1);
platillosTemp=null;
jugadorMuerto(); }
}
//misiles del platillo contra jugador
cantidadMisilesPlatillo =
misilesDelPlatillo.length-1;

misilesPlatillos:for (var
cuentaMisilesPlatillo =
cantidadMisilesPlatillo;
cuentaMisilesPlatillo >= 0;
cuentaMisilesPlatillo--){

misilesPlatilloTemp =
misilesDelPlatillo[cuentaMisilesPlatillo];

if (colisionCuadroDelimitador(jugador,
misilesPlatilloTemp)){ ConsoleLog.log(misil
del platillo impacta al jugador);
jugadorMuerto();
misilesDelPlatillo.splice(cuentaPlatillos,
1); misilesPlatilloTemp = null;
break misilesPlatillos; }
}
}

misilDisparadoPorJugador()
Crea un objeto misilJugador en el centro de la nave del jugador y
disparado en la misma direccin de avance de la nave.

function misilDisparadoPorJugador(){
ConsoleLog.log(jugador dispara misil);
var nuevoMisilJugador={};
nuevoMisilJugador.dx=5*Math.cos(Math.PI*
(jugador.rotacion)/180);
nuevoMisilJugador.dy=5*Math.sin(Math.PI*
(jugador.rotacion)/180);
nuevoMisilJugador.x=jugador.x+jugador.widthMed
nuevoMisilJugador.y=jugador.y+jugador.heightM
nuevoMisilJugador.life=60;
nuevoMisilJugador.lifeCtr=0;
nuevoMisilJugador.width=2;
nuevoMisilJugador.height=2;
misilesDelJugador.push(nuevoMisilJugador);

misilDisparadoPorPlatillo()
Crea un objeto misilPlatillo en el centro del platillo y es disparado en la
direccin actual de la nave del jugador.

function misilDisparadoPorPlatillo(platillo)
{
var nuevoMisilPlatillo = {};
nuevoMisilPlatillo.x = platillo.x+.5 *
platillo.width; nuevoMisilPlatillo.y =
platillo.y+.5 * platillo.height;

nuevoMisilPlatillo.width=2;
nuevoMisilPlatillo.height=2;
nuevoMisilPlatillo.speed =
platillo.missileSpeed;

ConsoleLog.log(disparo del platillo);


//fuego al jugador desde pequeo platillo
var grados = 360 * radianes / (2 * Math.PI);
nuevoMisilPlatillo.dx = platillo.missileSpeed
*

Math.cos(Math.PI*(grados)/180);
nuevoMisilPlatillo.dy = platillo.missileSpeed
*
Math.sin(Math.PI*(grados)/180);
nuevoMisilPlatillo.life=160;
nuevoMisilPlatillo.lifeCtr=0;
misilesDelPlatillo.push(nuevoMisilPlatillo);
}

jugadorMuerto()
crea una explosin para la nave, cuando sta es alcanzada por un
misil del platillo o es impactada por el platillo o por una piedra,
llamando a la funcin crearExplosin(), cambiando de esta
manera el estado de la aplicacin a ESTADO_JUGADOR_MUERTO.
function jugadorMuerto() {
ConsoleLog.log(jugador muerto);
crearExplosion(jugador.x+jugador.widthMedio,
jugador.y+jugador.heightMedio,50);
cambioEstadoApp(ESTADO_JUGADOR_MUERTO);
}

crearExplosion()
Esta funcin crea una explosin y para ello acepta tres argumentos, los
primeros indican las coordenadas de la explosin y el tercer
argumento representa la cantidad de particulas desprendidas por la
explosin.

function crearExplosion(x,y,num) {
//create 10 particles
for (var
contarParticulas=0;contarParticulas<num;contar
{

var nuevaParticula=new Object();


nuevaParticula.dx=Math.random()*3;
if (Math.random()<.5){

nuevaParticula.dx*=-1;
}
nuevaParticula.dy=Math.random()*3;
if (Math.random()<.5){

nuevaParticula.dy*=-1;
}

nuevaParticula.lifeCtr=0;
nuevaParticula.x=x;
nuevaParticula.y=y;
ConsoleLog.log(nuevaParticula.life= +
nuevaParticula.life);
particulas.push(nuevaParticula);

}
}

colisionCuadroDelimitador()
Determina si la caja rectangular que abarca la anchura y la altura de
un objeto coincide con el cuadro delimitador de otro objeto. Se
necesita de dos objetos de visualizacin lgicas como parmetros y
devuelve true si se las areas de los objetos coinciden y falso si no
coinciden. Vea la seccin Aplicacin de deteccin de colisiones en
las siguientes pginas de este tutorial para obtener ms informacin
acerca de esta funcin.

function colisionCuadroDelimitador(objeto1,
objeto2) { var izquierda1 = objeto1.x;
var izquierda2 = objeto2.x;
var derecha1 = objeto1.x + objeto1.width; var
derecha2 = objeto2.x + objeto2.width; var
superior1 = objeto1.y;
var superior2 = objeto2.y;
var inferior1 = objeto1.y + objeto1.height;
var inferior2 = objeto2.y + objeto2.height;
if (inferior1 < superior2)

return(false);
if (superior1 > inferior2)
return(false);

if (derecha1 < izquierda2) return(false);


if (izquierda1 > derecha2) return(false);

return(true); }

dividirPiedras()
cuando las piedras grandes son impactadas por misiles del jugador,
misiles del platillo o simplemente colicionan con el platillo o la nave del
jugador, estas se dividen en dos piedras medianas, que a su vez, si les
pasa lo mismo que a las piedras grandes, se dividen en dos piedras
pequeas. Acepta como argumentos la escala y las coordenadas x e y
donde se creara la divisin.

function dividirPiedras(scale,x,y){
for (var
nuevasPiedrastr=0;nuevasPiedrastr<2;nuevasPied
{ var nuevaPiedra={};
//ConsoleLog.log(split rock);

if (scale==2){
nuevaPiedra.valorPuntuacion=puntosPiedrasMedia
nuevaPiedra.width=25;
nuevaPiedra.height=25;
nuevaPiedra.widthMedio=12.5;
nuevaPiedra.heightMedio=12.5;

}else {
nuevaPiedra.valorPuntuacion=puntosPiedrasPequ
nuevaPiedra.width=16;
nuevaPiedra.height=16;
nuevaPiedra.widthMedio=8;
nuevaPiedra.heightMedio=8;

nuevaPiedra.scale=scale;
nuevaPiedra.x=x;
nuevaPiedra.y=y;
nuevaPiedra.dx=Math.random()*3; if
(Math.random()<.5){

nuevaPiedra.dx*=-1;
}
nuevaPiedra.dy=Math.random()*3;
if (Math.random()<.5){

nuevaPiedra.dy*=-1;
}
nuevaPiedra.rotacionInc=(Math.random()*5)+1;
if (Math.random()<.5){

nuevaPiedra.rotacionInc*=-1;
}
nuevaPiedra.rotacion=0;
ConsoleLog.log(nueva escala de roca+
(nuevaPiedra.scale));
piedras.push(nuevaPiedra);

}
}
agregarAPuntuacion()

Esta funcin acepta como argumento un valor y lo suma a la puntuacin


del jugador.

function agregarAPuntuacion(valor){
puntuacion+=valor;
}

Variables globales de la aplicacin


Ahora vamos a ver todo el conjunto de juego de variables de mbito de
aplicacin necesarias para nuestro juego.

Variables que luyen en la pantalla de control


Estas variables se utilizan cuando aparecen por primera vez la pantalla
con el ttulo y el Fin de Juego . Sern establecidas en true despus
de que se hayan dibujado en la pantalla. Cuando estas variables han
sido establecidas en true, la pantalla de juego buscar un evento
que muestre que la barra espaciadora ha sido presionada y solo
despus de eso pasar al siguiente estado de la aplicacin:

//titulos en pantalla
var titulosIniciales=false;

Variables del entorno del juego


Estas variables coniguran los valores predeterminados necesarios
para un nuevo juego. Vamos a discutir elpuntoParaNaveExtra y
naveExtraGanada en la seccin La concesin de las naves
adicionales del jugador en las siguientes paginas:
//entorno de juego
var puntuacion=0;
var nivel=0;
var puntosParaNaveExtra=10000; var
naveExtraGanada=0;
var navesJugador=3;

Variables del campo de juego


Estas variables coniguran las coordenadas mximas y mnimas para el
campo del juego y todas sus etapas:

//campo de juego var xMin=0;


var xMax=400; var yMin=0;
var yMax=600;

Variables para los valores de puntuacin


Estas variables coniguran los valores para cada uno de los objetos
que el jugador pueda destruir:

//valores de puntuacin
var puntosPiedrasGrandes=50; var
puntosPiedrasMedianas=75; var
puntosPiedrasPequenas=100; var
puntosPlatillos=300;

Constantes para los tamaos de las piedras


Estas variables establecen algunos valores legibles para los tres
tamaos de piedra que usaremos en el juego, esto nos permite utilizar
simplemente la constante en lugar de un valor literal. A continuacin,
puede cambiar el valor literal, si es necesario:
//constantes para la escala de las piedras
const ROCK_SCALE_LARGE=1;
const ROCK_SCALE_MEDIUM=2;
const ROCK_SCALE_SMALL=3;

Objetos lgicos mostrados


Estas variables establecen el objeto solo jugador y matrices para
almacenar los dems objetos de visualizacin lgicas para nuestro
juego. Ver en las prximas secciones El objeto Jugador y Matrices
de objetos lgicos mostrados en pantalla para obtener ms
informacin acerca de cada uno de estos:

//crear objetos del juego y las matrices var


jugador={};
var piedras=[];
var platillos=[];
var misilesDelJugador=[];
var particulas=[];
var misilesDelPlatillo=[];

Variables especiicas de nivel


Las variables especiicas de nivel son las encargadas de manejar el
grado de diicultad en cada uno de los niveles del juego cuando este
va aumentando de nivel, Vea la seccin Mandos de nivel para tener
una mayor informacin de como usar estas variables:

var nivelAjusteVelocidadMaxPiedra=1;
var nivelPlatilloMax = 1;
//este ser multiplicado por el nivel y la
mxima puede ser en s var
nivelPromedioAparicionPlatillo=25;
var nivelVelocidadPlatillo=1;
var nivelRetrasoDisparoPlatillo=300;
var nivelPromedioDisparoPlatillo=30;
var nivelVelocidadMisilPlatillo=1;

El objeto jugador

El objeto jugador contiene muchas de las variables que nos


encontramos al principio de este tutorial, cuando hemos hablado de
animacin, rotacin y movimiento de la nave del jugador en la pantalla
de juego. Tambin hemos aadido tres nuevas variables que no has
visto antes. Todas estas variables son instanciadas en la funcin
estadoNuevoJuego() que anteriormente habamos deinido:

jugador.velocidadMax=5;
jugador.width=30;
jugador.height=20;
jugador.widthMedio=15;
jugador.heightMedio=10;
jugador.velocidadDeRotacion=5; //cuantos
grados gira la nave
jugador.aceleracionAvance= .05;
jugador.retrasoMisilFotograma = 5;
jugador.avance = false;

Las nuevas variables introducidas en el objeto jugador y que no


hemos visto anteriormente son widthMedio, heightMedio y
retrasoMisilFotograma. widthMedio y heightMedio
simplemente guardan la mitad de los valores del ancho y el alto, por lo
que evitamos que estos sean calculados en cada fotograma en los
mltiples lugares dentro del cdigo, ahorrando para ello muchos
recursos del sistema. La variable retrasoMisilFotograma
contiene el nmero de fotogramas que debe haber entre cada disparo
de misil del jugador. De esta manera, el jugador no podr disparar un
lujo constante de misiles destruyendo asi todo lo que este a su alcance
con una diicultad casi nula.

Algoritmos del juego Defensa Espacial

Vamos a tratar de explicar con mas detalle lo que vamos a estudiar en


esta seccin ya que implica mucho de javascript y como hemos dicho a
lo largo del libro, no es uno de los objetivos de este libro, profundizar
en el tema del aprendizaje de javascript, si crees que tienes o tendrs
problemas para entender lo que aquo se quiere explicar, dirijete al
capitulo 1 de este libro y lee la seccin javascript, tambin te
recomendamos leas libros especializados del tema para un mayor
aprovechamiento del canvas de HTML5.

Matrices de objetos lgicos mostrados en la pantalla de juego


Hemos utilizado matrices para almacenar todos los objetos de
visualizacin lgicos, y tenemos una gran variedad para cada tipo de
objeto usado en nuestro juego (piedras, platillos, misilesDelJugador,
misiliesDelPlatillo y partculas). Cada objeto de visualizacin lgico es
una instancia de un objeto simple. Hemos creado una funcin
separada para dibujar y actualizar cada uno de los objetos.

El objeto prototype
El uso de un objetde la clase prototype similar a
ContadorDeFotogramas puede ser implementado fcilmente por varios
de los tipos de objetos mostrados. Sin embargo, estos objetos nos
permitira separar el cdigo para actu
Atento
alizar y dibujar de las funciones comunes actuales y luego poner ese
cdigo dentro de un objeto prototype individual. Hemos incluido un
prototype Piedra al final de este tutorial como ejemplo de lo que
estamos aqui discutiendo.
Usted se dar cuenta que los platillos y las piedras estn dibujados
con puntos en la misma manera que esta dibujada la nave del jugador.
Piedras

Las rocas sern simples cuadrados que giran en el sentido de las


agujas del reloj o contrario a este. Las instancias de piedra estarn en
la matriz rocas. Cuando se inicia un nuevo nivel, todos estos sern
creados en la esquina superior izquierda de la pantalla del juego.
Estos son las variables atributos de un objeto piedra:

nuevaPiedra.scale = 1;
nuevaPiedra.width = 50;
nuevaPiedra.height = 50;
nuevaPiedra.widthMedio = 25;
nuevaPiedra.heightMedio = 25;
nuevaPiedra.x
nuevaPiedra.y
nuevaPiedra.dx
nuevaPiedra.dy
nuevaPiedra.valorPuntuacion =
puntosPiedrasMedianas; nuevaPiedra.rotacion =
0;

El tamao de la piedra estar conigurado en una de las tres constantes


que deinen el tamao de las piedras discutidas anteriormente en este
tutorial. Los atributos widthMedio y heightMedio se establecen
basados en la escala, y se usarn de la misma forma que la version del
objeto jugador. Los valores de los atributos dx y dy representan los
valores de los ejes x e y en el sistema de coordenadas del canvas
cuando las piedras son actualizadas en cada fotograma.

Platillos
A diferencia del juego Asteroids de Atari, que cuenta con grandes y
pequeos platillos, vamos a tener un solo tamao en nuestro juego
Defensa Espacial. Se almacena en la matriz de platillos.

imagen 3.4
- Trazado que representa el platillo
Los variables atributos del objeto platillo son muy similares a los
atributos de un objeto piedra, aunque sin el atributo scale de la piedra.
Los platillos tampoco tienen rotacin como atributo, por lo que siempre
estar conigurada en 0. El platillo tambin contiene variables que se
actualizan en cada nuevo nivel para hacer el juego ms desaiante
para el jugador. Estas son las variables que sern discutidas con ms
detalle en la seccin Mandos de nivel en las prximas pginas:

nuevoPlatillo.disparosPromedios=nivelPromedioD
nuevoPlatillo.retrasoDisparo=nivelRetrasoDispa
nuevoPlatillo.cantRetrasoDisparo=0;
nuevoPlatillo.velocidadMisil=nivelVelocidadMi
Misiles

Tanto los misiles del jugador como los del platillo, estarn diseados en
un bloque de 2x2 pixeles. Ellos sern almacenados en las matrices
misilesDelJugador y misilesDelPlatillo, respectivamente. Los objetos
son en s muy simples. Ellos contienen suicientes atributos para
moverse a travs de la pantalla de juego y para calcular los valores de
vida.

nuevoMisilJugador.dx=5*Math.cos(Math.PI*
(jugador.rotacion)/180);
nuevoMisilJugador.dy=5*Math.sin(Math.PI*
(jugador.rotacion)/180);
nuevoMisilJugador.x=jugador.x+jugador.widthMed
nuevoMisilJugador.y=jugador.y+jugador.heightM
nuevoMisilJugador.life=60;
nuevoMisilJugador.lifeCtr=0;
nuevoMisilJugador.width=2;
nuevoMisilJugador.height=2;

nuevoMisilPlatillo.x = platillo.x + .5 *
platillo.width;
nuevoMisilPlatillo.y = platillo.y + .5 *
platillo.height; nuevoMisilPlatillo.width=2;
nuevoMisilPlatillo.height=2;
nuevoMisilPlatillo.speed =
platillo.velocidadMisil;
nuevoMisilPlatillo.dx =
platillo.velocidadMisil * Math.cos(Math.PI*
(grados)/180);
nuevoMisilPlatillo.dy =
platillo.velocidadMisil * Math.sin(Math.PI*
(grados)/180);
nuevoMisilPlatillo.life=160;
nuevoMisilPlatillo.lifeCtr=0;

Explosiones y partculas

Cuando una piedra, un platillo, o la nave del jugador es destruida, el


objeto explota creando una serie de partculas. La funcin
crearExplosion() crea lo que llamamos una explosin de
partculas. Las partculas son simplemente objetos de visualizacin
lgicas individuales con sus propios valores para los atributos life,
dx y dy. La generacin aleatoria de estos valores hace que cada
explosin parezca nica. Las partculas se almacenan en la matriz de
partculas.

Al igual que los misiles del jugador, los objetos partculas son bastante
simples. Estos tambin contienen informacin suiciente para moverlos
por la pantalla y calcular su tiempo de vida en cada fotograma:
nuevaParticula.dx=Math.random()*3;
nuevaParticula.dy=Math.random()*3;

nuevaParticula.lifeCtr=0; nuevaParticula.x=x;
nuevaParticula.y=y;

Mandos de nivel

A pesar de que no estamos mostrando el nmero del nivel del juego al


jugador, estamos ajustando la diicultad del juego cada vez que la
totalidad de las piedras de un nivel son destruidas y renovada la
pantalla de juego. Hacemos esto mediante el aumentar en 1 la variable
nivel y luego volver a calcular estos valores antes de que comience el
nuevo nivel. Nos referimos a la variacin en el nivel de diicultad como
mandos que se reiere a las marcas o interruptores. Estas son las
variables que utilizaremos para estos botones:

level ++;

Se reiere al numero de piedras.


nivelAjusteVelocidadMaxPiedra = nivel * .25;
La velocidad mxima de las piedras.

El nmero de platillos simultaneos.


nivelPromedioAparicionPlatillo = 10 + 3 *
nivel;
El porcentaje de probabilidad de que aparezca un platillo.
nivelVelocidadPlatillo = 1 + .5 * nivel;
La velocidad del platillo.
nivelRetrasoDisparoPlatillo = 120 - 10 *
nivel;
El tiempo entre cada misil del platillo.
nivelPromedioDisparoPlatillo = 20 + 3 *
nivel;

Porcentaje de probabilidades de que el platillo dispare al jugador.


nivelVelocidadMisilPlatillo = 1 + .2*nivel;
La velocidad de los misiles del platillo.

Nivel y Fin de Juego


Tenemos que comprobar el juego y el inal de nivel, as podemos crear
la transicin entre un nuevo juego o al siguiente nivel.
Final de nivel
Vamos a chequear el in de nivel en cada fotograma, para llevar esto a
efecto nuestro cdigo deber parecerse a esto:
function chequearFinDeNivel(){
if (piedras.length==0) {
cambioEstadoApp(ESTADO_NUEVO_NIVEL); }
}
Cuando la cantidad de elementos en la matriz piedras es igual a 0,
cambiamos el estado a ESTADO_NUEVO_NIVEL.
Final de juego
No necesitamos comprobar el inal del juego en cada fotograma.
Tenemos que comprobar cuando el jugador pierde una nave. Esto lo
hacemos dentro de la estadoJugadorMuerto():

function estadoJugadorMuerto(){
if (particulas.length > 0 ||
misilesDelJugador.length > 0) {
rellenarFondo();
renderizarTableroPuntuacion();
actualizarPiedras();
actualizarPlatillos();
actualizarParticulas();
actualizarMisilesDelPlatillo();
actualizarMisilesDelJugador();
renderizarPiedras();
renderizarPlatillos();
renderizarParticulas();
renderizarMisilesDelPlatillo();
renderizarMisilesJugador();
contadorDeFotogramas.cuentaFotogramas();

}else{ navesJugador--;
if (navesJugador < 1) {
cambioEstadoApp(ESTADO_JUEGO_TERMINADO);

}else{
resetearJugador();
cambioEstadoApp(ESTADO_JUGADOR_INICIAL);

}
}
}

Esta es la funcin que se llama en cada fotograma durante el estado


ESTADO_JUGADOR_MUERTO. En primer lugar, se comprueba que
ya no estn las partculas de la explosin en la pantalla de juego. Esto
nos asegura que el juego no terminar hasta que la nave del jugador
ha terminado de explotar. Tambin comprobamos que a todos los
misiles de los jugadores se les han terminado su tiempo de vida.
Hacemos esto para que podamos comprobar si hay colisiones de las
piedras con los misiles del jugador y colisiones de piedras contra los
platillos. De esta manera el jugador puede ganar una nave extra antes
de llamar a la variable navesJugador.
Cuando las partculas de la explosin y los misiles del jugador han
salido de la pantalla de juego, restamos 1 de la variable
navesJugador y luego cambiamos el estado de la aplicacin a
ESTADO_JUEGO_TERMINADO si el nmero de naves del jugador
es menor que 1.

Adjudicar naves extras a los jugadores


Queremos premiar a los jugadores con naves adicionales cada cierto
tiempo basado en su puntuacin. Hacemos esto mediante el
establecimiento de una cantidad de puntos que el jugador debe
alcanzar para ganar un nueva nave, esto tambin ayuda a mantener
un recuento del nmero de naves ganadas:

function chequearParaNaveExtra() {
navesJugador++; naveExtraGanada++; }
}

Llamamos a esta funcin en cada fotograma. El jugador gana una nave


adicional si la variable puntuacion/puntosParaNaveExtra
(los decimales se eliminaron) es mayor que el nmero de naves
ganadas. En nuestro juego, hemos ijado el valor de la variable
puntosParaNaveExtra en 10000. Cuando el juego comienza,la
variable naveExtraGanada es 0. Cuando la puntuacin del
jugador es 10000 o ms,puntuacion/puntosParaNaveExtra
ser igual a 1, la cual es mayor que el valor de la variable
naveExtraGanada que es 0. Una nave adicional se da al jugador,
y el valor naveExtraGanada se incrementa en 1.

Aplicar Deteccin de Colisiones

Estaremos veriicando la caja alrededor de cada objeto cuando


hacemos nuestra deteccin de colisiones. Un cuadro delimitador es el
rectngulo ms pequeo que abarcar las cuatro esquinas de un
objeto en la lgica del juego. Hemos creado una funcin para ello:

function colisionCuadroDelimitador(objeto1,
objeto2) { var izquierda1 = objeto1.x;
var izquierda2 = objeto2.x;
var derecha1 = objeto1.x + objeto1.width; var
derecha2 = objeto2.x + objeto2.width; var
superior1 = objeto1.y;
var superior2 = objeto2.y;
var inferior1 = objeto1.y + objeto1.height;
var inferior2 = objeto2.y + objeto2.height;

if (inferior1 < superior2) return(false);


if (superior1 > inferior2) return(false);

if (derecha1 < izquierda2) return(false);


if (izquierda1 > derecha2) return(false);

return(true);
}

Podemos pasar dos objetos cualesquiera de los muchos que se


encuentran en la pantalla de juego a esta funcin como parmetros,
siempre y cuando cada uno contenga los atributos x, y, width y
height. Si los dos objetos se superponen, la funcin devuelve un
valor true. De lo contrario, devolver false. La funcin
chequearColisin() para nuestro juego Defensa Espacial es
un poco complicada de entender a priori, debe examinarse con mucho
cuidado y detenimiento. Al inal de la seccin escribiremos el cdigo
completo de nuestra funcin, per antes, vamos a examinar algunos de
los conceptos bsicos. Una cosa que usted notar es el uso de
etiquetas al lado de las construcciones del bucle for. El uso de
etiquetas, como en la siguiente lnea, puede ayudar a agilizar la
deteccin de colisiones:

piedras: for (var cuentaPiedras =


cantidadPiedras; cuentaPiedras >= 0;
cuentaPiedras--){

Tendremos que recorrer cada uno de los distintos tipos de objetos que
deben ser comprobados uno contra el otro. Pero no queremos
comprobar un objeto que fue destruido previamente contra otros
objetos. Para asegurarse de que hacemos la menor cantidad de
controles de colisin necesarias, hemos implementado una rutina que
utiliza la etiqueta y la sentencia break.
Esta es la lgica de nuestra rutina para detectar colisiones:
1. Creamos una etiqueta piedras: luego pasamos un bucle a travs de
la matriz piedras. 2. Creamos una etiqueta misiles: La etiqueta debe
estar en el interior de la iteracin piedras, y recorrer la matriz
misilesDelJugador.
3. Hacer un cuadro delimitador de deteccin de colisiones entre la
ltima piedra y el ltimo misil. Tenga en cuenta que el ciclo que
comienza en el inal de cada matriz para que podamos eliminar los
elementos (cuando se producen colisiones) de la matriz sin afectar a
miembros de la matriz que no han sido chequeados todava.
4. Si una piedra y un misil chocan, sacarlos desde sus respectivas
matrices, y luego llamar a la sentencia break en las rocas y en los
misiles. Tenemos que aplicar la sentencia break de nuevo al
siguiente elemento en una matriz para cualquier tipo de objeto que se
elimina.
5. Continuar recorriendo la matriz misiles hasta que todos hayan sido
veriicados contra la piedra actual (a menos que ya se le haya aplicado
la sentencia break cuando fue disparado y removido en una colisin
piedras/misiles).
6. Comprobar cada platillo, cada misil del platillo, y el jugador contra
cada una de las piedras. El jugador no necesita una etiqueta, porque
slo hay una instancia jugador.
Los platillos y misilesDelPlatillo seguirn la misma
lgica que los misiles. Si se produce una colisin entre un platillo y
una piedra, aplicamos la sentencia break de nuevo a sus respectivas
etiquetas despus eliminamos los objetos de sus respectivas matrices.
7. Despus de haber chequeado las piedras contra todos los otros
objetos del juego, chequeamos los misilesDelJugador contra
los platillos, usando la misma lgica bsica del ciclo de etiquetas,
comenzando el ciclo por el ltimo elemento de las matrices y
aplicandoles la sentencia break nuevamente a las etiquetas cuando
hayan sido eliminados objetos de la pantalla de juego.
8. Chequear los misilesDelPlatillo contra el jugador de la
misma manera.

Con los aos se ha encontrado que esta es una manera muy efectiva
de comprobar mltiples matrices de objetos, unos contra otros. Es cierto
que no es la nica forma de hacerlo. Ahora bien, si usted no se siente
cmodo trabajando con las etiquetas en los bucles, puede usar un
mtodo como el siguiente:

1. Agregar un atributo Hit booleano a cada uno de los objetos y


conigurarlos como false cuando estos objetos son creados.
2. Pasar un bucle a travs de las piedras y chequearlos contra los
otros objetos del juego. Esta vez la direccin (hacia atrs o hacia
adelante) a travs del bucle, no es importante.
3. Antes de llamar a la funcin
colisionCuadroDelimitador(), debes estar seguro de que
cada atributo Hit de los objetos esta conigurado como false. Si no es
as, omite la comprobacin de colisin.
4. Si los objetos colisionan, se debe conigurar cada atributo Hit de los
objetos en true. No hay necesidad de eliminar objetos de las
matrices esta vez.
5. Pasar un bucle a travs de los misilesDelJugador y
comprobarlos contra los platillos, luego, un bucle a travs de los
platillos para comprobarlos contra el jugador.
6. Cuando toda la rutina de deteccin de colisin est completada.
Pasar nuevamente un bucle a travs de cada objeto del juego (esta
vez hacia atrs) y eliminar todos los objetos con el atributo Hit
conigurado como true.

Hemos usado dos mtodos (y sus variaciones) en cada uno. Mientras


que el segundo mtodo es un poco ms limpio, tambin es cierto, que
este ltimo bucle a travs de todos los objetos podra aadir una
sobrecarga al procesador, cuando se trata de un gran nmero de
objetos. Dejaremos la aplicacin de este segundo mtodo para usted
como un ejercicio, en caso de que quiera probarlos. A continucin
mostraremos el cdigo completo de la aplicacin.

Archivo base HTML para el juego


nombre del archivo - defensaEspacial.html <!DOCTYPE html>
<html>

<head>
<title>
Defensa Espacial </title>
<style>
body {
background: #eaeaea;

}
#contenedor{
width:400px;
margin:0px auto;
padding-top:20px;
}
#canvas {
margin-left: 20px;
margin-right: 0;
margin-bottom: 20px; border: thin solid
#aaaaaa; cursor: crosshair;
}
</style>
</head>

<body>
<div id=contenedor>
<canvas id=canvas width=400 height=600>

Tu navegador no soporta canvas de HTML5


</canvas>
</div>
<script src=defensaEspacial.js></script>
</body>
</html>

nombre del archivo - defensaEspacial.js


window.addEventListener(load,
eventWindowLoaded, false); function
eventWindowLoaded() {

canvasApp();
}

function canvasApp(){
var canvas =
document.getElementById(canvas); if
(!canvas || !canvas.getContext) {

return;
}
var context = canvas.getContext(2d);

if (!context) { return;
}

//estados de la aplicacin
const ESTADO_TITULO_DEL_JUEGO = 0;
const ESTADO_NUEVO_JUEGO = 1; const
ESTADO_NUEVO_NIVEL = 2; const
ESTADO_JUGADOR_INICIAL = 3; const
ESTADO_NIVEL_DEL_JUEGO = 4; const
ESTADO_JUGADOR_MUERTO = 5; const
ESTADO_JUEGO_TERMINADO = 6; var
estadoActualDeJuego = 0;
var funcionActualEstadoDeJuego=null;

//titulos en pantalla
var titulosIniciales=false;
//objetos del juego

//entorno de juego
var puntuacion=0;
var nivel=0;
var puntosParaNaveExtra=10000; var
naveExtraGanada=0;
var navesJugador=3;

//campo de juego var xMin=0;


var xMax=400; var yMin=0;
var yMax=600; var
puntosPiedrasMedianas=75; var
puntosPiedrasPequenas=100; var
puntosPlatillos=300;

//valores de puntuacin var


puntosPiedrasGrandes=50;
//constantes para la escala de las
piedras const ROCK_SCALE_LARGE=1;
const ROCK_SCALE_MEDIUM=2;
const ROCK_SCALE_SMALL=3;

//crear objetos del juego y las


matrices var jugador={};
var piedras=[];
var platillos=[];
var misilesDelJugador=[];
var particulas=[];
var misilesDelPlatillo=[];

var nivelAjusteVelocidadMaxPiedra=1;
var nivelPlatilloMax = 1;

var nivelPromedioAparicionPlatillo=25;
var nivelVelocidadPlatillo=1;
var nivelRetrasoDisparoPlatillo=300;
var nivelPromedioDisparoPlatillo=30;
var nivelVelocidadMisilPlatillo=1;

//teclas presionadas o pulsadas var


listaTeclasPres=[];

function iniciarJuego(){
funcionActualEstadoDeJuego();
}

function cambioEstadoApp(nuevoEstado)
{ estadoActualDeJuego = nuevoEstado;
switch (estadoActualDeJuego) { break;

caseESTADO_TITULO_DEL_JUEGO:
funcionActualEstadoDeJuego=
estadoTituloJuego; break;
case ESTADO_NUEVO_JUEGO:
funcionActualEstadoDeJuego =
estadoNuevoJuego; break;
case ESTADO_NUEVO_NIVEL:
funcionActualEstadoDeJuego =
estadoNuevoNivel; break;
caseESTADO_JUGADOR_INICIAL:
funcionActualEstadoDeJuego =
estadoJugadorInicial; break;
case ESTADO_NIVEL_DEL_JUEGO:
funcionActualEstadoDeJuego =
estadoNivelDelJuego; break;
case ESTADO_JUGADOR_MUERTO:
funcionActualEstadoDeJuego =
estadoJugadorMuerto;
case ESTADO_JUEGO_TERMINADO:
funcionActualEstadoDeJuego =
estadoJuegoTerminado; break;
}
}
function estadoTituloJuego() { if
(titulosIniciales !=true){
rellenarFondo();

titulosIniciales=true; }else{
//esperando click en la barra de
espacio
if (listaTeclasPres[32]==true){
ConsoleLog.log(espacio presionado);
cambioEstadoApp(ESTADO_NUEVO_JUEGO);
titulosIniciales=false;

}
}
}
function estadoNuevoJuego(){
ConsoleLog.log(estadoNuevoJuego);

nivel=0;
puntuacion=0;
navesJugador=3;
jugador.velocidadMax=5;
jugador.width=30;
jugador.height=20;
jugador.widthMedio=15;
jugador.heightMedio=10;
jugador.velocidadDeRotacion=5;
//cuantos grados gira la nave
jugador.aceleracionAvance= .05;
jugador.retrasoMisilFotograma = 5;
jugador.avance = false;

rellenarFondo();
renderizarTableroPuntuacion();
cambioEstadoApp(ESTADO_NUEVO_NIVEL);

function estadoNuevoNivel(){ piedras=


[];
platillos=[];
misilesDelJugador=[];
particulas=[];
misilesDelPlatillo=[];
nivel++;
nivelAjusteVelocidadMaxPiedra = nivel
* .25; if
(nivelAjusteVelocidadMaxPiedra > 3){

nivelAjusteVelocidadMaxPiedra = 3; }
if (nivelPlatilloMax > 5){
nivelPlatilloMax = 5;
}
nivelPromedioAparicionPlatillo = 10 +
3 * nivel;
if (nivelPromedioAparicionPlatillo >
35){
nivelPromedioAparicionPlatillo=35;
}
nivelVelocidadPlatillo = 1 + .5 *
nivel;
if (nivelVelocidadPlatillo > 5){
nivelVelocidadPlatillo = 5;
}
nivelRetrasoDisparoPlatillo = 120 - 10
* nivel;
if (nivelRetrasoDisparoPlatillo < 20)
{ nivelRetrasoDisparoPlatillo = 20;
}

nivelPromedioDisparoPlatillo = 20 + 3
* nivel; if
(nivelPromedioDisparoPlatillo < 50) {
nivelPromedioDisparoPlatillo = 50; }
nivelVelocidadMisilPlatillo = 1 +
.2*nivel;
if (nivelVelocidadMisilPlatillo > 4){
nivelVelocidadMisilPlatillo = 4;

}
//crear el nivel de las piedras
for (var contarNuevaPiedra = 0;
contarNuevaPiedra < nivel+3;

contarNuevaPiedra++){
varnuevaPiedra={};

nuevaPiedra.scale=1;
//scale
//1=large
//2=medium
//3=small
//estos se pueden usar como, el
divisor para el nuevo tamao //50/1=50
//50/2=25
//50/3=16
nuevaPiedra.width=50;
nuevaPiedra.height=50;
nuevaPiedra.widthMedio=25;
nuevaPiedra.heightMedio=25;

//todas las nuevas piedras se inician


en la esquina superior izquierda
//para seguridad de la nave del
jugador
//ConsoleLog.log(nuevaPiedra.x= +
nuevaPiedra.x);

//ConsoleLog.log(nuevaPiedra.y= +
nuevaPiedra.y); nuevaPiedra.dx=
(Math.random()*2)+nivelAjusteVelocidadM
if (Math.random() < .5){

nuevaPiedra.dx *= -1;
}
nuevaPiedra.dy=
(Math.random()*2)+nivelAjusteVelocidadM
if (Math.random()<.5){

nuevaPiedra.dy*=-1;
}
//velocidad de rotacin y direccin
nuevaPiedra.rotacionInc=
(Math.random()*5)+1;
if (Math.random()<.5){

nuevaPiedra.rotacionInc *= -1;
}
nuevaPiedra.valorPuntuacion =
puntosPiedrasGrandes;
nuevaPiedra.rotacion = 0;

piedras.push(nuevaPiedra);
//ConsoleLog.log(piedras creadas
rotacionInc= +
nuevaPiedra.rotacionInc);
}
resetearJugador();
cambioEstadoApp(ESTADO_JUGADOR_INICIAL)

}
function estadoJugadorInicial(){

rellenarFondo();
renderizarTableroPuntuacion();
if (jugador.alpha < 1){

jugador.alpha += .02;
context.globalAlpha = jugador.alpha;

}else{
cambioEstadoApp(ESTADO_NIVEL_DEL_JUEGO)
}

renderizarNaveJugador(jugador.x,
jugador.y, 270, 1);
context.globalAlpha=1;
actualizarPiedras();
renderizarPiedras();

} chequearFinDeNivel();
contadorDeFotogramas.cuentaFotogramas()

function estadoNivelDelJuego(){
chequearTeclas();
actualizar();
renderizar();
chequearColisiones();
chequearParaNaveExtra();

function resetearJugador() {
jugador.rotacion = 270; jugador.x = .5
* xMax; jugador.y = .5 * yMax;

jugador.avanceY = 0;

jugador.moverY = 0;
jugador.alpha = 0;
jugador.cuentaMisilesPorFotograma=0;

}
function chequearParaNaveExtra() {
navesJugador++; naveExtraGanada++; }
}
function chequearFinDeNivel(){
if (piedras.length==0) {
cambioEstadoApp(ESTADO_NUEVO_NIVEL); }
}

function estadoJugadorMuerto(){
if (particulas.length > 0 ||
misilesDelJugador.length > 0) {
rellenarFondo();
renderizarTableroPuntuacion();
actualizarPiedras();
actualizarPlatillos();
actualizarParticulas();
actualizarMisilesDelPlatillo();
actualizarMisilesDelJugador();
renderizarPiedras();
renderizarPlatillos();
renderizarParticulas();
renderizarMisilesDelPlatillo();
renderizarMisilesJugador();
contadorDeFotogramas.cuentaFotogramas()

}else{ navesJugador--;
if (navesJugador < 1) {
cambioEstadoApp(ESTADO_JUEGO_TERMINADO)
}else{

resetearJugador();
cambioEstadoApp(ESTADO_JUGADOR_INICIAL)
} }
function estadoJuegoTerminado() {
ConsoleLog.log(Estado juego
terminado);
rellenarFondo();
renderizarTableroPuntuacion();

}else{ //esperar por click en la barra


de espacio if (listaTeclasPres[32] ==
true){

ConsoleLog.log(espacio presionado);
cambioEstadoApp(ESTADO_TITULO_DEL_JUEGO
} }
}
function rellenarFondo() {
// dibujar el fondo y los textos
}
context.font = 15px sans-serif;
context.textBaseline = top;
}
function renderizarTableroPuntuacion()
{
renderizarNaveJugador(200,10,270,0.5);
contadorDeFotogramas.ultimoContadorDeFo
}
function chequearTeclas() { //chequear
las teclas pulsadas
if (listaTeclasPres[38]==true){
//avance
var angulosEnRadianes =
jugador.rotacion * Math.PI / 180;
jugador.avanceY =
Math.sin(angulosEnRadianes);
var moverYNuevo = jugador.moverY +
jugador.aceleracionAvance *
jugador.avanceY;
(moverYNuevo*moverYNuevo));
if (velocidadActual <
jugador.velocidadMax) {

jugador.moverY = moverYNuevo; }
jugador.avance = true;

}else{
jugador.avance = false;
}
if (listaTeclasPres[37]==true) {
//rotar direccion contraria a las
agujas del reloj jugador.rotacion -=
jugador.velocidadDeRotacion;

if (listaTeclasPres[39]==true) {
//rotar direccion a las agujas del
reloj jugador.rotacion +=
jugador.velocidadDeRotacion;

if (listaTeclasPres[32]==true) {
//ConsoleLog.log(jugador.cuentaMisiles
= +
//jugador.cuentaMisilesPorFotograma);
//ConsoleLog.log(jugador.retrasoMisilF
= +
//jugador.retrasoMisilFotograma);
if (jugador.cuentaMisilesPorFotograma
> jugador.retrasoMisilFotograma){

misilDisparadoPorJugador();
jugador.cuentaMisilesPorFotograma = 0;
}
}
}

function actualizar() {
actualizarJugador();
actualizarMisilesDelJugador();
actualizarPiedras();
actualizarPlatillos();
actualizarMisilesDelPlatillo();
actualizarParticulas();

function renderizar() {
rellenarFondo();
renderizarTableroPuntuacion();
renderizarNaveJugador(jugador.x,jugador
renderizarMisilesJugador();
renderizarPiedras();
renderizarPlatillos();
renderizarMisilesDelPlatillo();
renderizarParticulas();
function actualizarJugador() {
jugador.cuentaMisilesPorFotograma++;
jugador.y+=jugador.moverY;

if (jugador.x > xMax) {


jugador.x =- jugador.width;
}else if (jugador.x <- jugador.width){
jugador.x = xMax;
}

if (jugador.y > yMax) {


jugador.y=-jugador.height;
}else if (jugador.y <- jugador.height)
{ jugador.y = yMax;
}
}

function actualizarMisilesDelJugador()
{
var misilesJugadorTemp={};
var
cantMisilesJugador=misilesDelJugador.le
1;
ConsoleLog.log(actualizar cantidad de
misiles = + cantMisilesJugador); for
(var
contarMisilesJugador=cantMisilesJugador

contarMisilesJugador--){

ConsoleLog.log(actualizar misiles del


jugador + contarMisilesJugador);
misilesJugadorTemp=misilesDelJugador[co
misilesJugadorTemp.x+=misilesJugadorTem
misilesJugadorTemp.y+=misilesJugadorTem
if (misilesJugadorTemp.x > xMax) {
misilesJugadorTemp.x=-
misilesJugadorTemp.width;
}else if (misilesJugadorTemp.x<-
misilesJugadorTemp.width){
misilesJugadorTemp.x=xMax;
}

if (misilesJugadorTemp.y > yMax) {


misilesJugadorTemp.y=-
misilesJugadorTemp.height;
}else if (misilesJugadorTemp.y<-
misilesJugadorTemp.height){
misilesJugadorTemp.y=yMax;
}

misilesJugadorTemp.lifeCtr++;
if (misilesJugadorTemp.lifeCtr >
misilesJugadorTemp.life){
ConsoleLog.log(removermisiles del
jugador);
misilesDelJugador.splice(contarMisilesJ
misilesJugadorTemp=null;
}
}
}

function actualizarPiedras(){ for (var


contarPiedras=cantidadPiedras;contarPie
contarPiedras--){
piedrasTemp=piedras[contarPiedras];
piedrasTemp.x += piedrasTemp.dx;
piedrasTemp.y += piedrasTemp.dy;
piedrasTemp.rotacion+=piedrasTemp.rotac
ConsoleLog.log(rock rotacionInc=+
piedrasTemp.rotacionInc)
ConsoleLog.log(rock rotacion=+
piedrasTemp.rotacion) if
(piedrasTemp.x > xMax) {

var piedrasTemp={};
var cantidadPiedras=piedras.length-1;
ConsoleLog.log(actualizar cantidad de
piedras = + cantidadPiedras);

piedrasTemp.x=xMin-piedrasTemp.width;
}else if (piedrasTemp.x<xMin-
piedrasTemp.width){
piedrasTemp.x=xMax;
}
if (piedrasTemp.y > yMax) {
piedrasTemp.y=yMin-piedrasTemp.width;
}else if (piedrasTemp.y<yMin-
piedrasTemp.width){
piedrasTemp.y=yMax;
}

ConsoleLog.log(actualizar piedras +
contarPiedras); }
}
function actualizarPlatillos() {
//lo primero es chequear para saber si
queremos un platillo
if (platillos.length<
nivelPlatilloMax){

<= nivelPromedioAparicionPlatillo){
ConsoleLog.log(crear platillo); var
nuevoPlatillo={};

nuevoPlatillo.width=28;
nuevoPlatillo.height=13;
nuevoPlatillo.heightMedio=6.5;
nuevoPlatillo.widthMedio=14;
nuevoPlatillo.valorPuntuacion=puntosPla
nuevoPlatillo.disparosPromedios =
nivelPromedioDisparoPlatillo;
nuevoPlatillo.retrasoDisparo=
nivelRetrasoDisparoPlatillo;
nuevoPlatillo.cuentaDisparosRetrasos=0;
nuevoPlatillo.velocidadMisil =
nivelVelocidadMisilPlatillo;
nuevoPlatillo.dy=(Math.random()*2);

nuevoPlatillo.dy*=-1; }
//seleccionar entre los extremos
derecho e izquierdo para empezar
//comenzar en la derecha e ir a la
izquierda nuevoPlatillo.x=450;
nuevoPlatillo.dx=-1*nivelVelocidadPlati

}else{ //izquierda a derecha


nuevoPlatillo.x=-50;
nuevoPlatillo.dx=nivelVelocidadPlatillo

nuevoPlatillo.velocidadMisil=
nivelVelocidadMisilPlatillo;
nuevoPlatillo.retrasoDisparo=
nivelRetrasoDisparoPlatillo;
nuevoPlatillo.disparosPromedios=
nivelPromedioDisparoPlatillo;
platillos.push(nuevoPlatillo); }
}

var platilloTemp = {};


var cantidadPlatillos =
platillos.length - 1;
ConsoleLog.log(actualizar cantidad de
platillos= +

cantidadPlatillos);
for (var
contarPlatillos=cantidadPlatillos;conta
contarPlatillos--){
platilloTemp =
platillos[contarPlatillos];

//debe disparar el platillo


platilloTemp.cuentaDisparosRetrasos++;

platilloTemp.disparosPromedios &&
platilloTemp.cuentaDisparosRetrasos >
platilloTemp.retrasoDisparo ){
misilDisparadoPorPlatillo(platilloTemp)
platilloTemp.cuentaDisparosRetrasos=
0;

}
var remover = false;
platilloTemp.x += platilloTemp.dx;
platilloTemp.y += platilloTemp.dy;

//remover los platillos en los


extremos izquierdo y derecho if
(platilloTemp.dx > 0 && platilloTemp.x
> xMax){ remover=true;
}else if (platilloTemp.dx < 0 &&
platilloTemp.x < xMin
platilloTemp.width){
remover=true;
}

//recuperar platillos fuera de los


bordes verticales if (platilloTemp.y >
yMax || platilloTemp.y < yMin
platilloTemp.width) {
platilloTemp.dy *= -1; }

if (remover==true) {
//remover el platillos
ConsoleLog.log(platillo removido);
platillos.splice(contarPlatillos,1);
platilloTemp=null;

}
}
}

function
actualizarMisilesDelPlatillo() {
var misilesDelPlatilloTemp={};
var cantidadMisilesDelPlatillo =
misilesDelPlatillo.length-1; for (var
contarMisilesDelPlatillo =
cantidadMisilesDelPlatillo;

contarMisilesDelPlatillo >= 0;
contarMisilesDelPlatillo--){

ConsoleLog.log(actualizar misiles del


platillo + contarMisilesDelPlatillo);
misilesDelPlatilloTemp=
misilesDelPlatillo[contarMisilesDelPlat
misilesDelPlatilloTemp.x +=
misilesDelPlatilloTemp.dx;
misilesDelPlatilloTemp.y +=
misilesDelPlatilloTemp.dy;
if (misilesDelPlatilloTemp.x > xMax) {
misilesDelPlatilloTemp.x=
misilesDelPlatilloTemp.width;
}else if (misilesDelPlatilloTemp.x <
misilesDelPlatilloTemp.width){
misilesDelPlatilloTemp.x = xMax;
}

if (misilesDelPlatilloTemp.y > yMax) {


misilesDelPlatilloTemp.y =
misilesDelPlatilloTemp.height;
}else if (misilesDelPlatilloTemp.y <
misilesDelPlatilloTemp.height){
misilesDelPlatilloTemp.y = yMax;

}
misilesDelPlatilloTemp.lifeCtr++;
if (misilesDelPlatilloTemp.lifeCtr >

misilesDelPlatilloTemp.life){
//remover
misilesDelPlatillo.splice(contarMisiles
1); misilesDelPlatilloTemp=null;

}
}

}
var remover = false;
particulasTemp =
particulas[contarParticulas];
particulasTemp.x += particulasTemp.dx;
particulasTemp.y += particulasTemp.dy;

function actualizarParticulas() {
var particulasTemp={};
var cantidadParticulas =
particulas.length-1;
ConsoleLog.log(particulas = +
cantidadParticulas);
for (var contarParticulas =
cantidadParticulas; contarParticulas
>= 0;

contarParticulas--){

particulasTemp.lifeCtr++;
ConsoleLog.log(particulas.lifeCtr= +
particulasTemp.lifeCtr);
try{ if(particulasTemp.lifeCtr >
particulasTemp.life){ remover=true;

} else if ((particulasTemp.x > xMax)


|| (particulasTemp.x < xMin) ||
(particulasTemp.y > yMax) ||
(particulasTemp.y < yMin)){

remover=true;
}
}
catch(err){

ConsoleLog.log (error en
particulas);
ConsoleLog.log(particulas: +
contarParticulas);
}

if (remover) {
particulas.splice(contarParticulas,1);
particulasTemp=null;

}
} }

function
renderizarNaveJugador(x,y,rotacion,
scale) {
//transformacin
var angulosEnRadianes = rotacion *
Math.PI / 180; context.save();
//salvar el estado actual en la pila
context.setTransform(1,0,0,1,0,0); //
resetear la identidad
//mover el canvas original al centro
del jugador
context.translate(x +
jugador.widthMedio,
y+jugador.heightMedio);
context.rotate(angulosEnRadianes);
context.scale(scale,scale);

//dibujarNave

//dibujar la nave espacial estatica


(jugador) context.strokeStyle = red;
context.moveTo(0,0);
context.lineTo(-10,-15);
context.moveTo(-10,-15);

context.beginPath();
context.moveTo(-10,-15);
context.lineTo(15,0);
context.lineTo(-10,15);
context.lineTo(0,0);

if (jugador.avance == true && scale ==


1) {
//comprobar escala == 1 para saber que
la nave no esta en avance
context.moveTo(-4,-2);
context.lineTo(-4,1);
context.moveTo(-5,-1);
context.lineTo(-10,-1);
context.moveTo(-5,0);
context.lineTo(-10,0);
}
context.stroke();

context.closePath();
//restaurar el contexto
context.restore(); //estado anterior a
la pantalla }

function renderizarMisilesJugador() {
var misilesJugadorTemp = {};
var cantMisilesJugador =
misilesDelJugador.length-1;
ConsoleLog.log(renderizar
cantMisilesJugador= +
cantMisilesJugador); for (var
contarMisilesJugador =
cantMisilesJugador;

contarMisilesJugador >= 0;
contarMisilesJugador--){
//ConsoleLog.log(dibujar misil del
jugador +
//contarMisilesJugador);
misilesJugadorTemp =
misilesDelJugador[contarMisilesJugador]
context.save(); //salvar el estado
actual en la pila
context.setTransform(1,0,0,1,0,0); //
resetear la identidad

//trasladar el canvas original al


centro del jugador
context.translate(misilesJugadorTemp.x+
misilesJugadorTemp.y+1);
context.strokeStyle = cyan;
context.beginPath();

//dibujar compensado por medio de


todo.Zero relativo 1/2 es de 15
context.moveTo(-1,-1);
context.lineTo(1,-1);
context.lineTo(1,1);
context.lineTo(-1,1);
context.lineTo(-1,-1);

context.stroke();
context.closePath();
context.restore(); //recuperar viejo
estado de la pantalla
}

}
contarPiedras--){
piedrasTemp = piedras[contarPiedras];
var angulosEnRadianes =
piedrasTemp.rotacion * Math.PI / 180;
ConsoleLog.log(renderizar rotacion de
las piedras +

function renderizarPiedras() {
var piedrasTemp = {};
var cantPiedras=piedras.length-1;
for (var contarPiedras = cantPiedras;
contarPiedras >= 0;

(piedrasTemp.rotacion));
context.save(); //salvar el estado
actual en la pila
context.setTransform(1,0,0,1,0,0); //
resetear la identidad

//trasladar el canvas original al


centro del jugador
context.translate(piedrasTemp.x +
piedrasTemp.widthMedio, piedrasTemp.y
+ piedrasTemp.heightMedio);

ConsoleLog.log(renderizar piedra x+
(piedrasTemp.x+
piedrasTemp.widthMedio));
ConsoleLog.log(renderizar piedra y+
(piedrasTemp.y+
piedrasTemp.heightMedio));
context.rotate(angulosEnRadianes);
context.strokeStyle= brown;

context.beginPath();

context.moveTo(-
(piedrasTemp.widthMedio-1),
(piedrasTemp.heightMedio-1));
context.lineTo((piedrasTemp.widthMedio-
1), (piedrasTemp.heightMedio-1));
context.lineTo((piedrasTemp.widthMedio-
1), (piedrasTemp.heightMedio-1));
context.lineTo(-
(piedrasTemp.widthMedio-1),
(piedrasTemp.heightMedio-1));
context.lineTo(-
(piedrasTemp.widthMedio-1),
(piedrasTemp.heightMedio-1));
context.stroke();
context.closePath();
context.restore(); //restaurar el
estado antiguo en la pantalla }
}

function renderizarPlatillos() {
varplatilloTemp={};
var cantidadPlatillos =
platillos.length-1;
for (var contarPlatillos =
cantidadPlatillos; contarPlatillos >=
0;

contarPlatillos--){
ConsoleLog.log(platillos: +
contarPlatillos); platilloTemp =
platillos[contarPlatillos];

context.save(); //salvar el estado


actual en la pila
context.setTransform(1,0,0,1,0,0); //
resetear la identidad
//trasladar el canvas original al
centro del jugador
//context.translate(this.x+widthMedio,t
context.translate(platilloTemp.x,
platilloTemp.y); context.strokeStyle =
green;
context.beginPath(); //no se movi
hasta el centro, ya que se dibuja en
el espacio exacto

context.moveTo(4,0);
context.lineTo(9,0);
context.lineTo(12,3);
context.lineTo(13,3);
context.moveTo(13,4);
context.lineTo(10,7);
context.lineTo(3,7);
context.lineTo(1,5);
context.lineTo(12,5);
context.moveTo(0,4);
context.lineTo(0,3);
context.lineTo(13,3);
context.moveTo(5,1);
context.lineTo(5,2);
context.moveTo(8,1);
context.lineTo(8,2);
context.moveTo(2,2);
context.lineTo(4,0);

context.stroke();
context.closePath();
context.restore(); //recuperar el
viejo estado de la pantalla }
}

function
renderizarMisilesDelPlatillo() {
var misilesDelPlatilloTemp = {};
var cantMisilesPlatillo =
misilesDelPlatillo.length-1;
//ConsoleLog.log(misilesDelPlatillo =
+ misilesDelPlatillo.length); for
(var contarMisilesPlatillo =
cantMisilesPlatillo;

contarMisilesPlatillo >= 0;
contarMisilesPlatillo--){
//ConsoleLog.log(dibujar misiles del
platillo + cantMisilesPlatillo);
misilesDelPlatilloTemp=
misilesDelPlatillo[contarMisilesPlatill
context.save(); //salvar el estado
actual en la pila
context.setTransform(1,0,0,1,0,0); //
resetear la identidad

//trasladar el canvas original al


centro del jugador
context.translate(misilesDelPlatilloTem
+ 1, misilesDelPlatilloTemp.y+ 1);
context.strokeStyle= green;

context.beginPath();
context.lineTo(-1,1);
context.lineTo(-1,-1);

//dibujar compensado por medio de


todo. Zero relativa media es de 15
context.moveTo(-1,-1);
context.lineTo(1,-1);
context.lineTo(1,1);

context.stroke();
context.closePath();
context.restore(); //restaurar el
estado anterior en la pantalla

} }
function renderizarParticulas() {

var particulasTemp={};
var
cantidadParticulas=particulas.length-
1;
for (var contarParticula =
cantidadParticulas; contarParticula >=
0;

contarParticula--){
particulasTemp =
particulas[contarParticula];
context.save(); //save current state
in stack
context.setTransform(1,0,0,1,0,0); //
reset to identity

//translate the canvas origin to the


center of the player
context.translate(particulasTemp.x,
particulasTemp.y);
context.strokeStyle= orange;

context.beginPath();
context.moveTo(0,0);
context.lineTo(1,1);

context.stroke();
context.closePath();
context.restore(); //pop old state on
to screen
}
}
function chequearColisiones() {
//Pasar un bucle a traves de las
piedras y luego a los misilies. Siem

var piedrasTemporales={};
var cantidadPiedras = piedras.length-
1;
var misilesJugadorTemp = {};
var cantidadMisilesJugador =
misilesDelJugador.length-1; var
cantidadPlatillos = platillos.length-
1;
var platillosTemp = {};
var cantidadMisilesPlatillo =
misilesDelPlatillo.length-1;
piedrasTemporales =
piedras[cuentaPiedras];

piedras: for (var cuentaPiedras =


cantidadPiedras; cuentaPiedras >= 0;
cuentaPiedras--){
misiles:for (var cuentaMisilesJugador
= cantidadMisilesJugador;
cuentaMisilesJugador >= 0;
cuentaMisilesJugador--){
misilesJugadorTemp =
misilesDelJugador[cuentaMisilesJugador]

if
(colisionCuadroDelimitador(piedrasTempo
misilesJugadorTemp)){
//ConsoleLog.log(colision con
piedra);
crearExplosion(piedrasTemporales.x +
piedrasTemporales.widthMedio,
piedrasTemporales.y

+ piedrasTemporales.heightMedio, 10);
if (piedrasTemporales.scale < 3) {
dividirPiedras(piedrasTemporales.scale+
piedrasTemporales.x,
piedrasTemporales.y);

}
agregarAPuntuacion(piedrasTemporales.va
misilesDelJugador.splice(cuentaMisilesJ
misilesJugadorTemp = null;

piedras.splice(cuentaPiedras, 1);
piedrasTemporales=null;
break piedras; break misiles; }
}

platillos:for (var cuentaPlatillos =


cantidadPlatillos; cuentaPlatillos >=
0; cuentaPlatillos--){
platillosTemp=platillos[cuentaPlatillos

if
(colisionCuadroDelimitador(piedrasTempo
platillosTemp)){
ConsoleLog.log(colision con roca);
crearExplosion(platillosTemp.x +

platillosTemp.widthMedio,
platillosTemp.y +
platillosTemp.heightMedio, 10);
crearExplosion(piedrasTemporales.x +
piedrasTemporales.widthMedio,piedrasTem
+ piedrasTemporales.heightMedio, 10);

if (piedrasTemporales.scale < 3) {
dividirPiedras(piedrasTemporales.scale+
piedrasTemporales.x,
piedrasTemporales.y);

}
platillos.splice(cuentaPlatillos, 1);
platillosTemp = null;
break piedras;
break platillos;

piedras.splice(cuentaPiedras, 1);
piedrasTemporales = null;

}
}
//misiles del platillo contra las
piedras
//esto se hace aqu, as que no
tenemos que recorrer las rocas //de
nuevo ya que probablemente la matriz
seria mayor misilesPlatillos:for (var
cuentaMisilesPlatillo =

cantidadMisilesPlatillo;
cuentaMisilesPlatillo >= 0;
cuentaMisilesPlatillo--){
misilesPlatilloTemp =
misilesDelPlatillo[cuentaMisilesPlatill

if
(colisionCuadroDelimitador(piedrasTempo
misilesPlatilloTemp)){
ConsoleLog.log(colision con piedra);

crearExplosion(piedrasTemporales.x +
piedrasTemporales.widthMedio,piedrasTem
+ piedrasTemporales.heightMedio, 10);

if (piedrasTemporales.scale < 3) {
dividirPiedras(piedrasTemporales.scale
+ 1,
piedrasTemporales.x,piedrasTemporales.y
}
misilesDelPlatillo.splice(cuentaPlatill
1); misilesPlatilloTemp=null;
piedras.splice(cuentaPiedras, 1);
piedrasTemporales=null;

breakpiedras;
break misilesPlatillos; }

}
//chequear jugador contra las rocas

if(colisionCuadroDelimitador(piedrasTem
jugador)){ ConsoleLog.log(colision
jugador);
crearExplosion(piedrasTemporales.x +
piedrasTemporales.widthMedio,
piedrasTemporales.heightMedio, 10);
agregarAPuntuacion(piedrasTemporales.va
if (piedrasTemporales.scale < 3) {
dividirPiedras(piedrasTemporales.scale+
1,
piedrasTemporales.x,piedrasTemporales.y
}
piedras.splice(cuentaPiedras, 1);
piedrasTemporales = null;
//Ahora compruebe jugador contra
platillos y luego platillos contra los
//misiles de jugadores y por ltimo
jugador contra misiles platillo
cantidadMisilesJugador =
misilesDelJugador.length-1;
cantidadPlatillos = platillos.length-
1;
platillos:for (var cuentaPlatillos =
cantidadPlatillos;
cuentaPlatillos >= 0; cuentaPlatillos-
-){
platillosTemp=platillos[cuentaPlatillos

jugadorMuerto(); }
misiles:for (var
cuentaMisilesJugador=cantidadMisilesJug
cuentaMisilesJugador>=0;cuentaMisilesJu
-){
misilesJugadorTemp=misilesDelJugador[cu

if
(colisionCuadroDelimitador(platillosTem
misilesJugadorTemp)){
ConsoleLog.log(colisioncon piedras);
crearExplosion(platillosTemp.x +

platillosTemp.widthMedio,
platillosTemp.y +
platillosTemp.heightMedio, 10);
agregarAPuntuacion(platillosTemp.valorP
misilesDelJugador.splice(cuentaMisilesJ
misilesJugadorTemp = null;
platillos.splice(cuentaPlatillos,1);
platillosTemp = null;
break platillos; break misiles; }
}

//jugador contra platillo


if
(colisionCuadroDelimitador(platillosTem
jugador)){
ConsoleLog.log(colisionjugador);
crearExplosion(platillosTemp.x + 16,
platillosTemp.y + 16, 10);
agregarAPuntuacion(platillosTemp.valorP

platillos.splice(cuentaPiedras,1);
platillosTemp=null;
jugadorMuerto(); }
}
//misiles del platillo contra jugador
cantidadMisilesPlatillo =
misilesDelPlatillo.length-1;

misilesPlatillos:for (var
cuentaMisilesPlatillo =
cantidadMisilesPlatillo;
cuentaMisilesPlatillo >= 0;
cuentaMisilesPlatillo--){
jugadorMuerto();
misilesDelPlatillo.splice(cuentaPlatill
1); misilesPlatilloTemp = null;

misilesPlatilloTemp =
misilesDelPlatillo[cuentaMisilesPlatill
if (colisionCuadroDelimitador(jugador,
misilesPlatilloTemp)){
ConsoleLog.log(misil del platillo
impacta al jugador);
break misilesPlatillos; }
}
}

function misilDisparadoPorJugador(){
ConsoleLog.log(jugador dispara
misil);
var nuevoMisilJugador={};
nuevoMisilJugador.dx=5*Math.cos(Math.PI
(jugador.rotacion)/180);
nuevoMisilJugador.dy=5*Math.sin(Math.PI
(jugador.rotacion)/180);
nuevoMisilJugador.x=jugador.x+jugador.w
nuevoMisilJugador.y=jugador.y+jugador.h
nuevoMisilJugador.life=60;
nuevoMisilJugador.lifeCtr=0;
nuevoMisilJugador.width=2;
nuevoMisilJugador.height=2;
misilesDelJugador.push(nuevoMisilJugado

function
misilDisparadoPorPlatillo(platillo) {
var nuevoMisilPlatillo = {};
nuevoMisilPlatillo.x = platillo.x + .5
* platillo.width; nuevoMisilPlatillo.y
= platillo.y + .5 * platillo.height;

nuevoMisilPlatillo.width=2;
nuevoMisilPlatillo.height=2;
nuevoMisilPlatillo.speed =
platillo.velocidadMisil;

ConsoleLog.log(disparo del
platillo); //fuego al jugador desde
pequeo platillo
var grados = 360 * radianes / (2 *
Math.PI); nuevoMisilPlatillo.dx =
platillo.velocidadMisil *

Math.cos(Math.PI*(grados)/180);
nuevoMisilPlatillo.dy =
platillo.velocidadMisil *
Math.sin(Math.PI*(grados)/180);
nuevoMisilPlatillo.life=160;
nuevoMisilPlatillo.lifeCtr=0;
misilesDelPlatillo.push(nuevoMisilPlati
}
function crearExplosion(x,y,num) {
//crear 10 particulas
for (var
contarParticulas=0;contarParticulas<num
{ var nuevaParticula=new Object();
nuevaParticula.dx=Math.random()*3;
if (Math.random()<.5){
nuevaParticula.dx*=-1;
}
nuevaParticula.dy=Math.random()*3;
if (Math.random()<.5){
nuevaParticula.dy*=-1;
}

function jugadorMuerto() {
ConsoleLog.log(jugador muerto);
crearExplosion(jugador.x+jugador.widthM

jugador.y+jugador.heightMedio,50);
cambioEstadoApp(ESTADO_JUGADOR_MUERTO);

nuevaParticula.lifeCtr=0;
nuevaParticula.x=x;
nuevaParticula.y=y;
ConsoleLog.log(nuevaParticula.life=
+ nuevaParticula.life);
particulas.push(nuevaParticula);

}
}
function
colisionCuadroDelimitador(objeto1,
objeto2) {

var izquierda1 = objeto1.x;


var izquierda2 = objeto2.x;
var derecha1 = objeto1.x +
objeto1.width; var derecha2 =
objeto2.x + objeto2.width; var
superior1 = objeto1.y;
var superior2 = objeto2.y;
var inferior1 = objeto1.y +
objeto1.height; var inferior2 =
objeto2.y + objeto2.height;

if (inferior1 < superior2)


return(false);
if (superior1 > inferior2)
return(false);

if (derecha1 < izquierda2)


return(false);
if (izquierda1 > derecha2)
return(false);

return(true);
}
function dividirPiedras(scale,x,y){
for (var
contarNuevasPiedras=0;contarNuevasPiedr
{ var nuevaPiedra={};
ConsoleLog.log(dividir piedras);

if (scale==2){
nuevaPiedra.valorPuntuacion=puntosPiedr
nuevaPiedra.width=25;
nuevaPiedra.height=25;
nuevaPiedra.widthMedio=12.5;
nuevaPiedra.heightMedio=12.5;

}else {
nuevaPiedra.valorPuntuacion=puntosPiedr
nuevaPiedra.width=16;
nuevaPiedra.height=16;
nuevaPiedra.widthMedio=8;
nuevaPiedra.heightMedio=8;

nuevaPiedra.scale=scale;
nuevaPiedra.x=x;
nuevaPiedra.y=y;
nuevaPiedra.dx=Math.random()*3;
if(Math.random()<.5){
nuevaPiedra.dx*=-1;
}
nuevaPiedra.dy=Math.random()*3;
if(Math.random()<.5){

nuevaPiedra.dy*=-1;
}
nuevaPiedra.rotacionInc=
(Math.random()*5)+1;
if (Math.random()<.5){

nuevaPiedra.rotacionInc*=-1;
}
nuevaPiedra.rotacion=0;
ConsoleLog.log(nueva escala de roca+
(nuevaPiedra.scale));
piedras.push(nuevaPiedra);

}
}

function agregarAPuntuacion(valor){
puntuacion+=valor;
}

document.onkeydown=function(e){
e=e?e:window.event;
ConsoleLog.log(e.keyCode + down);
listaTeclasPres[e.keyCode]=true;

}
//*** inicio de la aplicacin
cambioEstadoApp(ESTADO_TITULO_DEL_JUEGO

document.onkeyup=function(e){
//document.body.onkeyup=function(e){
e=e?e:window.event;
ConsoleLog.log(e.keyCode + up);
listaTeclasPres[e.keyCode]=false;
};

//**** application loop


contadorDeFotogramas = new
ContadorDeFotogramas(); const
PROM_FOTOGRAMA = 45;
var intervaloTiempo =
1000/PROM_FOTOGRAMA; temporizador();

function temporizador(){
iniciarJuego();
window.setTimeout(temporizador,
intervaloTiempo);
}
}
//***** objectos prototype *****

//*** objeto consoleLog


//llamamos al constructor de la clase
function ConsoleLog(){

}
console_log=function(message) {

console.log(message);
}
}
//agregar la funcin clase/estatica
para la clase por asignacin
ConsoleLog.log=console_log;

//*** objecto prototype


contadorDeFotogramas
function ContadorDeFotogramas() {
this.ultimoContadorDeFotogramas = 0;
var tiempo = new Date();
this.ultimoFotograma =
tiempo.getTime();
delete tiempo;
this.contadorF = 0;
}
ContadorDeFotogramas.prototype.cuentaFo
{
var tiempo = new Date();
this.contadorF++;
if (tiempo.getTime()
>=this.ultimoFotograma+1000) {
ConsoleLog.log(evento fotograma);
this.ultimoContadorDeFotogramas =
this.contadorF; this.ultimoFotograma =
tiempo.getTime(); this.contadorF = 0;
}
delete tiempo;
}

El resultado se mostrar mas o menos de esta manera:


imagen 3.5
- Vista del juego Defensa Espacial
Ayuda en linea
En este captulo listaremos una serie de aplicaciones canvas y otras
tantas herramientas tiles para desarrolladores de canvas, que bien
podran ayudar a adquirir ideas para crear grandes aplicaciones
canvas. El objetivo de este captulo no es otro mas que ayudar a
desarrollar el conocimiento adquirido y la habilidad para usarlo,
juntamente con su creatividad, estamos seguros que en el futuro, sern
referentes para otros autores e inspiracin para muchos que se inician
en este fabuloso mundillo. HTML5 Canvas se esta convirtiendo en una
parte muy importante de la world wide web y esto se debe en gran
medida al apoyo de un creciente grupo a nivel mundial de
desarrolladores.

El nmero de interesantes y entretenidas aplicaciones canvas crece


continuamente todos los das. Los desarrolladores estn conectando el
canvas de HTML5 con toda la actividad en la web, experimentando con
las nuevas tcnicas y mezclando el arte con la ciencia.

A continuacin listaremos varios de los mejores sitios encontrados en la


web, incluyendo a algunos que son a su vez coleccin de aplicaciones
canvas y lugares para explorar rpidamente nuevas aplicaciones.

Bomomo(www.bomomo.com)

Descripcin Es una aplicacin que combina el arte controlado con el


movimiento aleatorio de pinceles de mltiples facetas. Es como si usted
tiene procesadores de pequeos canvas en sus manos. Y realmente es
muy divertido y entretenido. Pruebelo usted mismo!.
imagen 4.1 - aplicacin canvas bomomo

Canvas Cycle(www.effectgames.com/demos/canvascycle)

Descripcin
El Canvas Cycle App muestra una serie de escenas en movimiento,
como el agua y la nieve. Es una buena manera de obtener
perspectivas rpida de la variedad de fondos que pueden ser creados
usando canvas.
imagen 4.2 - aplicacin canvas cycle

Chrome Experiments(www.chromeexperiments.com)

Descripcin
Google patrocina un sitio web que contiene una coleccin de algunos
de los mejores

experimentos para desarrolladores que utilizan el canvas de HTML5 y


las tecnologas relacionadas. Para encontrar experimentos de canvas,
buscar en el sitio de canvas . Tal vez haban incluyen una de sus
obras maestras.
imagen 4.3 - sitio web patrocinado por google chrome

Grow a face(www.growaface.com)

Descripcin
Por qu alguien querra hacer crecer una cara? Hay un montn de
razones: tener un poco de diversin, obtener algunas ideas para los
gricos, y obtener ayuda para crear caras que podra utilizar en sus
propias aplicaciones.
imagen 4.4 - aplicacin divertida acerca de rostros y sus
cambios

Burn Canvas (http://guciek.github.com/burn_canvas.html)

Descripcin Se trata de un proyecto de demostracin de cdigo abierto


de la modiicacin basada en pxeles de un canvas.
imagen 4.5- aplicacin de cdigo abierto que muestra la
modiicacin de pixeles

Canvas Sketch (www.gartic.uol.com.br/sketch/)

Descripcin Esta aplicacin muestra cmo se pueden implementar


programas de dibujo tradicionales usando HTML5 Canvas
imagen 4.6- aplicacin dedibujo patrocinado por google chrome

Canvas 3D Engine (http://peterned.home.xs4all.nl/3d/)

Descripcin Este sitio muestra cmo el contexto Canvas 2D puede


simular ambientes 3D sin el uso de WebGL
imagen 4.7- simulacin 3D en un contexto 2D

Canvas Raytracer (http://jupiter909.com/mark/jsrt.html)

Este sitio muestra cmo se puede dibujar supericies soisticadas y


relexiones sobre Descripcin
un canvas sin cargas computacionales WebGL o alta. Trazado de
rayos es una tcnica para la creacin de imgenes relejadas en las
supericies virtuales.
imagen 4.8 - dibujar supericies y relejos en 3D bajo un contexto
2D

Pocket Full of
Canvas(www.nihilogic.dk/labs/pocket_full_of_canvas/#pres

Descripcin Esta aplicacin muestra una serie de efectos del canvas


junto con el cdigo que las genera. Es una gran demostracin y
tambin es til para su kit de herramientas de desarrollador.
imagen 4.9 - Excelente herramienta para desarrolladores
En este seccin, enumeraremos algunas herramientas que pueden
mejorar su vida como un desarrollador de aplicaciones Canvas.

Audacity(http://audacity.sourceforge.net)

Descripcin
Hasta que todos los navegadores sean compatibles con todo los tipo
de archivos de
audio, usted debe, por regla general, incluir varias versiones de sus
archivos de audio en las aplicaciones que construya. Audacity es una
herramienta de sotware libre, de cdigo abierto multiplataforma para
convertir un archivo de audio en varios formatos, incluyendo MP3, OGG
y WAV.
imagen 4.9 - Audacity, aplicacin muy til para convertir formato
de audio.

Can I Use(http://www.caniuse.com)

Descripcin Este sitio web proporciona el estado ms reciente de la


compatibilidad con exploradores para una amplia variedad de
caractersticas y funciones, incluyendo Canvas HTML5

EaselJS(www.createjs.com/#!/EaselJS)

Descripcin
EaselJS es una serie de bibliotecas de JavaScript que se pueden
utilizar para ayudar a simpliicar el desarrollo de Canvas en JavaScript.

Electrotank(www.electrotank.com)
Descripcin
Electrotank proporciona una serie de productos de sotware que
apoyan el desarrollo de juegos sociales multijugador de escritorio y
dispositivos mviles.

Firebug(http://getfirebug.com/)

Descripcin Firebug es una herramienta de sotware libre para la


depuracin de cdigo JavaScript y HTML. Proporciona la capacidad
para establecer puntos de interrupcin, comprueba los valores de
variables, y seguir la ejecucin de cdigo. Usted puede incluirlo como
un add-on para la mayora de los navegadores, incluyendo Firefox,
Chrome, Internet Explorer y Opera.

Gamepad API(https://wiki.mozilla.org/GamepadAPI)

Descripcin El API Gamepad es una especiicacin para el uso de


dispositivos de juego a travs de cdigo JavaScript Canvas

HTML5 Test(http://html5test.com)

Descripcin La pgina web html5test prueba los navegadores de


escritorio y mviles para el estado de su compatibilidad con las
caractersticas de HTML5, como el canvas. Este proratea las
caractersticas individuales y proporciona una puntuacin para el
navegador en todo su conjunto.

Kuler(https://kuler.adobe.com/)
Descripcin El sitio web de Kuler es una herramienta de Adobe para el
desarrollo de paletas de colores y experimentar con combinaciones de
colores.

Miro Video Converter(www.mirovideoconverter.com)

Descripcin Como es en el caso de audio, hasta que todos los


navegadores sean compatibles con todo tipo de archivos de vdeo, es
necesario incluir varias versiones de sus archivos de vdeo en sus
aplicaciones. Miro Video Converter es una herramienta de sotware
libre, de cdigo abierto multiplataforma para convertir un archivo de
vdeo en mltiples formatos, incluyendo MP4, OGG y WebM.

WebGL(http://www.khronos.org/webgl/)

Descripcin
HTML5 Canvas no soporta actualmente un contexto integrado, 3D.
WebGL es una plataforma-cruzada web estndar de rayaltee-free para
una API de gricos 3D. WebGL est creciendo como el estndar
indicativo para el 3D Canvas.
Apndice A
Este apendice provee informacin bsica sobre el uso de color en la
web. La referencia no solo cubre los formatos de colores deinidos,
nombres y valores para la especiicacin X(HTML) y CSS, pero presenta
los nombres de colores menos evidentes estandarizados pero de uso
comn.

Colores (X)HTML

Versiones transitorias de HTML y XHTML apoyan coniguraciones de


color para el texto y el color de fondo de los documentos, los bordes de
marcos, tablas o celdas de la tabla, incluso valores individualizados.
Hay 16 nombre de colores conocidos ampliamente y deinidos por
HTML. Estos nombres y sus valores hexadecimales asociado RGB se
muestran en la tabla A1.

Nota destacada!
Los nombres y los valores de los colores no son sensitivos a las
mayusculas o minusculas, es decir un color red y RED son
equivalentes, asi como lo son #FF0000 y #ff0000.
Atento

Nombre de los colores no standard y equivalencias


nmericas

La tabla A2 muestra un conjunto de nombres de colores no standard


comunmente soportado por los mayores navegadores. Estos nombres
de colores fueron inicialmente introducidos por netscape y
aparentemente son los colores deinidos por el X11 windowing system
para los sistemas UNIX hace aproximadamente dos dcadas.
Recordando su origen, estos colores son documentados en la
especiicacin SVG y en la emergente especiicacin CSS3; todos ellos
estn siendo muy usados y pueden que algn da lleguen a ser
considerados estandar como los otros.
Puede haber algunas situaciones, como en el caso del navegador
Opera, que algunos de los grandes navegadores no soporten estos
valores. Las pruebas actuales muestran que al momento de escribir
este libro, la mayora de los grandes navegadores s soportan estos
valores, puede probarlos usted mismo en la pgina web
http://htmlref.com/AppC/colorchart html. Si existe alguna duda de la
compatibilidad de estos valores, los autores de aplicaciones canvas o
web, deben usar valores hexadecimales en lugar de los nombres de
los colores.
Algunas referencias de color airman que otras variaciones de color se
pueden introducir mediante la adicin de los nmeros 1 al 4 para los
nombres de colores. Si esto fuera correcto, cadetblue1, cadetblue2,
cadetblue3 y cadetblue4, se mostraran como diferentes tonos de un
mismo color. Por lo que particularmente pienso que no es adecuado ni
correcto.

Color Name Hex Equivalent


Black #000000
Silver #C0C0C0
Gray #808080
White #FFFFFF
Maroon #800000
Red #FF0000
Purple #800080
Fuchsia #FF00FF
Green #008000
Lime #00FF00
Olive #808000
Yellow #FFFF00
Navy #000080
Blue #0000FF
Teal #008080
Aqua #00FFFF

tabla A!
- Nombre de colores y sus equivalencias hexadecimales
estandard HTML 4.0

aliceblue #F0F8FF 240,248,255 antiquewhite #FAEBD7 250,235,215


aqua #00FFFF 0,255,255 aquamarine #7FFFD4 127,255,212 azure
#F0FFFF 240,255,255 beige #F5F5DC 245,245,220 bisque #FFE4C4
255,228,196 black #000000 0,0,0 blanchedalmond #FFEBCD
255,235,205 blue #0000FF 0,0,255 blueviolet #8A2BE2 138,43,226
brown #A52A2A 165,42,42 burlywood #DEB887 222,184,135
cadetblue #5F9EA0 95,158,160 chartreuse #7FFF00 127,255,0
chocolate #D2691E 210,105,30 coral #FF7F50 255,127,80
cornlowerblue #6495ED 100,149,237 cornsilk #FFF8DC 255,248,220
crimson #DC143C 220,20,60 cyan #00FFFF 0,255,255 darkblue
#00008B 0,0,139 darkcyan #008B8B 0,139,139 darkgoldenrod
#B8860B 184,134,11 darkgray #A9A9A9 169,169,169 darkgreen
#006400 0,100,0 darkkhaki #BDB76B 189,183,107 darkmagenta
#8B008B 139,0,139 darkolivegreen #556B2F 85,107,47 darkorange
#FF8C00 255,140,0 darkorchid #9932CC 153,50,204 darkred
#8B0000 139,0,0 darksalmon #E9967A 233,150,122 darkseagreen
#8FBC8F 143,188,143 darkslateblue #483D8B 72,61,139
darkslategray #2F4F4F 47,79,79 darkturquoise #00CED1 0,206,209
darkviolet #9400D3 148,0,211 deeppink #FF1493 255,20,147
deepskyblue #00BFFF 0,191,255 dimgray #696969 105,105,105
dodgerblue #1E90FF 30,144,255 irebrick #B22222 178,34,34
loralwhite #FFFAF0 255,250,240 forestgreen #228B22 34,139,34
fuchsia #FF00FF 255,0,255 gainsboro #DCDCDC 220,220,220
ghostwhite #F8F8FF 248,248,255 gold #FFD700 255,215,0 goldenrod
#DAA520 218,165,32 gray #808080 127,127,127 green #008000
0,128,0 greenyellow #ADFF2F 173,255,47 honeydew #F0FFF0
240,255,240 hotpink #FF69B4 255,105,180 indianred #CD5C5C
205,92,92 indigo #4B0082 75,0,130 ivory #FFFFF0 255,255,240 khaki
#F0E68C 240,230,140 lavender #E6E6FA 230,230,250 lavenderblush
#FFF0F5 255,240,245 lawngreen #7CFC00 124,252,0 lemonchifon
#FFFACD 255,250,205 lightblue #ADD8E6 173,216,230 lightcoral
#F08080 240,128,128 lightcyan #E0FFFF 224,255,255
lightgoldenrodyellow #FAFAD2 250,250,210 lightgreen #90EE90
144,238,144 lightgrey #D3D3D3 211,211,211 lightpink #FFB6C1
255,182,193 lightsalmon #FFA07A 255,160,122 lightseagreen
#20B2AA 32,178,170 lightskyblue #87CEFA 135,206,250 lightslategray
#778899 119,136,153 lightsteelblue #B0C4DE 176,196,222 lightyellow
#FFFFE0 255,255,224 lime #00FF00 0,255,0 limegreen #32CD32
50,205,50 linen #FAF0E6 250,240,230 magenta #FF00FF 255,0,255
maroon #800000 128,0,0 mediumaquamarine #66CDAA 102,205,170
mediumblue #0000CD 0,0,205 mediumorchid #BA55D3 186,85,211
mediumpurple #9370DB 147,112,219 mediumseagreen #3CB371
60,179,113 mediumslateblue #7B68EE 123,104,238
mediumspringgreen #00FA9A 0,250,154 mediumturquoise #48D1CC
72,209,204 mediumvioletred #C71585 199,21,133 midnightblue
#191970 25,25,112 mintcream #F5FFFA 245,255,250 mistyrose
#FFE4E1 255,228,225 moccasin #FFE4B5 255,228,181 navajowhite
#FFDEAD 255,222,173 navy #000080 0,0,128 navyblue #9FAFDF
159,175,223 oldlace #FDF5E6 253,245,230 olive #808000 128,128,0
olivedrab #6B8E23 107,142,35 orange #FFA500 255,165,0 orangered
#FF4500 255,69,0 orchid #DA70D6 218,112,214 palegoldenrod
#EEE8AA 238,232,170 palegreen #98FB98 152,251,152 paleturquoise
#AFEEEE 175,238,238 palevioletred #DB7093 219,112,147
papayawhip #FFEFD5 255,239,213 peachpuf #FFDAB9 255,218,185
peru #CD853F 205,133, 63 pink #FFC0CB 255,192,203 plum
#DDA0DD 221,160,221 powderblue #B0E0E6 176,224,230 purple
#800080 128,0,128 red #FF0000 255,0,0 rosybrown #BC8F8F
188,143,143 royalblue #4169E1 65,105,225 saddlebrown #8B4513
139,69,19 salmon #FA8072 250,128,114 sandybrown #F4A460
244,164,96 seagreen #2E8B57 46,139,87 seashell #FFF5EE
255,245,238 sienna #A0522D 160,82,45 silver #C0C0C0 192,192,192
skyblue #87CEEB 135,206,235 slateblue #6A5ACD 106,90,205
slategray #708090 112,128,144 snow #FFFAFA 255,250,250
springgreen #00FF7F 0,255,127 steelblue #4682B4 70,130,180 tan
#D2B48C 210,180,140 teal #008080 0,128,128 thistle #D8BFD8
216,191,216 tomato #FF6347 255,99,71 turquoise #40E0D0
64,224,208 violet #EE82EE 238,130,238 wheat #F5DEB3 245,222,179
white #FFFFFF 255,255,255 whitesmoke #F5F5F5 245,245,245 yellow
#FFFF00 255,255,0 yellowgreen #9ACD32 139,205,50
Desafortunadamente, las pruebas revelan que este esquema de
variacin de color no funciona en otros navegadores principales.
En general, los autores de aplicaciones canvas y web deben tener
cuidado al usar nombres de colores no estndar. En algunos casos, los
nombres desconocidos se interpretan como valores, y otros casos, el
navegador simplemente ajustar el color negro.
Teniendo en cuenta todas las posibilidades de error, los autores de
aplicaciones canvas y web deben pensar dos veces antes de emplear
los nombres de colores especiales, aunque los de la Tabla A2 son
seguros en la prctica.

Valores de colores CSS

Teniendo en cuenta todas las posibilidades de error, los autores de


aplicaciones canvas y web deben pensar dos veces antes de emplear
los nombres de colores especiales, aunque los de la Tabla A2 son
seguros en la prctica.

tabla A3- Valores para los colores CSS


Nota destacada!
Las pruebas revelan que en funcin de los cambios de color de los
sistemas operativos, algunos navegadores no pueden asignar
correctamente estos nombres de color en la interfaz de usuario y con
frecuencia lo hacen por Atento defecto en negro.

Propiedades CSS relacionadas con el color


Son numerosas las propiedades CSS que permiten valores de color. La
tabla A5 muestra en detalle una lista de estas propiedades, un breve
ejemplo de su uso, as como una indicacin de cual fu la versin CSS
donde por primera vez apareci esta propiedad. Los lectores pueden
buscar mas informacin acerca de estas propiedades en textos
especializados, ya que no es el objetivo de este libro, aunque creemos
que lo relativo al color es parte importante en el desarrollo de
aplicaciones canvas.

tabla A4 - Nombre de colores CSS2 para la interface de


usuario(UI) Propiedad Ejemplo Version CSS tabla A5 - Valores de
colores soportados por propiedad CSS

Colores seguros para los navegadores

Al principio de la poca, todos los ordenadores contaban con una


gama de 256 colores para todos los navegadores y sistemas
operativos, una paleta especial de slo 216 colores que eran
seguros se deini. Este grupo de colores seguros para la Web es a
menudo llamada la paleta de colores para una navegacin segura. En
teora, el uso de otros colores ms all de este conjunto seguro poda
dar lugar a cambios de colores, sobre todo en condiciones de colores
limitados como VGA, que apoya a los colores de 8 bits, proporcionando
una miseria de 256 colores. La realidad de hoy es que la paleta
segura para la Web es ms una cuestin histrica que preocupante,
sobre todo teniendo en cuenta cmo algunos dispositivos estn
limitadas a una paleta de 8 bits. Sin embargo, muchas herramientas y
muchos diseadores continan promoviendo el uso de esta gama de
colores, as que lo presentan y su diseo est completo.
La seleccin de los 216 colores seguros es bastante comprensible si
se tiene en cuenta la naturaleza aditiva de los colores RGB. Considere
la posibilidad de un color que se compone de diferentes cantidades de
rojo, verde o azul que se podran establecer mediante el ajuste de una
lnea de color imaginario de los extremos de algn color de mxima
saturacin de color. Los colores seguros utilizan seis posibles ajustes
de intensidad para cada valor de rojo, verde o azul. Los ajustes son
0%, 20%, 40%, 60%, 80%, y 100%. Un valor de 0%, 0%, 0% en el dial
de color imaginario es equivalente a negro. Un valor de 100%, 100%,
100% indica blanco puro, mientras que un valor de 100%, 0%, 0% es
de color rojo puro, y as sucesivamente. Los colores seguros son los
que tienen un valor RGB slo en uno de los ajustes de intensidad
fuerte. Las conversiones hexadecimales para la saturacin se
muestran en la Tabla A6.
La coniguracin de un color seguro es simplemente una cuestin de
seleccionar una combinacin de valores hexadecimales seguros. En
este caso, # 9966FF es un color hexagonal segura; # 9370DB no lo es.
La mayora de las herramientas de edicin web como Adobe
Dreamweaver y Microsot Expression contienen selectores de color de
seguridad; al igual que las herramientas de imgenes como Adobe
Photoshop. Sin embargo, la asignacin directa de un color inseguros
a su color seguro ms cercano es bastante fcil-a la vuelta de cada red
en particular, verde, azul o el valor hacia arriba o hacia abajo al valor
seguro ms cercano. Una conversin completa de hexadecimal a los
valores decimales se muestra en la Tabla A7, los valores de seguridad
se indican en negrita.
Intensidad de Color Valor Hex Valor Decimal tabla A6 - Tabla de
conversin para la intensidad de color
tabla A7
- Tabla de conversin de colores RGB a Hexadcimal
Apndice B
Considerando que en la mayora de los libros especializados en la
materia solo se nos da las instrucciones bsicas o simples para crear
las aplicaciones que queremos, en este libro, hemos querido hacer un
esfuerzo adicional y extender una aplicacin bsica o muy simple, que
previamente hemos creado en el capitulo 3, a una de mayor
complejidad, con el slo objetivo didctico de mostrarles el mundo de
posibilidades dentro del campo de las aplicaciones web y en especial
las aplicaciones para juegos, en este caso, los de arcade.

Extendiendo nuestro juego Defensa Espacial

Previamente en el capitulo 3 creamos una aplicacin para juego muy


bsico, ahora en esta seccin, vamos a dar una aproximacin mas real
de lo que es crear aplicaciones de juegos, agregandole imagenes y
sonidos a nuestro juego. Mucha de la lgica de este juego es la misma,
pero al agregar imagenes para reemplazar a nuestros dibujos hechos
con los paths del canvas de HTML5 nos permitir optimizar el
renderizado del juego. Optimizar el renderizado es muy importante
cuando el objetivo son los dispositivos de procesadores limitados,
como lo son los telfonos mviles. Tambin vamos a agregarles sonidos
y aplicaremos un grupo de objetos a las partculas usadas para las
explosiones del juego.

Trabajar con mosaicos

En el captulo 3 dibujamos todos los objetos de nuestro juego con


trazados que luego transformamos sobre la marcha. Vamos a optimizar
el renderizado de nuestro juego bsico. Haremos esto, mediante el
renderizado previo de todos los gricos del juego y los transformamos
como imgenes. Luego usaremos estas imgenes en lugar de los
trazos y los transformamos de modo inmediato como lo habiamos hecho
anteriormente.

La siguiente imagen muestra una de las hojas de mosaicos que hemos


creado para este juego. Esta hoja contiene las 36 rotaciones que
usaremos en nuestra nave espacial. Estamos comprimiendo las
rotaciones en una hoja de mosaicos para evitar la carga excesiva en la
que muchas veces se ve expuesto los procesadores, transformandolos
en cada fotograma tal y como lo sacamos al canvas.

imagen B.1
- Hoja de mosaicos nave.png
A continuacin mostraremos un segundo conjunto de cuadros para la
nave con las turbinas encendidas listas para avanzar. Usaremos esta
imagen para representar la nave del jugador cuando el jugador
presiona la tecla hacia arriba del teclado, lo que traducimos en nuestro
juego como avanzar o acelerar.

imagen B.2
- Hoja de mosaicos nave2.png que representa la nave acelerada
Para representar las piedras que el jugador debe esquivar o destruir
tenemos los siguientes tres conjuntos de imagenes de hojas de
mosaicos, las cuales cada una describe el tamao de roca, dado que
tenemos tres tamaos, ellas son grandes, medianas y pequeas.

imagen B.2 - Hoja de mosaicos nave2.png que representa la


nave acelerada

imagen B.2 - Hoja de mosaicos nave2.png que representa la


nave acelerada
imagen
B.2 - Hoja de mosaicos nave2.png que representa la nave
acelerada
El platillo enemigo que intenta destuir la nave del jugador esta
contenido en un solo mosaico.
imagen B.2
- Hoja de mosaicos nave2.png que representa la nave acelerada
Finalmente, el archivo partes png es una pequea hoja de mosaicos
de 8x2, que contiene cuatro particulas de 2x2. Estos son usados para
la animar la explosin de los misiles del jugador y del platillo.

El primer cuadro es verde y ser usado para las explosiones de las


piedras pequeas y la explosin del platillo, el segundo cuadro es
azul claro y representa los misiles del jugador y la explosin del
jugador, el tercer cuadro es color rosa (o salmon si lo preiere), y este
ilustra la explosin de las piedras grandes. El ltimo color purpura es
usado para la explosin de las piedras medianas.

Ahora que tenemos nuestros mosaicos en su lugar, vamos a revisar los


mtodos que usaremos para tyransformar el trazo de modo inmediato
del juego renderizandolo para que sea un juego basado en imagenes.

Calcular la localizacin de los mosaicos


Dado que tenemos una hoja e mosaicos tal como el archivo nave.png,
podemos localizar el cuadro que queramos mostrar con un simple truco
matematico.

El archivo nave.png es una hoja de mosaicos de animacin de 36


cuadros con la nave esttica del jugador comenzando en una posicin
de 0 grados o punto de direccin correcta. Cada uno de los restantes
35 mosaicos muestra la nave con una rotacin de 10 grados de
incremento.

Si quisieramos mostrar el mosaico 19 (la nave apuntando a la izquierda


o en un angulo de 190 grados), primero tenemos que encontrar las
coordenadas x e y de la esquina superior izquierda del cuadro
calculando las variables origenX y origenY.

A continuacin mostraremos el pseudocdigo para el clculo de


origenX:
origenX = integer(indice_fotograma_actual
modulo numero_columnas_hoja_
mosaicos)*anchoMosaico
El operador modulo(%) devuelve l resto de una divisin. El
siguiente es el cdigo real (con variables reemplazadas por valores
literales) que usaremos para este clculo:
El resultado es x=9*32 = 288;
El calculo para el valos origenY es similar, excepto que dividimos en
lugar del operador modulo:
origenY = integer(indice_fotograma_actual
dividido por
numero_columnas_hoja_mosaicos)*altoMosaico
Aqu el cdigo que usaremos para calcular esto:
El resultado es y= 1*32 = 32;
Por lo tanto la ubicacion de la esquina superior izquierda de
nave.png desde donde comenzaremos a copiar pixeles es 288,32.
Para copiar esto en el canvas usaremos la siguiente sentencia:
context.drawImage(mosaicoNave, origenX,
origenY, 32, 32, jugador.x, jugador.y, 32,
32);

En el capitulo 3, necesitabamos un montn de cdigo para dibujar y


renderizar la nave del jugador a la rotacin actual. Cuando se usa una
hoja de mosaico, este cdigo se reduce considerablemente. A
continuacin el cdigo que usaremos para renderizar la nave del
jugador:

function renderizarNaveJugador(x,y,rotacion,
scale) { //transformacion
context.save(); //salvar actual estado en la
pila context.globalAlpha =
parseFloat(jugador.alpha); var
anguloEnRadianes = rotacion * Math.PI / 180;

if (jugador.avance){
context.drawImage(mosaicoNave2, origenX,
origenY, 32,32, jugador.x,jugador.y,32,32);
}else{
context.drawImage(mosaicoNave, origenX,
origenY, 32,32, jugador.x,jugador.y,32,32);
}
//restaurar contexto
context.restore(); //pop old state on to
screen
context.globalAlpha = 1;
}

La funcin renderizarNaveJugador() divide el atributo


jugador.rotacion entre 10 para determinar cual de los 36
mosaicos en la instancia imagen de la nave mostrar en el canvas. Si el
jugador est en modo avance, la imagen nave2 es usada como
instancia de la imagen de la nave.

Esto funciona porque le hemos puesto a la nave que gire 10 grados


cada vez que es presionada la tecla izquierda o derecha del teclado.
En la versin del captulo 3 girabamos la nave cada 5 grados. Si
hubiramos creado una hoja de mosaicos con 72 cuadros, con la nave
del jugador rotando 5 grados de incremento, podramos haber
mantenido el atributo jugador.velocidadRotacion en 5.
Para este tutorial hemos hecho solo 36 cuadros para la nave del
jugador, por lo que usaremos un valor de 10 para la velocidad de
rotacin. Desde luego que podramos usar 72 o incluso 360 mosaicos
para los fotogramas de rotacin de la nave del jugador. Esto est
limitado slo por la creatividad (y paciencia con la herramienta de
dibujo). Vamos a ver la velocidadRotacion asignado
anteriormente a estadoNuevoJuego():

function estadoNuevoJuego(){
ConsoleLog.log(estadoNuevoJuego);

nivel = 0; puntuacion = 0;
navesJugador = 3;
jugador.velocidadMax = 5;
jugador.width = 32;
jugador.height = 32;
jugador.widthMedio = 16;
jugador.heightMedio = 16;
jugador.hitWidth = 24;
jugador.hitHeight = 24;
jugador.velocidadRotacion = 10; //cuantos
grados gira la nave jugador.aceleracion =
.05;
jugador.missileFrameDelay = 5;
jugador.avance = false;
jugador.alpha = 1;
jugador.rotacion = 0;
jugador.x = 0;
jugador.y = 0;

rellenarFondo();
renderizarTableroPuntuacion();
cambioEstadoApp(ESTADO_NUEVO_NIVEL);

Nuevos atributos para los jugadores

junto con el cambio en la velocidad de rotacin, tambin hemos


modiicado los valores width y height, estos son ahora de 32
para ambos, que es la misma que el ancho y el alto del mosaico. Si nos
ijamos en el primer mosaico de la hoja de mosaicos naves.png, se
ve que la nave del jugador no ocupa el area completa del mosaico. Se
centra en el centro teniendo un cuadro de hasta 24 x 24, lo que deja
suiciente espacio alrededor de los bordes del cuadro para eliminar el
recorte cuando la nave gira. Tambin vamos a usar este mismo
concepto cuando vayamos a crear la rotacin de las piedras.

Los pixeles adicionales de relleno aadido para eliminar el recorte


durante la rotacin del fotograma, plantean un pequeo problema
para la deteccin de colisiones. En la versin del captulo 3 del juego,
se us los valores width y height para la deteccin de colisiones en el
cuadro delimitador. No vamos a usar estos valores en esta nueva
versin, ya que hemos creado dos nuevas variables para usar en la
deteccin de colisiones: hitWidth y hitHeight. En lugar de
conigurar estos valores a 32, estos sern de 24. Este nuevo valor ms
pequeo hace que nuestra deteccin de colisiones sea ms preciso
que s usamos todo el ancho y el alto del cuadro.

El nuevo algoritmo para la funcion colisionCuadroDelimitador()

Todos los demas objetos del juego tienen sus nuevos atributos
hitWidth y hitHeight. Vamos a modiicar la funcin
colisionCuadroDelimitador() de nuestro juego para usar
estos nuevos valores para todas las comprobaciones de colision.

function colisionCuadroDelimitador(objeto1,
objeto2) {

var izquierda1 = objeto1.x;


var izquierda2 = objeto2.x;
var derecha1 = objeto1.x + objeto1.hitWidth;
var derecha2 = objeto2.x + objeto2.hitWidth;
var superior1 = objeto1.y;
var superior2 = objeto2.y;
var inferior1 = objeto1.y +
objeto1.hitHeight; var inferior2 = objeto2.y
+ objeto2.hitHeight;

if (inferior1 < superior2) return(false); if


(superior1 > inferior2) return(false);
if (derecha1 < izquierda2) return(false); if
(izquierda1 > derecha2) return(false);
return(true);
}

seguidamente, vamos a ver como podemos usar esta misma idea para
renderizar el resto de los objetos del juego con la nueva hoja de
mosaicos.

Renderizar los otros objetos del juego

Las piedras, platillos, misiles y particulas estn todos renderizados de


una manera similar al mtodo implementado por la nave del jugador.
Primero, vemos el cdigo de la funcin para renderizar los platillos.
Renderizar los platillos
Los platillos no tienen una hoja de mosaicos, pero, para ser
coherentes, lo renderizamos como hemos pensado hacerlo. Esto nos
permite aadir mas ichas de animacin para el platillo despues:

function renderizarPlatillos() {
var platilloTemp = {};
var cantidadPlatillos = platillos.length-1;
for (var contarPlatillos =
cantidadPlatillos;contarPlatillos>=0;

contarPlatillos--){
//ConsoleLog.log(platillos: +
contarPlatillos); platilloTemp =
platillos[contarPlatillos];

context.save(); //salvar estado actual en la


pila var origenX = 0;
var origenY = 0;
context.drawImage(mosaicoPlatillos, origenX,
origenY, 30,15,
platilloTemp.x,platilloTemp.y,30,15);

context.restore(); //traer el viejo estado a


la pantalla }
}

No hay necesidad de calcular los valores origenX y origenY para


el platillo porque solo es un cuadro en este caso, solo podemos
ajustarlo a 0. hemos ijado las medidas a platillos.width (30) y
platillos.height (15) como un ejemplo, pero con todo el resto
de los objetos del juego, usaremos los atributos width y height en
lugar de literales.

A continuacin vamos a ver el renderizado de las piedras, que vara


ligeramente del platillo y de la nave del jugador.

Renderizar las piedras

Los mosaicos de las rocas estn dentro de tres hojas de mosaicos


basadas en sus tamaos (grandes, medianas y pequeas) y hemos
usado solo 5 cuadros para cada tamao de piedra. Las piedras
cuadradas con un patrn simtrico, as que solo tenemos que crear
previamente un solo cuadro de rotacin para cada uno de los tres
tamaos. A continuacin la funcin renderizarPiedras(). Note
que debemos cambiar la escala de las piedras (1 = grandes, 2 =
medianas, 3 = pequeas) para seleccionar la hoja de mosaicos
correctas para el renderizado.

function renderizarPiedras() {
var piedrasTemp = {};
var cantPiedras = piedras.length-1;

for (var contarPiedras =


cantPiedras;contarPiedras>=0;contarPiedras--)
{
context.save(); //salvar el estado actual en
la pila piedrasTemp = piedras[contarPiedras];

switch(piedrasTemp.scale){ case 1:
piedrasTemp.width;

piedrasTemp.height;
context.drawImage(mosaicoPiedrasGrandes,
origenX, origenY,
piedrasTemp.width,piedrasTemp.height,piedrasT

piedrasTemp.y,piedrasTemp.width,piedrasTemp.h
break;
case 2:
piedrasTemp.width;
piedrasTemp.height;
context.drawImage(mosaicoPiedrasMedianas,
origenX,
origenY,piedrasTemp.width,piedrasTemp.height,
piedrasTemp.x,piedrasTemp.y,piedrasTemp.width
piedrasTemp.height);

break;
case 3:
piedrasTemp.width;

piedrasTemp.height;
context.drawImage(mosaicoPiedrasPeque,
origenX,
origenY,piedrasTemp.width,piedrasTemp.height,
piedrasTemp.x,piedrasTemp.y,piedrasTemp.width
piedrasTemp.height);
break;

}
context.restore(); //recuperar viejo estado a
la pantalla
} }

En la funcin renderizarPiedras(), ya no estamos usando el


atributo piedras rotacion como el angulo de giro, as como lo hicimos en
el desarrollo del juego del captulo 3, en cambio hemos reutilizado el
atributo rotacion para representar el id de los mosaicos (0-4) en las
hojas de mosaicos para renderizar.
En la versin del capitulo 3, podamos simular velocidades ms rapidas
o mas lentas para las rotaciones de las piedras, simplemente dando a
cada piedra un valor al azar para el atributo rotationInc. Este valor,
negativo para la direccin contraria a las agujas del reloj o positivas
para ir a favor de las agujas del reloj, era agregado al atributo rotacion
en cada fotograma. En esta nueva versin basada en hojas de
mosaicos, solo tenemos cinco fotogramas de animacin, por lo que no
queremos saltar cuadros porque se vera muy agitado. En su lugar
vamos a aadir dos nuevos atributos a cada piedra:
cuentaAnimacion y retrasoAnimacion.

El atributo retrasoAnimacion representa el nmero de


fotogramas entre cada cambio de mosaico para la piedra dada. La
variable cuentaAnimacion se reinicia a 0 despues de cada
cambio de mosaico y aumenta en 1 en cada fotograma siguiente.
Cuando cuentaAnimacion es mayor que retrasoAnimacion, el valor de
piedra.rotacion se incrementa (en el sentido de las agujas del
reloj) o disminuye (en el sentido contrario de las agujas del reloj). A
continuacin el nuevo cdigo en nuestra funcin
actualizarPiedras().

piedrasTemp.cuentaAnimacion++;
if (piedrasTemp.cuentaAnimacion >
piedrasTemp.retrasoAnimacion){
piedrasTemp.cuentaAnimacion = 0;
piedrasTemp.rotacion +=
piedrasTemp.rotacionInc; if
(piedrasTemp.rotacion > 4){
piedrasTemp.rotacion = 0; }else if
(piedrasTemp.rotacion <0){
piedrasTemp.rotacion = 4; }
}

Observe que hemos tenido que incluir en el cdigo los valores


maximos y minimos para los ID de los mosaicos, 4 y 0 . Podramos haber
usado fcilmente una constante o dos variables para este propsito.

Renderizar los misiles

Ambos los misiles del jugador y los misiles del platillo son renderizados
de identica manera. Para cada uno de ellos, simplemente
necesitaremos saber el ID del mosaico que destinamos para este
propsito, esta imagen del mosaico representa la imagen de lo que
queremos mostrar. Para los misiles del jugador, el ID asignado al
mosaico es 1; para los misiles del platillo el ID asignado al mosaico es
el 0.

Vamos a revisar rpidamente estas dos funciones:

function renderizarMisilesJugador() {
var misilesJugadorTemp = {};
var
cantMisilesJugador=misilesDelJugador.length-
1;
//ConsoleLog.log(render cantMisilesJugador=
+
//cantMisilesJugador);
for (var
contarMisilesJugador=cantMisilesJugador;

contarMisilesJugador>=0;contarMisilesJugador-
-){ //ConsoleLog.log(dibujar misiles del
jugador + //contarMisilesJugador)
misilesJugadorTemp =
misilesDelJugador[contarMisilesJugador];
context.save(); //salvar el estado actual en
la pila

context.drawImage(mosaicoParticulas, origenX,
origenY,
misilesJugadorTemp.width,misilesJugadorTemp.h
misilesJugadorTemp.x,misilesJugadorTemp.y,
misilesJugadorTemp.width,misilesJugadorTemp.h

context.restore(); //recuperar el antiguo


estado de la pantalla }
}

function renderizarMisilesDelPlatillo() {
var misilesDelPlatilloTemp = {};
var cantMisilesPlatillo =
misilesDelPlatillo.length-1;
//ConsoleLog.log(misilesDelPlatillo= +
misilesDelPlatillo.length)

for (var
contarMisilesPlatillo=cantMisilesPlatillo;
contarMisilesPlatillo>=0;contarMisilesPlatillo
-){ //ConsoleLog.log(dibujar misiles del
platillo + //contarMisilesPlatillo)
misilesDelPlatilloTemp =

misilesDelPlatillo[contarMisilesPlatillo];
context.save(); //salvar el estado actual en
la pila

context.drawImage(mosaicoParticulas, origenX,
origenY,
misilesDelPlatilloTemp.width,misilesDelPlatill
misilesDelPlatilloTemp.x,misilesDelPlatilloTem
misilesDelPlatilloTemp.width,misilesDelPlatill

context.restore(); //restaurar el viejo


estado en la pantalla
} }

La explosion de las partculas tambin es renderizada usando las


imagenes de las hojas de mosaico, y su cdigo es muy similar al cdigo
de los misiles. A continuacin examinaremos las partculas.

Renderizando las partculas

Las partculas usarn los mismos cuatro mosaicos del archivo parts png
que renderiza a los misiles. El juego Defensa Espacial en el captulo 3
usaba solo una sencilla partcula blanca para animar las explosiones.
Reemplazaremos la funcin crearExplosin() desde ese juego
previo con una nueva que pueda usar un color de partcula diferente
para cada uno de los diferentes tipos de explosin, de esta forma, las
piedras, platillos y la nave del jugador pueden todos ellos tener un
nico color que diferencie sus explosiones.

La nueva funcin crearExplosion() manejar un nuevo


parmetro: tipo, que ser agregado a la lista de sus parmetros.
Vamos a revisar este cdigo:
function crearExplosion(x,y,num,tipo) {
reproducirSonido(SONIDO_EXPLOSION,.5); for
(var contarParticulas=0;contarParticulas<num;
contarParticulas++){
if (contenedorDeParticulas.length > 0){
nuevaParticula =
contenedorDeParticulas.pop();
nuevaParticula.dx = Math.random()*3;
if (Math.random()<.5){

nuevaParticula.dx *= -1;
}
nuevaParticula.dy = Math.random()*3;

if (Math.random()<.5){
nuevaParticula.dy *= -1;
}

nuevaParticula.lifeCtr = 0;
nuevaParticula.x = x;
nuevaParticula.width = 2;
nuevaParticula.height = 2;
nuevaParticula.y = y;
nuevaParticula.tipo = tipo;
//ConsoleLog.log(nuevaParticula.vida= +
//nuevaParticula.vida);
particulas.push(nuevaParticula);

}
}
}

Como los objetos particulas son creados en la funcin


crearExplosion(), agregamos tipo como un nuevo atributo.
Cuando una nueva explosin es activada en la funcin
chequearColision(), la llamada a crearExplosion()
ahora incluira el valor tipo basado en el objeto que ser destruido.
Cada piedra alrededor tiene un parametro scale que varia desde los
valores 1 hasta 3 basados en el tamao. Vamos a usar estos mismos
valores para para el nuevo atributo tipo. Ahora solo necesitamos los
valores tipo para el jugador y para el platillo. Dado que es una buena
idea, tener valores continuos, para un mejor control de este atributo,
usaremos para el platillo un valor de 0 y para el jugador, usaremos un
valor de 4. Deinidos ya, todos estos valores para este nuevo atributo, el
desglose del atributo tipo sera como sigue a continuacin:

platillos: tipo = 0
piedras grandes: tipo = 1 piedras medianas: tipo = 2 piedras
pequeas: tipo = 3 jugador: tipo = 4

Estos valores tipo, vamos a necesitar usarlo en una sentencia switch


dentro de la funcin renderizarParticulas() para
determinar cual de los cuatro cuadros dentro de nuestra hoja de
mosaicos renderiza la partcula dad. Vamos a examinar como quedara
esta funcin despues de agregarles los cambios mencionados
anteriormente:

function renderizarParticulas() {

var particulasTemp = {};


var cantidadParticulas = particulas.length-1;
for (var
contarParticulas=cantidadParticulas;contarPar

;contarParticulas--){
particulasTemp =
particulas[contarParticulas]; context.save();
//salvar el estado actual en la pila var
mosaico;
//console.log(partes tipo= +
particulasTemp.tipo)
switch(particulasTemp.tipo){
case 0: // platillo
mosaico = 0;
break;
case 1: //piedras grandes
mosaico = 2;
break;
case 2: //piedras medianas
mosaico = 3;
break;
case 3: //piedras pequeas
mosaico = 0;
break;
case 4: //jugador
mosaico = 1;
break;
}

context.drawImage(mosaicoParticulas, origenX,
origenY,
particulasTemp.width,particulasTemp.height,par
particulasTemp.y,particulasTemp.width,particul

context.restore(); //restaurar el viejo


estado en la pantalla
} }

En chequearColisiones(), necesitamos pasar el nuevo


parmetro tipo a la funcin crearExplosion() para que
pueda ser asignadas a las particulas en la explosin. A continuacin
un ejemplo del llamado a la funcion crearExplosion() en la
instancia del objeto piedra:

crearExplosion(piedrasTemp.x+piedrasTemp.width
+
piedrasTemp.heightMedio,10,piedrasTemp.scale)
Pasamos el atributo piedrasTemp.scale como ltimo parmetro
porque en las piedras estamos usando el parmetro scale como el
parmetro tipo.
Para el platillo:
crearExplosion(platillosTemp.x+platillosTemp.w
platillosTemp.y + platillosTemp.heightMedio,
10, 0);
Para el platillo y el jugador, pasamos como ltimo parmetro un nmero
literal dentro de la funcin crearExplosion(). En el caso del
platillo, pasamos un 0. Para la nave del jugador pasaremos un 4:
crearExplosion(jugador.x +
jugador.widthMedio, jugador.y +
jugador.heightMedio, 50, 4);
Note que la funcin crearExplosion() llamada para el jugador
esta en la funcin jugadorMuerto(), la cual es llamada desde
chequearColisiones().

Agregar Sonido

Los juegos de arcade necesitan reproducir muchos sonido


simultneamente, y en algunos casos, esos sonidos se reproducen
rapidamente en sucesin.
Los sonidos para nuestro juego

Nosotros agregaremos tres sonidos para el desarrollo de nuestro


juego:
a) Un sonido para cuando el jugador dispare un misil
(shoot1.mp3, .ogg, .wav) b) Un sonido para explosiones
(explode1.mp3, .ogg, .wav)
c) Un sonido para cuando el platillo dispare un misil
(saucershoot.mp3, .ogg, .wav)

En los archivos descargables de este libro, hemos agregado cada uno


de los archivos de los tres sonidos en los tres formatos: .wav,
.ogg, .mp3.

Agregando instancias de sonido y administrando las variables para el


juego
En la seccin deinicin de variables de nuestro cdigo, creamos las
variables para administrar el sonido. crearemostres instancias de cada
sonido que ira dentro de nuestro grupo:

var sonidoExplosion;
var sonidoExplosion2;
var sonidoExplosion3;
var sonidoDisparo;
var sonidoDisparo2;
var sonidoDisparo3;
var sonidoDisparoPlatillo; var
sonidoDisparoPlatillo2; var
sonidoDisparoPlatillo3;

Tambin necesitamos crear una matriz para guardar nuestro grupo de


sonidos:
var grupoSonido = new Array();

Para controlar el sonido que queremos reproducir, asignamos una


cadena constante para cada uno, y para reproducir el sonido, solo
necesitamos usar la constante. De esta forma, podemos cambiar el
nombre del sonido fcilmente, la cual ayudar en la refactorizacin del
cdigo si queremos modiicar los sonidos mas adelante.

var SONIDO_EXPLOSION = explode1;


var SONIDO_DISPARO = shoot1;
var SONIDO_DISPARO_PLATILLO = saucershoot;

Finalmente, necesitaremos una variable tipoDeAudio, la cual usaremos


para referenciar el tipo de archivo de sonido actual (.ogg, .wav,
.mp3) para el cdigo que administra el sonido.
var tipoDeAudio;

Carga de nuestros sonidos y de nuestras hojas de mosaicos

Usaremos una funcin para cargar todos esos elementos del juego
que hemos agregado en este apndice, mientras que nuestro estado
de la aplicacin esperar en un estado inerte. Agregamos este cdigo
a nuestro juego a travs de la funcin estadoInicial()

Nota destacada!
Los sonidos no trabajan de la misma forma en todos los navegadores
web. En este juego, estamos cargando todas las imagenes y sonidos
del juego. Para Internet Explorer 9 y 10, esta precarga, algunas veces,
no funciona.
Atento
Tu puedes cambiar el nmero de elementos a precargar de 16 a 7,
para probar el cdigo del juego sin sonido en navegadores Internet
Explorer que tienen o dan problema con la precarga de los elementos
del juego.
function estadoInicialJuego() {
crearTodosObjetos();
cantElemCarga = 0;
elementosACargar=16; // cambiar a 7 si
experimenta problemas con IE

sonidoExplosion =
document.createElement(audio);
document.body.appendChild(sonidoExplosion);
tipoDeAudio =
supportedAudioFormat(sonidoExplosion);
sonidoExplosion.setAttribute(src,
explode1. + tipoDeAudio);
sonidoExplosion.addEventListener(canplaythrou

elementoCargado,false);

sonidoExplosion2 =
document.createElement(audio);
document.body.appendChild(sonidoExplosion2);
sonidoExplosion2.setAttribute(src,
explode1. + tipoDeAudio);
sonidoExplosion2.addEventListener(canplaythro

elementoCargado,false);

sonidoExplosion3 =
document.createElement(audio);
document.body.appendChild(sonidoExplosion3);
sonidoExplosion3.setAttribute(src,
explode1. + tipoDeAudio);
sonidoExplosion3.addEventListener(canplaythro

elementoCargado,false);

sonidoDisparo =
document.createElement(audio); audioType =
supportedAudioFormat(sonidoDisparo);
document.body.appendChild(sonidoDisparo);
sonidoDisparo.setAttribute(src, shoot1. +
tipoDeAudio);
sonidoDisparo.addEventListener(canplaythrough

elementoCargado,false);

sonidoDisparo2 =
document.createElement(audio);
document.body.appendChild(sonidoDisparo2);
sonidoDisparo2.setAttribute(src, shoot1.
+ tipoDeAudio);
sonidoDisparo2.addEventListener(canplaythrou

elementoCargado,false);

sonidoDisparo3 =
document.createElement(audio);
document.body.appendChild(sonidoDisparo3);
sonidoDisparo3.setAttribute(src, shoot1.
+ tipoDeAudio);
sonidoDisparo3.addEventListener(canplaythrou

elementoCargado,false);

sonidoDisparoPlatillo =
document.createElement(audio); audioType =
supportedAudioFormat(sonidoDisparoPlatillo);
document.body.appendChild(sonidoDisparoPlatill
sonidoDisparoPlatillo.setAttribute(src,
saucershoot. +

tipoDeAudio);
sonidoDisparoPlatillo.addEventListener(canpla
elementoCargado,false);

sonidoDisparoPlatillo2 =
document.createElement(audio);
document.body.appendChild(sonidoDisparoPlatill
sonidoDisparoPlatillo2.setAttribute(src,
saucershoot. +

tipoDeAudio);
sonidoDisparoPlatillo2.addEventListener(canpl
elementoCargado,false);

sonidoDisparoPlatillo3 =
document.createElement(audio);
document.body.appendChild(sonidoDisparoPlatill
sonidoDisparoPlatillo3.setAttribute(src,
saucershoot. + tipoDeAudio);

sonidoDisparoPlatillo3.addEventListener(canpl
elementoCargado,false);

mosaicoNave = new Image();


mosaicoNave.src = ship_tiles.png;
mosaicoNave.onload = elementoCargado;

mosaicoNave2 = new Image();


mosaicoNave2.src = ship_tiles2.png;
mosaicoNave2.onload = elementoCargado;

mosaicoPlatillos= new Image();


mosaicoPlatillos.src = saucer.png;
mosaicoPlatillos.onload = elementoCargado;
mosaicoPiedrasGrandes = new Image();
mosaicoPiedrasGrandes.src = largerocks.png;
mosaicoPiedrasGrandes.onload =
elementoCargado;

mosaicoPiedrasMedianas = new Image();


mosaicoPiedrasMedianas.src =
mediumrocks.png;
mosaicoPiedrasMedianas.onload =
elementoCargado;

mosaicoPiedrasPeque = new Image();


mosaicoPiedrasPeque.src = smallrocks.png;
mosaicoPiedrasPeque.onload = elementoCargado;

mosaicoParticulas = new Image();


mosaicoParticulas.src = parts.png;
mosaicoParticulas.onload = elementoCargado;

cambioEstadoApp(ESTADO_ESPERA_CARGUE_JUEGO);
}

Note que debemos crear y precargar tres instancias de cada sonido, a


pesar de que comparten el mismo archivo de sonido (o archivos). En
esta funcin tambin cargaremos nuestras hojas de mosaicos. La
aplicacin chequea el alcance de los elementos a cargar a traves de la
variable elementosACargar contra el alcance de elementos
cargados a traves de la variable cantElemCarga, en los eventos
de carga llamados a traves de la funcin elementoCargado(),
que es compartida por todos los elementos que han de cargarse. Esto
hace que sea fcil para que la aplicacin cambie de estado y se pueda
comenzar a jugar el juego siempre y cuando todos los elementos se
hayan cargado satisfactoriamente. Vamos a examinar brevemente la
funcin elementoCargado() ahora:

function elementoCargado(evento) {
cantElemCarga++;
console.log(loading: + cantElemCarga);

console.log(itemsToLoad: +
elementosACargar); if (cantElemCarga >=
elementosACargar) {

sonidoDisparo.removeEventListener(canplaythro
elementoCargado, false);
sonidoDisparo2.removeEventListener(canplaythr
elementoCargado,false);
sonidoDisparo3.removeEventListener(canplaythr
elementoCargado,false);
sonidoExplosion.removeEventListener(canplayth
elementoCargado,false);
sonidoExplosion2.removeEventListener(canplay
elementoCargado,false);
sonidoExplosion3.removeEventListener(canplay
elementoCargado,false);
sonidoDisparoPlatillo.removeEventListener(can
elementoCargado,false);
sonidoDisparoPlatillo2.removeEventListener(ca
elementoCargado,false);
sonidoDisparoPlatillo3.removeEventListener(ca
elementoCargado, false);

grupoSonido.push({nombre:explode1,
elemento:sonidoExplosion, juega:false});
grupoSonido.push({nombre:explode1,
elemento:sonidoExplosion2, juega:false});
grupoSonido.push({nombre:explode1,
elemento:sonidoExplosion3, juega:false});
grupoSonido.push({nombre:shoot1,
elemento:sonidoDisparo, juega:false});
grupoSonido.push({nombre:shoot1,
elemento:sonidoDisparo2, juega:false});
grupoSonido.push({nombre:shoot1,
elemento:sonidoDisparo3, juega:false});
grupoSonido.push({nombre:saucershoot,
elemento:sonidoDisparoPlatillo,
juega:false});
grupoSonido.push({nombre:saucershoot,
elemento:sonidoDisparoPlatillo2,
juega:false});
grupoSonido.push({nombre:saucershoot,
elemento:sonidoDisparoPlatillo3,
juega:false});

cambioEstadoApp(ESTADO_TITULO_DEL_JUEGO);
} }

En esta funcin primero removemos todos los listener de los eventos de


cada uno de los elementos cargados y luego agregamos el sonido a
nuestro grupo de sonidos. Finalmente podemos llamar a la funcin
cambioEstadoApp() para que envie la pantalla con los titulos y
crditos del juego.

Reproducir sonidos

Para reproducir el sonido que necesitamos en nuestro juego,


usaremos la funcin reproducirSonido(). Esta funcin es
llamada en varias instancias de nuestro cdigo para que reproduzca
exactamente el sonido que necesitamos. Por ejemplo, la funcin
crearExplosion() presentada con anterioridad en esta seccin
incluye esta linea:

reproducirSonido(SONIDO_EXPLOSION,.5);

Cuando queremos reproducir la instancia de un sonido desde nuestro


grupo, llamamos a la funcin reproducirSonido() y
pasamos las constantes que representan el sonido y el volumen del
sonido. Si una instancia del sonido esta disponible en el grupo, esta es
usada, y el sonido se reproducir. Vamos a revisar como esta
constituida esta funcin:

function reproducirSonido(sonido,volume) {
ConsoleLog.log(reproducir sonido + sonido);
var sonidoEncontrado = false;
var indiceSonido = 0;
var sonidoTemp;

if (grupoSonido.length> 0) {
var sonidoT = grupoSonido[indiceSonido];
nombre == sonido) {
sonidoEncontrado = true; sonidoT.juega =
true;

} else {
indiceSonido++;
}

} }

if (sonidoEncontrado) {
ConsoleLog.log(sonido encontrado);
sonidoTemp =
grupoSonido[indiceSonido].elemento;
//sonidoTemp.setAttribute(src, sonido + .
+ tipoDeAudio); //sonidoTemp.loop = false;
//sonidoTemp.volume = volume;
sonidoTemp.play();

} else if (grupoSonido.length < VOLUMEN_MAX){


ConsoleLog.log(sonido no encontrado);
sonidoTemp = document.createElement(audio);
sonidoTemp.setAttribute(src, sonido + . +
tipoDeAudio); sonidoTemp.volume = volume;
sonidoTemp.play();
grupoSonido.push({nombre:sonido,
elemento:sonidoTemp,

tipo:tipoDeAudio,juega:true});
}
}
Ahora vamos a movernos dentro de otro tipo de contenedor de
aplicacin, el objeto contenedor.

Instancias del objeto contenedor

Hemos visto como los objetos contenedores se relacionan con los


sonidos, pero no hemos aplicado este concepto a los objetos de
nuestro juego. La agrupacin de objetos es una tcnica diseada para
ahorrar tiempo de procesado, por lo que es til y aplicable a las
aplicaciones de juegos arcade, como la que estamos construyendo.
Mediante la combinacin de instancias de objetos, se evita el uso
intensivo del procesador muchas veces al crear instancias de objetos
sobre la marcha durante la ejecucin del juego. Esto es especialmente
aplicable a las explosiones de particulas, ya que creamos varios
objetos en el mismo fotograma. En una plataforma de baja potencia,
como un dispositivo manual, la agrupacin de objetos puede ayudar a
incrementar la velocidad de los fotogramas.

El Objeto conetenedor en nuestro juego


En nuestro juego, aplicamos el concepto de agrupar a las explosiones
de partculas. Por supuesto, podemos extender este concepto a las
piedras, misiles, platillos y a cualquier tipo de objeto que requiera
mltiples instancias.

Para este ejemplo, pensamos enfocarnos en las partculas. Como


veremos, agregar contenedores en javascript es relativamente simple,
pero una tcnica muy poderosa.

Agregando variables contenedor a nuesto juego


Necesitamos agregar cuatro variables de mbito a nuestra aplicacin
para usar cuatro contenedores de partculas en nuestro juego.

var contenedorDeParticulas = []; var


particulasMax = 200;
var nuevaParticula; var particulasTemp;

La matriz contenedorDeParticulas almacena la lista de objetos


particulas instanciadas que estn esperando ser usadas. Cuando la
funcin crearExplosion() necesita usar una particula, este ve
primeramente si hay alguna disponible. Si alguna est disponible, esta
la extrae de la parte superior de la pila de la matriz
contenedorDeParticulas y la coloca en la aplicacin al alcance de la
variable nuevaParticula, la cual es una referencia a la partcula
agrupada. La funcin crearExplosion() conigura las propiedades de
nuevaParticula y luego lo empuja al inal de la matriz de las particulas
existentes.

Cuando la vida de una partcula llega a su in, la funcin


actualizarParticulas() une la particula desde la matriz particulas y la
coloca en lo ltimo de la matriz contenedorDeParticula. Hemos creado
la referencia a la variable particulaTemp para aliviar a la funcin
actualizarParticulas(), necesaria para crear esta instancia en cada
fotograma.

El valor de la variable particulasMax es usada en una nueva funcin


llamada crearObjetosContenedores(). Llamamos a esta funcin en la
funcin estadoInicial(), antes de crear los sonidos y los eventos de
carga de las hojas de mosaico. Vamos a revisar la funcin
crearObjetosContenedores():

function crearObjetosContenedores(){
for (var ctr = 0; ctr < particulasMax; ctr++){
var nuevaParticula = {};
contenedorDeParticulas push(nuevaParticula);

}
console.log( contenedorDeParticulas= +
contenedorDeParticulas length); }

Cmo podrs ver, simplemente iterar 0 a 1 menos que el valor de


particulasMax y colocar una instancia de objeto genrico en cada
elememnto del contenedor. Cuando se necesita una partcula, la
funcin crearExplosion() ve si contenedorDeParticulas lenght es mayor
que 0. Si una partcula esta disponible, se aade a la amtriz de las
aprtculas despus de haber conigurado sus atributos. Si ninguna
partcula est disponible no se usa.

Nota destacada!
La funcionalidad puede ser extendida para agregar una partcula al
contenedor cuando no este disponible. No tenemos que agregar esa
funcionalidad a nuestro juego, pero es bastante comn hacerlo en
algunos algoritmos Atento de contenedores.
Aqu esta la nueva funcin crearExplosion() modiicada completamente:
function crearExplosion(x,y,num,tipo) {
reproducirSonido(SONIDO_EXPLOSION,.5); for
(var contarParticulas=0;contarParticulas<num;
contarParticulas++){
if (contenedorDeParticulas.length > 0){

nuevaParticula =
contenedorDeParticulas.pop();
nuevaParticula.dx = Math.random()*3;
if (Math.random()<.5){

nuevaParticula.dx *= -1;
}
nuevaParticula.dy = Math.random()*3;

if (Math.random()<.5){
nuevaParticula.dy *= -1;
}

nuevaParticula.contarVida = 0;
nuevaParticula.x = x;
nuevaParticula.width = 2;
nuevaParticula.height = 2;
nuevaParticula.y = y;
nuevaParticula.tipo = tipo;

//ConsoleLog.log(nuevaParticula.vida= +
nuevaParticula.vida);
particulas.push(nuevaParticula);
}
} }

La funcin actualizarParticulas() pasar un bucle a traves


de las instancias particulas, actualiza los atributos de cada una, y luego
chequea cuando la vida de las partculas ha terminado. Si es as, la
funcin coloca las partculas en la parte inal del contenedor. A
continuacin se muestra el cdigo que agregamos a la funcin
actualizarParticulas():

if (remover) {
contenedorDeParticulas.push(particulasTemp);
particulas.splice(contarParticulas,1);

Agregando un temporizador de paso

En nuestra aplicacin del captulo 3, creamos un simple objeto


prototype ContadorDeFotogramas que mostraba la cantidad de
fotogramas actuales mientras el juego estaba en plena accin. Ahora
vamos a extender la funcionalidad de nuestro contador agregando un
temporizador de paso. El temporizador de paso usa la diferencia de
tiempo calculada entre los fotogramas para crear un factor paso. Este
factor paso es usado cuando se actualiza la posicin de los objetos en
el canvas. El resultado ser el renderizado mas suave de los objetos
del juego cuando hay cadas en la velocidad de fotogramas y el juego
es relativamente constante en los navegadores y sistemas que no
pueden mantener la velocidad de fotogramas necesarios para jugar
eicazmente.

Actualizamos el constructor de la funcin ContadorDeFotogramas para


que acepte un nico parametro al que llamaremos fps. Este valor
representa los fotogramas por segundo que queremos que nuestro
juego tenga.
function ContadorDeFotogramas(fps) { if (fps == undeined){

this.fps = 40; }else{


this.fps = fps; }

Si el valor del parmetro fps no es pasado junto con la funcin,


entonces ser usado el valor de 40.
Tambin agregamos dos nuevas variables de nivel al objeto, para
calcular el paso en nuestro temporizador de paso:
this ultimaTiempo = tiempo.getTime(); this.paso = 1;

La variable ultimaTiempo contiene el tiempo en la cual el anterior


fotograma completado trabaj. Calculamos el paso comparando el
valor del tiempo actual con el valor de la variable ultimaTiempo en cada
uno de los fotogramas. Este calculo ocurre en la funcion
ContadorDeFotogramas cuentaFotogramas():

ContadorDeFotogramas prototype.cuentaFotogramas = function() {

var tiempo = new Date();


var diferenciaTiempo = tiempo.getTime()-this ultimaTiempo; this.paso =
(diferenciaTiempo/1000)*this.fps;
this ultimaTiempo = tiempo.getTime();

El valor local de la variable diferenciaTiempo es calcualda restando el


valor de la variable ultimaTiempo de la hora actual (representada por
el valor devuelto por tiempo.getTime()).

Para calcular el valor del paso, se divide el valor de la variable


diferenciaTiempo entre 1000 (la cantidad de milisegundos en un
segundo) y el resultado se mltiplica por la cantidad de fotogramas
deseado. Si el juego est rodando sin superavit o deicit de tiempo
entre los fotogramas, el valor del paso ser 1. Si el actual fotograma
toma ms tiempo que un fotograma para terminar, el valor es mayor que
uno (deicit). Si el actual fotograma toma menos tiempo que un
fotograma, el valor del paso es menor que 1 (superavit).

Por ejemplo si el ltimo fotograma tom demasiado tiempo para


procesar, el actual fotograma compensar moviendo cada objeto un
poco ms que el valor del paso, que en este caso es igual a 1. Vamos a
ilustrar esto con un simple objeto. Digamos que queremos que el
platillo se mueva 5 pixeles a la derecha en cada fotograma, esto sera
un valor para la variable dx igual a 5. Para este mismo ejemplo decimos
que deseamos una cantidad de fotogramas igual a 40fps. Esto signiica
que queremos que cada fotograma use 26 milisegundos (1000/40 =
25).

Vamos tambin a suponer que la variable diferenciaTiempo entre el


actual fotograma y el ltimo fotograma es de 25 milisegundos. Nuestro
juego esta corriendo con un deicit de 1 milisegundo por fotograma - Lo
que signiica que el procesar el juego esta tomando mas tiempo del que
queremos.

Para calcular el valor del paso, dividimos la variable diferenciaTiempo


entre 1000 : 26/1000 = 26. Mltiplicamos este valor por la cantidad de
fotogramas que deseamos para nuestro juego: .26*40=1.04. Nuestro
paso tiene un valor de 1.04 para el actual fotograma. Debido al deicit
en el tiempo de procesado, queremos mover todos los objetos del
juego algo mas de un fotograma de lo que tengamos.En el caso de
deicit, el valor de incremento ser 1. Si hay superavit el valor del paso
sera menor que 1.

El valor del paso es mltiplicado para los cambios de movimientos en


cada uno de los vectores de los objetos dentro de la funcion
actualizar(). Esto le permite al juego tener una suavidad relativa,
siempre y cuando existan luctuaciones en la cantidad de fotogramas.
Ademas, el juego actualiza la pantalla de una manera relativamente
constante a travs de los diversos navegadores y sistemas, lo que
resulta en que el juego es relativamente constante para cada usuario.
A continuacin los nuevos clculos de vectores de movimiento para
cada objeto dentro de la funcin actualizar():

jugador
jugador x += jugador.moverX*contadorDeFotogramas.paso; jugador.y
+= jugador moverY*contadorDeFotogramas paso;

misilesDelJuagdor
misilesJugadorTemp x +=
misilesJugadorTemp.dx*contadorDeFotogramas.paso;
misilesJugadorTemp.y +=
misilesJugadorTemp.dy*contadorDeFotogramas paso;

piedras
piedrasTemp x += piedrasTemp.dx*contadorDeFotogramas paso;
piedrasTemp.y += piedrasTemp.dy*contadorDeFotogramas.paso;

platillo
platilloTemp x += platilloTemp.dx*contadorDeFotogramas paso;
platilloTemp.y += platilloTemp.dy*contadorDeFotogramas.paso;

misilesDelPlatillo
misilesDelPlatilloTemp.x +=
misilesDelPlatilloTemp.dx*contadorDeFotogramas paso;
misilesDelPlatilloTemp.y +=
misilesDelPlatilloTemp.dy*contadorDeFotogramas.paso;

particulas
particulasTemp x += particulasTemp.dx*contadorDeFotogramas paso;
particulasTemp.y += particulasTemp.dy*contadorDeFotogramas.paso;
Ya hemos cubierto casi todos los cambios que pensamos hacer para
acercar nuestra pequea aplicacin a la realidad.

Crear rutinas para hoja de mosaicos dinmicas

Das könnte Ihnen auch gefallen