Heyyyyyyyyyyyyyyy

Aprende a programar microcontroladores en C... http://tecdigitaldelbajio.com/software-tarjeta.html

miércoles, 18 de agosto de 2010

Ejemplo #18 “Animación usando GameCanvas: Pelota rebotando”



La animación es un proceso de movimiento de imágenes o dibujos, hoy se muestra un pelotita o bolita o circulo, rebotando por toda la pantalla del celular, esa es la primera animación de varias que se van a realizar. La animación siguiente muestra lo que se pretende hacer con Java en el celular:

>


Como hacer la pelotita
Recuerde que la clase Graphics contiene métodos para dibujar ya se han visto algunas de estos métodos, hay una función que me permite dibujar arcos se llama así

fillArc
Es posible realizar un círculo con esta función, esto se hace así porque la clase Graphics no tienen ninguna instrucción para directamente crear un círculo. La función anterior requiere de 4 parámetros, estos se puede ver en la ayuda de J2ME para la clase Graphics, los parámetros son así:

fillArc(int x, int y, int width, int height, startAngle, arcAngle);

Una imagen vale más que 1000 palabras, así que muestro un par de imágenes con la instrucción fillArc.

Aquí hay otra imagen, que muestra incluso dos líneas para que quede bien claro donde se ubica el circulo cuando se dibuja.
El lector puede seguir experimentando con los parámetros si así lo desea. Note que el primer par de parámetros, que en el ejemplo son (10, 10) ubican la posición de una esquina de un rectángulo imaginario, ese es el punto de referencia para iniciar el dibujo del círculo, después siguen las coordenadas (30, 30) que es el ancho y el alto del circulo, y luego va el ángulo de inicio y el ángulo del arco, para que sea un circulo completo se inicia con el ángulo en 0 y se termina con el ángulo en 360.

Por otro lado, en ese par de imágenes anteriores se puede ver que si la bolita se “desplaza” (primero se puso en la coordenada (0,0) y luego en la (10,10) ), podemos decir que la bolita “se movio”, eso es la animación, sensación de movimiento.

Ciclo para la animación
La animación, se puede resumir en lo siguiente: dibujar la pelota en una posición, borrar la pantalla y volver a dibujarla ahora en otra posición, y repetir todo, una y otra vez, ¿Cómo se hace esto? Bien simple con un ciclo, dando clic aquí para ver el post de los ciclos, si así lo deseas.

Por facilidad se usa el ciclo while(), la condición la colocamos en “true”, con eso basta para lograr un ciclo infinito, después de todo se desea que la pelotita rebote “siempre”, entonces el código para el ciclo es así:


while (true) {
   // código para la animación
}


Pero ¿Dónde va el ciclo? Sencillo, en el método run(), después de todo este ciclo se ejecuta cuando se inicia el subproceso, y como se vio en la entrada anterior aquí es donde van las instrucciones para graficar, así que el método run se va formando así:

public void run() {
   while (true) {
       // Código para la animación
    }
}


El método “sleep” del subproceso

Se mencionó arriba que la animación es simplemente dibujar, borrar, volver a dibujar en otra posición, borrar, y repetirlo, pero necesito hacerlo en pausas, es decir, dibujar por un tiempo (algunos milisegundos), luego borrar todo y volver a dibujar en otra posición después de otro tiempo, esto se puede realizar por medio del subproceso, ya se vio en el post anterior algo de los subprocesos, al crear y después de iniciar el subproceso, se puede hacer uso de sus métodos, hay un método llamado “sleep” (ver la documentación de la clase Thread, si se desean ver más detalles), este método me permite hacer una pausa, un ejemplo en código puede ser el siguiente:

subproceso.sleep(100);

Al ejecutar esa instrucción el programa se detiene durante 100 milisegundos, este método debe ser encerrado en un par de instrucciones así:

try {
  subproceso.sleep(10);
} catch (InterruptedException e) { }


El “try y catch” son requeridos por el programa, si no se agregan hay un error de compilación y nunca podre ejecutar el programa. Esas instrucciones, me permiten capturar algún error, en java se llaman excepciones, ya que el método sleep, puede crear errores por eso se usa el “try” y el “catch”, el código va dentro del ciclo while y va quedando así:


public void run() {
  while (true) {
    // Código para la animación
    try {
      subproceso.sleep(100);
    } catch (InterruptedException e) { }
  }
}

No se profundizará sobre las excepciones quizá más adelante se haga un post de esto, por lo pronto nos interesa la animación, así que continuamos.

Variables usadas en la animación
Se vio en la sección anterior, que la pelotita se “mueve” con solo mover el parámetro x y el parámetro y de fillArc, entonces, como inicio se pueden declarar esos parámetros con una variable para después cambiarlos, así:

