Animaciones con App Inventor (sprites)

Vamos a aprender a hacer nuestra primera animación usando el acelerómetro de nuestro dispositivo para mover una imagen por la pantalla.

 Un viaje a la luna

Para crear animaciones con App Inventor utilizamos Sprites. Los sprites son imágenes que puedes mover por la pantalla siempre dentro de un lienzo (Canvas). Estas imágenes reaccionan a eventos como tocar (touch) o arrastrar (drag) y se pueden mover por el lienzo a una velocidad y dirección determinadas en sus propiedades. Vamos a verlo con un ejemplo.
Empieza un proyecto nuevo y llámalo "viaje_luna".
En las propiedades de la pantalla (Screen) asegúrate de que la propiedad Scrollable está desactivada. Además en la propiedad ScreenOrientation selecciona Portrait (vertical).
Ahora añade los siguientes componentes a tu programa: En primer lugar una etiqueta (label), después un lienzo (canvas) y por último el componente OrientationSensor.
Selecciona la etiqueta y cambia su nombre por marcador. En la propiedad texto escribe 0.
Ahora selecciona el componente canvas y cambia la imagen de fondo (BackgroundImage) y selecciona la imagen estrellas.png que encontrarás en la carpeta de recursos.
Cambia también las propiedades Width (ancho) y Height (largo) a "fill parent".
Ahora vamos a añadir las imágenes para nuestra primera animación. El componente que vamos a usar se llama ImageSprite y lo encontrarás dentro de la categoría Drawing and Animation (dibujos y animaciones). Vamos a necesitar dos, así que coge dos componentes y ponlos dentro del canvas.

 Animando el cohete

Selecciona el primer componente ImageSprite y cambia su nombre a cohete. Vamos a ver en detalle sus propiedades.
La primera propiedad que nos interesa se llama Heading (ángulo de dirección) y nos indica la dirección hacia la que queremos mover nuestra imagen. Podemos utilizar un valor desde 0 hasta 360. 0 indica una dirección de izquierda a derecha, 90 de abajo hacia arriba, 180 de derecha a izquierda y 270 de arriba hacia abajo. Así:

10 En nuestro caso queremos que nuestro cohete vaya subiendo por la pantalla de abajo hacia arriba, por lo tanto pondremos en esta propiedad 90.
11 La siguiente propiedad se llama Interval (intervalo) y representa cada cuanto tiempo vamos a mover la imagen. Para nuestro ejemplo vamos a empezar poniendo 1000. Este dato se representa en milisegundos. Por lo tanto 1000 milisegundos = 1 segundo.
12 En la propiedad Picture (imagen) vamos a seleccionar nuestra imagen para el cohete. Puedes encontrar la imagen que necesitas en la carpeta de recursos. Se llama cohete.png.
13 Desactiva la opción Rotates.
14 La siguiente propiedad que nos interesa se llama Speed (velocidad) y nos indica el número de pixeles que se va a mover nuestra imagen en el intervalo que hemos definido antes. Para empezar pon 1.
15 Por último, cambia el ancho (width) y largo (height) de nuestro cohete por 50 x 50.
Si todo ha funcionado correctamente nuestro cohete se debería de estar moviendo por la pantalla pero muy despacio. La razón está en las propiedades Interval y Speed que hemos usado. Ahora vamos a entender mejor cómo usarlas.
16 Antes de nada, si tu cohete llega al margen superior de la pantalla se detendrá. Para volver a ponerlo en su posición original basta con que lo muevas un poco desde el Diseñador. De esta manera volverá a su posición original. Después veremos cómo manejar esto desde el Editor de bloques.
17 Hasta ahora le hemos pedido a nuestro cohete que cada segundo (Interval = 1000) se moviera 1 pixel (Speed = 1) Si cambias la propiedad interval y vas poniendo valores cada vez más pequeños, el cohete avanza más rápido porque se mueve cada menos tiempo. Si aumentas el número de pixeles que avanza nuestra imagen (Speed) también avanzará más rápido porque los saltos serán mayores. Recuerda que la velocidad depende de la distancia y del tiempo. Prueba a cambiar estos valores hasta que encuentres el que más te guste dependiendo de tu dispositivo. Un intervalo de 25 y una velocidad de 5 suelen funcionar bien.
18 Ahora vamos al Editor de bloques. En primer lugar vamos a colocar nuestro cohete en la posición inicial que queremos. Como se trata de la posición inicial lo lógico es hacerlo nada más arrancar nuestro programa, por lo tanto vamos a usar el evento Screen1.Initialize que se activa al inicio como hemos visto ya. Desde el componente Screen1 coge el evento Screen1.Initialize y ponlo en tu programa.
19 Para colocar un sprite en un punto en concreto de la pantalla podemos usar sus coordenadas como hemos visto antes. Si seleccionas el componente cohete verás los bloques verdes "set cohete.X to" y "set cohete.Y to" cógelos y ponlos dentro del evento .Initialize.
20 Queremos poner el cohete en el margen de abajo de la pantalla, pero tenemos el inconveniente de que nuestra aplicación puede funcionar en muchos tipos distintos de dispositivos (móviles, tablets, etc) y cada uno de ellos tendrá un tamaño de pantalla distinto, por lo tanto tenemos que buscar una manera de saber siempre cuál es el tamaño de la pantalla en la que está funcionando nuestra aplicación. Para ello tenemos dos bloques dentro del componente Canvas que se llaman Canvas.Height (alto) y Canvas.Width (ancho) que nos dicen el alto y ancho del lienzo en cada momento. Esto es importante también si el usuario cambia la orientación de la pantalla en algún momento puesto que cambiará también el tamaño del lienzo. En nuestro caso hemos desactivado la posibilidad de que el usuario lo haga, pero esta sería la forma de hacerlo.
21 Como queremos colocar nuestro cohete centrado en la pantalla, lo primero que tenemos que hacer es fijar su propiedad cohete.X a la mitad del ancho del lienzo (Canvas.Width / 2). Primero coge un bloque numérico de división "/" y pégalo al bloque "set cohete.X to".
22 Ahora coge un bloque Canvas.Width y ponlo como primer argumento de la división. El segundo argumento será un 2. De esta manera conseguimos centrar el cohete.
23 Como el ancho de la imagen del cohete (sprite) es 50. Su centro sería 25. Para centrar con precisión el cohete en la pantalla habría que restar al cálculo anterior estos 25 pixeles adicionales. Es decir el bloque "set cohete.X to" sería igual a
[ (canvas.Width / 2) - 25] así:

