Programación de juegos para móviles con J2ME

Como vimos en el anterior cap�tulo, J2ME se sustenta en dos APIs, por un lado CLDC que hereda algunas de las clases de J2SE, y MIDP que a�ade nuevas clases que nos permitir�n crear interfaces de usuario.

Las clases que nos ofrece CLDC, son las m�s importantes de los siguientes paquetes de J2SE:

java.lang
java.util
java.io

Adem�s cuenta con el �Generic Conection Framework� que ofrece posibilidades de conexi�n y comunicaci�n.

Por su parte la API MIDP tambi�n hereda de J2SE las clases:

Timer
TimerTask

Adem�s MIDP a�ade los siguientes paquetes:

javax.microedition.midlet
javax.microedition.lcdui
javax.microedition.io
javax.microedition.rms

El paquete javax.microedition.midlet, es el m�s importante de todos. S�lo contiene una clase: la clase MIDlet, que nos ofrece un marco de ejecuci�n para nuestras aplicaciones sobre dispositivos m�viles.

El paquete javax.microedition.lcdui nos ofrece una serie de clases e interfaces de utilidad para crear interfaces de usuario. Es algo as� como un peque�o entorno gr�fico similar al AWT, pero, evidentemente, mucho m�s limitado. B�sicamente, nos permite dos tipos de entorno, por un lado podremos trabajar con �Screens� sobre las que podremos colocar elementos de la interfaz de usuario, como textos, menus, etc., por otro, podremos basar nuestras aplicaciones en �Canvas� sobre las que podemos trabajar a nivel gr�fico, es decir, a m�s bajo nivel. Tanto Screen como Canvas son objetos que heredan de la clase �Displayable�.

Todo aquello que puede ser mostrado por la pantalla del dispositivo hereda de forma directa o indirecta de la clase Displayable.

Para el desarrollo de juegos, el objeto Canvas es el que nos va a resultar m�s interesante, y es el que usaremos m�s intensivamente a partir del cap�tulo siguiente.

.��C�mo funciona un MIDlet?

Vamos a entrar directamente en materia analizando el programa de ejemplo del cap�tulo anterior.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

Con estas dos l�neas importamos las clase MIDlet, que es obligatoria para que nuestro programa se ejecute en el dispositivo m�vil, y tambi�n importamos (con la segunda l�nea) los elementos que vamos a utilizar el la interfaz de usuario.

