Comenzando a programar nuestro juego

Arreglando las bases de nuestro applet

Ahora que ya sabemos crear applets, creemos uno nuevo de nombre "snake", que será el que usaremos para nuestro primer juego. Copiemos el GameLib del applet1 que aprendimos a hacer en la última parte del curso de introducción a applets, y pegemoslo en el "src" de nuestro proyecto actual. En nuestra clase snake, pogamos el fondo de nuestro applet de color negro y dejemos todo listo para comenzar nuestro nuevo juego.

Para empezar, crearemos un punto que nos indicará la posición de nuestro personaje. Un punto es una función especial que almacena dos variables enteras, X y Y, que sirven como su nombre indica, para indicar un punto en una coordenada. Comencemos agregando la librería correspondiente para poderle usar:

import java.awt.Point;

Ahora, declaremos una nueva variable de tipo punto, que haremos de la siguiente forma en su lugar correspondiente:

	Point personaje = new Point(50,50);

Notaremos que a la variable le asignamos un nuevo punto con dos valores. Esto es para inicializarla de forma correcta, pasandole aquí los valores iniciales de sus coordenadas en X y en Y. Por último, dibujaremos un pequeño círculo verde en el lugar donde estará nuestro personaje, de la siguiente forma:

		g.setColor(Color.green);
		g.drawOval(personaje.x, personaje.y, 10, 10);

Si lo hemos hecho todo de forma correcta, nuestro código debe lucir hasta este momento de esta forma:

import GameLib.Game;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Point;

public class snake extends Game
{
	// Aquí se declaran nuestras variables
	Point personaje = new Point(50,50);
	
	public void init()
	{
		// Comienza descarga asíncrona de recursos pesados
		setBackground(Color.black);
	}

	public void game()
	{
		// Aquí va el código de nuestro juego
		
	}
	
	public void paint(Graphics g)
	{
		// Aquí se dibujan todos los objetos
		g.clearRect(0, 0, this.getWidth(), this.getHeight());
		g.setColor(Color.green);
		g.drawOval(personaje.x, personaje.y, 10, 10);
	}
}

Probemos nuestro código con Shift+F6, si lo hemos hecho bien, veremos nuestro pequeño círculo en la pantalla. No olvidemos copiar el html que se genera en nuestro build y quitarle todo aquello que no sea requerido, como lo vimos en la parte uno de nuestra introducción a applets.

Manipulando el personaje con el teclado

Ahora que ya tenemos listo nuestro código para hacer nuestro juego, aprenderemos a manipular nuestro personaje por medio del teclado. Para ello, lo primero que necesitamos es declarar una variable entera que nos indique la dirección que tenga el personaje:

	int direccion = 1;

Para manejar esta variable, lo haremos de esta forma: Cuando la variable tenga un valor de 0, el personaje avanzará para arriba, de ahi lo giraremos en sentido a las manecillas del reloj, asignandole al valor 1 la derecha, 2 hacia abajo y 3 hacia la izquiera. Ahora que ya imaginamos el significado de los valores, usaremos la función que manipule el teclado. Java ya nos ofrece una función dentro de la librería de eventos, así que para hacer uso de ella, importaremos la librería necesaria:

import java.awt.Event;

Ahora, mandaremos a llamar la función que indica cuando una tecla ha sido presionada, la cual recibirá los eventos de la teclas presionadas, así como los valores ascii de algunas teclas más. Escribamos esta función:

	public boolean keyDown(Event e, int key)
	{
		return true;
	}

Noten que como la función es booleana, al final debemos regresarle un verdadero para asegurarle que la función se ha llevado a cabo con éxito. Ahora, agregaremos un switch dentro de esta función que comparará las teclas que han sido presionadas, y así decidir que rumbo tomará nuestra variable direccion:

	public boolean keyDown(Event e, int key)
	{
		switch(key)
		{
			//	Cambia el rumbo de la serpiente
			case Event.UP:
				direccion = 0;
				break;
		}
		return true;
	}

De esta forma, decimos que en el caso que la tecla que haya sido presionada, sea "arriba", entonces la dirección de nuestro personaje será 0 (arriba). Hagamos lo mismo con las otras tres flechas, a fin que podamos cambiar la dirección en todos los casos:

	public boolean keyDown(Event e, int key)
	{
		switch(key)
		{
			//	Cambia el rumbo de la serpiente
			case Event.UP:
				direccion = 0;
				break;
			case Event.RIGHT:
				direccion = 1;
				break;
			case Event.DOWN:
				direccion = 2;
				break;
			case Event.LEFT:
				direccion = 3;
				break;
		}
		return true;
	}

