Cuando se dise�� J2ME, los ingenieros de Sun ya sab�an que una de las claves para que su tecnolog�a tuviera �xito era que ten�a que ser capaz de hacer funcionar juegos, y hacerlo de forma medianamente decente. Para ello deb�an dotar a los MIDlets de la capacidad de controlar la pantalla al m�s bajo nivel posible, es decir, a nivel gr�fico.
En el cap�tulo anterior, hemos profundizado en las clases que nos permit�an trabajar con interfaces de usuario. Todas ellas derivaban de la clase Screen, que a su vez derivaba de Displayable. Si nos fijamos en el diagrama de clases vemos como de Displayable tambi�n deriva la clase Canvas. Esta clase es capaz de mostrar informaci�n gr�fica a nivel de p�xel. Es por ellos que la llamamos interfaz de bajo nivel.

B�sicamente podemos realizar tres operaciones sobre un Canvas:
- Dibujar primitivas gr�ficas
- Escribir texto
- Dibujar im�genes
Es este cap�tulo vamos a cubrir estas operaciones, y as� sentar las bases necesarias para abordar las materias concretas relativas a la programaci�n de videojuegos.
Tal y como hicimos en el anterior cap�tulo utilizaremos un c�digo de ejemplo para ir explicando sobre �l los conceptos b�sicos.

