Mono muy mono con una ventana de un juego 2d al lado

CutreMotor2d implementado: ¿se puede hacer más con menos?

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étodo actualizar de cada objeto para actualizar su estado.
  • Método paintComponent: Sobrescribe el método de JPanel 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

  1. Crear Objetos: Implementar clases que hereden de CutreObjeto (ej: CutreRectangulo, CutreCirculo, CutrePersonaje).
  2. Añadir Lógica: Implementar la lógica de juego dentro de los métodos actualizar() de los objetos.
  3. Experimentar: Modificar los atributos y métodos de las clases para ver cómo afectan al juego.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.