Anda di halaman 1dari 12

Crea tus propios videojuegos

Para hacer un juego con Java En este artculo explicamos cmo programar en Java la estructura bsica de un videojuego. Nota: Este artculo asume que ya tienes unos conocimientos bsicos de Java y quieres entender cmo se puede usar para hacer un videojuego. No es un tutorial de introduccin a Java. Por otra parte, las explicaciones son bastante detalladas y probablemente las puedas seguir sin problema si ya conoces algn otro lenguaje de programacin orientado a objetos.

Ciclo principal de un videojuego


La estructura bsica de un videojuego es muy sencilla. Despus de inicializar el estado del juego simplemente ejecuta un ciclo infinito con los tres pasos siguientes: 1. 2. 3. Lee los controles Ejecuta la lgica del juego Redibuja la pantalla

En el primer paso --Lee los Controles-- checa si el jugador presion algn botn del control y en que posicin estn los joysticks. En el segundo paso --Ejecuta la lgica del juego-- es donde interpreta lo que ley de los controles para mover el personaje o vehculo del jugador, ejecuta los algoritmos de inteligencia artificial de los oponentes y calcula la fsica del juego. En el tercer paso --Redibuja la pantalla-- vuelve a dibujar la pantalla para que todos los objetos del juego (personaje del jugador, oponentes, items, etc.) aparezcan en sus nuevas posiciones. Al ejecutar estos tres pasos repeditamente y con suficiente velocidad, por lo menos unas decenas de veces por segundo, el programa simula objetos en movimiento que reaccionan a las acciones del jugador.

La estructura bsica de un videojuego con Java


Aunque esta estructura bsica es muy sencilla, no es obvio cmo programarla en Java porque primero hay que saber cmo escribir un programa que habra una ventana y actualice su contenido periodicamente. Para hacer esto se emplea Swing, la biblioteca estndar de Java para hacer aplicaciones que manejan ventanas. Swing es un sistema muy flexible para manejo de ventanas y todos sus componentes como botones, mens y listas. Pero esta flexibilidad tiene un precio: Swing es muy extenso y toma algo de tiempo aprender cmo usarlo correctamente. Por suerte, para hacer un videojuego slo es necesario conocer una pequea parte de Swing. En este artculo vamos a ver lo mnimo que se necesita hacer un programa que abre una ventana en la cual despliega una animacin. Para mantener el ejemplo lo ms sencillo posible no vamos a permitir ninguna interaccin, es decir que nuestro ciclo principal nicamente va ejecutar los pasos Ejecuta lgica del juego y Redibuja la pantalla.

Aunque este ejemplo es muy sencillo est escrito con mucho cuidado de seguir estrctamente todas las reglas para el uso correcto de Swing. Es posible escribir un programa que rompa estas reglas y de todas maneras funcione, pero existe el peligro que al hacerle algn cambio empiece a mostrar comportamientos extraos muy difciles de entender.

Una animacin sencilla


A continuacin est el fuente completo de un programa en Java que abre una ventana en la cual muestra una bola roja moviendose.

import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Demo1 extends JComponent { private final static int ANCHO = 512; private final static int ALTO = 384; private final static int DIAMETRO = 20; private float x, y; private float vx, vy; public Demo1() { setPreferredSize(new Dimension(ANCHO, ALTO)); x = 10; y = 20; vx = 300; vy = 400; } private void fisica(float dt) { x += vx * dt; y += vy * dt; if (vx < 0 && x <= 0 || vx > 0 && x + DIAMETRO >= ANCHO) vx = -vx; if (vy < 0 && y < 0 || vy > 0 && y + DIAMETRO >= ALTO) vy = -vy; } public void paint(Graphics g) { g.setColor(Color.WHITE); g.fillRect(0, 0, ANCHO, ALTO); g.setColor(Color.RED); g.fillOval(Math.round(x), Math.round(y), DIAMETRO, DIAMETRO); } private void dibuja() throws Exception { SwingUtilities.invokeAndWait(new Runnable() { public void run() { paintImmediately(0, 0, ANCHO, ALTO); } }); } public void cicloPrincipalJuego() throws Exception { long tiempoViejo = System.nanoTime(); while (true) { long tiempoNuevo = System.nanoTime();

float dt = (tiempoNuevo - tiempoViejo) / 1000000000f; tiempoViejo = tiempoNuevo; fisica(dt); dibuja(); } } public static void main(String[] args) throws Exception { JFrame jf = new JFrame("Demo1"); jf.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); jf.setResizable(false); Demo1 demo1 = new Demo1(); jf.getContentPane().add(demo1); jf.pack(); jf.setVisible(true); demo1.cicloPrincipalJuego(); } }

