Unity Tutorial
Unity Tutorial
ii
Contents
Primeros pasos 1
¡Pongamos el juego en funcionamiento! . . . . . . . . . . . . . . . . . . 2
Diseñando nuestro primer juego . . . . . . . . . . . . . . . . . . . . . . 3
Ambientando la escena en el espacio . . . . . . . . . . . . . . . . . . . 8
Creando más actores . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Agregando colisiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Reaccionando a las colisiones . . . . . . . . . . . . . . . . . . . . . . . 18
Es solo el principio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
El intérprete 27
Accediendo a las variables pilas y actores . . . . . . . . . . . . . . . . 30
Algunos consejos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Autómatas y estados 37
Animaciones 39
Crear animaciones desde el editor . . . . . . . . . . . . . . . . . . . . . 41
Cómo usar las animaciones . . . . . . . . . . . . . . . . . . . . . . . . 44
Crear animaciones desde el código . . . . . . . . . . . . . . . . . . . . 44
Detectar la finalización de las animaciones . . . . . . . . . . . . . . . . 46
Cámara 47
Mover la cámara desde el editor . . . . . . . . . . . . . . . . . . . . . . 47
Mover la cámara mientras se ejecuta el juego . . . . . . . . . . . . . . 48
Usando la función hacer_recorrido . . . . . . . . . . . . . . . . . . . . 49
Etiquetas 53
Etiquetas para distinguir colisiones . . . . . . . . . . . . . . . . . . . . 55
Habilidades 57
Desde el editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Desde el código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Olvidar o eliminar habilidades . . . . . . . . . . . . . . . . . . . . . . . 58
iii
iv CONTENTS
Comportamientos 59
Realizando comportamientos . . . . . . . . . . . . . . . . . . . . . . . 59
Comportamientos incluidos en pilas . . . . . . . . . . . . . . . . . . . 60
Comportamientos personalizados . . . . . . . . . . . . . . . . . . . . . 60
Observables 65
Funciones manejar el tiempo . . . . . . . . . . . . . . . . . . . . . . . 67
Cancelar repeticiones o eliminar temporizadores . . . . . . . . . . . . . 68
Métodos especiales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Ángulos y distancias 71
Ángulo entre actores o puntos . . . . . . . . . . . . . . . . . . . . . . . 71
Distancia entre puntos y actores . . . . . . . . . . . . . . . . . . . . . 72
Colisiones 75
Tipos de colisiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Colisiones entre figuras estáticas (no dinámicas) . . . . . . . . . . . . . 77
Escenas 83
Cambiar o reiniciar escenas . . . . . . . . . . . . . . . . . . . . . . . . 83
Gravedad y simulación física . . . . . . . . . . . . . . . . . . . . . . . 84
Código de proyecto 85
Un ejemplo breve . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Animaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
En esta sección me gustaría describir los pasos iniciales para comenzar a hacer
juegos.
Pilas ha sido diseñada especialmente para que todas las personas puedan aprender
a programar realizando videojuegos, de forma sencilla y totalmente en español.
Esta es la pantalla inicial que aparecerá cuando abras pilas por primera vez:
Figure 1: portada
1
2 PRIMEROS PASOS
Figure 2: editor-1
El botón que aparece arriba del area de juego es muy importante, porque nos
permite poner en funcionamiento el juego y hacer una prueba real.
DISEÑANDO NUESTRO PRIMER JUEGO 3
Figure 3: editor-partes
Figure 4: boton-ejecutar
Pulsá el botón que dice “detener” en el editor (o pulsá la tecla Esc), tendrías
que volver a ver el resto de los elementos del editor nuevamente habilitados.
Borremos
cada uno de los actores que aparecen en la pantalla, selecciona al actor pelota y
luego pulsa el botón del cesto de basura tal y como muestra esta imagen:
DISEÑANDO NUESTRO PRIMER JUEGO 5
Figure 5: primer-ejecucion
Figure 6: borrar
6 PRIMEROS PASOS
Repetí esos pasos hasta que la escena quede limpia, sin ningún actor:
Figure 7: image-20200601230444058
Figure 8: crear-actor-1
Una vez que selecciones el actor vas a verlo formar parte de la escena así:
Ahora pulsemos de nuevo el botón “ejecutar” y pulsa las flechitas del teclado
para mover la nave por el escenario (¡y con la barra espaciadora vas a poder
disparar!):
DISEÑANDO NUESTRO PRIMER JUEGO 7
Figure 9: crear-actor-2
8 PRIMEROS PASOS
historia:
Bueno, no es una gran idea. . . pero es algo, algo que podemos construir, jugar y
divertidos. ¡así que vamos a intentarlo!
Pero a diferencia de antes, que elegimos la nave, ahora elegí el actor que no tiene
una imagen asignada:
Luego, podes mover este actor usando el mouse, así no tapa a la nave:
Ahora cambiemos la apariencia del actor. Este paso es muy similar al que hicimos
antes, tendrías que seleccionar al actor, ir al panel de propiedades pero ahora
pulsar la propiedad “imagen”:
Agregando colisiones
Vamos a hacer que la manzana se pueda destruir con los disparos de la nave.
Para eso tenemos que volver a seleccionar el actor con apariencia de manzana y
asignarle una figura física así:
Vas a notar que en la pantalla aparecerá un círculo azul al rededor del actor nuevo.
Esto significa que el actor tiene un area de contacto para poder interactuar con
el resto de los actores:
Para hacer que el actor manzana reaccione tenemos que escribir un poquito de
código.
Cuando pulses esa pestaña, vas a ver que se abre un panel nuevo; un panel en
donde tenemos código y un botón que dice “Recetas”:
El código es una de las cosas más importantes que incluye pilas, ya que el código
nos permite darle órdenes a la computadora para que haga cosas, como eliminar
actores, reaccionar al movimiento del mouse, emitir sonidos y todo lo que se te
ocurra.
Sin embargo para empezar vamos a tomar un atajo, vamos a pedirle a pilas que
nos ayude a escribir el código para que la manzana se pueda eliminar fácilmente.
Cuando hagas eso, vas a notar que pilas escribió por nosotros una porción de
código que hace algunas cosas por nosotros:
Mas adelante en el manual vamos a escribir algo de código sin usar recetas, desde
cero y comprendiendo cada función y expresión, por ahora lo dejaremos ahí.
Ahora pulsa “Ejecutar” y corrobora cómo los disparos pueden limpiar el espacio
de frutas:
REACCIONANDO A LAS COLISIONES 19
Es solo el principio
Pilas es una herramienta super completa, y este mini-tutorial es solo el comienzo
de una gran aventura. Seguí leyendo este manual para conocer muchas más
cosas que incluye pilas o explora nuestro sitio web, vas a encontrar tutoriales,
videos, juegos y muchas cosas más.
¡Te damos la bienvenida a el mundo de la programación!
ES SOLO EL PRINCIPIO 23
27
28 EL INTÉRPRETE
Y esto está bien, si bien el texto rojo parece algo grave, no lo es. La computadora
nos explica que no sabe de que se trata “numero” y por lo tanto no sabría
decirnos el resultado de esa cuenta.
Si le indicamos que el “numero” es 10 sí va a poder decirnos el resultado:
numero = 10;
2 + numero;
Ahora bien, el intérprete no solo puede realizar cuentas aritméticas, también nos
da la posibilidad de realizar pruebas, crear o modificar los actores en la pantalla
y varias cosas mas.
Al principio de esta sección mencioné que pilas nos avisaba que había dos
variables listas para utilizar “pilas” y “actores”:
Estas dos palabras se denominan variables, porque representan un nombre que
almacena un valor asignado con anterioridad. En nuestro caso, “numero” también
es una variable, porque básicamente es el nombre que le dimos al valor 10.
Ahora bien, ¿qué podemos hacer con estas variables?.
La variable pilas nos permite acceder a todas las funcionalidades del motor. Si
escribimos algo como:
ALGUNOS CONSEJOS 31
pilas.actores.nave()
Vas a notar que aparecerá una nave en la pantalla como respuesta al código que
escribimos:
También vas a notar que en el intérprete aparece el mensaje <nave en (0, 0)>,
esto es así para indicarnos que obedeció a nuestras orden. Pilas creó el actor
nave y lo dejó en la posición (0, 0) de la pantalla.
Si haces click en la pantalla, vas a notar que la nave está “viva”, se puede mover
y disparar usando el teclado.
Ahora bien, aquí es donde entra en juego la otra variable que te comenté llamada
“actores”. Esta variable va a permitirnos referirnos a cualquier actor dentro de la
escena.
Escribí estas lineas de código en el intérprete para ver el resultado:
nave.escala = 2
nave.rotacion = 90
nave.decir("hola")
Lo que deberías ver es que la nave cambia de tamaño, apunta hacia arriba y
además muestra un mensaje:
Esto es bastante útil, porque el código que escribimos en el intérprete también
se puede trasladar al editor. Si tenemos dudas sobre alguna función o forma de
hacer algo en pilas podemos probar en el intérprete, y si todo sale bien, llevarlo
al editor y que forma parte de nuestro juego.
Algunos consejos
Otra necesidad muy común es querer volver a repetir una instrucción anterior,
para eso podes pulsar las flechitas del teclado hacia arriba y abajo para navegar:
Un desafío muy común en el desarrollo de juegos es lograr que los actores puedan
mostrar animaciones y reaccionar de acuerdo a modos particulares: saltar,
caminar, quedarse parado, perdiendo, etc. . .
Para estas cosas Pilas incorpora un mecanismo de autómatas y estados.
Un actor puede estar en un estado a la vez, por ejemplo, “parado” podría ser el
estado de un actor en un juego de plataformas. Cuando el usuario pulsa hacia
arriba, podría pasar al estado “saltando”, pero solo cuando toca el piso podría
pasar al estado “parado” nuevamente.
Este modelo de estados y transiciones es lo que llamamos un autómata, y si bien
puede parecer algo complejo al principio, con el tiempo notarás que se trata de
algo muy práctico y sencillo.
Para crear un estado simplemente tenemos que editar el código de un actor y
asignarle un valor a la propiedad “estado” y crear dos métodos para que pilas
sepa a qué métodos llamar cuando el actor esté en ese estado:
class MiActor extends Actor {
iniciar() {
this.estado = "parado";
}
actualizar() {
}
parado_iniciar() {
this.animacion = "parado";
}
parado_actualizar() {
// código que se ejecutará 60 veces por segundo
// cuando el actor esté en el estado "parado".
}
}
37
38 AUTÓMATAS Y ESTADOS
Animaciones
Para crear animaciones se tiene que utilizar el editor que aparece en la parte
superior de la pantalla:
Este botón abrirá una ventana en donde se pueden previsualizar todas la anima-
ciones del proyecto:
Estas animaciones también se pueden editar fácilmente, solo tienes que pasar el
mouse sobre el nombre de la animación y pulsar el botón “editar”:
39
40 ANIMACIONES
Las animaciones son simplemente una lista de imágenes que pilas mostrará una
detrás de la otra, a determinada velocidad. Vas ver toda esta información en el
editor de animaciones:
CREAR ANIMACIONES DESDE EL EDITOR 41
Para crear animaciones hay que pulsar el botón “Crear una animación”:
y luego cargar cada uno de los cuadros de animación pulsando el botón “+” que
aparece en la parte superior de la ventana:
42 ANIMACIONES
Ahora sí, podes cerrar la ventana del editor y continuar con la siguiente sección.
44 ANIMACIONES
Ese código, sirve para indicarle al actor qué animación tiene que reproducir. Por
ejemplo, si quieres que el actor muestre esta animación al comenzar deberías
colocarlo dentro de la función “iniciar” así:
Por ejemplo, para crear una animación de un actor mientras está esperando usé
lo siguiente:
this.crear_animacion("conejo_parado", ["imagenes:conejo/conejo_parado1", "imagenes:conejo/conejo_
El valor “2” significa que la animación se debe mostrar a una velocidad de 2
cuadros por segundo.
Luego, una vez creada la animación, se puede reproducir usando esta llamada:
this.animacion = "conejo_parado";
La creación de animaciones generalmente se realiza en el método iniciar de esta
forma:
class Conejo extends Actor {
iniciar() {
this.crear_animacion("conejo_parado", ["imagenes:conejo/conejo_parado1", "imagenes:conejo/con
this.crear_animacion("conejo_camina", ["imagenes:conejo/conejo_camina1", "imagenes:conejo/con
this.crear_animacion("conejo_salta", ["imagenes:conejo/conejo_salta"], 20);
this.crear_animacion("conejo_muere", ["imagenes:conejo/conejo_pierde"], 1);
this.animacion = "conejo_parado";
}
actualizar() {}
}
Luego, para cambiar de animación, se puede re-definir el valor del atributo
animación así:
class Conejo extends Actor {
iniciar() {
this.crear_animacion("conejo_parado", ["imagenes:conejo/conejo_parado1", "imagenes:conejo/con
this.crear_animacion("conejo_camina", ["imagenes:conejo/conejo_camina1", "imagenes:conejo/con
this.crear_animacion("conejo_salta", ["conejo_salta"], 20);
this.crear_animacion("conejo_muere", ["conejo_muere"], 1);
this.animacion = "conejo_parado";
}
actualizar() {
if (this.pilas.control.izquierda) {
this.animacion = "conejo_camina";
this.x -= 5;
}
if (this.pilas.control.derecha) {
this.animacion = "conejo_camina";
this.x += 5;
46 ANIMACIONES
// Otros métodos
cuando_finaliza_animacion(nombre: string) {
this.eliminar();
}
}
Cámara
Si bien el juego tendrá un tamaño fijo en la pantalla, pilas incorpora una cámara
que nos permite realizar desplazamientos para mostrar otras partes de la escena.
En esta sección vamos a controlar cámara de la escena tanto desde el editor
como desde el juego en ejecución.
47
48 CÁMARA
Esos dos atributos también se utilizan para definir la posición inicial de la cámara
cuando comienza a ejecutarse el juego.
También vas a observar otros dos atributos llamados “Ancho” y “Alto”. Estos
dos atributos van a definir el tamaño total del escenario. Podes cambiar esos
parámetros para hacer que el escenario total sea más grande o más chico.
actualizar() {
this.camara.seguir_al_actor(this, 10, true);
}
}
Ten en cuenta que esta función se tiene que llamar todo el tiempo, por eso la
tenemos que incluir dentro del método actualizar.
También ten en cuenta que la función lleva 3 parámetros:
seguir_al_actor(actor, suavidad, ignorar_bordes)
• actor: el actor que la cámara tiene que seguir.
• suavidad: tiene que ser un número indicando cuán gradual tiene que ser
el movimiento de la cámara, cuanto menor sea el número mas rápido y
brusco será el movimiento de la cámara.
• ignorar_bordes: el último parámetro tiene que ser true o false. Si se
envía true la cámara seguirá al actor incluso si sale del area del escenario,
esto es ideal para juegos con area de movimiento infinita. Si se coloca
false la cámara se detendrá en los bordes del escenario. # Recorridos
Los recorridos nos permiten realizar movimientos de actores de manera muy
simple, lo que tenemos que hacer es enumerar todos los puntos “x” e “y” que
queremos recorrer y llamar a una sola función.
USANDO LA FUNCIÓN HACER_RECORRIDO 49
Ten en cuenta que el actor va a visitar todos los puntos pero de manera gradual,
siguiendo el recorrido pero realizando una curva de movimiento muy suave:
USANDO LA FUNCIÓN HACER_RECORRIDO 51
52 CÁMARA
Etiquetas
53
54 ETIQUETAS
actualizar() {}
}
cuando_comienza_una_colision(actor) {
if (actor.etiqueta === "moneda") {
actor.eliminar();
this.pilas.reproducir_sonido("moneda");
// sumar puntaje, emitir particulas etc...
}
Cuando realizamos juegos hay ciertos comportamientos que son tan comunes
que ni siquiera necesitamos programarlos escribiendo código.
Un ejemplo de estos comportamientos comunes incluyen “hacer que un actor se
mueva con el teclado”, “poder arrastrar y soltar un actor con el mouse” etc. . .
A todos estos comportamientos los llamamos “habilidades”, y lo interesante es
que podemos tomar a cualquier actor y “enseñarle” cualquier de las habilidades
para mejorar nuestro juego.
Desde el editor
Desde el código
57
58 HABILIDADES
Realizando comportamientos
Para indicarle a un actor que realice un comportamiento tenemos que llamar a
la función hacer indicándole el nombre del comportamiento:
let mi_actor = pilas.actores.actor();
mi_actor.hacer("aparecer");
Ten en cuenta que los comportamientos se pueden encadenar para lograr efectos
o animaciones una detrás de otra. Por ejemplo, si queremos mostrar y ocultar
un actor podemos hacerlo así:
let mi_actor = pilas.actores.actor();
mi_actor.hacer("aparecer");
mi_actor.hacer("desaparecer");
59
60 COMPORTAMIENTOS
Comportamientos personalizados
iniciar(argumentos) {
}
actualizar() {
// retornar true para detener el comportamiento.
}
terminar() {}
}
Luego, deberías vincularlo al módulo de comportamientos:
pilas.comportamientos.vincular("mi comportamiento", MiComportamiento);
COMPORTAMIENTOS PERSONALIZADOS 61
Una utilidad muy utilizada en los juegos son las funciones para obtener números
aleatorios. Pilas incluye una función muy simple para esto llamada pilas.azar:
La función pilas.azar retorna un número aleatorio entre dos números. Por
ejemplo, si buscas que pilas retorne un número al hacer entre 1 y 5 podrías
llamar a la función así:
pilas.azar(1, 5)
Es importante mencionar que el rango de valores incluye los extremos. En el
caso anterior la función podría retorna 1, 2, 3, 4 o 5.
63
64 AZAR O CÁLCULOS ALEATORIOS
Observables
65
66 OBSERVABLES
actualizar() {
this.pilas.observar("mi actor", this)
this.pilas.observar("rotación", this.rotacion)
}
}
Si buscas un ejemplo aplicado de observables abrí el ejemplo angulos:
# Manejo de tiempo
Pilas ofrece varias formas de ejecutar funciones cada determinado tiempo. Esto
FUNCIONES MANEJAR EL TIEMPO 67
es útil para crear enemigos, crear relojes para hacer más desafiante un juego o
incluso para aumentar la dificultad de un juego.
• pilas.luego(cantidad_de_segundos_a_esperar, función)
• pilas.cada(segundos_para_el_intervalo, función, veces_a_repetir:
opcional)
pilas.luego(3, () => {
mi_actor.decir("¡Han pasado 3 segundos!");
});
Hay que tener en cuenta que esta función se ejecutará una sola vez.
Por ejemplo, imagina que queremos crear actores pelota cada medio segundo,
podemos hacer algo así:
pilas.cada(0.5, () => {
var pelota = pilas.actores.pelota();
pelota.y = 100;
pelota.x = pilas.azar(-200, 200);
});
Si ejecutas esas instrucciones, vas a ver en pantalla algo así. Cada medio segundo
se creará un actor pelota en una posición diferente:
68 OBSERVABLES
Si utilizas la función pilas.cada para repetir una acción varias veces, es probable
que ante una determinada condición quieras dejas de repetir la ejecución de la
función.
Una forma de lograr esto es diciéndole a pilas cuantas veces tiene que repetir
la función, por ejemplo, para llamar 5 veces una función cada dos segundos
deberías llamar a la función así:
var actor = pilas.actores.aceituna();
pilas.cada(
2,
() => {
actor.decir("prueba");
},
5
);
Otra opción, es detener el temporizador directamente desde la función retornando
true:
Por ejemplo, imagina que tienes un actor que se mueve 50 pixeles a la derecha
cada 2 segundos, pero que quieres que deje de moverse cuando llegue a la posición
MÉTODOS ESPECIALES 69
pilas.cada(2, () => {
actor.x += 50;
Métodos especiales
También existe un método llamado cada_segundo que los actores pueden utilizar
para disparar una acción cada vez que transcurre un segundo en el juego. Por
ejemplo, si queremos crear un actor que aumente su tamaño cada un segundo
podemos definir el método así:
class caja extends Actor {
cada_segundo() {
this.escala += 0.5;
}
}
O bien, si ya tenemos la referencia al actor también sería válido escribir algo así:
var mi_actor = pilas.obtener_actor_por_nombre("caja");
mi_actor.cada_segundo = () => {
mi_actor.escala += 0.5;
mi_actor.decir("¡pasó un segundo!");
};
70 OBSERVABLES
Ángulos y distancias
Pilas trae varias funciones para realizar cálculos geométricos sencillos, como
obtener la distancia entre actores o incluso el ángulo entre ellos.
Un ejemplo práctico sería poder mirar en dirección a donde está el puntero del
mouse: Observa uno de los ejemplos que trae pilas, el usuario puede mover el
puntero del mouse y observar cómo el cañon ajusta su rotación correctamente:
71
72 ÁNGULOS Y DISTANCIAS
Otras dos funciones útiles en esta categoría son las funciones obtener_distancia_entre_puntos
y obtener_distancia_entre_actores. Ambas reciben los argumentos de
manera muy similar a las funciones de ángulos anteriores. Aquí unos ejemplos:
DISTANCIA ENTRE PUNTOS Y ACTORES 73
75
76 COLISIONES
cuando_comienza_una_colision(actor) {
if (actor.etiqueta === "caja") {
return true;
}
Tipos de colisiones
Hay 3 instantes muy importantes cuando se producen colisiones:
• Cuando se detecta el contacto inicial.
• Cuando los dos actores permanecen en contacto prolongado. Por ejemplo
cuando un actor se posa sobre una plataforma.
• El instante en donde la colisión desaparece porque los actores dejan de estar
en contacto. Por ejemplo cuando un actor posando sobre una plataforma
“salta” y deja de estar en contacto.
Para distinguir estos casos pilas llamará a las tres funciones de forma diferente.
Este es un ejemplo de cómo se declaran esas funciones en el código de un actor:
class mi_actor extends Actor {
cuando_comienza_una_colision(actor: Actor) {
if (actor.etiqueta === "moneda") {
COLISIONES ENTRE FIGURAS ESTÁTICAS (NO DINÁMICAS) 77
this.pilas.reproducir_sonido("moneda");
actor.eliminar();
}
}
cuando_se_mantiene_una_colision(actor: Actor) {}
cuando_termina_una_colision(actor: Actor) {}
}
Luego, el tipo de colisión más común que se llamará siempre tiene la siguiente
forma:
cuando_colisiona(actor: Actor) {
Un ejemplo típico que se suele dar de mensajes son los mensajes globales, estos
mensajes se pueden enviar desde un actor a todos los demás, estos mensajes
globales incluso llegan a la escenas.
Para enviar un mensaje global tenemos que escribir este código en el actor emisor:
this.pilas.enviar_mensaje_global("mi_mensaje");
Y para que otros actores puedan atender este mensaje simplemente tenemos que
crear un método que se llame “cuandollega_el_mensaje” seguido del nombre
del mensaje así:
cuando_llega_el_mensaje_mi_mensaje() {
this.decir("Algún actor envió el mensaje 'mi_mensaje'");
}
opcionalmente, si queremos un actor o escena que capture todos los mensajes
podemos usar este método:
79
80 MENSAJES ENTRE ACTORES Y ESCENAS
cuando_llega_un_mensaje(mensaje:string) {
this.decir("llegó el mensaje " + mensaje);
}
if (actor.tiene_etiqueta("diamante")) {
actor.eliminar();
this.pilas.enviar_mensaje_global("aumentar_puntaje", {cantidad: 10});
}
}
Luego, del lado del receptor (o los receptores) del mensaje, tenemos que leer los
parámetros adicionales así:
MENSAJES CON PARÁMETROS 81
cuando_llega_el_mensaje_aumentar_puntaje(datos) {
this.puntaje_acumulado += datos.cantidad;
}
82 MENSAJES ENTRE ACTORES Y ESCENAS
Escenas
Un juego típico tendrá al menos una escena como el menú principal, una presen-
tanción y una pantalla de juego.
pilas.cambiar_escena("escena2");
pilas.reiniciar_escena();
83
84 ESCENAS
Un ejemplo breve
Para ejemplificar cómo podemos usar el código de la escena voy a dar un ejemplo.
Imagina que tenemos un juego en el que tenemos que recolectar monedas con el
mouse, pero queremos que la cantidad de monedas persista entre un nivel y otro.
85
86 CÓDIGO DE PROYECTO
Luego, vamos a ver que en el panel de código aparece el código del proyecto:
El código está casi vacío, así que vamos a crear el contador de monedas recolec-
tadas y vamos a darle un valor inicial:
class Proyecto {
monedas: number;
UN EJEMPLO BREVE 87
iniciar() {
this.monedas = 0;
}
}
Ahora editemos el código para que este actor pueda acceder a la variable puntaje
del proyecto. Tenemos que cambiar estas lineas de código:
88 CÓDIGO DE PROYECTO
// @ts-ignore
class puntaje extends ActorTextoBase {
iniciar() {
this.actualizar_texto();
}
aumentar(cantidad: number = 1) {
this.proyecto.monedas += cantidad;
this.actualizar_texto();
}
actualizar_texto() {
this.texto = `MONEDAS: ${this.proyecto.monedas}`;
}
}
// @ts-ignore
class moneda extends Actor {
cuando_hace_click() {
this.proyecto.monedas += 1;
this.eliminar();
}
}
y por último, cambia el código de este actor para que nos permita pasar a la
siguiente escena cuando se pulsa:
// @ts-ignore
class boton extends ActorTextoBase {
cuando_hace_click() {
this.pilas.cambiar_escena("escena2");
}
}
Si bien este ejemplo es muy simple, es un punto de partida para poder mantener
los datos del jugador durante toda su partida.
Te recomiendo mirar el proyecto “mantener-valores-entre-escenas” de la sección
“ejemplos” de pilas para que veas cómo se puede mejorar este mismo proyecto
que realizamos acá.
92 CÓDIGO DE PROYECTO
Eventos del mouse
En pilas llamamos “eventos” a las señales que emiten desde dispositivos como el
mouse o teclado. Por ejemplo, un “click” del mouse es un evento al igual que la
pulsación de una tecla.
Y lo interesante de los eventos es que podemos capturarlos y disparar alguna
acción dentro del juego para responder. Por ejemplo, en un juego de acción, el
“click” del mouse podría realizar una explosión o hacer que un personaje salte.
actualizar() {
// la sentencias a continuación hacen que el actor siga la
// posición del cursor del mouse en todo momento
this.x = this.pilas.cursor_x;
this.y = this.pilas.cursor_y;
93
94 EVENTOS DEL MOUSE
}
}
Para capturar un evento desde el mouse simplemente hay que declarar alguna
de estas funciones en el código:
• cuando_hace_click(x, y, evento_original)
• cuando_termina_de_hacer_click(x, y, evento_original)
• cuando_mueve(x, y, evento_original)
• cuando_sale(x, y, evento_original)
Estas funciones se pueden crear en el código de una escena o de un actor. La
diferencia es que en las escenas el “click” o el movimiento se van a detectar en
toda la pantalla, mientras que en el código del actor solo se detectarán si el
mouse apunta al actor.
Si desde un actor necesitas detectar el click del mouse en la pantalla deberías
usar este otro método:
• cuando_hace_click_en_la_pantalla(x, y, evento_original)
Veamos un ejemplo, imaginá que queremos crear actores de la clase “Pelota” cada
vez que el usuario hace “click” sobre la pantalla. Podríamos hacerlo colocando
este código en la escena:
class escena2 extends Escena {
iniciar() {}
actualizar() {}
cuando_mueve(x, y, evento_original) {}
cuando_hace_click(x, y, evento_original) {
let pelota = this.pilas.actores.pelota();
pelota.x = x;
pelota.y = y;
}
}
Para capturar eventos en el contexto de un actor, tenemos que usar las mismas
funciones, pero declarándolas dentro del código del actor.
¿CÓMO CAPTURAR EVENTOS DEL MOUSE EN UN ACTOR? 95
Por ejemplo, imaginá que estamos haciendo un juego de cartas y queremos que la
carta se pueda hacer girar con un “click” de mouse y que cambie de transparencia
cuando el mouse esté sobre ella:
iniciar() {
this.transparencia = 50;
}
actualizar() {}
cuando_mueve(x, y, evento_original) {
this.escala = 1.2;
this.transparencia = 0;
}
cuando_sale(x, y, evento_original) {
this.transparencia = 50;
this.escala = 1;
}
cuando_hace_click(x, y, evento_original) {
this.rotacion = [360];
}
cuando_termina_de_hacer_click(x, y, evento_original) {}
96 EVENTOS DEL MOUSE
}
Los manejadores de eventos como cuando_mueve, cuando_sale y cuando_hace_click
van a ser llamados internamente cuando se produzcan esos eventos sobre el
actor.
El teclado se puede utilizar de dos formas básicas: por consulta para mover
personajes o mediante eventos para responder a pulsaciones de teclas específicas:
actualizar() {
if (this.control.izquierda) {
this.x -= 5;
}
if (this.control.derecha) {
this.x += 5;
}
}
El objeto “control” tiene varios atributos que podemos consultar (mediante la
palabra “if”) para saber si en ese instante la tecla está pulsada o no.
Estas son otros atributos que tiene el objeto “control”:
Tecla | Código para consultar la tecla | nombre |
-||–|
97
98 USO DEL TECLADO
Otra forma de acceder al teclado es mediante eventos, para ejecutar una función
justo cuando se pulsa una tecla o se suelta.
Esto es útil por ejemplo en los juegos por turnos o cuando queremos que el
teclado funcione sin repetición, imaginá que si hacemos un juego donde el jugador
pueda disparar, queremos que pulse y suelte la tecla de disparo muchas veces,
no que la deje pulsada y eso dispare automáticamente.
Para capturar eventos de teclado de esta forma tendrías que definir los métodos
cuando_pulsa_tecla y cuando_suelta_tecla así:
cuando_pulsa_tecla(tecla) {
if (tecla == "espacio") {
this.disparar();
}
}
cuando_suelta_tecla(tecla) {
if (tecla == "1") {
this.decir("Has soltado la tecla 1")
}
}
Estos métodos están disponibles tanto en las escenas como en los actores. Puedes
comprobarlo escribiendo “cuando” en el editor y viendo cómo se sugieren las
opciones:
100 USO DEL TECLADO
Dibujado simple en pantalla
En esta sección veremos como dibujar libremente, ya sean lineas, círculos, etc..
Comenzaremos con una forma de dibujado muy sencilla, existe un actor llamado
Pizarra que podemos colocar en una escena para dibujar figuras geométricas
sencillas.
Cuando se agrega el actor pizarra, vas a observar que soporta algunos métodos
para dibujar. Esta es una lista de los más utilizados:
Dibujar círculos
Para dibujar círculos tenemos una función que pinta el contenido de un círculo
en base a 4 parámetros:
101
102 DIBUJADO SIMPLE EN PANTALLA
Colores
En los ejemplos anteriores utilicé colores como “rojo”, “negro” y “verde”; sin
embargo esta no es la única forma de especificar colores. Los nombres de colores
son útiles y fáciles de recordar, pero no ofrecen mucha variedad.
Otra forma de definir colores con mucha flexibilidad es mediante la función
RECTÁNGULOS 103
Rectángulos
De forma similar a los círculos, también existen funciones para dibujar rectángulos
y bordes de rectángulos.
this.dibujar_rectangulo(0, 0, 120, 50, "naranja");
this.dibujar_borde_de_rectangulo(0, 0, 120, 50, "rojo", 5);
104 DIBUJADO SIMPLE EN PANTALLA
Los argumentos de estas funciones son: el punto de originen, en este caso x=0
y=0, luego el ancho y alto del rectángulo y por último el color.
Lineas
Para dibujar lineas, tenemos que especificar dos coordenadas, color y grosor de
la linea:
Por ejemplo, para dibujar una linea de color “verde” desde el punto (0, 0) al
punto (200, 100) podemos escribir:
this.dibujar_linea(0, 0, 200, 100, "verde", 10);
Animaciones
Si bien el actor pizarra pude moverse en pantalla, tener una figura física e incluso
ser utilizado como cualquier otro actor. También es posible usarlo para crear
animaciones cuadro a cuadro.
El actor Pizarra incluye una función llamada limpiar que si se combina con
funciones de dibujado se pueden hacer algunas animaciones simples.
Por ejemplo, si queremos dibujar una linea que señale la posición del mouse
constántemente podemos hacerlo así, usando la función actualizar:
actualizar() {
this.limpiar();
this.dibujar_linea(0, 0, this.pilas.cursor_x, this.pilas.cursor_y, "verde", 10);
}
ANIMACIONES 105
106 DIBUJADO SIMPLE EN PANTALLA
Cómo exportar juegos
Para exportar un juego simplemente hay que pulsar el botón Exportar del editor:
107
108 CÓMO EXPORTAR JUEGOS
Este archivo .zip aloja el proyecto completo, así que podemos utilizarlo para
punto de partida para llevar nuestro juego a otro lugar.
El archivo .zip se puede descomprimir fácilmente con las herramientas que vienen
instaladas en cualquier sistema operativo.
npm install
A partir de este punto, vas a tener la posiblidad de hacer alguna de estas cosas:
npm start
Otra opción es lanzar el juego como si se tratara de una aplicación dedicada, sin
necesidad de un navegador.
Pilas incluye una forma sencilla de probar juegos en celulares y tablets, si solo
quieres probar tus juegos te recomendamos mirar ahí primero.
Ahora bien, si en realidad lo que buscas es llevar tu juego de forma permanente
a un celular o tablet, ya sea para tí, amigos o para publicar en un tienda oficial,
lo que necesitas es instalar cordova, los SDK oficiales para tu tipo de dispositivo
(android o ios) y compilar tu juego por completo.
115
Y para android:
cd cordova
cordova platform add android
En este punto, asegúrate de haber movido todos los archivos del directo-
rio “proyecto” (index.html, pilas-engine.js etc. . . ) dentro del directorio “cor-
dova/www”.
Luego tienes que generar el proyecto para android con este comando:
cordova build android
116 CÓMO EXPORTAR JUEGOS
O bien, abrí el menú “Build” y luego “Build APK(s)” o “Generate Signed APK”
para crear el un archivo .apk e instalarlo directamente en tu equipo o subirlo a
la tienda Play Store de Google.
Colaborar con Pilas Engine
Todas las personas que quieran participar del desarrollo son bienvenidas, Pilas
nos es solo una herramienta de software, es un proyecto colaborativo que sostiene
un equipo de personas amigables y respetuosas que buscan mejorar la calidad de
la educación brindándole a los Jóvenes la posibilidad de volverse protagonistas
en el uso de la tecnología.
Por ese motivo, queremos invitarte a participar. ¡Vos también podes formar
parte del equipo de Pilas!.
117
118 COLABORAR CON PILAS ENGINE
El primer paso para incorporar pilas como biblioteca es descargar los archivos
javascript phaser, nineslice y pilas-engine del directorio public de nuestro
repositorio y colocarlos en un directorio local:
• https://github.com/pilas-engine/pilas-engine/tree/master/public
Luego, deberías agregar en ese mismo directorio los archivos “ima-
genes/sin_imagen.png” y el directorio “fuentes” que también aparencen
en el link anterior.
Por último, deberías crear un archivo index.html con la estructura inicial que
necesita pilas.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<body>
<script>
var pilas = pilasengine.iniciar(600, 600);
pilas.onready = function() {
let actor = pilas.actores.actor();
};
</script>
</body>
</html>
Este archivo index.html se tiene que cargar en un navegador usando un web-
server y no directamente abriendo el archivo index.html. Esto se tiene que
hacer debido a que pilas (y phaser) usan ajax para cargar imágenes y otros
recursos.
Adicionalmente, si tu juego utiliza recursos propios, u otros actores de pilas, te
recomendamos ver este otro ejemplo en donde se cargan varios recursos:
• https://github.com/pilas-engine/pilas-engine/blob/feature/adaptar-para-
ser-usada-como-biblioteca/public/ejemplo-minimo-con-recursos.html
Vas a notar que la diferencia más grande de este otro ejemplo es que usamos
un parámetro para especificar la lista de recursos a cargar y opcionalmente
enumeramos los detalles del proyecto.
120 COLABORAR CON PILAS ENGINE
Entorno para colaboradores
de Pilas
121
122 ENTORNO PARA COLABORADORES DE PILAS
Estructura de directorios
Estos son los archivos principales del repositorio y qué función cumplen:
Directorio | ¿Qué función cumple? |
-||
api_docs | Almacena el resultado de la documentación automática. Si ejecutás
“make api” vas a ver cómo se recorre el código de Pilas y se genera esta docu-
mentación. |
app | Es un directorio importante, aquí está todo el código fuente de la aplicación
realizado con Ember. Dentro están las plantillas, los controladores, componentes
y rutas. Más adelante en este tutorial damos detalles sobre cómo editar los
archivos de este directorio. Pero a grandes razgos, con “make ejecutar” o “make
compilar” se puede invocar a Ember para que convierta todo ese directorio en
una aplicación web. |
manual | Contiene todo el manual de Pilas en formato markdown. Podes editar
el contenido con cualquier editor de textos, y para convertirlo en html y que se
vea dentro de la aplicación deberías ejecutar el comando “make pilas_manual”. |
pilas-engine | Contiene el código fuente del motor de pilas. El código está
diseñado usando typescript, por ese motivo para compilarlo hay que ejecutar el
comando “make compilar_pilas” o “make compilar_pilas_live” para hacerlo de
forma continua. |
public | Almacena todos los archivos que se deben servir desde la aplicación
emberjs sin procesar. Por ejemplo imágenes, fuentes y sonidos. Pero además,
este directorio también se actualiza desde otros comandos. Por ejemplo, cuando
compilamos el código del directorio pilas-engine con el comando “make compi-
lar_pilas”, el archivo generado se copia a este directorio “public”. |
tests | Almacena todos los tests de unidad, integración y aceptación. Estos tests
se ejecutan cuando se invoca el comando “make test” o cuando se ejecuta “make
ejecutar” y luego se ingresa a http://localhost:4200/tests. Además, se ejecutan
en remoto cada vez que se hace un push al repositorio. Más adelante en este
documento se describe cómo funcionan los tests en la estructura del proyecto. |
• https://github.com/pilas-engine/pilas-engine
Una vez que tengas realizado el fork, cloná el repositorio con estos comandos e
instalá las dependencias del proyecto:
make iniciar
Deberías ver cómo se van instalando todas las dependencias dentro del directorio
“node_modules”. Esto puede demorar varios minutos:
make ejecutar
Ten en cuenta que el servidor de Ember va a estar en ejecución; cada vez que
modifiques un archivo del código de la aplicación Ember se va a encargar de
actualizar el navegador automáticamente.
Estilo de programación
Tests
El proyecto incluye tests que intentamos llevar de la mano con cada característica
que agregamos a la herramienta. Los tests se almacenan en el directorio “tests”
y cada uno de ellos está diseñado para encargarse del funcionamiento de una
característica de la herramienta.
126 ENTORNO PARA COLABORADORES DE PILAS
Cada sentencia del archivo intenta simular una acción del usuario y viene
acompañada de alguna validación:
En la imagen marqué dos opciones que me parecen útiles para todas las personas,
la primera evita que la pantalla se llene con detalles de tests que corren bien y la
segunda es simplemente estética: sirve para ver cómo se ven los tests visualmente
al costado de la pantalla.
Hay varias tareas que se realizan de forma automática cada vez que realizamos
un push al repositorio.
Por ejemplo, cada vez que se ejecuta un push sobre github, un servicio llamado
“circle-ci” se encarga de correr todos los tests del proyecto desde cero.
Este servicio no solo ejecuta los tests, sino que nos avisa por email si alguna de
las pruebas falló o si alguna fase de la instalación tuvo problemas. Además nos
genera un listado histórico para corroborar si un cambio introduce algún tipo de
error:
128 ENTORNO PARA COLABORADORES DE PILAS
La forma que utilizamos para marcar que Pilas se puede publicar es realizando
un tag. Los tags los va a detectar circle CI para generar binarios y subir una
versión actualizada de la aplicación a la web.
AUTOMATIZACIÓN E INTEGRACIÓN CONTÍNUA 129
Por
ejemplo, en la imagen se ve el tag de la versión v2.0.25. Cuando eso sucedió,
“circle-ci” generó estos archivos para que esa versión de pilas esté compilada y
disponible para descargar desde aquí:
130 ENTORNO PARA COLABORADORES DE PILAS
Si bien estos pasos son automáticos, todo el detalle de lo que se debe ejecutar
está en el archivo .circleci/config.yml.