import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class Canvas1 extends MIDlet implements CommandListener { private Command exitCommand; private Display display; private SSCanvas screen; public Canvas1() { display=Display.getDisplay(this); exitCommand = new Command("Salir",Command.SCREEN,2); screen=new SSCanvas(); screen.addCommand(exitCommand); screen.setCommandListener(this); } public void startApp() throws MIDletStateChangeException { display.setCurrent(screen); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable s) { if (c == exitCommand) { destroyApp(false); notifyDestroyed(); } } } class SSCanvas extends Canvas { public void paint(Graphics g) { g.setColor(255,255,255); g.fillRect (0, 0, getWidth(), getHeight()); q.setColor(10,200,100); g.drawLine (0, 0, 100, 100); g.fillRect (50, 50, 30, 30); } }
La Primera parte del c�digo, es decir, la clase Canvas1 debe ya sernos familiar. La �nica diferencia con el c�digo del cap�tulo anterior, es que, en lugar de utilizar un objeto de la clase Form como pantalla principal de la aplicaci�n, utilizamos uno derivado de la clase SSCanvas que implementamos justo debajo.
private SSCanvas screen;
Como puedes observar, la clase SSCanvas hereda de la clase Canvas. Es por ello que podemos utilizarla como pantalla principal (recuerda que Canvas es una clase derivada de Displayable).
class SSCanvas extends Canvas {
La clase SSCanvas implementa el m�todo paint(), que hereda de la clase Canvas. �ste es el m�todo que se invoca cada vez que la pantalla necesita ser redibujada. Por lo tanto, todo el c�digo encargado de pintar en la pantalla ha de situarse aqu�.
public void paint(Graphics g) {
El par�metro g, es el llamado contexto gr�fico, que es de tipo Graphics. Esta clase posee los m�todos necesarios para dibujar en pantalla, mostrar gr�ficos y mostrar textos. Las siguientes l�neas se ocupan de borrar la pantalla y dibujar una l�nea y un rect�ngulo utilizando los m�todos de la clase Graphics.
Vamos a entrar a continuaci�n en detalles sobre los m�todos de esta clase.
�Primitivas Gr�ficas
�Colores
En la naturaleza hay millones de posibles tonalidades de color. necesitamos pues un m�todo que nos permita expresar un color concreto de una gama muy amplia. Newton, experimentando con un prisma de vidrio, constat� como la luz pod�a descomponerse en una serie de colores b�sicos. Lo cierto es que este experimento s�lo trataba de reproducir lo que en la naturaleza conocemos como arco iris, que se produce por la difracci�n de la luz al atravesar las gotas de agua. Un color, por lo tanto, se forma a partir de las distintas aportaciones de los colores b�sicos. Seg�n predomine m�s o menos cada color b�sico, el color resultante ser� distinto. Utilizando esta misma t�cnica, en inform�tica utilizamos tres colores b�sicos para especificar colores complejos. Estos colores son el Rojo, el Verde y el Azul, y abreviamos con RGB (de Red, Green y Blue).
C�digo RGB | Color |
---|---|
255, 0, 0 | Rojo |
0, 255, 0 | Verde |
0, 0, 255 | Azul |
128, 0, 0 | Rojo oscuro |
255, 255, 0 | Amarillo |
0, 0, 0 | Negro |
255, 255, 255 | Blanco |
128, 128, 128 | Gris |
Para especificar el color que queremos utilizar al dibujar en la pantalla utilizamos el m�todo setColor() de la clase Graphics.
void setColor(int rojo, int verde, int azul)
Los par�metros de color tienen un rango de 0 a 255.
Pero, no todos los dispositivos poseen pantalla a color. El siguiente m�todo establece un tono de gris dentro de la grama de grises de una pantalla monocromo.
void setGrayScale(int tono)
El par�metro tono puede tomar un valor entre 0 y 255.
�Primitivas
Aunque no vamos a necesitarlas muy a menudo para desarrollar nuestros juegos, es interesante que conozcamos las primitivas b�sicas con las que contamos para dibujar.
void drawLine (int x1, int y1, int x2, int y2)
Este m�todo dibuja una l�nea que une los puntos de la coordenada (x1, y1) de la pantalla y la coordenada (x2, y2).
void drawRect (int x, int y, int ancho, int alto)
Con drawRect() podemos dibujar rect�ngulos. Los par�metros x e y indican cual ser� la esquina superior izquierda del rect�ngulo, mientras que los otros dos par�metros nos indican el ancho y el alto que tendr� el rect�ngulo en p�xeles.
En nuestro programa de ejemplo, adem�s de utilizarlo para dibujar un cuadrado, le hemos asignado la misi�n de borrar la pantalla. Esto se hace dibujando un rect�ngulo del tama�o de la pantalla del dispositivo y de color blanco.
void drawRoundRect (int x, int y, int ancho, int alto, int ancho_arco, int alto_arco)
Este m�todo es similar a drawRect(), excepto porque sus esquinas son redondeadas. Los otros dos par�metros son al ancho y el alto del arco de las esquinas.
void drawArc(int x, int y, int ancho, int alto, int �ngulo_inicial, int �ngulo)
Con drawArc() seremos capaces de dibujar secciones de arco. Los cuatro primeros par�metros no deber�an necesitar ya explicaci�n. El per�metro �ngulo_inicial indica cual ser� el �ngulo a partir del que se comenzar� a dibujar el segmento de arco. El par�metro �ngulo indica la longitud de arco (en grados) que ser� dibujado.
void fillRect (int x, int y, int ancho, int alto) void fillRoundRect (int x, int y, int ancho, int alto, int ancho_arco, int alto_arco) void fillArc(int x, int y, int ancho, int alto, int �ngulo_inicial, int �ngulo)
Estos tres m�todos son iguales que los anteriores con la diferencia de que la primitiva que dibujan estar� rellena. Es decir, dibuja las primitivas como s�lidas en lugar de huecas.
�Texto
Aunque estemos trabajando a nivel gr�fico, es muy probable que necesitemos mostrar informaci�n textual en pantalla. Un ejemplo claro es el marcador de puntuaci�n de un juego.
El m�todo que nos permite escribir texto en un Canvas es:
void drawString (String texto, int x, int y, int ancla)
El primer par�metro es el texto que queremos mostrar. Los par�metros x e y es la posici�n donde queremos situar el texto dentro de la pantalla. El cuarto par�metro indica cu�l es el punto de referencia para situar el texto en las coordenadas deseadas. Los valores posibles son TOP, BASELINE y BUTTOM para la posici�n vertical del texto y LEFT, HCENTER y RIGHT para la posici�n horizontal del texto. Por ejemplo, si quisi�ramos posicionar un texto en la posici�n 100,100 y con centro en la esquina superior izquierda utilizaremos la siguiente l�nea:
g.drawString (�Hola.�, 100, 100, Graphics.LEFT | Graphics.TOP);

Ahora que tenemos control sobre la posici�n del texto, nos falta por controlar el tipo de letra que queremos utilizar.
void setFont(Font fuente)
Esta funci�n selecciona la fuente a utilizar. El m�todo getFont() de la clase Font nos devuelve un objeto de tipo Font que podemos utilizar con setFont().
static Font getFont (int espaciado, int estilo, int tama�o)
Los valores posibles para estos par�metros son:
Para... | Variables |
---|---|
Tama�o | SIZE_SMALL, SIZE_MEDIUM, SIZE_LARGE |
Estilo | STYLE_PLAIN, STYLE_ITALICS, STYLE_BOLD, STYLE_UNDERLINED |
Espaciado | FACE_SYSTEM, FACE_MONOSPACE, FACE_PROPORTIONAL |
Veamos un ejemplo:
Font fuente = Font.getFont (Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_MEDIUM); g.setFont(fuente);
�Im�genes
Las primitivas gr�ficas nos permiten ya cierta capacidad de dibujar gr�ficos, pero para crear un videojuego, necesitamos algo m�s elaborado. La clase Graphics nos ofrece dos m�todos:
public static Image createImage(String name) throws IOException
El m�todo createImage() carga un archivo gr�fico en formato .PNG. Dependiendo del dispositivo podr� soportar m�s formatos gr�ficos, pero en principio, al menos, debe soportar el formato .PNG. Recuerda que los gr�ficos (y el resto de recursos, como sonidos, etc...) han de estar en el directorio �res�.
boolean drawImage(Image img, int x, int y, int ancla)
El �ltimo par�metro es similar al de drawString(). Sus posibles valores son TOP, VCENTER y BUTTON para la posici�n vertical y LEFT, HCENTER, RIGHT para la posici�n horizontal.
Veamos un ejemplo:
Image img = Image.createImage(�\logo.png�); g.drawImage (img, 10, 10, Graphics.HCENTER, Graphics.VCENTER);
El siguiente c�digo es un ejemplo real de lo que hemos visto en �ste cap�tulo.

import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class Canvas2 extends MIDlet implements CommandListener { private Command exitCommand; private Display display; private SSCanvas screen; public Canvas2() { display=Display.getDisplay(this); exitCommand = new Command("Salir",Command.SCREEN,2); screen=new SSCanvas(); screen.addCommand(exitCommand); screen.setCommandListener(this); } public void startApp() throws MIDletStateChangeException { display.setCurrent(screen); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable s) { if (c == exitCommand) { destroyApp(false); notifyDestroyed(); } } } class SSCanvas extends Canvas { public void paint(Graphics g) { Image img=null; // Borrar la pantalla g.setColor(255,255,255); g.fillRect (0, 0, getWidth(), getHeight()); // Dibujar l�nea g.setColor(10,200,100); g.drawLine (0, 80, getWidth(), 80); // Poner texto Font fuente = Font.getFont (Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_MEDIUM); g.setFont(fuente); g.drawString("J2ME", getWidth()/2, 10,Graphics.BASELINE|Graphics.HCENTER); // Cargar y mostrar gr�fico try { img = Image.createImage("/logo.png"); } catch (Exception e) { System.err.println("error: " + e); } g.drawImage (img, getWidth()/2, 40, Graphics.HCENTER|Graphics.VCENTER); } }