Para compilar y ejecutar el programa


Te vamos a indicar los pasos a seguir para que puedas compilar y ejecutar este programa en tu computadora desde la linea de comandos (si prefieres emplear algn IDE como Eclipse o NetBeans no deberas tener ningn problema en adecuar estas instrucciones para la herramienta que ests empleando). Sigue estos pasos: 1. Copia el fuente del programa a tu editor favorito y almacenalo (slvalo) con el nombre Demo1.java. Es indispensable que el archivo en el cual est almacenado el fuente se llame as, no se puede llamar de ninguna otra manera. Ese fuente contiene la definicin de una clase que se llama Demo1 y por lo tanto Java requiere que est almacenado en un archivo llamado Demo1.java, no puede tener otro nombre. Inclusive, es importante que respetes las minsculas y maysculas en el nombre: empieza con una 'D' mayscula y lo dems est en minsculas. Ahora tienes que compilar el programa. Para eso ejecuta el comando siguiente:

2.

3. javac Demo1.java El programa javac es el compilador de Java. Lee el programa Demo1.java y lo traduce a bytecodes que almacena en tres archivos: Demo1.class, Demo1$1.class yDemo1$2.class. 4. Ejecuta el programa con este comando:

5. java Demo1 El programa java es la mquina virtual de Java (JVM). Lee los bytecodes del archivo Demo1.class y los ejecuta (al ejecutarlos lee tambin los bytecodes deDemo1$1.class y Demo1$2.class). Al ejecutar el programa Demo1, en la pantalla

de tu computadora aparece una ventana con una bola roja que se mueve y rebota contra los bordes.

Cmo funciona el programa


Veamos ahora el programa parte por parte para entender cmo funciona.

Packages empleados
Empieza con estas tres lineas:

import java.awt.*; import java.awt.event.*; import javax.swing.*; que indican los packages en los cuales se encuentran las clases e interfaces que vamos a usar. En Java las clases se pueden agrupar dentro de packages. Dentro de un package el nombre de una clase debe ser nico, no puede existir otra clase en ese package con el mismo nombre. No hay ningn problema si tenemos dos o ms clases con el mismo nombre siempre y cuando estn dentro de packages diferentes. Esto es para que sea ms sencillo seleccionar el nombre para una clase sin tener que preocuparse de si otro programador ya emple ese mismo nombre para otra clase. Cuando deseamos emplear clases de otro package es necesario indicarselo al compilador, por medio de un import, para que sepa donde buscarlas. En este caso le estamos indicando que las busque en los packages java.awt, java.awt.event yjavax.swing.

Nombre de la clase, constantes y variables de instancia


La linea siguiente:

public class Demo1 extends JComponent { indica el inicio de la definicin de la clase Demo1. Dice que Demo1 extiende JComponent, eso indica que hereda de la clase JComponent. Un JComponent es un componente grfico de Swing que se puede incluir dentro de una ventana, sabe cmo desplegarse y cmo interactuar con el jugador. En este caso el componente grfico es el area de la ventana en donde vamos a mostrar la animacin y no tiene ninguna interaccin con el "jugador". Las lineas siguientes declaran algunas constantes:

private final static int ANCHO = 512; private final static int ALTO = 384; private final static int DIAMETRO = 20; Las constantes ANCHO y ALTO indican el ancho y alto del componente, mientras queDIAMETRO es el diametro de la bola que vamos a dibujar. Todas estas dimensiones estn en unidades de pixeles. Despus vienen las declaraciones de la variables de instancia empleadas para almacenar la posicin y velocidad de la bola:

private float x, y; private float vx, vy; Las variables x y y son para almacenar la coordenadas de la esquina superior izquierda de la bola. S, ya s que una bola no tiene esquinas. Imagnate que la bola est dentro de un cuadrado; estamos hablando de la esquina superior izquierda de ese cuadrado:

Al dibujar dentro de un componente de Swing, el origen del sistema de coordenadas est en la esquina superior izquierda del componente (en este caso es el componenteDemo1); los valores en el eje x se incrementan hacia la derecha y los valores en el eje yse incrementan hacia abajo:

Las coordenadas se miden en pixeles y deben ser nmeros enteros. Si ests leyendo esta explicacin cuidadosamente, seguramente te preguntas en este momento: Si las coordenadas tienen que ser nmeros enteros, entonces porqu estamos usando variables de tipo float para almacenarlas? La respuesta es simple, las almacenamos como float porque as es ms sencillo hacer los clculos para el movimiento de la bola y basta con redondear los valores a enteros cuando queremos dibujarla. La velocidad de la bola es un vector. Tiene una magnitud --qu tn rpido va la bola-- y una direccin --hacia donde va la bola. Podramos almacenar esta informacin en dos variables, una llamada magnitud y otra llamada direccin, pero resulta ms prctico para los clculos de movimiento representar el vector velocidad separado en sus componentes horizontal y vertical dentro de las variables vx y vy respectivamente:

En otras palabras, vx y vy representan la velocidad horizontal y la velocidad vertical de la bola. Si vx es positivo la bola se est moviendo hacia la derecha, y si es negativo se est moviendo hacia la izquierda. De la misma manera, si vy es positivo la bola se esta moviendo hacia abajo, y si es negativo se est moviendo hacia arriba. El movimiento exacto de la bola es la suma de su movimiento horizontal y su movimiento vertical.

El constructor
La parte siguiente del programa:

public Demo1() { setPreferredSize(new Dimension(ANCHO, ALTO)); x = 10; y = 20; vx = 300; vy = 400; } Es el constructor que se ejecuta cuando creamos la instancia de la clase Demo1 (el componente) donde se muestra la animacin de la bola. Lo primero que hace es llamar al mtodo setPreferredSize() para definir de que tamao debe ser el componente al desplegarse en la pantalla. Los componentes de Swing tienen un tamao mximo, un tamao mnimo y un tamao preferido. Swing emplea esta informacin para acomodar los componentes dentro de una ventana y asignarles su tamao. En este programa, el nico componente que contiene la ventana es una instancia de Demo1 y, por lo tanto, basta con definir su tamao preferido ya que no tiene que compartir la ventana con ningn otro componente. Este mtodo espera como argumento un objeto de tipo Dimension, as que creamos uno con el ancho y alto que debe tener el componente y se lo pasamos a setPreferredSize(). Despus, le damos una posicin inicial a la bola --en las variables x y y--, y tambin una velocidad inicial --en las variables vx y vy. Las velocidades estn en unidades de pixeles/segundo, es decir que empieza con una velocidad horizontal de 300 pixeles/segundo y una velocidad vertical de 400 pixeles/segundo.

La fsica: movimiento y colisiones


Despus viene la definicin del mtodo fsica():

private void fisica(float dt) { x += vx * dt; y += vy * dt; if (vx < 0 && x <= 0 || vx > 0 && x + DIAMETRO >= ANCHO) vx = -vx; if (vy < 0 && y < 0 || vy > 0 && y + DIAMETRO >= ALTO) vy = -vy; } En este mtodo es donde se calcula la nueva posicin de la bola y si es que hay que modificar su velocidad porque choc contra alguno de los bordes. Nota: cuando hablamos aqu de modificar su velocidad hay que recordar que estamos tratando con un vector y hay dos cosas que se pueden modificar: su magnitud y su direccin. En este caso, cuando la bola choca contra un borde, no modificamos su magnitud, la bola sigue yendo igual de rpido; lo que modificamos es su direccin, ahora va hacia otro lado. El mtodo fisica() recibe un parmetro dt que le indica el tiempo transcurrido, en segundos, desde la ltima vez que se movi la bola. Usamos ese tiempo transcurrido para calcular cual debe ser su nueva posicin en las dos lineas siguientes:

x += vx * dt; y += vy * dt; Supongamos que vx contiene en ese momento un -300, la bola se est moviendo hacia la izquierda a una velocidad de 300 pixeles/segundo, y que dt es 0.1, ha transcurrido una dcima

de segundo desde la ltima vez que se movimos la bola. Al multiplicar -300 pixeles/segundo por 0.1 segundos nos da un resultado de -30 pixeles. Al emplear el operador +=, le sumamos un -30 a x y la bola ahora queda 30 pixeles ms a la izquierda. Lo que sigue es checar si la bola choco contra alguno de los bordes y, en caso de que esto ocurra, modificar su velocidad. Si la pelota est moviendose hacia la izquierda y choca contra el borde izquierdo entonces ahora se tiene que mover hacia la derecha. Lo mismo pasa cuando se est moviendo hacia la derecha y choca contra el borde derecho, ahora se tiene que mover hacia la izquierda. Saber si la bola se est moviendo hacia la izquierda es muy sencillo, basta con ver si el valor de vx es negativo. Para checar si choc contra el borde izquierdo simplemente vemos si el valor de x es inferior o igual a cero. Por lo tanto, la expresin vx < 0 && x <= 0 es verdadera si la bola se est moviendo hacia la izquierda y choc contra el borde izquierdo. Si el valor de vx es mayor a cero entonces la bola se est moviendo hacia la derecha. Para ver si la bola choc contra el borde derecho tenemos que saber donde est el lado derecho de la bola. El lado derecho de la bola lo podemos calcular sumndole el ancho de la bola (DIAMETRO) a la coordenada horizontal del lado izquierdo de la bola (x). Es decir que el lado derecho de la bola est en x + DIAMETRO. Por lo tanto, la expresinvx > 0 && x + DIAMETRO >= ANCHO es verdadera si la bola se est moviendo hacia la derecha y choc contra el borde derecho. Por lo tanto, la expresin vx < 0 && x <= 0 || vx > 0 && x + DIAMETRO >= ANCHO es verdadera si la bola se est moviendo hacia la izquierda y choc contra el borde izquierdo o si se est moviendo hacia la derecha y choc contra el borde derecho. Cuando eso ocurre, ejecutamos vx = -vx para cambiar el signo de vx, si era negativo ahora es positivo, es decir que si se estaba moviendo hacia la izquierda ahora se va a mover hacia la derecha. Y lo mismo ocurre cuando cuando se estaba moviendo hacia la derecha (vx positivo), ahora se mueve hacia la izquierda (vx negativo). Hacemos lo mismo con el componente vertical de la velocidad (vy) y con eso ya estamos detectando las colisiones con los cuatro bordes de la pantalla y modificando apropiadamente la velocidad de la bola. Nota: Este sistema de deteccin de colisiones no es muy bueno pero funciona bastante bien para este ejemplo sencillo. Para entender porqu no es muy bueno veamos un ejemplo. Imagnate que el valor de x es 10, el valor de vx es -300 y el valor de dt es 0.1. Al ejecutar la linea donde dice x += vx * dt; el nuevo valor de x es -20. Obviamente, eso est mal. El valor correcto de x debera ser 20: si la bola se est moviendo a una velocidad de 300 pixeles por segundo entonces en una dcima de segundo se mueve de 30 pixeles, primero 10 pixeles hacia la izquierda y choca contra el borde, cambia su direccin y se mueve 20 pixeles hacia la derecha. En este ejemplo el error no es muy grave porque, al ser tan sencillo lo que estamos haciendo, tu computadora calcula la nueva posicin de la bola y la dibuja en la pantalla cientos de veces por segundo. Por lo tanto el valor de dt es inferior a 0.01 (una centsima de segundo) y en ese tiempo la bola se mueve de muy pocos pixeles. Lo peor que puede ocurrir es que la bola se salga de la venta por un par de pixeles, y eso ocurre tan rpido que ni se nota.

La parte grfica
Lo que sigue en el programa es el mtodo para dibujar el componente en la pantalla:

public void paint(Graphics g) { g.setColor(Color.WHITE); g.fillRect(0, 0, ANCHO, ALTO); g.setColor(Color.RED); g.fillOval(Math.round(x), Math.round(y), DIAMETRO, DIAMETRO);

} El mtodo paint() es un mtodo que se hereda de JComponent y que Swing llama para dibujar el componente en la pantalla. Hay varias situaciones en las cuales se ejecuta este mtodo, algunas de ellas son: cuando se despliega por primera vez en la pantalla la ventana que contiene este componente, si haba otra ventana delante de esta y ahora ya no est, si la ventana estaba minimizada y se abre. En nuestro ejemplo este mtodo tambin se va a ejecutar cuando nosotros le pidamos a Swing que se redibuje el componente para se vea la bola en su nueva posicin. El mtodo paint() recibe un parmetro g que es de tipo Graphics. Este es el contexto grfico que se emplea para dibujar. El contexto grfico es un objeto que contiene la informacin necesaria para dijujar algo, como: en donde hay que dibujar, el color a emplear, el grueso de las lineas, el tipo de font para los textos y varias otras cosas. Lo primero que hacemos ah es dibujar el fondo. Empleamos g.setColor(Color.WHITE);para seleccionar "pintura" blanca y llenamos un rectangulo que cubre toda el area del componente con g.fillRect(0, 0, ANCHO, ALTO);. El mtodo fillRect() llena un rectangulo con la pintura actual del contexto grfico; espera estos argumentos: fillRect(int x, int y, int width, int height). Donde x y y indican la posicin de la esquina superior izquierda del rectngulo, mientras que width y height son el ancho y alto del rectngulo. Despus dibujamos la bola. Seleccionamos pintura roja con g.setColor(Color.RED); y despus dibujamos la bola con g.fillOval(Math.round(x), Math.round(y), DIAMETRO, DIAMETRO);. El mtodo fillOval() llena un valo con la pintura actual del contexto grfico; espera estos argumentos: fillOval(int x, int y, int width, int height). Donde x y yindican la posicin de la esquina superior izquierda del rectngulo que contiene al valo, mientras que width y height son el ancho y alto del valo (si el ancho es igual al alto entonces tenemos un caso particular de valo: un crculo). Fijate cmo estamos empleando el mtodo Math.round() para redondear los valores de x y y a enteros. Ya tenemos nuestro mtodo paint() para dibujar la bola en la pantalla, lo que nos falta es una manera de decirle a Swing que queremos hacerlo. Una manera sencilla es llamando a otro mtodo que heredamos de JComponent: paintImmediately(). Este mtodo espera los siguientes argumentos: paintImmediately(int x, int y, int width, int height). Estos argumentos le indican a Swing el rea rectangular dentro de nuestro componente que hay que dibujar. Se especifca esta area para optimizar la aplicacin y no perder tiempo redibujando partes del componente que no han cambiado. Para no hacer ms complicado nuestro ejemplo vamos a pedirle as que redibuje todo el componente: paintImmediately(0, 0, ANCHO, ALTO);. Nota: Al llamar a paintImmediately() le estamos especificando un rea rectangular que hay que redibujar, pero en nuestro mtodo paint() no hay nada que tome en cuenta explcitamente esa especificacin de un rea. Esto se debe a que una de las cosas que se almacenan dentro del contexto grfico es el clip area que especifca el rea dentro de la cual se puede pintar algo. Al emplear el contexto grfico para pintar con mtodos como fillRectangle() y fillOval() nicamente se pinta dentro de la interseccin de esa figura (rectngulo u valo) con el clip area, esta es una optimizacin que, en ciertos casos, puede hacer mucho ms rpido el redibujado. De hecho, nuestro ejemplo es bastante ineficiente en cuanto a eso: para dibujar la bola en su nueva posicin estamos primero pintando de blanco todo el fondo del componente, un area de 512 por 384 pixeles (196,608 pixeles). Al principio de este artculo dijimos que: "Aunque este ejemplo es muy sencillo est escrito con mucho cuidado de seguir estrctamente todas las reglas para el uso correcto de Swing". Una de

las reglas ms importantes para el uso correcto de Swing es que no se deben modificar sus componentes o redibujarlos en un thread que no sea el Swing event thread. Java est diseado para poder escribir aplicaciones que sonmultithreaded, es decir que pueden estar ejecutando simulatneamente varios hilos (secuencias, threads) de instrucciones. La arquitectura de Swing aprovecha esto y tiene un hilo de ejecuccin, el Swing event thread, dedicado a atender todos los eventos del sistema de ventanas y el redibujado de sus componentes. Los eventos del sistema de ventanas son cosas que ocurren cuando una persona est interactuando con la aplicacin, por ejemplo: un click del mouse sobre algn componente o un cambio en el tamao de la ventana. Para nuestro ejemplo esta regla de Swing implica que tenemos que encontrar algn mecanismo para que sea el Swing event thread el que ejecute el llamado al mtodopaintImmediately(). Por suerte, Swing cuenta con el mecanismo apropiado para hacer justamente esto dentro de su clase SwingUtilities: los mtodos estticos invokeLater()e invokeAndWait(). Con cualquiera de esos dos mtodos le podemos pedir al Swing event thread que ejecute algo por nosotros. La diferencia entre los dos es que coninvokeLater() le pedimos que lo ejecute y seguimos con la ejecucin de las instrucciones en nuestro propio thread, sabiendo que pronto el Swing event thread ejecutar lo que le pedimos. Al emplear invokeAndWait(), la ejecucin de instrucciones en nuestro thread se detiene hasta que el Swing event thread haya terminado de ejecutar lo que le pedimos. En este caso el mtodo apropiado es invokeAndWait(), porque no debemos seguir con la ejecucin de nuestro ciclo de animacin mientras que no se haya redibujado la bola en su nueva posicin. En nuestro mtodo dibuja() encapsulamos la solicitud al Swing event thread de ejecutar el llamado a paintImmediately():

private void dibuja() throws Exception { SwingUtilities.invokeAndWait(new Runnable() { public void run() { paintImmediately(0, 0, ANCHO, ALTO); } }); } El mtodo invokeAndWait() espera como argumento un objeto de una clase que implemente la interfaz Runnable. Esta interfaz es muy sencilla, simplemente exige que las clases que la implementen tengan un mtodo llamado run(). Este mtodo run() no espera ningn argumento ni devuelve ningn resultado. En el caso de invokeAndWait()ese mtodo run() es el que contiene las instrucciones que se deben ejecutar dentro del Swing event thread. En el mtodo dibuja() estamos empleando una notacin de Java que nos permite, directamente en esa parte de nuestro programa, especificar una clase annima que implementa alguna interfaz y, ah mismo, crear una instancia de esa clase. Lo nico que queda por explicar del mtodo dibuja() es la parte donde dice: throws Exception. La definicin del mtodo invokeAndWait() especifca que puede mandar varios tipos de excepciones, eso nos obliga a hacer una de dos cosas: 1. 2. Cachar esa excepcin con un try/catch Tambin nosotros mandar esa excepcin

El manejo correcto de excepciones en Java es un tema bastante amplio, aqu nos vamos a limitar a hacerte un par de recomendaciones.

La primera recomendacin es: si no sabes que hacer con una excepcin mandasela al que te llam. Y la segunda recomendacin es: nunca, absolutamente por ningn motivo, debes escribir un try con un catch vacio. Si lo haces, algn dia tendrs la oportunidad de arrepentirte (y si no eres t ser alguien ms, pero alguien tarde o temprano tendr que pagar por eso). Como nosotros somos buenos nios, seguimos nuestras propias recomendaciones. No tenemos la menor idea de algo que sea apropiado hacer con las excepciones que manda invokeAndWait(), por lo tanto se las mandamos a quien nos llam. Eso se traduce en el throws Exception del mtodo dibuja().

El ciclo principal del juego


Ya que vimos cmo esta implementada la fsica y la parte grfico de nuestro programa, al fn llegamos al ciclo principal del "juego" (y, en este caso, el nico ciclo que hay en todo el programa):

public void cicloPrincipalJuego() throws Exception { long tiempoViejo = System.nanoTime(); while (true) { long tiempoNuevo = System.nanoTime(); float dt = (tiempoNuevo - tiempoViejo) / 1000000000f; tiempoViejo = tiempoNuevo; fisica(dt); dibuja(); } } El ciclo principal est encapsulado dentro del mtodo cicloPrincipalJuego(). Es un ciclo infinito que llama repetidamente a los mtodos fisica() y dibuja, que ya vimos anteriormente. El nico detalle interesante es que tenemos que calcular el tiempo transcurrido en cada iteracin y pasarselo al mtodo fisica() para que pueda calcular de cuanto se tiene que mover la bola. Para medir el tiempo transcurrido empleamos el mtodo esttico nanoTime() de la claseSystem. Este mtodo nos devuelve el tiempo transcurrido, en nanosegundos, desde algn momento arbitrario (y desconocido) en el tiempo. Almacenamos ese valor dentro de la variable tiempoViejo y, con una simple resta podemos averiguar el tiempo transcurrido. Como el resultado de esa resta est en nanosegundos y el mtodofisica() espera un valor en segundos, lo dividimos entre 1,000,000,000 para hacer la conversin. Nota: al crear la variable tiempoViejo la inicializamos con el valor que devuelve nanoTime()e, inmediatamente despus, volvemos a llamarlo y hacemos la resta. Lo ms problable es que el resultado sea cero (nanoTime() devuelve un resultado en unidades de nanosegundos, pero no mide algo tan pequeo como un nanosegundo!) y que en el primer llamado a fisica() la bola no se mueva. No es grave, en la siguiente iteracin del ciclo, menos de una centsima de segundo ms tarde, ya empieza a moverse. Tenemos que hacer eso porque no podemos emplear una variable que no ha sido inicializada y ese es el nico valor inicial razonable que le podemos asignar (Que pasara si le damos un valor inicial de cero?). Este mtodo tambin tiene una declaracin throws Exception. Esto se debe que llama a nuestro mtodo dibuja() que manda una excepcin y, como tampoco sabemos aqu que hacer con ella, se la mandamos a quien nos llam .

El programa "principal"
Ya est listo nuestro componente, lo nico que falta es colocarlo dentro de una ventana y llamar a su mtodo cicloPrincipalJuego(). Para encargarse de eso definimos un mtodo esttico main():

public static void main(String[] args) throws Exception { JFrame jf = new JFrame("Demo1"); jf.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); jf.setResizable(false); Demo1 demo1 = new Demo1(); jf.getContentPane().add(demo1); jf.pack(); jf.setVisible(true); demo1.cicloPrincipalJuego(); } Este mtodo tambin tiene una declaracin throws Exception porque llama acicloPrincipalJuego(), que manda una excepcin con la cual no sabemos que hacer. Cuando el mtodo main() de una aplicacin en Java manda una excepcin, se interrumpe la ejecucin de la aplicacin y se despliega un stack trace indicando la parte exacta del programa donde ocurri el problema. Para un juego que tengamos la intencin de vender ese no es un comportamiento muy apropiado. Pero, como no creo que alguien est dispuesto a comprar este programa, ese comportamiento es bastante aceptable (y permite que este programa de ejemplo sea ms sencillo). Lo primero que hacemos es crear la ventana. En Swing las ventanas son instancias de la clase JFrame. Creamos una instancia de esa clase y la almacenamos en la variable jf(en realidad se almacena una referencia a esa instancia):

