Beruflich Dokumente
Kultur Dokumente
ejemplos
Juan Carlos Reyes C.
Sissi, si se pudo!
Juan Carlos Reyes C.
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.
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.
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.
Navegadores web
Navegadores mobiles
HTML5
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.
Javascript
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.
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.
object [propertyNameExpression]
coche.marca
coche[marca]
coche[m + a + r + c + a]
var coche = {
marca : Ford,
modelo : Mondeo,
anio : 2013,
fechaCompra : new Date(2013,01,08),
propietario: {
}
};
Utilizando un literal del objeto, este fragmento crea el mismo objeto
coche que construimos anteriormente con la sentencia de asignacin
de la seccin precedente.
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
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 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:
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.
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.
(){
alert(haces alguna cosa);
}
window
unNumeroMaravilloso hacerAlgunaCosa
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:
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
marca : Ford,
modelo : Mondeo,
anio : 2013,
fechaCompra : new Date(2013,01,08),
propietario: {
Cadena Ford
Cadena Mondeo Nmero 2013
Fecha
08-01-2013
Cadena Juan Reyes
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.
<head>
<title>funcion Contexto</title> <script>
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.
Closures
<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.
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
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>.
Height
Descripcin
Tipo
Valores permitidos
Valores por defecto
</head>
<body>
<canvas id=canvas width=600 height=300>
</body>
</html>
atributos
valor
getContext(contextId)
Descripcin
Devuelve el contexto grico asociado con el elemento canvas. Cada
elemento
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)
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.
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
elemen
Descripcin
Devuelve un objeto CanvasProxy que se puede utilizar para
transferir el
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
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;
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
scale(float x, float y)
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>
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>
//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(); }
}
<head>
<title>Ejemplo del mé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>
//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();
<head>
<title>Ejemplo del mé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>
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().
Descripcin
Aplica la transformacin especiicada por los seis (6) argumentos. Las
trans
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
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); }
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>
//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();
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>
//
Funciones....................................
function dibujarTexto() {
context.strokeText(texto, 0, 0); }
// Manejadores de
eventos..................................
}
}, 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();
<head>
<title>Aplicación del método
setLineDash() </title>
<style>
body {
background: #eaeaea;
}
#contenedor{
width:500px;
margin:0px auto;
padding-top:50px;
}
#canvas {
}
</style> </head>
<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
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()
closePath()
Descripcin
Explcitamente cierra un path abierto. Este mtodo es para abrir paths
de arcos y paths creados con lneas o curvas.
Descripcin
Agrega los subpaths que vienen a representar un arco o un crculo al
actual
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);
}
context.restore(); }
dibujarCuadricula(context, lightgray, 10,
10); drawScreen();
context.moveTo(x, y);
context.lineTo(x + w, y);
context.lineTo(x + w, y + h);
context.lineTo(x, y + h);
context.closePath();
<head>
<title>
Aplicación del mé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>
<script src=javascript/rect.js></script>
</body>
</html>
}else {
context.moveTo(x, y);
context.lineTo(x + w, y);
context.lineTo(x + w, y + h);
context.lineTo(x, y + h);
}
context.closePath();
}
El mtodo fill()
Atento
odd rule). Los subpaths abiertos deben ser implcitamente cerrados
cuando ha sido rellenado (sin afectar los subpaths reales).
stroke(Path path)
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.
}
#radios {
padding: 10px; }
</style>
</head>
<body>
</body>
</html>
// Dibujar
atributos....................................
context.font = 28pt Helvetica;
context.strokeStyle = green;
//
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();
context.beginPath();
context.arc(500, 280, 40, 0, Math.PI*3/2);
context.stroke();
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.
<style>
#canvas {
background: #eaeaea;
}
#radios {
padding: 10px; }
</style>
</head>
<body>
//
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>
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>
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.
#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>
{ 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(); }
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.
<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>
<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>
<input id=botonOkInstrucciones
type=button value=Okay autofocus/>
<input id=botonNoMasInstrucciones
type=button value=No mostrar mas las
instrucciones/>
</div>
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);
}
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);
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 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_
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);
}
}
};
if(lineasGuias) {
dibujarLineasGuias(loc.x, loc.y);
}
}
if (arrastrar) {
actualizarBandas(loc);
dibujarPuntosControlYFinales();
}
else if (puntoArrastre) {
actualizarPuntoDeArrasytre(loc);
dibujarPuntosControlYFinales();
dibujarCurvasBezier();
}
};
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...............................
ESPACIO_CUADRICULA);
editar = false; arrastrar = false;
};
// Manejadores de eventos -
instrucciones......................
botonNoMasInstrucciones.onclick = function
(e) { instrucciones.style.display = none;
mostrarInstrucciones = false;
};
// Iniciar
aplicacin...................................
context.strokeStyle =
selectEstiloLinea.value;
dibujarCuadricula(context, ESTILO_CUADRICULA,
ESPACIO_CUADRICULA, ESPACIO_CUADRICULA);
#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>
//
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);
}, 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......................................
// Iniciar
aplicacin...................................
dibujarCuadricula(context, lightgrey, 10,
10); dibujarTexto();
#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>
</body>
</html>
//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.strokeStyle = blue;
context.rect(200,100,200,200); //manejadores
de
eventos......................................
context.canvas.onmousedown = function (e) {
if (context.isPointInPath(200,150)) {
} };
scrollPathIntoView(path, element)
Atento
Descripcin
Dibuja una elipse segn los argumentos especicados. Si la trayectoria
del obje
position:absolute;
left:10px;
top:1.5em;
margin:20px;
border:thin solid #aaaaaa;
}
</style>
</head>
<body>
</body>
</html>
}
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();
}
context.beginPath();
context.strokeStyle = black;
context.lineWidth = 2;
//full circle
context.stroke(); context.closePath();
}
dibujarCuadricula(context, lightgray, 10,
10); drawScreen();
resetClip()
Mtodos de Rectangulos
La API de Canvas provee tres mtodos para aclarar o limpiar, dibujar y
rellenar rectngulos, respectivamente:
background: #dddddd;
}
#canvas {
position:absolute;
left:10px;
top:1.5em;
margin:20px;
border:thin solid #aaaaaa;
}
</style>
</head>
<body>
</body>
</html>
context.strokeStyle = blue;
context.strokeRect(75, 100, 200, 200);
background: #dddddd; }
#canvas {
position:absolute;
left:10px;
top:1.5em;
margin:20px;
border:thin solid #aaaaaa;
}
</style>
</head>
<body>
</body>
</html>
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>
</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>
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.
<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>
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
<head>
<title>Aplicación del mé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
</body>
</html>
escalaDeSalida =
document.getElementById(escalaDeSalida);
guiaDeEscala =
document.getElementById(guiaDeEscala),
escala = guiaDeEscala.value,
escala = 1.0,
ESCALA_MINIMA = 1.0,
//
Funciones....................................
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() {
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;
Descripcin
Este mtodo acepta los mismos argumentos y trabaja de la misma
manera que
measureText(string text)
Descripcin
Este mtodo acepta solo un argumento: la cadena de texto a ser
medida.
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.
<head>
<title>Aplicación de los
mé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 {
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>
<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ño: <input type=range
id=tamaoTexto
min=0 max=200 step=1 value=50/>
<br>
</div>
<div id=colores>
<option value=stroke>Delinear</option>
<option value=both>Ambos</option> </select>
<br>
Alineació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ó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>
<br>
</div>
<div id=adicionales>
min=-100
max=100
step=1
value=1/>
<br>
<br>
<br>
Color sombra: <input class=color
id=colorSombra value=707070/>
<br>
<br>
Alto del canvas:
<input type=range id=altoDelCanvas
min=0
max=1000
step=1
value=300/>
<br>
<br>
Estiloalto canvas:
<input type=range
id=estiloDeAltoDelCanvas min=0
max=1000
step=1
value=300/>
<br>
<br>
</div>
<div id=areaTexto>
</div>
var sombreadoY = 1;
var desenfoqueSombra = 1;
var colorSombra = #707070;
var alineacionVertical = middle; var
alineacionHorizontal = center;
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);
vartempColor;
if (tipoRelleno == colorFill) {
tempColor = colorRellenoTexto;
} else if (tipoRelleno == linearGradient) {
var gradient = context.createLinearGradient(
gradient.addColorStop(0,colorRellenoTexto);
gradient.addColorStop(.6,colorRellenoTexto2);
tempColor = gradient;
1);
gradient.addColorStop(0,colorRellenoTexto);
gradient.addColorStop(.6,colorRellenoTexto2);
tempColor = gradient;
} else {
tempColor = colorRellenoTexto;
}
switch(RellenarODelinear) {
break;
case stroke:
context.strokeStyle = tempColor;
context.strokeText ( mensajeBienvenida,
function cambiarCajaTexto(e) {
var target = e.target;
mensajeBienvenida = target.value;
dibujarEnCanvas();
}
var target = e.target;
dibujarEnCanvas(); }
}
function cambiarTransparenciaTexto(e) { var
target = e.target;
transparenciaTexto = (target.value);
dibujarEnCanvas();
}
function cambiarTamanoCanvas(e) {
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 eventWindowLoaded() {
var patrones = new Image();
patrones.src = texture.jpg;
patrones.onload = cargarRecursosAplicacion;
}
function cargarRecursosAplicacion() {
aplicacionTextos();
}
Atento
(400 x 400) pixeles de dispositivo. Tu puedes sacar muchos pixeles de
dispositivo con las propiedades width y height de tu objeto
imagedata.
canvas
y imagedata
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.
Atento
<head>
<title>
Aplicaciónde los mé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>
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
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;
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);
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().
Descripcin
Este mtodo puede tomar solo un set de argumentos:
<head>
<title>Ejemplo de los mé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>
image.onload = demo;
image.src = images/slider-img2.jpg;
}
function demo() {
var canvas =
document.getElementsByTagName(canvas)[0];
var context = canvas.getContext(2d);
// deteccin de bordes
for (var y = 1; y < h-1; y += 1) {
for (var x = 1; x < w-1; x += 1) {
-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);
}
drawSystemFocusRing(path, element)
Nota destacada!
Atento
drawCustomFocusRing(path, element)
La regin Clipping
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>
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();
false);
//circulo full
context.stroke(); context.closePath();
context.restore();
fillStyle
Descripcin
Tipo
Valor por defecto
font
Descripcin
Tipo
Valor por defecto
Atento
Configurar las propiedades de la fuente.
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.
<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>
<script src=javascript/font.js></script>
</body>
</html>
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();
}
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;
});
globalAlpha
Descripcin
Tipo
Valor por defecto
Atento
Nota destacada!
globalComposite-Operation
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
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>
//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
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
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
shadowBlur
Descripcin
Tipo
Valor por defecto
Numbers
0.0
shadowColor
Descripcin
Tipo
Valor por defecto
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)
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
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
textAlign
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
textBaseLine
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
<script src=javascript/posicionTextos.js>
</script> </body> </html>
//
Funciones....................................
function dibujarCuadricula(context, color,
stepx, stepy) { context.save();
context.strokeStyle = color;
context.lineWidth = 0.5;
height);
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);
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
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
<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>
</div>
<script src=javascript/dash.js></script>
</body>
</html>
// 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
width, actualBoundingBoxLeft,
actualBoundingBoxRight,
fontBoundingBoxAscent,
fontBoundingBoxDescent,
actualBoundingBoxAscent,
actualBoundingBoxDescent, emHeightAscent,
emHeightDescent, hangingBaseline,
alphabeticBaseline, ideographicBaseline
Direccion horizontal X
width
Descripcin
Representa el ancho del texto dado. viene expresado en pixeles CSS
actualBoundingBoxLeft
Descripcin
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
Direccion vertical Y
fontBoundingBoxAscent
fontBoundingBoxDescent
actualBoundingBoxAscent
Descripcin
actualBoundingBoxDescent
emHeightAscent
emHeightDescent
hangingBaseline
alphabeticBaseline
ideographicBaseline
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
Especiica colores ijos dentro de un gradiente. Si tu especicas 2 o mas
para
El Objeto ImageData
height
Descripcin
Devuelve el componente de altura real de los datos en el objeto
ImageData,
Descripcin
Devuelve el nmero terico de pixeles en los datos del objeto
ImageData
data
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.
moveTo(float x, float y)
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
Crea un path para una curva Bzier cuadrtica. Este mtodo acepta
cuatro (4)
Descripcin
Agrega una curva bezier cubica al actual subpath. Este mtodo acepta
seis (6)
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.
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();
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.
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.
miterLimit
lineDashOffset
font
Descripcin
Especiica la fuente usada por el objeto DrawingStyle. La sintaxis es la
misma
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.
textAlign
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.
getLineDash(segments)
La regin Hit
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)
La regin Hit puede ser usada para una gran variedad de propsitos!
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)
<head>
<title>Aplicación de La Region
Hit</title> <style>
body {
background: #eaeaea;
}
#contenedor{
width:500px; margin:0px auto; padding-
top:50px; }
#canvas {
}
</style> </head>
<script src=javascript/regionHit.js>
</script> </body>
</html>
Descripcin
Para probar si un punto P esta dentro de un path, utilizando la regla
nonzeron
imagen 2.37
- aplicacin de la regla nonzero
EvenOdd Rule
Descripcin
El valor EvenOdd indica la regla par-impar, en el que un punto se
considerar
Adicional al canvas
ctx.beginPath();
ctx.arc(75, 75, 75, 0, Math.PI*2, true);
ctx.arc(75, 75, 25, 0, Math.PI*2, true);
Un potente escenario
<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>
<script src=defensaEspacial.js></script>
</body>
</html>
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;
}
}
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 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.
Que necesitaremos
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.
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();
context.stroke();
Animacin en el canvas
crearDibujo();
window.setTimeout(gameLoop, intervaloTiempo);
}
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
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() {
//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++;
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
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:
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:
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() {
//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);
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);
}
}
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);
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
transparencia=0; }
}
function temporizador(){
crearDibujo();
window.setTimeout(temporizador,
intervaloTiempo);
}
}
x = x+moverX; y = y+moverY;
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:
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; };
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.
canvasApp();
}
function canvasApp(){
var canvas =
document.getElementById(canvas); if
(!canvas || !canvas.getContext) {
return;
}
var context = canvas.getContext(2d);
if (!context) { return;
}
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);
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;
};
}
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:
ESTADO_TITULO_DEL_JUEGO
ESTADO_NUEVO_JUEGO
ESTADO_NUEVO_NIVEL
ESTADO_JUGADOR_INICIAL
ESTADO_NIVEL_DEL_JUEGO
ESTADO_JUGADOR_MUERTO
ESTADO_JUEGO_TERMINADO
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();
}
canvasApp();
}
function canvasApp(){
var canvas =
document.getElementById(canvas);
if (!canvas || !canvas.getContext) {
return;
}
if (!context) { return;
}
//estados de la aplicacin
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();
}
function temporizador() {
iniciarJuego();
window.setTimeout(temporizador,intervaloTiempo
}
}
//***** objecto prototypes *****
}
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
}
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) {
y=y+moverY;
}
function renderizar() {
//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
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();
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;
};
}
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
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;
};
}
console.log(message);
}
}
//agregar la funcin clase/estatica para la
clase por asignacin
ConsoleLog.log=console_log;
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; }
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;
//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()
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.
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);
}
jugador.avance = true;
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];
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(); }
}
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; }
}
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;
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
{
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);
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()
function agregarAPuntuacion(valor){
puntuacion+=valor;
}
//titulos en pantalla
var titulosIniciales=false;
//valores de puntuacin
var puntosPiedrasGrandes=50; var
puntosPiedrasMedianas=75; var
puntosPiedrasPequenas=100; var
puntosPlatillos=300;
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
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;
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
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;
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
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
level ++;
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 chequearParaNaveExtra() {
navesJugador++; naveExtraGanada++; }
}
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;
return(true);
}
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:
<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>
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;
var nivelAjusteVelocidadMaxPiedra=1;
var nivelPlatilloMax = 1;
var nivelPromedioAparicionPlatillo=25;
var nivelVelocidadPlatillo=1;
var nivelRetrasoDisparoPlatillo=300;
var nivelPromedioDisparoPlatillo=30;
var nivelVelocidadMisilPlatillo=1;
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);
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;
//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();
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;
function actualizarMisilesDelJugador()
{
var misilesJugadorTemp={};
var
cantMisilesJugador=misilesDelJugador.le
1;
ConsoleLog.log(actualizar cantidad de
misiles = + cantMisilesJugador); for
(var
contarMisilesJugador=cantMisilesJugador
contarMisilesJugador--){
misilesJugadorTemp.lifeCtr++;
if (misilesJugadorTemp.lifeCtr >
misilesJugadorTemp.life){
ConsoleLog.log(removermisiles del
jugador);
misilesDelJugador.splice(contarMisilesJ
misilesJugadorTemp=null;
}
}
}
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
nuevoPlatillo.velocidadMisil=
nivelVelocidadMisilPlatillo;
nuevoPlatillo.retrasoDisparo=
nivelRetrasoDisparoPlatillo;
nuevoPlatillo.disparosPromedios=
nivelPromedioDisparoPlatillo;
platillos.push(nuevoPlatillo); }
}
cantidadPlatillos);
for (var
contarPlatillos=cantidadPlatillos;conta
contarPlatillos--){
platilloTemp =
platillos[contarPlatillos];
platilloTemp.disparosPromedios &&
platilloTemp.cuentaDisparosRetrasos >
platilloTemp.retrasoDisparo ){
misilDisparadoPorPlatillo(platilloTemp)
platilloTemp.cuentaDisparosRetrasos=
0;
}
var remover = false;
platilloTemp.x += platilloTemp.dx;
platilloTemp.y += platilloTemp.dy;
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--){
}
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;
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
context.beginPath();
context.moveTo(-10,-15);
context.lineTo(15,0);
context.lineTo(-10,15);
context.lineTo(0,0);
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
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
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.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
context.beginPath();
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
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];
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; }
}
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; }
}
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) {
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;
};
function temporizador(){
iniciarJuego();
window.setTimeout(temporizador,
intervaloTiempo);
}
}
//***** objectos prototype *****
}
console_log=function(message) {
console.log(message);
}
}
//agregar la funcin clase/estatica
para la clase por asignacin
ConsoleLog.log=console_log;
Bomomo(www.bomomo.com)
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
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
Pocket Full of
Canvas(www.nihilogic.dk/labs/pocket_full_of_canvas/#pres
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)
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/)
Gamepad API(https://wiki.mozilla.org/GamepadAPI)
HTML5 Test(http://html5test.com)
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.
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
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
tabla A!
- Nombre de colores y sus equivalencias hexadecimales
estandard HTML 4.0
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.
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;
}
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);
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) {
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.
function renderizarPlatillos() {
var platilloTemp = {};
var cantidadPlatillos = platillos.length-1;
for (var contarPlatillos =
cantidadPlatillos;contarPlatillos>=0;
contarPlatillos--){
//ConsoleLog.log(platillos: +
contarPlatillos); platilloTemp =
platillos[contarPlatillos];
function renderizarPiedras() {
var piedrasTemp = {};
var cantPiedras = piedras.length-1;
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
} }
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; }
}
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.
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
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
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.
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);
}
}
}
platillos: tipo = 0
piedras grandes: tipo = 1 piedras medianas: tipo = 2 piedras
pequeas: tipo = 3 jugador: tipo = 4
function renderizarParticulas() {
;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
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
var sonidoExplosion;
var sonidoExplosion2;
var sonidoExplosion3;
var sonidoDisparo;
var sonidoDisparo2;
var sonidoDisparo3;
var sonidoDisparoPlatillo; var
sonidoDisparoPlatillo2; var
sonidoDisparoPlatillo3;
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);
cambioEstadoApp(ESTADO_ESPERA_CARGUE_JUEGO);
}
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);
} }
Reproducir sonidos
reproducirSonido(SONIDO_EXPLOSION,.5);
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();
tipo:tipoDeAudio,juega:true});
}
}
Ahora vamos a movernos dentro de otro tipo de contenedor de
aplicacin, el objeto contenedor.
function crearObjetosContenedores(){
for (var ctr = 0; ctr < particulasMax; ctr++){
var nuevaParticula = {};
contenedorDeParticulas push(nuevaParticula);
}
console.log( contenedorDeParticulas= +
contenedorDeParticulas length); }
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);
}
} }
if (remover) {
contenedorDeParticulas.push(particulasTemp);
particulas.splice(contarParticulas,1);
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.