No lo hagas ahora si no quieres, pero tenlo en cuenta en tus futuros proyectos.
24 Una vez centrado en el eje horizontal ahora toca colocar el cohete en el margen inferior de la pantalla, por lo que vamos a utilizar un truco parecido al anterior. Como sabemos el tamaño vertical del lienzo, porque lo tenemos en la propiedad Canvas.Height (Alto), basta con asignar este valor al cohete en su coordenada Y. Así lo colocamos siempre al final del lienzo, sea cual sea su tamaño.

25 Ya tenemos nuestro cohete colocado en la posición inicial, ahora sólo queda que cuando llegue al borde superior de la pantalla el cohete vuelva a su posición original. Para detectar si un sprite ha llegado al borde de la pantalla tenemos un evento llamado EdgeReached (Borde alcanzado). Este evento lo encontrarás dentro de cada sprite que uses en tu programa. En nuestro caso vamos a usar el del cohete. Selecciona el componente cohete y coge el evento cohete.EdgeReached.
26 Verás que aparece una propiedad (argumento) llamado edge (borde) que nos indica el borde al que ha llegado el cohete. En este caso no lo vamos a usar.
27 Ya sabemos que este evento se va a activar cuando nuestro cohete llegue al borde de la pantalla. Sólo nos queda que cuando esto ocurra volvamos a situar el cohete en su posición inicial, tal y como hemos hecho anteriormente en el evento .Initialize. Coge un bloque "set cohete.Y to" y ponlo dentro de este evento.
28 Ahora tenemos que tener en cuenta un detalle importante. Al colocar de esta manera el cohete lo que ocurre es que lo estamos poniendo en el mismo borde. Por lo tanto el evento cohete.EdgeReached se va a activar de nuevo. Es decir, el cohete siempre estará tocando el borde, por lo que el evento se activará de forma continua y el cohete no se moverá porque entraremos en bucle infinito. Para que entiendas esto mejor, haz lo siguiente: Dentro del componente Canvas coge el bloque Canvas.Height y pégalo al bloque "set cohete.Y". ¿Ves qué ocurre? El cohete no se mueve, ¿verdad? ¿Comprendes lo que está ocurriendo? Vamos a repasarlo de nuevo.
29 El cohete está en el borde, por lo tanto el evento cohete.EdgeReached se activa. Dentro del evento hemos dicho que si llega al borde lo coloque de nuevo en la posición canvas.Height que es el tamaño máximo del lienzo y es, por lo tanto, el borde, con lo cual el evento se vuelve a activar. Al activarse volvemos a colocar el cohete en el borde y así indefinidamente. ¿Cómo lo solucionamos? Basta con que coloquemos el cohete un poco antes del borde, de esta manera el evento no se activará. Como el tamaño del sprite del cohete es 50 x 50, basta con que restemos el tamaño del cohete (50) del borde. Es decir "set cohete.Y to" = (canvas.Height - 50). Así:

De esta forma estamos colocando el cohete 50 pixeles antes del borde inferior y el evento no se activará más en este caso. Sin embargo, al llegar al borde superior, el evento se vuelve a activar, poniendo el cohete en su posición correcta. Haciéndolo así tu cohete debería de despegar y volver a su posición original de forma continua.
Aunque podríamos saber cuál es el bloque contra el que está chocando (parámetro edge del evento .EdgeReached) así nos ahorramos un poco de trabajo.

 Animando la luna

