viernes, 26 de octubre de 2012

Ejemplo #2: Otra versión de PONG, en JAVA.

Ya vimos cómo hacer un juego de PONG en C.
Ahora voy a mostrar otra forma de resolverlo con un código un poco mas compacto.
Para esto utilizaremos el lenguaje JAVA.



En este ejemplo sólo vamos a emplear las clases para almacenar campos de acceso público. Esto no es lo correcto de acuerdo al paradigma de la programación orientada a objetos. Ya veremos como escribir un código verdaderamente orientado a objetos en el Ejemplo #4.

Primero vamos a crear la clase Paleta y la clase Pelota.

El código de la clase Paleta:


Esta paleta tiene sólo 2 atributos: alto que guarda el tamaño de la paleta e y que guarda la posición sobre el eje Y.


La clase pelota tiene 4 atributos:


Los primeros dos, x e y guardan la posición de la pelota. veloX y veloY van a ser utilizados para darle dirección. Esto lo veremos al analizar el loop del juego en la función pelota() de la clase Pong.

Ahora que ya tenemos estas dos clases vamos a crear la clase Pong.

Presento el código completo:


Lo primero que vemos es que la clase Pong extiende de JFrame para poder crear la ventana del juego, y que ademas implementa la interfaz KeyListener para controlar los eventos del teclado.

En el método principal main instanciamos un objeto Pong().

A continuación vemos las siguientes lineas en el constructor:



En el primer bloque definimos las propiedades de la ventana y la hacemos visible.

En la siguiente linea: this.createBufferStrategy(2); lo que hacemos es crear un buffer doble, de manera que uno esta en pantalla y el otro no. Esto nos permite redibujar la pantalla sin que el usuario lo note.

La próxima linea: this.addKeyListener(this); la tenemos que agregar para poder utilizar la interfaz KeyListener.

Antes de entrar en el loop del juego creamos los objetos Pelota y Paleta llamando a inicializoObjetos().

Lo próximo es crear un loop infinito. En cada vuelta del loop llamamos a pelota() que es la función donde esta toda la lógica del juego y a sleep() para producir las demoras necesarias.



Ahora vemos la función pelota():



Las primeras dos lineas mantienen la posición de la pelota siempre actualizada. Si pelota.veloX o pelota.veloY fueran negativos, la pelota se movería a la izquierda sobre el eje X y hacia abajo sobre el eje Y.

La llamada a chequearColision() comprueba que la pelota no haya alcanzado una de las paletas.

El siguiente if comprueba si la pelota alcanzó una pared lateral. En tal caso invierte el valor de veloX. Hay que aclarar que pelota.veloX = -pelota.veloX lo que hace no es negativizar el valor de veloX sino invertirlo.

En caso de que la pelota toque un lateral incrementa Malas en 1.

Realizamos a continuación la misma comprobación para los lados superior e inferior.

Esta forma de setear la dirección de la pelota es un poco mas compleja que la del ejemplo anterior en C, pero tiene la ventaja de ser un código mas compacto y económico en cuanto a recursos.


La siguiente función, chequearColision() esta construida igual que la del ejemplo anterior.



Cada bloque if es para una paleta. Si la posición de la pelota coincide con el area ocupada por la paleta entonces cambia la dirección. Si la pelota proviene de adentro de la cancha incrementa en 1 el valor de Buenas.


La próxima función es dibujoPantalla(). Alli vamos a inicializar todos los objetos gráficos para poder utilizarlos con las otras funciones


En las primeras dos lineas inicializamos los objetos g y bf.

Luego abrimos un try. Ya que JAVA maneja las excepciones automáticamente (a diferencia de C#) es conveniente inicializar los gráficos de esta forma por si el programa arroja alguna excepción.

En la siguiente linea g=bf.getDrawGraphics(); le asignamos a g el valor devuelto por bf.getDrawGraphics(). Esta función crea un objeto de tipo GRAPHICS2D que nos permite utilizar el doble buffer. Cuando terminamos de dibujar llamamos a bf.show() para reemplazar el buffer que esta en pantalla por el de fondo.

Llamamos a las funciones que imprimen puntos, pelota, y paletas, siempre pasando como parámetro el objeto de gráficos g.

Dentro del finally llamamos a g.dispose() para deshacernos de g ya que no tenemos que volver a hacer uso del mismo.

Ahora ya terminamos de dibujar y llamamos a bf.show().

La última linea sincroniza con el refresh rate de la pantalla.


La función dibujoPelota() no nos ofrece ninguna complicación:



La función dibujoPaleta():



Contiene un switch para mantener actualizada la posición de la paleta de acuerdo a la dirección del curso vigente. En caso que el valor ingresado por teclado sea la tecla 'e' llama a System.exit(0) y termina la ejecución del programa.

Luego dibujamos la paleta en ambos lados de la pantalla. Si bien se perciben como dos paletas, al moverse juntas las controlamos como un solo objeto. Si quisiéramos agregar un segundo jugador tendríamos que crear otro objeto.


La función muestroPuntos():



Muestra los puntos en la parte superior-izquierda de la pantalla.


La ultima función que vemos es sleep().



Construida igual que en el ejemplo anterior, primero creamos el valor de referencia, lo guardamos en goal y luego lo comparamos con Sustem.currentTimeMillis() hasta que este último alcanza el valor de goal.

Los 3 métodos que estan al final son obligatorios y tenemos que sobreescribirlos para poder utilizar la interfaz KeyListener. El único que en verdad necesitamos es el primero de ellos, que corre cuando se presiona una tecla. En ese caso el valor de la tecla presionada es almacenado en key para utilizarlo en el switch que actualiza la posición de las paletas en la función dibujoPaletas().



De esta manera queda completa la exposición del código.

Hemos podido ver, en este segundo ejemplo, otra forma de abordar el problema lógico planteado en el primer ejemplo, en este caso utilizando el lenguaje JAVA para resolverlo.

También vimos como crear una ventana con los JFrame de Swing y como crear gráficos con AWT.

Links para descargar el código:

clases:
https://dl.dropbox.com/u/103165598/pongJava-src.rar

pongJava.JAR:
https://dl.dropbox.com/u/103165598/pongJava.jar