int coordX = 0;
int coordY = 0

Recuerde que la declaración va al inicio del método, ya con las variables declaradas, se puede crear el circulo con la instrucción fillArc, en este caso es un circulo con 20 pixeles de ancho y alto, esta es la instrucción

g.fillArc(coordX, coordY, 20, 20, 0, 360)

La instrucción va dentro del ciclo, el código toma la forma siguiente:

public void run() {
  int coordX = 0;
  int coordY = 0
  while (true) {
     g.fillArc(coordX, coordY, 20, 20, 0, 360)   

     try {
       subproceso.sleep(100);
    } catch (InterruptedException e) { }

  }
}

¿Ahora que se necesitará para mover la pelotitia? Simplemente desplazar las coordenadas, estas que son variables se pueden desplazar sumandoles un valor, así:
coordX = coordX + 1
coordY = coordY + 1

Otro ejemplo sería así:

coordX = coordX + 5
coordY = coordY + 5

O uno con desplazamientos diferentes,

coordX = coordX + 5
coordY = coordY + 3

Vea los ejemplos, en el primero solo se desplaza la pelotita 1 pixel, el segundo 5 pixeles ¿Qué diferencia hay? Entre 1 pixel o 5 pixeles en el desplazamiento, la animación siguiente nos da la respuesta:

>

Nota: La animación es para fines ilustrativos solamente, está realizada con un programa llamado SwishMax 2, por lo que no se si vaya más rápido o más lento cuando se programe en Java.

Obviamente la pelotita va más rápido con 5 pixeles que con 1, por que los incrementos en las coordenadas son mayores, podemos entonces decir que el sumarle una variable a la coordenada hace que se cambie su velocidad, por comodidad se va a almacenar este desplazamiento en variables también, se declaran así:

int velX = 5;
int velY = 5;


Yo las inicie en 5, el lector puede hacerlo en 1 o en otro valor, queda el código así:
public void run() {
   int coordX = 0;
   int coordY = 0;
   int velX = 5;
   int velY = 5;
 

   while (true) {
     g.fillArc(coordX, coordY, 20, 20, 0, 360)
     try {
       subproceso.sleep(100);
     } catch (InterruptedException e) { }
     coordX = coordX + velX;
     coordY = coordY + velY;
   }
}

Es obvio también, que si se ejecuta este código la pelotita se va de largo ¿Por qué? Ya se imaginará el lector que falta agregar un código que haga que la pelotita rebote esto es que cambie de dirección como se ve en la figura:


Aparte, en la figura se observa donde está el punto (0,0) en el sistema de coordenadas de Java para que el lector lo recuerde, también se muestra el alto y ancho de la pantalla, que es donde la pelotita rebota, entonces bastaría con que yo compare la posición de la pelotita para saber si llego a lo alto de la pantalla (o a lo ancho) y simplemente cambio de dirección.

Entonces, una simple comparación puede detectar si la pelotita llego a lo alto del panel, primero pues vamos a usar un par de variables para obtener el alto y ancho del panel así:

int ancho = getWidth();
int alto = getHeight();

Ahora sí, se inician las comparaciones, que tal un if para “ver “ si ya toco el alto así:

if (coordY > alto) {
  // código para cambiar de dirección
}

Pero vea la figura y recuerde lo que se menciono arriba, el círculo se dibuja tomando como referencia la esquina de un rectángulo, que justo son las coordenadas x e y:



¿Cómo se cambia la dirección?

La respuesta es bien simple, para el ejemplo que se muestra, la pelotita se desplaza hacia abajo por que se suma se suma la velocidad (variable velY) pero que tal si envés de sumar se resta la velocidad, la pelotita se iría hacia arriba.

Entonces para que la pelotita cambie la dirección basta con restar la velocidad, esto se hace simplemente con cambiar el signo de la variable así:

velY = -velY;

Con esa instrucción la pelotita rebotará al llegar a lo alto de la pantalla, el código del método run queda de la siguiente forma al agregar el primer if:

public void run() {
 int coordX = 0;
 int coordY = 0;
 int velX = 5;
 int velY = 5;
 while (true) {
   g.fillArc(coordX, coordY, 20, 20, 0, 360)
   try {
     subproceso.sleep(100);
   } catch (InterruptedException e) { }
   coordX = coordX + velX;
   coordY = coordY + velY;
   if ((coordY + 20) > alto) {
     velY = -velY;
   }
 

 }
}
Ahora vea en la figura el siguiente caso que tiene que ver con la coordenada Y todavía:

La pelotita se dirige a la coordenada 0, de Y, para ese momento la velocidad es negativa obviamente deseamos que rebote de ahí, entonces se requiere otra comparación para hacerlo, así:

if (coordY < 0) {
   velY = -velY;
}
Con eso basta para que detecte el límite de la pantalla y al cambiar de signo la velocidad, la pelotita cambia de dirección.

Es posible unir los dos if’s para la coordenada Y usando el operador OR (operador lógico) de Java, el operador OR en Java es así || el código queda entonces con un solo if de esta forma:

if ((coordY + 20) > alto || (coordY < 0 ))
  velY = -velY;
También quitamos las { }, puesto que sigue solo una instrucción no son necesarias.

Todo lo que se hizo para la coordenada Y se aplica para la coordenada X y el ancho de la pantalla , así que les dejo como va quedando el código para el método run ya con los if’s para las ambas coordenadas

public void run() {
  int coordX =0, coordY=50;
  int velX = 5;
  int velY = 5;
  int ancho = getWidth();
  int alto = getHeight();
  while(true) {
    g.fillArc(coordX,coordY,20,20,0,360);
    try {
      subproceso.sleep(30);
    } catch (InterruptedException e) { }
    coordX = coordX + velX;
    coordY = coordY + velY;
    if ((coordX + 20) > ancho || (coordX < 0) )

       velX = -velX;
    if ((coordY + 20) > alto || (coordY < 0 ))
       velY = -velY; 

    flushGraphics();
  }
}

También en el código anterior se agrego  el método flushGraphics al final del código.

Recuerde la animación es un ciclo de dibujar, borrar, dibujar en otra posición, borrar…. Y así sucesivamente, para terminar falta el borrado el código anterior, no funcionaría como se desea si no es borrada la pantalla, esto se hace colocando el fondo del color que se quiera, en este caso es en color negro, aparte se agrega el código para pintar la pelotita en color azul.

g.setColor(0x000000); //color negro
g.fillRect(0, 0, ancho, alto);
g.setColor(0x0000FF); //color azul


Por fin se muestra el código completo para el método run(), el código para borrar se coloca después del while

public void run() {
  int coordX =0, coordY=50;
  int velX = 5;
  int velY = 5;
  int ancho = getWidth();
  int alto = getHeight();
  while(true) {
    g.setColor(0x000000); //color negro
    g.fillRect(0, 0, ancho, alto);
    g.setColor(0x0000FF); //color azul
   

    g.fillArc(coordX,coordY,20,20,0,360);
    try {
      subproceso.sleep(30);
    } catch (InterruptedException e) { }
    coordX = coordX + velX;
    coordY = coordY + velY;
    if ((coordX + 20) > ancho || (coordX < 0 )

      velX = -velX;
    if ((coordY + 20) > alto || (coordY < 0 ))
      velY = -velY;
    flushGraphics();
  }
}

Vaya este post se me hizo larguísimo, pero ya es todo, fiel a mi costumbre se muestra el video-tutorial completito para que no haya errores de ningún tipo y el lector pueda implementarlo con toda la confianza del mundo.
 



9 comentarios:

  1. Che muy groso todo esto me voy a poner a estudiar cuando tenga tiempo en las vacas felicitaciones desde cordoba argentina

    ResponderEliminar
  2. la verdad te felicito por la claridad con la que explicás. Muchas gracias. Saludos desde Montevideo, Uruguay

    ResponderEliminar
  3. Gracias que bueno que les gusto el blog, seguiremos colocando más artítculos espero que sea uno por semana, solo les ruego paciencia, también yo les mando saludos desde irapuato, México

    ResponderEliminar
  4. Cuando tenga tiempo voy a leer todos los artículos. Gracias por la colaboración.

    ResponderEliminar
  5. olle causa toy siguiendo paso a paso tu tutorial y toy q aprendo como mela bueno mi pekeño aporte amigo es q al final en el segundo if pongas asi :

    if ((coordY + 20) >= alto || (coordY <= 0)) {
    velY = -velY;
    }
    q pongas >= y <= pq la bolita desaparece la mitad cuando choca con el suelo bueno seguire aprendiendo amigo ta muy bueno tu post felicitaciones

    ResponderEliminar
  6. Ok Juanko, muchas gracias por el aporte, si me parece mejor agregar el <= y el >= es mas correcto así , tienes toda la razón...

    saludos

    ResponderEliminar
  7. Bien brother esta excelente el post me gusto demasiado ademas tiene estilo para explicar muy bien las cosas, una pregunta para que funcione ¿no hay necedidad de agragar alguna biblioteca?

    ResponderEliminar
  8. No Adre3s no es necesario ninguna biblioteca extra basta con que tengas instalado el paquete J2ME de java y alguna IDE como netbeans o eclipse para desarrollar la aplicación lo demás es tal cual lo muestran los pasos del vídeo tutorial saludos desde El Salvador

    ResponderEliminar