JFrame jf = new JFrame("Demo1"); El string, "Demo1", que le pasamos como argumento al constructor de la claseJFrame es el ttulo que va a aparecer en la parte superior de nuestra ventana. Nota: Al crear una instancia de JFrame ya tenemos un objeto que representa una ventana, pero esa ventana todava no es visible en la pantalla. Cuando un jugador cierra una ventana, espera que en ese instante se detenga la ejecucin del programa. En Swing eso no ocurre automticamente, es necesario programar ese comportamiento. Una manera de terminar la ejecucin de un programa en Java es llamando al mtodo esttico exit() de la clase System. Ese mtodo espera que le pasemos un nmero entero indicanco la razn por la cual se termin la ejecucin del programa. En muchos sistemas operativos, un cero como razn indica una terminacin normal del programa. Ahora tenemos que encontrar una manera de enterarnos que el jugador cerr la ventana. Para eso (y varias otras cosas ms) las ventanas de Swing permiten que se registren con ellas unos objetos listeners (escuchadores) a los que les avisan cuando ocurren ciertos eventos en la ventana con la cual estn registrados. Estos listeners tienen que implementar la interfaz WindowListener. Esta interfaz define varios mtodos que deben estar existir en cualquier clase que la implemente. A nosotros nicamente nos interesa el mtodo windowClosing(), que se llama cuando el jugador cierra la ventana. Para no tener que implementar una clase con todos los otros mtodos que no nos interesan, existe una clase