Si en este momento no resistes más la curiosidad y corres tu programa, notarás que aun no hace nada. Esto se debe a que le hemos dicho como cambiar de dirección, pero no qué hacer con estas. Para ello, agregaremos el siguiente código a nuestra función de game, en su sección correspondiente:

			// Aquí va el código de nuestro juego
			switch	(direccion)
			{
				case 0:
					personaje.y -= 10;
					break;
				case 1:
					personaje.x += 10;
					break;
				case 2:
					personaje.y += 10;
					break;
				case 3:
					personaje.x -= 10;
					break;
			}

Ahora si, corramos nuestro applet con Shift+F6, podremos ver que ahora ya podremos controlar nuestro personaje con las flechas. Es posible que debamos hacer clic en el applet antes para activarlo. Con esto, ya tenemos las bases de nuestro movimiento. Nuestro código debe verse hasta este momento de la siguiente forma:

import GameLib.Game;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Point;
import java.awt.Event;

public class snake extends Game
{
	// Aquí se declaran nuestras variables
	Point personaje = new Point(50,50);
	int direccion = 1;
	
	public void init()
	{
		// Comienza descarga asíncrona de recursos pesados
		setBackground(Color.black);
	}

	public void game()
	{
		// Aquí va el código de nuestro juego
		switch	(direccion)
		{
			case 0:
				personaje.y -= 10;
				break;
			case 1:
				personaje.x += 10;
				break;
			case 2:
				personaje.y += 10;
				break;
			case 3:
				personaje.x -= 10;
				break;
		}
	}
	
	public void paint(Graphics g)
	{
		// Aquí se dibujan todos los objetos
		g.clearRect(0, 0, this.getWidth(), this.getHeight());
		g.setColor(Color.green);
		g.drawOval(personaje.x, personaje.y, 10, 10);
	}
	
	public boolean keyDown(Event e, int key)
	{
		switch(key)
		{
			//	Cambia el rumbo de la serpiente
			case Event.UP:
				direccion = 0;
				break;
			case Event.RIGHT:
				direccion = 1;
				break;
			case Event.DOWN:
				direccion = 2;
				break;
			case Event.LEFT:
				direccion = 3;
				break;
		}
		return true;
	}
}

Hacer que el personaje regrese a la pantalla

Muy posiblemente habremos ya notado que cuando el personaje sale de la pantalla, se va, se va... y nunca regresa... (A menos claro, que lo movamos de regreso en la dirección opuesta, pero este no es el punto). En la gran mayoría de los juegos, esto no es conveniente, pues deseamos mantener al personaje dentro de nuestra pantalla. Para ello hay dos soluciones: impedirle el paso una vez que llegue a los límites externos, o regresar a nuestro personaje por el lado opuesto de nuestra pantalla. En nuestro caso, por el tipo de juego que estamos haciendo, haremos el segundo de los casos. Para esto, agregaremos el siguiente código en nuestro applet dentro de la función game, justo después del movimiento de nuestro personaje:

		//	Salida del escenario
		if (personaje.x < 0)
		{
			personaje.x = this.getWidth()-10;
		}
		if (personaje.x > this.getWidth()-10)
		{
			personaje.x = 0;
		}
		if (personaje.y < 0)
		{
			personaje.y = this.getHeight()-10;
		}
		if (personaje.y > this.getHeight()-10)
		{
			personaje.y = 0;
		}

Explico: En la primer línea, tenemos el caso de que, si la posición en x de nuestro personaje es menor que cero (se salió por la izquierda), entonces hará lo que está dentro de las llaves a continuación, que en este caso le decimos que su posición en x sea igual a la posición del ancho de nuestro applet, menos diez (Esto último por el tamaño del círculo que es nuestro personaje). Lo mismo repetimos para cada uno de los demás lados por donde podría salirse; no creo que necesite explicar renglón por renglón. Corramos con Shift+F6 nuestro código, y comprobaremos que efectivamente, al salir nuestro personaje de la pantalla, aparece del otro lado.

Otro detalle que me gustaría resaltar, es la facilidad de usar getWidth() y getHeight(), pues con ellos pedimos la altura y anchura de nuestro applet, y con esto además se hace adaptable a cualquier tamaño que sea este. Si hacemos en este momento más grande nuestro applet, veremos que nuestro personaje respetará los nuevos tamaños.

¡Pausa!

