Juegos en JME (o cómo convertir tu celular en una mini consola de video juegos)

junio 17th, 2010 by Enrique Leave a reply »

Con el poder de procesamiento que tienen los dispositivos móviles hoy en día y en particular los celulares, se puede -con un poco de esfuerzo, paciencia y muchas ganas- implementar juegos interesantes en Java para el celular.

El “celular” de hoy en día es como una computadora con un montón de periféricos integrados: cámara, teclado, pantalla, teléfono celular, lector de memoria externa, wifi, gps, gsm, etc. Y todo esto en la palma de la mano.

Algunos de estos dispositivos móviles traen sistemas operativos propietarios, otros utilizan alguna versión de Windows, Linux o Symbian OS. Pero hay una características que la gran mayoría tienen en común: Java. Obviamente no es la versión de Java full power que se instala en nuestro desktop, laptop o servidor. Se trata de una versión adaptada a dispositivos móviles en los cuales no se cuenta con Gigas de RAM, o múltiples CPUs con frecuencias de reloj del orden de los Giga Hetrz.

Sorprendentemente, Java Micro Edition (JME, A.K.A. J2ME) tiene las características que la hacen una plataforma bien interesante para desarrollar aplicaciones y particularmente juegos. Y estos últimos son los que vamos a explorar.


Primero un poco de teoría

Dada la cantidad de dispositivos móviles -todos con características diferentes- se inventaron los “perfiles de capacidades”: MIDP por Mobile Information Device Profile. Dependiendo de la versión de MIDP, el dispositivo va a tener más o menos capacidades de: comunicación, presentación, audio, etc.

Además de MIDP, existe otra especificación llamada CLDC por Connected Limited Device Configuration, que define capacidades de bajo nivel del dispositivo, por ejemplo, si tiene la capacidad de manejar número con punto flotante.

MIDP se apoya en CLDC para formar la plataforma Java ME. La idea es desarrollar en la plataforma más compatible que se pueda. Hoy por hoy, la mayoría de los celulares soportan MIDP 2.0 y CLDC 1.1, pero si podemos restringirnos a CLDC 1.0 mejor. El Motorola V360 es un ejemplo de teléfono móvil con MIDP 2.0 y CLDC 1.0.

Entonces cuando empecemos a desarrollar, tenemos que elegir que versión de MIDP y CLDC vamos a utilizar. En la página de Oracle (http://java.sun.com/javame/technology/index.jsp), se puede encontrar más información y el SDK (http://java.sun.com/javame/downloads/index.jsp).

Bien, tenemos el SDK instalado, tenemos nuestra IDE de confianza configurada. ¿Y ahora qué? ¡A programar! Bueno, no tan rápido. ¿Cómo se programa un juego? Esto es algo que los que venimos haciendo IT desde ya hace años, no tenemos muy claro. En Internet hay mucha documentación, pero la realmente buena es escasa.

Primero que nada, veremos como es el esqueleto de un juego -en pseudocódigo-:

proceso entrada del usuario
actualizo el estado del juego
dibujo la pantalla
goto 1

Santo patrono de la informática, perdón por el goto.

No hay nada revelador en estas 4 lineas, pero lo que si se pueden empezar a ver algunos problemas. Por ejemplo: este juego va a ejecutar a distinta velocidad según de la potencia del celular. Algo claramente no deseable. Obviamente queremos que nuestro juego funcione a la misma velocidad en cualquier celular, sin importar la potencia del mismo.

Para esto, hacemos un pequeño cambio:

proceso entrada del usuario
actualizo el estado del juego
dibujo la pantalla
esperar X milisegundos
goto 1

    Ahora variando X, podemos variar la velocidad del juego. Fácil… ¿no? Queda en manos del usuario elegir X mediante, por ejemplo, el menú el juego. Pero, ¿no se podría determinar X automáticamente? Mejor aún, ¿no se podría determinar X dinámicamente en cada vuelta del ciclo? Claro que sí. Ahora vemos como:

    ciclos_por_segundo = 30
    milisegundos_por_ciclo = 1000 / ciclos_por_segundo
    t_inicial = ahora()
    proceso entrada del usuario
    actualizo el estado del juego
    dibujo la pantalla
    t_ciclo = ahora() - t_inicial
    si (t_ciclo < milisegundos_por_ciclo) entonces
        esperar (milisegundos_por_ciclo - t_ciclo) milisegundos
    goto 3
    

    Nota: La función ahora() devuelve la hora actual en milisegundos, algo como lo que hace System.currentTimeMillis() en Java.

    Lo que se hace es, tomar el tiempo que toma un ciclo completo (4, 5 y 6). Si ese tiempo es menor que la cantidad de tiempo que establecimos para cada ciclo en 1 y 2, entonces esperamos esa diferencia de tiempo. Así, todos los ciclos demoran lo mismo y el tiempo de espera se ajusta dinámicamente.

    De esta forma logramos un rendimiento igual entre celulares de distinta potencia. Este método se puede mejorar implementando saltos de ciclos (frame skipping) cuando el celular es de muy baja potencia, pero corremos el riesgo de que el juego se vuelva injugable. Así, el juego ejecutará más lento en celulares de poca potencia, ya que todo el tiempo se consumirá en los puntos 4, 5 y 6 y nunca entrará en espera.

    Es sorprendente la cantidad de cosas interesantes que se pueden hacer utilizando esta sencilla técnica.

    A la práctica

    Vamos a implementar, con esta técnica, el “hola mundo” de los juegos: el PONG de a uno.

    Pong

    Pong

    Es como si fuera un Arkanoid, pero sin los ladrillos. Es verdad, no es muy divertido.

    La implementación en Java del bucle principal sería algo así:

    final int CICLOS_POR_SEGUNDO = 30;
    final int MILISEGUNDOS_POR_CICLO = 1000 / CICLOS_POR_SEGUNDO;
    while (true) {
        long tInicial = System.currentTimeMillis();
        procesarEntradaDelUsuario();
        actualizarEstadoDelJuego();
        dibujarLaPantalla();
        long tCiclo = System.currentTimeMillis() - tInicial;
        if (tCiclo < MILISEGUNDOS_POR_CICLO) {
            Thread.sleep(MILISEGUNDOS_POR_CICLO - tCiclo);
        }
    }
    

    Notar que hasta ahora no hay nada hecho particularmente para el PONG. Lo particular estará en las funciones procesarEntradaDelUsuario(), actualizarEstadoDelJuego() y dibujarLaPantalla().

    La primera tiene la responsabilidad de tomar la entrada del usuario y modificar algo en el juego, en este caso sería la posición de la paleta. Sí, la paleta es ese rectángulo verde.. hay que tener imaginación :-)

    La segunda debe actualizar el estado interno del juego. En este juego, esta función tiene dos objetivos: a) mover la pelota y b) si la pelota se va hacia abajo, entonces el juego termina con el fatídico “Game Over”.

    La tercer y última función, debe tomar el estado del juego y dibujarlo en la pantalla.

    El código fuente se puede bajar desde acá: pong-scr.tar. En esta implementación, nunca se pierde. Cuando la pelota se va para abajo, aparece nuevamente en el medio de la pantalla. Un buen ejercicio, sería agregarle vidas, que aumente la velocidad de la pelota, darle aceleración a la paleta, mejorar los gráficos, agregarle ladrillitos, sonidos, powerups y ponerle un nombre marketinero (que no sea Arkanoid, claro :) ) y de ahí, a la fama!

    Enjoy!

    Blogger PostDiggRedditGoogle ReaderShare
    Advertisement

    Deja un comentario

    Spam protection by WP Captcha-Free