llamada WindowAdapter. Esta clase implementaWindowListener definiendo todos los mtodos especificados por esa interfaz como mtodos vacios que no hacen nada. Lo nico que tenemos que hacer es definir una clase que herede de WindowAdapter, en la cual redefinimos nicamente los mtodos que nos interesan, crear una instancia de esa clase y registrarla como listener de la ventana. Usando una vez ms la notacin de Java para clases annimas, eso queda as:

jf.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); La linea siguiente es para indicarle a la ventana (JFrame) que el jugador no puede modificar su tamao (obviamente estamos hablando del tamao de la ventana, no sabemos si el jugador puede cambiar su propio tamao y tampoco tiene nada que ver con nuestro programa):

jf.setResizable(false); Despus creamos una instancia de nuestra clase Demo1 y lo colocamos dentro de la ventana (recuerda que Demo1 hereda de JComponent y por lo tanto es un componente grfico de Swing):

Demo1 demo1 = new Demo1(); jf.getContentPane().add(demo1); Ahora le decimos a nuestro JFrame (ventana) que acomode todos los componentes que contiene y defina su tamao:

jf.pack(); En este caso, la venta contiene un solo componente (nuestra instancia de Demo1), lo nico que tiene que hacer es darle su tamao preferido a ese componente (512 por 384 pixeles) y ajustar su propio tamao alrededor de l. Nuestra ventana ya est lista para aparecer en la pantalla. Y eso hacemos con la linea siguiente:

jf.setVisible(true); Lo nico que falta ahora es ejecutar el ciclo principal de nuestro "juego":

demo1.cicloPrincipalJuego();

Conclusin
Ya viste cmo programar la infraestructura ms bsica que se necesita para hacer un videojuego con Java. Es un programa bastante corto y sencillo (menos de 100 lineas). En el prximo artculo veremos cmo agregarle la parte de interaccin con el jugador.

Anda mungkin juga menyukai