Hoy vamos a continuar con la creación de nuestro motor 2D sencillo en Java: CutreMotor2D. Este proyecto nos ayudará a comprender conceptos clave de la programación orientada a objetos (POO) y los fundamentos del desarrollo de videojuegos.
¿Por Qué Java y Swing?
Java es un lenguaje versátil y ampliamente utilizado en la industria. Su enfoque en la POO facilita la creación de estructuras de código claras y reutilizables. Swing, por su parte, es una biblioteca gráfica que nos permite crear interfaces de usuario de manera sencilla. Aunque existen bibliotecas más avanzadas para desarrollo de juegos, como libGDX, utilizar Swing nos permite centrarnos en los fundamentos sin una curva de aprendizaje pronunciada.
Estructura del CutreMotor2D
Nuestro motor constará de las siguientes clases principales:
- Config: Gestiona la configuración del juego.
- CutreJuego: Controla la ventana principal y el bucle del juego.
- CutreLienzo: Área donde se dibujan los elementos del juego.
- CutreObjeto: Clase base para todos los objetos del juego.
A continuación, exploraremos cada una de estas clases con detalle.
Clase Config
Esta clase se encarga de cargar y almacenar la configuración del juego desde un archivo externo.
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import java.awt.Color;
public class Config {
// Atributos estáticos de configuración
public static int FPS;
public static int ANCHO_LIENZO;
public static int ALTO_LIENZO;
public static Color COLOR_FONDO;
// Método para cargar la configuración desde un archivo
public static void cargar(String rutaArchivo) {
Properties propiedades = new Properties();
try (FileInputStream entrada = new FileInputStream(rutaArchivo)) {
propiedades.load(entrada);
// Leer y asignar los valores del archivo
FPS = Integer.parseInt(propiedades.getProperty("FPS", "60"));
ANCHO_LIENZO = Integer.parseInt(propiedades.getProperty("ANCHO_LIENZO", "800"));
ALTO_LIENZO = Integer.parseInt(propiedades.getProperty("ALTO_LIENZO", "600"));
COLOR_FONDO = Color.decode(propiedades.getProperty("COLOR_FONDO", "#000000"));
} catch (IOException e) {
System.err.println("Error al cargar el archivo de configuración: " + e.getMessage());
// Valores por defecto en caso de error
FPS = 60;
ANCHO_LIENZO = 800;
ALTO_LIENZO = 600;
COLOR_FONDO = Color.BLACK;
}
}
}
Explicación:
- Atributos estáticos: Al ser estáticos, estos atributos pueden ser accedidos sin crear una instancia de la clase.
- Método
cargar
: Lee un archivo de propiedades y asigna los valores correspondientes. Si ocurre un error, se asignan valores por defecto.
Clase CutreJuego
Esta clase extiende JFrame
y representa la ventana principal del juego. Controla el bucle principal del juego.
import javax.swing.JFrame;
public class CutreJuego extends JFrame {
private CutreLienzo lienzo;
private boolean enEjecucion = false;
public CutreJuego() {
// Cargar la configuración al iniciar el juego
Config.cargar("config.properties");
setTitle("CutreMotor2D");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
lienzo = new CutreLienzo();
add(lienzo);
pack(); // Ajusta la ventana al tamaño del lienzo
setVisible(true);
}
public void iniciar() {
enEjecucion = true;
while (enEjecucion) {
lienzo.actualizar();
lienzo.repaint();
try {
Thread.sleep(1000 / Config.FPS); // Control de FPS
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void detener() {
enEjecucion = false;
}
}
Explicación:
- Constructor: Configura la ventana del juego según los parámetros de la clase
Config
y añade el lienzo donde se dibujarán los objetos. - Método
iniciar
: Contiene el bucle principal del juego, que actualiza y repinta el lienzo a una tasa de cuadros por segundo definida. - Método
detener
: Detiene la ejecución del bucle del juego.
Clase CutreLienzo
Esta clase extiende JPanel
y actúa como el área de dibujo del juego. Gestiona y dibuja los objetos del juego.
import javax.swing.JPanel;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
public class CutreLienzo extends JPanel {
private List<CutreObjeto> objetos = new ArrayList<>();
public CutreLienzo() {
setBackground(Config.COLOR_FONDO);
setPreferredSize(new Dimension(Config.ANCHO_LIENZO, Config.ALTO_LIENZO)); // Fija el tamaño del lienzo
}
public void actualizar() {
for (CutreObjeto obj : objetos) {
obj.actualizar();
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (CutreObjeto obj : objetos) {
obj.dibujar(g);
}
}
public void agregarObjeto(CutreObjeto obj) {
objetos.add(obj);
}
}
Explicación:
- Lista de objetos: Mantiene una lista de todos los objetos que se dibujarán en el lienzo.
- Método
actualizar
: Llama al métodoactualizar
de cada objeto para actualizar su estado. - Método
paintComponent
: Sobrescribe el método deJPanel
para dibujar cada objeto en el lienzo. - Método
agregarObjeto
: Permite añadir nuevos objetos
Clase CutreObjeto
Esta clase te permitirá crear objetos dentro del juego. Es la clase base para todos los objetos que se dibujarán (jugadores, enemigos, etc.).
import java.awt.*; // Importa la libreria AWT para dibujar
public abstract class CutreObjeto { // Clase abstracta (no se puede instanciar directamente)
protected int x, y, ancho, alto; // Atributos protegidos (accesibles desde las clases hijas)
public CutreObjeto(int x, int y, int ancho, int alto) { // Constructor
this.x = x;
this.y = y;
this.ancho = ancho;
this.alto = alto;
}
// Métodos abstractos (deben ser implementados por las clases hijas)
public abstract void actualizar(); // Actualiza la lógica del objeto
public abstract void dibujar(Graphics g); // Dibuja el objeto en el lienzo
}
Explicación:
CutrEs una clase abstracta:
- CutreObjeto es una clase abstracta, lo que significa que no se pueden crear objetos de esta clase, solo sirve para ser heredada.
- Define características y métodos comunes.
- Las clases hijas que heredan de esta clase y deberán implementar los métodos actualizar y dibujar de forma diferente cada una (polimorfismo).
Próximos Pasos
- Crear Objetos: Implementar clases que hereden de CutreObjeto (ej: CutreRectangulo, CutreCirculo, CutrePersonaje).
- Añadir Lógica: Implementar la lógica de juego dentro de los métodos actualizar() de los objetos.
- Experimentar: Modificar los atributos y métodos de las clases para ver cómo afectan al juego.
Deja una respuesta