jueves, 23 de abril de 2009

Estados de Juego

Muy bien, vamos a empezar con otro concepto, al cual llamo estados de juego.
Todos los juegos tienen diferentes estados, por ejemplo cuando empezamos, es muy seguro que se nos presente el menu de inicio o una animacion, luego pasamos a lo que es el juego, y finalmente los creditos. Tambien hay muchos mas estados, un ejemplo es cuando pausamos el juego o especificamos las opciones.
Hasta ahora veniamos muy directo, solo mostrando los conceptos y como ponerlos en practica, pero si queremos hacer un juego mas serio, vamos a querer que aunquesea tenga un menu, donde podemos elejir opciones, comenzar el juego, creditos, etc, para eso usaremos los estados de juego.
Comenzemos con el esqueleto basico. Las clases Main.java y Board.java ya estan explicadas anteriormente, usaremos la version de Board.java que usa el timer de swing que veniamos usando. Veamos ahora como agregar estados. Primero que nada, agregemos una interface, lo que esta tendra seran variables globales a todas nuestras clases.

package gamestates;

/**
*
* @author fede
*/
public interface Commons {
enum GameState {MenuScreen, Pause, Playing, GameOver};
}


Como veran solo definimos un nuevo tipo llamado GameState con los estados que deseamos, estos pueden ir modificandose mas adelante.

public class Board extends JPanel implements ActionListener, Commons {


Luego modificamos la clase para implementar la interface.
El constructor ahora se vera algo asi

public static GameState currentState;
public Board(){
setDoubleBuffered(true);
setFocusable(true);
addKeyListener(new Listener());
setBackground(Color.white);

timer = new Timer(5, this);
timer.start();
currentState = GameState.MenuScreen;
}


La pantalla inicial sera MenuScreen, es decir, la pantalla del menu.
Fijense que la variable currentState es estatica, esto es importante, para poder modificar el estado desde otras clases.
Estas clases seran una representando cada estado, en este caso haremos una para MenuScreen, otra Playing y otra GameOver.

MenuScreen.java
package gamestates;

import java.awt.Graphics2D;
import java.awt.event.KeyEvent;

/**
*
* @author fedekun
*/
public class MenuScreen implements Commons {
public void draw(Graphics2D g2d){
g2d.drawString("Este es el menu, presiona [ENTER] para jugar", 3, 10);
}

public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER)
Board.currentState = GameState.Playing;
}
}


Hay 3 partes en donde llamaremos a funciones de esta clase, una es la parte de dibujar, otra la de actualizar y otra la de input. En este caso no necesitamos actualizar, asi que solo dibujamos, y hacemos input.

Playing.java
package gamestates;

import java.awt.Graphics2D;
import java.awt.event.KeyEvent;

/**
*
* @author fedekun
*/
public class Playing implements Commons {
private int x, y, dx, dy, speed;

public Playing(){
x = 3;
y = 10;
dx = dy = 1;
speed = 1;
}

public void draw(Graphics2D g2d){
g2d.drawString("Presiona [Escape] para salir", 3, 10);
g2d.drawString("Estamos jugando!", x, y);
}

public void update(){
if(x > 200 || x < 0)
dx*=-1;
if(y > 280 || y < 0)
dy*=-1;
x+=speed*dx;
y+=speed*dy;
}

public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ESCAPE)
Board.currentState = GameState.GameOver;
}
}


Aca tenemos las 3 implementaciones, draw, udpdate e input.
Y finalmente...

GameOver.java
package gamestates;

import java.awt.Graphics2D;

/**
*
* @author fedekun
*/
public class GameOver {

public void draw(Graphics2D g2d){
g2d.drawString("GAME OVER", 100, 100);
}

}


Esos son los fundamentos, ahora unimos todo en Board.java

package gamestates;

import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;

// timer
import javax.swing.Timer;
import java.awt.Toolkit;

// teclas y timer
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

// teclas
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

/**
*
* @author fede
*/
public class Board extends JPanel implements ActionListener, Commons {
private Timer timer;
public static GameState currentState;
private MenuScreen menuScreen;
private Playing playing;
private GameOver gameOver;
public Board(){
setDoubleBuffered(true);
setFocusable(true);
addKeyListener(new Listener());
setBackground(Color.white);

timer = new Timer(5, this);
timer.start();
currentState = GameState.MenuScreen;
menuScreen = new MenuScreen();
playing = new Playing();
gameOver = new GameOver();
}

public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D)g;

// Dibuja aca
if(currentState == GameState.MenuScreen)
menuScreen.draw(g2d);
if(currentState == GameState.Playing)
playing.draw(g2d);
if(currentState == GameState.GameOver)
gameOver.draw(g2d);

Toolkit.getDefaultToolkit().sync();
g.dispose();
}

public void actionPerformed(ActionEvent e){
// Logica aca
if(currentState == GameState.Playing)
playing.update();

repaint();
}

private class Listener extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e){
// Metodo de los objetos que reciben input
if(currentState == GameState.MenuScreen)
menuScreen.keyPressed(e);
if(currentState == GameState.Playing)
playing.keyPressed(e);
}

@Override
public void keyReleased(KeyEvent e){
// Metodo de los objetos que reciben input
}
}
}


Como veran, en la parte de draw, update e input, hacemos un if para ver en que estado estamos, y segun el estado hacemos lo que debemos hacer.
En un proyecto mas grande esto es muy util, es lo basico de programacion modular, dividir el problema en subproblemas, con orientacion a objetos, es mas facil aun :)
Espero hallan podido entender la idea, cualquier cosa, contactenme.

Codigo fuente: de 4shared

2 comentarios:

  1. hola. muchas gracias por tus aportes. es un blog excelente este. Lo malo es que los enlaces de codigo no funkan. Podrias subirlos denuevo por favor, seria beunoi ppoder ver el codigio completo, me ayudaria mucho. Muchas gracias y sigue colaborando de esa manera.

    ResponderEliminar
  2. muchas gracias x todo, de verdad me has ayudado como no tienes idea
    ojala subas codigos de juegos mas profundos y completos y obvio q nos lo expliques xD gracias x todo.

    ResponderEliminar