30 Ahora vamos con la luna. Vuelve al Diseñador y selecciona el componente ImageSprite2.
31 Vamos a cambiar sus propiedades. Para empezar cambia el nombre del componente y llámalo "luna".
32 Ahora cambia el valor de la propiedad Heading y pon 0. Recuerda que un valor de 0 significa que queremos que la imagen se mueva desde la izquierda hacia la derecha.
33 Cambia el intervalo de tiempo (Interval) a 100 y para la imagen (Picture) selecciona la imagen luna.png. Cambia la velocidad (speed) por 10 y el tamaño del sprite (imagen) por 50 x 50.
34 Ahora sitúa la imagen de la luna con el ratón arriba de la pantalla.
35 Vuelve al Editor de bloques.
36 Ahora la luna se mueve por la pantalla desde la izquierda hacia la derecha y se detiene al llegar al borde. Lo que vamos a aprender ahora es a hacer que una imagen rebote cuando llega a un borde. Para empezar necesitamos el mismo bloque evento que usamos antes para detectar cuando un sprite toca un borde. Selecciona el componente luna y coge el evento luna.EdgeReached.
37 Ahora el bloque que necesitamos para que un sprite rebote se llama "call luna.Bounce" (rebotar). Cógelo y ponlo dentro del evento luna.EdgeReached.
38 Recuerda que el evento .EdgeReached nos dice cual es el borde que ha tocado nuestra imagen a través del parámetro edge. Así que tenemos que usar ese parámetro también en el bloque .Bounce. Pega este parámetro al bloque luna.Bounce y tu luna debería de rebotar de un lado a otro de la pantalla. ¿Funciona?

 Añadiendo interactividad

39 Ya tenemos dos sprites moviéndose por la pantalla, ahora vamos a añadirle interactividad, es decir, la posibilidad de controlarlos de alguna manera. Como nuestros dispositivos tienen sensores de movimiento, vamos a controlar nuestro cohete inclinando nuestro móvil o tablet. Para esto hemos añadido el componente OrientationSensor antes. Selecciona este componente y coge el evento OrientationSensor.OrientationChanged.
Este evento nos dice si hemos movido el dispositivo y en concreto nos dice si lo hemos inclinado en alguna dirección. Aunque lo veremos en detalle más adelante de momento nos interesa el parámetro "roll" que es el que nos indica la inclinación del dispositivo y la dirección. Si inclinamos hacia la izquierda el valor de roll será negativo y si lo inclinamos hacia la derecha el valor de roll será positivo. Cuanto más inclinamos en una dirección u otra el valor de rol será mayor o menor. Vamos a ver cómo usarlo.
40 Como queremos mover el cohete inclinando nuestro dispositivo lo primero que necesitamos es el bloque cohete.MoveTo. Cógelo y ponlo dentro del evento OrientationChanged que acabamos de usar.
41 Ahora tenemos que decirle al cohete cuáles son las coordenadas a las que queremos que se mueva. Recuerda que las coordenadas actuales del cohete, es decir, su posición en todo momento, las tenemos en las propiedades cohete.X y cohete.Y. Como el cohete se mueve por sí mismo de abajo hacia arriba, la coordenada Y no la vamos a tocar y vamos a dejar la que tenga en cada momento. Busca la propiedad cohete.Y y ponla en el bloque .MoveTo.
42 Ahora la coordenada X, es decir, la posición horizontal del cohete es la que queremos manejar inclinando el dispositivo. Basta con que sumemos a la coordenada actual cohete.X el valor de roll. Pega al valor de x del bloque .MoveTo la suma de la propiedad cohete.X más roll. Así:

43 Ahora deberías poder controlar tu cohete inclinando el dispositivo. ¿Funciona?
44 Por último queremos que cuando nuestro cohete toque la luna sumemos un punto a nuestro marcador. Es decir, cada vez que consigamos llevar el cohete a la luna ganamos un punto. Para detectar cuando un sprite toca a otro tenemos un evento llamado .CollideWith (colisiona con..). Para nuestro ejemplo podríamos usar el evento CollideWith tanto de la luna como del cohete puesto que el uno toca al otro indistintamente. Vamos a usar el evento del cohete. Busca el evento cohete.CollideWith y ponlo en tu programa. 
45 Verás que el evento nos pasa un parámetro llamado "other" que nos dice contra qué otro sprite nos hemos tocado. Para este caso no vamos a usarlo puesto que ya sabemos que sólo podemos haber chocado contra la luna. Ahora dentro de este evento vamos a sumar un punto a nuestro marcador. Selecciona el componente marcador y coge el bloque "set marcador.Text to".
46 Como en el Diseñador habíamos puesto un valor de 0 a nuestro marcador, ahora sólo tenemos que sumarle un punto más. Coge un bloque suma y como primer parámetro usa el bloque marcador.Text porque es donde tenemos guardado el valor de nuestro marcador.
47 Como segundo valor de la suma pon un 1. Así vamos sumando un punto más cada vez que nuestro cohete llegue a la luna.
48 Finalmente tenemos que volver a poner el cohete en su posición original, de lo contrario nuestro cohete al tocar la luna la atravesaría sin más. Puedes duplicar el bloque "set cohete.Y to" que usamos dentro del evento cohete.EdgeReached para hacer esto. El programa final quedaría así:

Ya tenemos nuestra pequeña aplicación terminada y funcionando. ¿Te atreves a añadirle sonidos?

Más información: