0% encontró este documento útil (0 votos)
117 vistas14 páginas

Juego

Este documento describe el proceso de creación de un juego móvil en HTML5 utilizando el framework Phaser. Explica que Phaser facilita el desarrollo mediante la provisión de herramientas para manejar tareas genéricas. Describe los diferentes estados del juego como Boot, Preloader, MainMenu y Game, y cómo cada archivo JavaScript gestiona una parte de la lógica del juego. Finalmente, detalla algunas de las funciones clave como create() y update() que controlan el inicio y actualización continua del juego.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
117 vistas14 páginas

Juego

Este documento describe el proceso de creación de un juego móvil en HTML5 utilizando el framework Phaser. Explica que Phaser facilita el desarrollo mediante la provisión de herramientas para manejar tareas genéricas. Describe los diferentes estados del juego como Boot, Preloader, MainMenu y Game, y cómo cada archivo JavaScript gestiona una parte de la lógica del juego. Finalmente, detalla algunas de las funciones clave como create() y update() que controlan el inicio y actualización continua del juego.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd

Introducción

En este tutorial iremos a través del proceso de construcción de un juego en HTML5 para
móviles que utilizará las APIs de Orientación para Dispositivos y Vibración para mejorar la
jugabilidad y estará construido utilizando el framework Phaser. Se recomienda tener
conocimientos básicos de JavaScript para sacar mayor provecho a este tutorial.

Ejemplo
Al finalizar este tutorial tendrás un juego demo completamente funcional: Cyber Orb. Se
verá más o menos así:

Phaser framework
Phaser es un framework para construir juegos, de móvil o escritorio, en HTML5 . Es nuevo
pero está creciendo velozmente gracias a la apasionada comunidad involucrada en el
proceso de desarrollo. Puedes chequearlo en GitHub donde se encuentra como open
source. Lee la documentación en línea y recorre su gran colección de ejemplos.
El framework Phaser provee una serie de herramientas que acelerarán el desarrollo y te
ayudaran a manejar las tareas genéricas necesarias para completar tu juego, para que así
puedas concentrarte en la idea del juego en sí.

Empezando con el proyecto


Puedes ver el código fuente de Cyber Orb en GitHub. La estructura de carpetas no es
nada complicada: el punto de partida es el archivo [Link] donde inicializaremos
el framework y configuraremos el canvas donde correrá el juego.

Puedes hacer clic en el archivo index desde tu navegador favorito para iniciar el juego y
probarlo. También hay tres carpetas en el directorio:
 img: Todas las imágenes que usaremos en el juego.
 src: Los archivos JavaScript que contienen todo el código fuente del juego definido
dentro.
 audio: Los archivos de sonido usados en el juego.

Configurando el canvas
Vamos a renderizar nuestro juego sobre el elemento <canvas>, pero no lo haremos
manualmente — de esto se ocupará el framework. Vamos a configurarlo: nuestro punto
de partida es el archivo [Link] con el siguiente contenido. Puedes crearlo tú mismo si
quieres hacer un seguimiento más detallado:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Cyber Orb</title>
<style> body { margin: 0; background: #333; } </style>
<script src="src/[Link]"></script>
<script src="src/[Link]"></script>
<script src="src/[Link]"></script>
<script src="src/[Link]"></script>
<script src="src/[Link]"></script>
</head>
<body>
<script>
(function() {
var game = new [Link](320, 480, [Link], 'game');
[Link]('Boot', [Link]);
[Link]('Preloader', [Link]);
[Link]('MainMenu', [Link]);
[Link]('Game', [Link]);
[Link]('Boot');
})();
</script>
</body>
</html>

Hasta ahora tenemos una simple página web HTML con el contenido básico en la
sección <head>: configuración de caracteres, título, estilo y las inclusión de los archivos
JavaScripts. El <body> contiene la inicialización del framework Phaser y las definiciones del
estado del juego.

var game = new [Link](320, 480, [Link], 'game');

La linea de arriba inicializará la intancia de Phaser — los argumentos son el ancho


del <canvas>, su altura, el método de renderizado (estamos utilizando CANVAS pero también
existen disponibles las opciones WEBGL y AUTO) y el ID opcional del contenedor DOM en el
que queremos poner el <canvas>. Si no hay nada especificado en el último argumento o el
elemento no es encontrado, el <canvas> será añadido a la etiqueta <body>. Sin
el framework para añadir el elemento canvas hubieses tenido que escribir algo como esto
dentro de la etiqueta <body>:

<canvas id='game' width='320' height='480'></canvas>

Es importante recordar que el framework está montando métodos útiles para acelerar un
montón de cosas como la manipulación de imagenes o la administración de elementos,
que serían más difíciles si tuvieramos que hacerlo manualmente.
Nota: Puedes leer este artículo: "Building Monster Wants Candy" para una introducción en
profundidad a las funciones y métodos específicos de Phaser.
Volviendo a los estados del juego: La linea de abajo añade un nuevo estado al juego
llamado Boot:
[Link]('Boot', [Link]);

El primer valor es el nombre del estado, el segundo es el objeto al que queremos


asignárselo. El metodo start está iniciando el estado dado y haciendolo activo. Veamos
qué es lo que son los estados realmente.

Gestionando los estados de juego


Los estados en Phaser son partes separadas de la lógica del juego, en nuestro caso los
estamos cargando de archivos JavaScript independientes para un mejor mantenimiento.
En este juego tenemos estados básicos: Boot, Preloader, MainMenu, Howto y Game. Boot se hará
cargo de la inicialización de algunas opciones de configuración, Preloader cargará todos los
elementos utilizados como los gráficos y el audio, MainMenu es el menu con el botón de
inicio, Howto muestra las intrucciones de cómo jugar y el estado Game es el que finalmente te
permite jugar el juego. Veamos rapidamente el contenido de esos estados.
[Link]
El estado Boot es el primero en el juego.

var Ball = {
_WIDTH: 320,
_HEIGHT: 480
};
[Link] = function(game) {};
[Link] = {
preload: function() {
[Link]('preloaderBg', 'img/[Link]');
[Link]('preloaderBar', 'img/[Link]');
},
create: function() {
[Link] = [Link].SHOW_ALL;
[Link] = true;
[Link] = true;
[Link]('Preloader');
}
};

El objeto principal Ball es definido y estamos añadiendo dos variables


llamadas _WIDTH y _HEIGHT esos seran el ancho y la altura del canvas de nuestro juego,
respectivamente — nos ayudarán a posicionar los elementos en la pantalla. Estamos
cargando dos imagenes primero que serán usadas después en el estado Preload para
mostrar el progreso de la carga de los demás elementos. La función create contiene
algunas de las configuraciones básicas: estamos configurando la escala y la alineación del
canvas, y avanzando al estado Preload cuando todo este listo.
[Link]
El estado Preloader se ocupa de cargar todos los elementos:
[Link] = function(game) {};
[Link] = {
preload: function() {
[Link] = [Link]((Ball._WIDTH-297)*0.5,
(Ball._HEIGHT-145)*0.5, 'preloaderBg');
[Link] = [Link]((Ball._WIDTH-158)*0.5,
(Ball._HEIGHT-50)*0.5, 'preloaderBar');
[Link]([Link]);

[Link]('ball', 'img/[Link]');
// ...
[Link]('button-start', 'img/[Link]',
146, 51);
// ...
[Link]('audio-bounce', ['audio/[Link]',
'audio/bounce.mp3', 'audio/bounce.m4a']);
},
create: function() {
[Link]('MainMenu');
}
};

Para crear un nuevo botón tenemos el método [Link] con la siguiente lista de
argumentos opcionales:
 Posición absoluta superior del canvas, en pixeles.
 Posición absoluta izquierda del canvas, en pixeles.
 Nombre del elemento imagen utilizado por el botón.
 Función que será ejecutada cuando alguien haga click sobre el botón.
 El contexto de la ejecución.
 Cuadro (frame) del elemento imagen utilizado para el estado 'hover' del botón
(cuando el mouse se encuentra sobre él).
 Cuadro (frame) del elemento imagen utilizado para el estado 'normal' o 'out' del
botón.
 Cuadro (frame) del elemento imagen utilizado para el 'click' o 'down' del botón.
El [Link] colocará el punto de ancla en el botón con el cual se realizarán y aplicarán
todos los cálculos de posición para el botón. En nuestro caso, está anclado a la mitad del
borde izquierdo y al comienzo del borde superior, para así centrarlo de manera horizontal
facilmente, sin necesidad de saber su ancho.
Cuando el boton de inicio es presionado, en lugar de saltar directamente a la acción, el
juego mostrará la pantalla con las intrucciones para jugar.
[Link]

[Link] = function(game) {
};
[Link] = {
create: function() {
[Link] = [Link](0, 0, 'screen-howtoplay',
[Link], this);
},
startGame: function() {
[Link]('Game');
}
};

El estado Howto muesta las intrucciones de juego en la pantalla antes de comenzar el


juego. Luego de clickear la pantalla el juego es lanzado.
[Link]
El estado Game del archivo [Link] es donde ocurre toda la magia. Todas las inicializaciones
estan en la función create() (que se lanza una vez al comienzo del juego). Luego de eso,
algunas funcionalidades requeriran más código para controlar — escribiremos nuestras
propias funciones para manejar tareas más complicadas. En particular, toma nota de la
función update() que es ejecutada en cada frame y actualiza cosas como la posición de la
pelota.

[Link] = function(game) {};


[Link] = {
create: function() {},
initLevels: function() {},
showLevel: function(level) {},
updateCounter: function() {},
managePause: function() {},
manageAudio: function() {},
update: function() {},
wallCollision: function() {},
handleOrientation: function(e) {},
finishLevel: function() {}
};

Las funciones create y update son específicas del framework, mientras que otras seran
nuestras propias creaciones:
 initLevels inicializa los datos del nivel.
 showLevel imprime los datos del nivel en la pantalla.
 updateCounter actualiza el tiempo dedicado a jugar cada nivel y registra el tiempo
total dedicado al juego.
 managePause pausa y reanuda el juego.
 manageAudio enciende y apaga el audio.
 wallCollision es ejecutado cuando la pelota golpea las paredes u otros objetos.
 handleOrientation es la función ligada al evento responsable por la API de
orientación de dispositivo, proporciona los controles de movimiento cuando el juego es
ejecutado en un dispositivo móvil con el hardware apropiado.
 finishLevel carga un nuevo nivel cuando se completa el nivel actual, o termina el
juego si se completa el nivel final.
Agregando la pelota y sus mecanismos de movimiento
Primero vamos a ir a la función create(), inicializamos el objeto ball y le asignamos unas
cuantas propiedades:

[Link] = [Link]([Link].x, [Link].y,


'ball');
[Link](0.5);
[Link]([Link], [Link]);
[Link](18, 18);
[Link](0.3, 0.3);

Aqui estamos agregando un sprite en un lugar de la pantalla y utilizando la imagen de la


pelota de los elementos gráficos ya cargados. También estamos configurando
el anchor (ancla) que realizará los cálculos de física para el centro de la pelota, habilitando
el motor de físicas Arcade (que manejara todas las físicas para el movimiento de la pelota),
y estableciendo el tamaño del cuerpo para la detección de colisiones. La
propiedad bounce es utilizada para configurar el 'rebote' de la pelota cuando golpea los
obstaculos.
Controlando la pelota
Es genial tener lista la pelota para poder lanzarla en la zona del juego, pero también es
importante poder realmente moverla! Ahora vamos a añadir la capacidad de controlar con
el teclado la pelota en los dispositivos de escritorio, y luego pasaremos a la
implementación de la API de Orientación de Dispositivo. Vamos a enfocarnos en el teclado
primero añadiendo lo siguiente a la función create():

[Link] = [Link]();

Como puedes ver, hay una función especial de Phaser llamada createCursorKeys() que nos
dará un objeto con controladores de evento para las cuatro teclas de flecha, que nos
permitira jugar con: arriba, abajo, izquierda y derecha.
A continuación añadiremos el siguiente código a la función update(), para que sea
ejecutado en cada frame. El objeto [Link] será chequeado con el input del jugador (las
teclas que presione por ejemplo) así la pelota podrá reaccionar acorde, con una fuerza
predefinida:

if([Link]) {
[Link].x -= [Link];
}
else if([Link]) {
[Link].x += [Link];
}
if([Link]) {
[Link].y -= [Link];
}
else if([Link]) {
[Link].y += [Link];
}

De esa manera podemos verificar qué tecla es presionada en determinado frame y aplicar
la fuerza definida a la pelota, así aumentar la velocidad en la dirección correcta.
Implementando la API de Orientación del Dispositivo
Probablemente la parte más interesante del juego es que utiliza la API de Orientación para
Dispositivos móviles. Gracias a esto puedes jugar el juego inclinando el dispositivo en la
dirección que quieres que la pelota ruede. Aquí está el código de la
función create() responsable por esto:
[Link]("deviceorientation", [Link],
true);

Vamos a añadir un detector de eventos al evento "deviceorientation" y vincularlo a la


función handleOrientation, se ve como esto:

handleOrientation: function(e) {
var x = [Link];
var y = [Link];
Ball._player.[Link].x += x;
Ball._player.[Link].y += y;
}

Mientras más inclines el dispositivo, más fuerza se aplica a la pelota y la velocidad en la


que se mueve es mayor.

Nota: Para encontrar más sobre implementar la orientación de los dispositivos y cómo se vé
en código crudo, lee Keep it level: responding to device orientation changes.
Añadiendo el agujero
El principal objetivo del juego es mover la pelota desde la posición inicial a la posición final:
un agujero en el suelo. Esta implementación es muy similar a la parte anterior en donde
creamos la pelota, y también es añadida en la función create() de nuestro estado Game:
[Link] = [Link](Ball._WIDTH*0.5, 90, 'hole');
[Link]([Link], [Link]);
[Link](0.5);
[Link](2, 2);

La diferencia está en que el cuerpo del agujero se configura como inamovible por lo que no
se moverá cuando acertamos con la pelota y tendrá calculada la detección de colisión
(esto se tratará más adelante en este artículo).
Construyendo el laberinto de bloques
Para hacer más difícil el juego, y más interesante, añadiremos algunos obstaculos entre la
pelota y la sálida. Podríamos usar un editor de niveles pero por motivo de este tutorial,
vamos a crear algo nosotros mismos.
Para contener el bloque de información usaremos un array con los datos de nivel: para
cada bloque almacenaremos las posiciones abolutas izquierda y superior en pixeles (x e y)
y el tipo de bloque: horizontal o vertical (t con el valor 'w' para el ancho, y 'h' para la
altura). Luego, para cargar el nivel analizaremos los datos y mostraremos los bloques
especificos para ese nivel. En la función initLevels tenemos:

[Link] = [
[
{ x: 96, y: 224, t: 'w' }
],
[
{ x: 72, y: 320, t: 'w' },
{ x: 200, y: 320, t: 'h' },
{ x: 72, y: 150, t: 'w' }
],
// ...
];

Todos los elementos del array contienen una colección de bloques con una posición x e y y
un valor t para cada uno. Luego de levelData pero dentro de la función initLevels,
añadiremos los bloques dentro de un array en el loop for usando algunos de los métodos
específicos del framework:

for(var i=0; i<[Link]; i++) {


var newLevel = [Link]();
[Link] = true;
[Link] = [Link];
for(var e=0; e<[Link][i].length; e++) {
var item = [Link][i][e];
[Link](item.x, item.y, 'element-'+item.t);
}
[Link]('[Link]', true);
[Link] = false;
[Link](newLevel);
}

Primero, [Link]() es usado para crear un nuevo grupo de items. Luego, el body
tipe ARCADE se configura para permitir los cálculos de física. El método [Link] crea
nuevos items en el grupo con posiciones superior e izquierda iniciales y su propia imagen.
Si no quieres recorrer nuevamente la lista de elementos para agregar una propiedad a
cada uno explicitamente, puedes usar setAll en un grupo para aplicarlo a todos los items
en ese grupo.
Los objetos son almacenados en el array [Link], el cual es por defecto invisible. Para
cargar niveles específicos, nos aseguramos de que los niveles previos esten escondidos, y
mostramos el nivel actual:

showLevel: function(level) {
var lvl = level | [Link];
if([Link][lvl-2]) {
[Link][lvl-2].visible = false;
}
[Link][lvl-1].visible = true;
}

Gracias a eso el juego da al jugador un reto: ahora tiene que rodar la pelota a través del
área de juego y guiarla por el laberinto construido por bloques. Es solo un ejemplo de
cargar los niveles, y solo hay 5 puramente para mostrar la idea, pero podés trabajar en
expandirlo por tu cuenta.
Detección de colisión
Hasta este punto tenemos la pelota, que puede ser controlada por el jugador, el agujero
que se tiene que alcanzar y los obstáculos que bloquean el camino. Sin embargo, hay un
problema: nuestro juego todavía no tiene ninguna detección de colisiones, así que no
sucede nada cuando la pelota golpea los bloques, sólo los atraviesa. Vamos a arreglarlo!
La buena noticia es que el framework se ocupará de calcular la detección de colisones,
nosotros sólo debemos especificar los objetos con los que colisionará en la
función update():

[Link]([Link], [Link],
[Link], null, this);
[Link]([Link], [Link][[Link]-1],
[Link], null, this);

Esto le dirá al framework que ejecute la función wallCollision cuando la pelota golpee
cualquiera de las paredes. Podemos usar la función wallCollision para añadir cualquier
funcionalidad que querramos, como por ejemplo agregar el sonido de rebote e implementar
la API de Vibración.
También debemos volver al objeto pelota y limitarlo a moverse sólo en la zona visible, para
que no salga de la pantalla. Hay una función muy útil en Phaser que se
llama collideWorldBounds:

[Link] = true;

Hace exactamente lo que necesitamos: ahora la pelota rebotará en los bordes de la


pantalla como de las paredes.
Añadiendo el sonido
Entre los elementos precargados hay una pista de audio (en varios formatos para asegurar
la compatibilidad con el navegador), que podremos usar ahora. Debe primero ser definida
en la función create():
[Link] = [Link]('audio-bounce');

Si el estado del audio es true (es decir que el sonido del juego está activado) podremos
reproducirlo en la función wallCollision:

if([Link]) {
[Link]();
}

Eso es todo: cargar y reproducir sonidos es sencillo con Phaser.


Implementando la API de Vibración
Cuando la detección de colisión funcione como es esperado, añadamos algunos efectos
especiales con la ayuda de la API de Vibración.

La mejor forma de usarla en nuestro caso es haciendo que el teléfono vibre cada vez que
la pelota golpee las paredes: dentro de la función wallCollision:

if("vibrate" in [Link]) {
[Link](100);
}

Si el método vibrate es soportado por el navegador y está disponible en el


objeto [Link], hará vibrar al telefono por 100 milisegundos. Eso es todo!
Añadiendo el tiempo transcurrido
Para mejorar la re-jugabilidad y dar a los jugadores la opción de competir entre ellos,
almacenaremos el tiempo transcurrido: los jugadores entonces intentaran mejorar su
tiempo de finalizacion. Para implementar esto en el juego tenemos que crear una variable
para almacenar el número actual de segundos transcurrido desde el inicio del juego y
mostrarselo al jugador durante el juego. Definamos primero las variables en la
función create:

[Link] = 0; // time elapsed in the current level


[Link] = 0; // time elapsed in the whole game

Luego, podemos inicializar los objetos de texto necesarios para mostrar la información al
usuario:

[Link] = [Link](15, 15, "Time: "+[Link],


[Link]);
[Link] = [Link](120, 30, "Total time:
"+[Link], [Link]);

Estamos definiendo la posición superior e izquierda del texto, el contenido que se muestra
y el estilo aplicado al texto. Lo hemos impreso en pantalla, pero sería bueno actualizar los
valores cada segundo:

[Link]([Link], [Link], this);

Este bucle, también en la función create, ejecutará la función updateCounter cada segundo
desde el comienzo del juego, así podemos aplicar los cambios acordes. Así es como se ve
la función updateCounter completa:

updateCounter: function() {
[Link]++;
[Link]("Time: "+[Link]);
[Link]("Total time: "+
([Link]+[Link]));
},

Como puedes ver estamos incrementando la variable [Link] y actualizando el


contenido del objeto de texto con el valor actual en cada iteración, por lo que el jugador
verá el tiempo transcurrido.
Terminando el nivel y el juego
La pelota está rodando en la pantalla, el temporizador funciona y tenemos el agujero al que
tenemos que llegar. Vamos a configurar la posibilidad de finalizar el juego! La siguiente
linea en la funcion update() añade un detector que se activa cuando la pelota llega al
agujero.

[Link]([Link], [Link], [Link], null,


this);

Esto funciona de manera similar al método colide explicado anteriormente. Cuando la


pelota se superpone con el agujero (en lugar de colisionar), la función finishLevel es
ejecutada:
finishLevel: function() {
if([Link] >= [Link]) {
[Link] += [Link];
alert('Congratulations, game completed!\nTotal time of play:
'+[Link]+' seconds!');
[Link]('MainMenu');
}
else {
alert('Congratulations, level '+[Link]+' completed!');
[Link] += [Link];
[Link] = 0;
[Link]++;
[Link]("Time: "+[Link]);
[Link]("Total time: "+[Link]);
[Link]("Level: "+[Link]+" /
"+[Link]);
[Link].x = [Link].x;
[Link].y = [Link].y;
[Link].x = 0;
[Link].y = 0;
[Link]();
}
},

Si el nivel actual es igual al maximo número de niveles (5, en este caso), entonces el juego
termina: recibiras un mensaje de felicitación junto con el numero de segundas transcurridos
durante todo el juego, y un botoón para presionar que te llevará al menú principal.
Si el nivel actual es menor que 5, todas las variables necesarias se reinician y el siguiente
nivel es cargado.

Ideas para nuevas características


Esto no es más que una demostración funcional de un juego que podría tener un montón
de características adicionales. Por ejemplo podemos añadir poderes para recoger en el
camino que harán que nuestra pelota ruede más rápido, otro podría detener el
temporizador durante unos segundos o dar la pelota poderes especiales para atravesar
obstáculos. También hay espacio para los obstáculos y trampas que harán más lenta la
pelota, acelerar el tiempo o trampas de la propia pelota. Puedes crear más niveles con
dificultades diferentes para cada uno. Incluso puedes obtener logros, tablas de clasificación
y medallas para diferentes acciones en el juego. Hay un sinfín de posibilidades: sólo
dependen de tu imaginación.

Resumen
Espero que este tutorial te ayude a introducirte dentro del desarrollo de los juegos 2D y te
inspire a crear asombrosos juegos por tu cuenta. Puedes jugar el demo de Cyber Orb y
chequear su código fuente en GitHub.
HTML5 nos da herramientas en bruto, los frameworks construidos sobre estas se están
volviendo más rápidos y mejores, por lo que ahora es un gran momento para meterse en el
desarrollo de juegos web. En este tutorial usamos Phaser, pero hay un gran número de
otros frameworks que vale la pena considerar también, como ImpactJS, Construct 2 o
PlayCanvas — depende de tus preferencias, habilidades de programación (o la falta de
estas), el tamaño de tu proyecto, los requerimientos y otros aspectos. Deberías
chequearlos todos y decidir cual es el que mejor se ajusta a tus necesidades.

También podría gustarte