public class HelloWorld extends MIDlet implements CommandListener {
	private Command exitCommand;
	private Display display;
	private Form screen;

En la primera l�nea declaramos la clase principal del programa, que es p�blica. Hereda de la clase MIDLet e implementa la interfaz CommandListener (en concreto implementaremos el m�todo commandAction()). Tambi�n declaramos una serie de variables que utilizaremos a continuaci�n.

public HelloWorld() {
		// Obtenemos el objeto Display del midlet.
		display = Display.getDisplay(this);

Este es el constructor de la clase. Observa que tiene el mismo nombre que la clase (may�sculas y min�sculas incluidas) y adem�s no tiene tipo de retorno, ni siquiera void.

Al ejecutarse un MIDlet, �ste crea un objeto display, que es el encargado de mostrar informaci�n en la pantalla. Para poder utilizarlo, tenemos que obtener una referencia a este objeto. Esto es lo que hace precisamente la siguiente l�nea mediante el m�todo getDisplay() del objeto est�tico Display.

		//  Creamos el comando Salir.
		exitCommand = new Command("Salir", Command.EXIT,2);

Un comando es un elemento que nos permite interaccionar con el usuario y le permite introducir comandos. Para crear un comando creamos una instancia (con new) de la clase Command(). Como par�metro le pasamos el texto del comando, el tipo de comando y la prioridad.

Disponemos de los siguientes tipos de comandos:

Comando Funci�n
OKConfirma una selecci�n
CANCELCancela la acci�n actual
BACKTraslada al usuario a la pantalla anterior
STOPDetiene una operaci�n
HELPMuestra una ayuda
SCREENTipo gen�rico para uso del programador referente a la pantalla actual
ITEMTipo gen�rico para uso del programador referente a un elemento de la pantalla actual

A veces, y dependiendo del modelo y marca del dispositivo, s�lo se pueden mostrar un n�mero limitado de comandos en la pantalla. Al resto se acceder� mediante un men�.

El tercer par�metro nos permite dar m�s prioridad a unos comandos que a otros a la hora de mostrarlos en la pantalla.

		// A�adimos el comando Salir e indicamos que clase lo manejar�
		screen.addCommand(exitCommand);
		screen.setCommandListener(this);

Nos resta a�adir el comando (mediante el m�todo addCommand() del objeto screen) a la lista de comandos y establecer que clase permanece a la �escucha� de esos comandos utilizando la clase setCommandListener(). En este caso, el m�todo encargado de procesar los comandos est�n dentro de la propia clase HelloWorld, por lo que utilizamos el operador this. Si quisi�ramos tener una clase separada encargada de procesar los comandos, la indicar�amos aqu�. En concreto, el m�todo que se encarga de procesar los comandos es commandAction(). Para eliminar un comando podemos utilizar removeCommand(Command cmd).

	public void commandAction(Command c, Displayable s) {
		// Salir
		if (c == exitCommand) {
			destroyApp(false);
			notifyDestroyed();	
		}	
	}

Cuando el usuario genera un comando, se llama al m�todo commandAction(). Este m�todo recibir� dos par�metros. El comando que se gener�, y un objeto de la clase Displayable, que contiene la pantalla del comando.

Cerraremos la aplicaci�n con los m�todos destroyApp() y notifyDestroyed().

		// Creamos la pantalla principal (un formulario)
		screen = new Form("HelloWorld");
		
		// Creamos y a�adimos la cadena de texto a la pantalla
		StringItem saludo = new StringItem("","Hola Mundo...");
		screen.append(saludo);

Dentro de la pantalla podemos situar diversos elementos gr�ficos. Vamos a crear un objeto de tipo Form (formulario) como elemento principal de la pantalla. Veremos dentro de este cap�tulo cu�les son estos elementos.

Seguidamente creamos una cadena de texto (StringItem) y la a�adimos a la pantalla principal mediante el m�todo append().

	public void startApp() throws MIDletStateChangeException {
		// Seleccionamos la pantalla a mostrar
		display.setCurrent(screen);	
	}

Mediante el m�todo setCurrent() del objeto display (aquel del que obtuvimos la referencia al principio del constructor) seleccionamos la pantalla actual para ser mostrada. Lo hacemos en el m�todo startApp() que es el que se ejecuta en primer lugar.

public void pauseApp() {}
public void destroyApp(boolean unconditional) {}

Estas dos l�neas pueden parecer extra�as, ya que son m�todos vac�os (sin c�digo). Como ya vimos, hay que implementar todas las clases heredadas de MIDlet (pauseApp, destroyApp y startApp), por lo que, aunque no contengan c�digo, hay que declararlas.

.�Elementos de la interfaz de usuario

Ahora que tenemos una idea b�sica sobre el funcionamiento de un MIDlet, pasaremos a describir los elementos gr�ficos de los que disponemos para crear interfaces de usuario.

Como ya vimos, la clase Screen hereda directamente de Displayable y permite crear las interfaces gr�ficas de alto nivel. Un objeto que herede de la clase Screen ser� capaz de ser mostrado en la pantalla. Disponemos de cuatro clases que heredan de Screen y que nos sirven de base para crear las interfaces de usuario. Son Alert, Form, List y TextBox.

Un MIDlet t�pico estar� compuesto de varios de estos elementos. Por desgracia, y debido al peque�o tama�o de la pantalla, no pueden mostrarse m�s de un elemento a la vez, por lo que tendremos que ir mostrando el elemento que necesitemos que ocupar� toda la pantalla.

Podemos imaginarlo como una serie de fichas de las cuales s�lo podemos mostrar una cada vez.

Para cambiar de una pantalla a otra usamos el m�todo setCurrent de la clase Display (como ya vimos en nuestro ejemplo):

display.setCurrent(list1);

Cada uno de las cuatro clases anteriores dispone de los m�todos (realmente los heredan de Screen):

  • String getTitle() - Devuelve el t�tulo de la pantalla
  • void setTitle(String s) - Establece el t�tulo de la pantalla
  • Ticker getTicker() - Devuelve el ticker de la pantalla
  • void setTicker(Ticker ticker) - Establece el ticker de la pantalla

Estos m�todos nos permiten establecer y recoger el T�tulo y el ticker de la pantalla. Un ticker es una l�nea de texto que aparece en la parte superior de la pantalla con un scroll lateral.

.�La clase Alert

Permiten mostrar una pantalla de texto durante un tiempo o hasta que se produzca un comando de tipo OK. Se utiliza para mostrar errores u otro tipo de mensajes al usuario.

Para crear una alerta utilizamos su constructor que tiene la siguiente forma:

Alert (String t�tulo, String texto_alerta, Image imagen_alerta, AlertType tipo_alerta)

El t�tulo aparecer� en la parte superior de la pantalla. El texto de alerta contiene el cuerpo del mensaje que queremos mostrar. El siguiente par�metro es una imagen que se mostrar� junto al mensaje. Si no queremos imagen le pasamos null como par�metro. El tipo de alerta puede ser uno de los siguientes:

  • ALARM
  • CONFIRMATION
  • ERROR
  • INFO
  • WARNING

La diferencia entre uno y otro tipo de alerta es b�sicamente el tipo de sonido o efecto que produce el dispositivo. Vemos un ejemplo:

Alert alerta = new Alert (�Error�,�El dato no es v�lido�, null, AlertType.ERROR); 

Y la siguiente l�nea mostrar� la alerta:

display.setCurrent(alerta);

Lo har� durante 1 � 2 segundos. Se puede establecer el tiempo del mensaje con el m�todo

setTimeout(int tiempo)

donde podemos especificar el tiempo en milisegundos. Tambi�n podemos hacer que el mensaje se mantenga hasta que se pulse un bot�n del dispositivo de la siguiente manera:

alerta.setTimeout(Alert.FOREVER);

.�La clase List

Mediante la clase List podemos crear listas de elementos seleccionables.

Veamos el constructor:

List (String t�tulo, int tipo_lista, String[] elementos, image[] im�genes) 

Los posibles tipos de lista son:

  • EXCLUSIVE - S�lo se puede seleccionar un elemento
  • IMPLICIT - Se selecciona el elemento que tiene el foco
  • MULTIPLE - Permite la selecci�n m�ltiple

Un ejemplo real:

String[] ciudades = {�M�laga�, �Madrid�, �Melilla�};
List lista = new List (�Seleccione una ciudad�, List.EXCLUSIVE, ciudades, null);

En las listas de tipo EXCLUSIVE e IMPLICIT se puede utilizar el m�todo getSelectedIndex() que retorna el �ndice del elemento seleccionado. Pasando como par�metro el �ndice al m�todo getString() nos devuelve el texto del elemento seleccionado. En listas de tipo MULTIPLE podemos utilizar el m�todo:

int getSelectedFlags(boolean[] array_seleccionados)

Esta funci�n rellenar� el array de tipo booleano que le pasamos como par�metro con valores true o false seg�n el elemento correspondiente est� seleccionado. Evidentemente, el array debe tener una correspondencia uno a uno en n�mero de elementos con la lista.

.�La clase TextBox

La clase TextBox permite introducir y editar texto a pantalla completa. Es como un peque�o editor de textos.

Veamos el constructor:

TextBox (String t�tulo, String texto, int tama�o_max, int limitaci�n)

Las limitaciones pueden ser alguna de los siguientes:

  • ANY - Sin limitaci�n
  • EMAILADDR - S�lo una direcci�n de email
  • NUMERIC - S�lo se permiten n�meros
  • PASSWORD - Los caracteres no ser�n visibles
  • PHONENUMBER - S�lo n�meros de telefono
  • URL - S�lo direcciones URL

El par�metro tama�o_max indica el m�ximo n�mero de caracteres que se pueden introducir. El par�metro texto es el texto inicial que mostrar� la caja.

TextBox texto = new TextBox (�Mensaje�, ��, 256, TextField.ANY);

Para conocer el texto que contiene la caja puede usarse los m�todos siguientes:

String getString()

int getChars (char[] texto)

En el caso de getChars(), el texto ser� almacenado en la variable texto en forma de array de caracteres.

.�La clase Form

Un Form es un elemento de tipo contenedor, es decir, es capaz de contener una serie de elementos visuales con los que podemos construir interfaces m�s elaboradas. Los elementos que podemos a�adir a un formulario son:

  • StringItem
  • ImageItem
  • TextField
  • DateField
  • ChoiceGroup
  • Gauge

Como vemos en el diagrama, la clase Form es capaz de manejar objetos derivados de la clase Item. La clase Item representa a un elemento visual que no ocupar� toda la pantalla, sino que formar� parte de la interfaz de usuario junto con otros elementos.

Ya hemos visto un ejemplo de la clase Form en el programa de ejemplo del anterior cap�tulo. En el ejemplo, creamos un elemento de tipo StringItem y lo a�adimos al formulario con el m�todo append().

Los m�todos de la clase Form que nos permiten a�adir, eliminar y modificar elementos del formulario son las siguientes:

int append(Item elemento)

Como ya sabes, append() a�ade al formulario un elemento. Cada vez que a�adimos algo al formulario, a �ste se le asocia un n�mero de �ndice para poder hacer referencia a �l posteriormente. El primer elemento que a�adamos tendr� el valor cero, y as� sucesivamente. Si todo va bien, el m�todo retornar� el �ndice del elemento.

void delete(int �ndice)

El m�todo delete() elimina un elemento del formulario.

void insert(int �ndice, Item elemento)

El m�todo insert() inserta un elemento en la posici�n que indiquemos en el primer par�metro.

Si lo que queremos es sustituir un elemento por otro utilizaremos el m�todo set():

void set(int �ndice, Item elemento) 

En alg�n momento es posible que necesitemos conocer el n�mero de elementos del formulario. El m�todo size() nos muestra esta informaci�n:

int size()

Por �ltimo, necesitaremos alg�n mecanismo que nos permitan responder a cambios en los elementos como, por ejemplo, un cambio de valor. El mecanismo es similar al de los comandos que vimos algunas l�neas atr�s. Hemos de implementar la interface ItemStateListener. Concretamente el m�todo siguiente:

void itemStateChanged(Item elemento)

Para indicar al formulario cu�l ser� la clase que responder� a los eventos podemos utilizar:

formulario.setItemStateListener(this);

Si la clase que manejar� los eventos es distinta a la que contiene el formulario sustituiremos el operando this por la clase deseada.

.�La clase StringItem

Esta clase ya la conocemos del ejemplo del cap�tulo anterior. Su funci�n es a�adir etiquetas de texto al formulario.

El constructor de la clase StringItem es el siguiente:

StringItem (String etiqueta, String texto)

Si s�lo queremos mostrar un texto, sin etiqueta, paramos una cadena vac�a como primer par�metro (��).

Como vimos antes, s�lo hay que utilizar el m�todo append() de la clase Form para a�adir el texto.

La clase StringItem nos provee adem�s de dos m�todos:

String getText()

void setText(String texto)

El primer m�todo devuelve el texto de un StringItem, el segundo, establece el texto que le pasamos como par�metro.

.�La clase ImageItem

Con esta clase podemos a�adir elementos gr�ficos a un formulario. El constructor tiene la siguiente forma:

ImageItem (String etiqueta, Image img, int layout, String texto_alternativo)

El par�metro texto_alternativo es un texto que se mostrar� en el caso en el que no sea posible mostrar el gr�fico. El par�metro layout indica c�mo se posicionar� el gr�fico en la pantalla. Sus posibles valores son:

  • LAYOUT_DEFAULT
  • LAYOUT_LEFT
  • LAYOUT_RIGHT
  • LAYOUT_CENTER
  • LAYOUT_NEWLINE_BEFORE
  • LAYOUT_NEWLINE_AFTER

Las cuatro primeras son auto explicativas. LAYOUT_NEWLINE_BEFORE a�ade un salto de l�nea antes de colocar la imagen. LAYOUT_NEWLINE_AFTER hace precisamente lo contrario, primero a�ade la imagen y despu�s un salto de l�nea.

Para cargar una imagen, utilizamos el m�todo createImage() de la clase Image. Veamos un ejemplo:

Image img;
try {
	img = Image.createImage(�/logo.png�);
} catch (IOException e) {
	 System.err.println(�Error: � + e);
}

A�adir la imagen al formulario es similar a c�mo lo hacemos con un StringItem:

ImageItem img = new ImageItem (��, �/logo.png� ,ImageItem.LAYOUT_DEFAULT, �logotipo�);

formulario.append(img);

Hay que tener en cuenta que las im�genes han de almacenarse en el directorio �res� que crea KToolBar, por lo tanto la barra (/) hace referencia a la ra�z de este directorio.

.�La clase TextField

La clase TextField es muy similar a la clase TextBox que ya vimos anteriormente. La principal diferencia es que TextField est� dise�ada para integrarse dentro de un formulario en vez de ocupar toda la pantalla.

El constructor de esta clase es similar al de TextBox:

TextField (String etiqueta, String texto, int tama�o_max, int limitaci�n)

Los par�metros tienen el mismo significado que TextBox, exepto el primero, que permite especificar una etiqueta.

.�La clase DateField

Con DateField tenemos una herramienta muy intuitiva que permite la entrada de datos de tipo fecha o tipo hora.

DateField (String etiqueta, int modo)

El par�metro modo puede tomar cualquiera de los siguientes valores:

  • DATE
  • TIME
  • DATE_TIME

Para seleccionar la entrada de una fecha o una hora.

DateField fecha=new DateField(�fecha�,DateField.DATE);
formulario.append (fecha);

La clase DateField nos provee estos dos m�todos:

Date getDate()
void setDate (Date fecha)

El primer m�todo recupera el valor del elemento DateField, y el segundo lo establece.

.�La clase ChoiceGroup

Este elemento es similar a la clase List, pero al igual que DateField, puede incluirse en un formulario, de hecho, su constructor es b�sicamente el mismo que el de List:

ChoiceGroup (String etiqueta, int tipo_lista, String[] elementos, image[] im�genes)

Excepto el primer par�metro (que ya conocemos), el resto es exactamente el mismo que el de la clase List.

String[] estados = {"Casado","Soltero","Divorciado","Viudo"};

ChoiceGroup estado = new ChoiceGroup ("Estado", List.EXCLUSIVE, estados, null);

screen.append(estado);

.�La clase Gauge

La clase Gauge representa un elemento tipo barra de estados que permite indicar un valor gr�ficamente.

El constructor tiene la siguiente forma:

Gauge (String etiqueta, bolean interactivo, int val_max, int val_ini)

Los par�metros val_ini y val_max indican el valor inicial y el valor m�ximo de la barra gr�fica. El par�metro interactivo si est� a true, permitir� al usuario modificar el valor de la barra, si no, s�lo podr� mostrar informaci�n.

La clase Gauge nos ofrece cuatro m�todos muy �tiles:

int getValue()
void setValue(int valor)
int getMaxValue()
void setMaxValue(int valor)

Las dos primeros para establecer y recoger el valor del Gauge, y las otras tienen el cometido de establecer y recoger el valor m�ximo del Gauge.

Gauge estado = new Gauge (�estado�, false, 1, 100);
fomulario.append(estado);

El siguiente programa muestra el uso de varios elementos en un formulario a la vez.


import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class UI extends MIDlet implements CommandListener {
	private Command exitCommand;
	private Display display;
	private Form screen;
	
	public UI() {
		String[] estados = {"Casado","Soltero","Divorciado","Viudo"};
		
		// Obtenemos el objeto Display del midlet.
		display = Display.getDisplay(this);
		
		//  Creamos el comando Salir.
		exitCommand = new Command("Salir", Command.EXIT,2);
		
		// Creamos la pantalla principal (un formulario)
		screen = new Form("Interfaz de usuario");
		
		// Creamos y a�adimos los elemento que vamos a utilizar
		TextField nombre = new TextField("Nombre","",30,TextField.ANY);
		DateField fecha_nac = new DateField("Fecha de nacimiento", DateField.DATE);
		ChoiceGroup estado = new ChoiceGroup("Estado",List.EXCLUSIVE,estados,null);
		screen.append(nombre);
		screen.append(fecha_nac);
		screen.append(estado);
		
		
		// A�adimos el comando Salir e indicamos que clase lo manejar�
		screen.addCommand(exitCommand);
		screen.setCommandListener(this);	
	}	

	public void startApp() throws MIDletStateChangeException {
		// Seleccionamos la pantalla a mostrar
		display.setCurrent(screen);	
	}
	
	public void pauseApp() {
	}
	
	public void destroyApp(boolean incondicional) {
	}
	
	public void commandAction(Command c, Displayable s) {
		// Salir
		if (c == exitCommand) {
			destroyApp(false);
			notifyDestroyed();	
		}	
	}
}

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
SIGUIENTE ARTÍCULO