¡Alto un momento he dicho! Y lo digo literalmente, pues un juego tiene mucha mejor calidad cuando a este se le puede poner pausa. No es algo obligatorio, ¿Pero nunca te ha sucedido que necesitas hacer algo urgente y el juego en línea que juegas en ese momento no tiene la opción de pausa? Es por eso que debemos agregar esta opción, pensando en aquellos que jugarán nuestro juego. Se que por no ser algo tan esencial podría dejarlo para después, pero confien en mi, mientras más pronto lo hagamos será mejor. No se preocupen, no es nada dificil. Primero que nada, deberemos crear una variable de tipo booleano que indicará cuando nuestro juego esté en pausa:

	boolean PAUSE = true;

Ya que lo tenemos, necesitaremos agregar el código que nos permita poner y quitar la pausa dentro de la función que controla nuestro teclado:

			case Event.ENTER:
				PAUSE = !PAUSE;
				break;

El signo "!" es una negación de los booleanos. Lo que le estamos diciendo ahi, es que presionar enter, cambie el valor de PAUSE al opuesto, o sea, que cuando sea falso se vuelva verdadero, y cuando sea verdadero, se vuelva falso. Ahora, crearemos un indicador que nos avise cuando el juego está en pausa. Esto lo haremos escribiendo tal texto en nuestro paint, de la siguiente forma:

		g.setColor(Color.white);
		if (PAUSE)
		{
			g.drawString("PAUSA", this.getWidth()/2-20, this.getHeight()/2);
		}

De esta forma, le estamos diciendo que si pausa es verdadero (escribir "PAUSE == true" es redundante), entonces se escriba "PAUSA" en el centro de nuestra pantalla (se le resta 20 al ancho como una aproximación para que quede más centrado). Por último, la parte más importante, es envolver todo nuestro código del juego en un "if (!PAUSE)", para que únicamente se ejecute cuando el juego no esté en pausa. Por tanto, nuestro código final debe verse de esta forma:

import GameLib.Game;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Point;
import java.awt.Event;

public class snake extends Game
{
	// Aquí se declaran nuestras variables
	boolean PAUSE = true;
	Point personaje = new Point(50,50);
	int direccion = 1;
	
	public void init()
	{
		// Comienza descarga asíncrona de recursos pesados
		setBackground(Color.black);
	}

	public void game()
	{
		// Aquí va el código de nuestro juego
		if (!PAUSE)
		{
			//	Se mueve el personaje
			switch	(direccion)
			{
				case 0:
					personaje.y -= 10;
					break;
				case 1:
					personaje.x += 10;
					break;
				case 2:
					personaje.y += 10;
					break;
				case 3:
					personaje.x -= 10;
					break;
			}
			
			//	Salida del escenario
			if (personaje.x < 0)
			{
				personaje.x = this.getWidth()-10;
			}
			if (personaje.x > this.getWidth()-10)
			{
				personaje.x = 0;
			}
			if (personaje.y < 0)
			{
				personaje.y = this.getHeight()-10;
			}
			if (personaje.y > this.getHeight()-10)
			{
				personaje.y = 0;
			}
		}
	}
	
	public void paint(Graphics g)
	{
		// Aquí se dibujan todos los objetos
		g.clearRect(0, 0, this.getWidth(), this.getHeight());
		g.setColor(Color.green);
		g.drawOval(personaje.x, personaje.y, 10, 10);
		g.setColor(Color.white);
		if (PAUSE)
		{
			g.drawString("PAUSA", this.getWidth()/2-20, this.getHeight()/2);
		}
	}
	
	public boolean keyDown(Event e, int key)
	{
		switch(key)
		{
			//	Cambia el rumbo de la serpiente
			case Event.UP:
				direccion = 0;
				break;
			case Event.RIGHT:
				direccion = 1;
				break;
			case Event.DOWN:
				direccion = 2;
				break;
			case Event.LEFT:
				direccion = 3;
				break;
			case Event.ENTER:
				PAUSE = !PAUSE;
				break;
		}
		return true;
	}
}

No olvides dejar el repaint y el sleep fuera de PAUSE, para que se dibuje el juego de forma correcta. Ahora, corramos el código con Shift+F6. Si lo tenemos bien, podremos poner y quitar pausa al juego, y el personaje solo se moverá cuando el juego no esté en pausa. Notemos que como valor inicial, el juego comienza en pausa, esto es para dejar a jugador a que inicie el juego cuando esté preparado. Si todo ha salido bien, tu juego debe verse hasta el momento como sigue:

[Un proyecto de Ayotli Diseño Web]