UI para nuestro RPG: Parte 3
Continuando con la UI para nuestro RPG
En esta tercera parte de la serie sobre la UI para nuestro RPG, continuamos desarrollando la interfaz gráfica utilizando Java Swing. En las partes anteriores, hemos creado una ventana básica y añadido algunos componentes iniciales. Ahora, vamos a añadir más componentes y funcionalidades para mejorar la experiencia del usuario.
El campo de texto para el nombre del personaje
Una de las funcionalidades que queremos añadir es un campo de texto donde el jugador pueda ingresar el nombre de su personaje. Para esto, utilizaremos la clase JTextField de Swing. Aquí te muestro cómo hacerlo:
package app.game.rpg.ui.components.inputs;
import app.game.rpg.ui.components.borders.RPGRoundedBorder;
import app.game.rpg.utils.FontCache;
import javax.swing.*;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.io.IOException;
import java.util.Objects;
public class RPGInputText extends JTextField {
public RPGInputText() {
super();
Font font;
try {
font = Font.createFont(Font.TRUETYPE_FONT, Objects.requireNonNull(getClass().getResourceAsStream("/fonts/BoldPixels.ttf"))).deriveFont(Font.PLAIN, 22f);
} catch (FontFormatException | IOException e) {
throw new RuntimeException(e);
}
setFont(font);
setBorder(new CompoundBorder(new RPGRoundedBorder(3, 10),
new EmptyBorder(5, 5, 5, 5)));
setOpaque(false);
}
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(getBackground());
g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 10, 10);
super.paint(g);
g2d.dispose();
}
}
Como puedes ver, hemos creado una clase RPGInputText que extiende de JTextField. En el constructor, configuramos la fuente personalizada y el borde redondeado utilizando una clase RPGRoundedBorder que hemos creado previamente. Además, sobrescribimos el método paint para dibujar un fondo redondeado detrás del campo de texto.
Algo importante en este caso es que estamos utilizando una fuente personalizada, por lo que es necesario cargarla desde un archivo de recursos. Para esto, utilizamos el método getResourceAsStream para obtener un InputStream de la fuente y luego la cargamos utilizando Font.createFont. Si ocurre algún error al cargar la fuente, lanzamos una excepción.
Barra de progreso para la salud del personaje
Otra funcionalidad que queremos añadir es una barra de progreso para mostrar la salud del personaje. Para esto, utilizaremos la clase JProgressBar de Swing. Aquí te muestro cómo hacerlo:
package app.game.rpg.ui.components.bars;
import app.game.rpg.ui.components.borders.RPGRoundedBorder;
import app.game.rpg.ui.components.delegates.RPGProgressBarUI;
import javax.swing.*;
import java.awt.*;
public abstract class RPGProgressBar extends JProgressBar {
protected Color startColor;
protected Color endColor;
protected int radius=5;
public RPGProgressBar(int min, int max) {
super(min, max);
setOpaque(false);
setBorder(new RPGRoundedBorder(3, radius));
setStringPainted(true);
setFont(new Font("Arial", Font.BOLD, 18));
setForeground(Color.white);
// 🔥 Asignamos UI personalizada
setUI(new RPGProgressBarUI());
}
public void setBarColor(Color start, Color end) {
this.startColor = start;
this.endColor = end;
repaint();
}
public Color getStartColor() {
return startColor;
}
public Color getEndColor() {
return endColor;
}
public int getRadius() {
return radius;
}
}
En esta clase RPGProgressBar, extendemos de JProgressBar y añadimos propiedades para los colores de inicio y fin de la barra, así como un radio para las esquinas redondeadas. En el constructor, configuramos la apariencia de la barra, incluyendo un borde redondeado y una fuente personalizada para el texto que muestra el porcentaje. Además, asignamos una UI personalizada utilizando la clase RPGProgressBarUI, que se encargará de dibujar la barra con un degradado de colores que veremos a continuación.
package app.game.rpg.ui.components.delegates;
import app.game.rpg.ui.components.bars.RPGProgressBar;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicProgressBarUI;
import java.awt.*;
public class RPGProgressBarUI extends BasicProgressBarUI {
@Override
protected void paintDeterminate(Graphics g, JComponent c) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
RPGProgressBar bar = (RPGProgressBar) c;
int width = bar.getWidth();
int height = bar.getHeight();
int value = bar.getValue();
int max = bar.getMaximum();
int progressWidth = (int) (width * (value / (double) max));
int radius = bar.getRadius();
// 🔲 Fondo
g2.setColor(new Color(30, 30, 30));
g2.fillRoundRect(0, 0, width, height, radius, radius);
// ❤️ Progreso con degradado
Point startPoint = new Point(0, 0);
Point endPoint = new Point(width, 0);
float[] fractions = {0f, 0.45f, 1f};
Color[] colors = {bar.getStartColor(), bar.getEndColor(), bar.getStartColor()};
LinearGradientPaint gradient = new LinearGradientPaint(startPoint, endPoint, fractions, colors);
g2.setPaint(gradient);
g2.fillRoundRect(0, 0, progressWidth, height, radius, radius);
// 🟡 Borde reutilizable
Border border = bar.getBorder();
if (border != null) {
border.paintBorder(bar, g2, 0, 0, width, height);
}
// 🔤 Texto centrado
String text = "%s/%s".formatted(value, max);
FontMetrics fm = g2.getFontMetrics();
int textWidth = fm.stringWidth(text);
int textHeight = fm.getAscent();
int textX = (width - textWidth) / 2;
int textY = (height + textHeight) / 2 - 2;
g2.setFont(bar.getFont());
g2.setColor(bar.getForeground());
g2.drawString(text, textX, textY);
g2.dispose();
}
}
En la clase RPGProgressBarUI, extendemos de BasicProgressBarUI y sobrescribimos el método paintDeterminate para personalizar la forma en que se dibuja la barra de progreso. Utilizamos un degradado de colores para el progreso y dibujamos un fondo oscuro para el resto de la barra. Además, centramos el texto que muestra el valor actual y el máximo.
RadialGradientPaint o ConicalGradientPaint para obtener efectos más interesantes y adapta la clase RPGProgressBar según tus necesidades para dicho degradado.Creando las barras de salud y maná
Ahora que tenemos nuestra clase RPGProgressBar, podemos crear instancias específicas para la salud y el maná de nuestro personaje. Aquí te muestro cómo hacerlo:
package app.game.rpg.ui.components.bars;
import java.awt.*;
public class RPGLifeBar extends RPGProgressBar{
public RPGLifeBar() {
super(75, 125);
this.startColor = new Color(255, 0, 0);
this.endColor = new Color(145, 1, 1);
}
}
package app.game.rpg.ui.components.bars;
import java.awt.*;
public class RPGManaBar extends RPGProgressBar {
public RPGManaBar() {
super(25, 100);
setBarColor(new Color(0, 0, 255), new Color(1, 1, 145));
}
}
En estas clases RPGLifeBar y RPGManaBar, extendemos de RPGProgressBar y configuramos los colores específicos para cada barra. La barra de vida utiliza tonos rojos, mientras que la barra de maná utiliza tonos azules. Puedes ajustar los valores máximos y mínimos según las necesidades de tu juego y crear las barras que necesites para otros recursos como la experiencia, la energía, etc.
Integrando los componentes en el panel de personaje
Finalmente, podemos integrar estos componentes en el panel de personaje para mostrar la información relevante del personaje. Aquí te muestro un ejemplo de cómo hacerlo:
package app.game.rpg.ui.panels;
import app.game.rpg.ui.components.bars.RPGLifeBar;
import app.game.rpg.ui.components.bars.RPGManaBar;
import app.game.rpg.ui.components.textfields.RPGInputText;
import javax.swing.*;
import java.awt.*;
public class RPGCharacterPanel extends JPanel {
private RPGLifeBar lifeBar;
private RPGManaBar manaBar;
private RPGInputText nameField;
public RPGCharacterPanel() {
setLayout(new BorderLayout());
setBackground(new Color(20, 20, 20));
// 🧑🦲 Campo de texto para el nombre del personaje
nameField = new RPGInputText();
nameField.setPreferredSize(new Dimension(200, 40));
add(nameField, BorderLayout.NORTH);
// ❤️ Barra de vida
lifeBar = new RPGLifeBar();
lifeBar.setPreferredSize(new Dimension(300, 30));
add(lifeBar, BorderLayout.CENTER);
// 🔵 Barra de maná
manaBar = new RPGManaBar();
manaBar.setPreferredSize(new Dimension(300, 30));
add(manaBar, BorderLayout.SOUTH);
}
public void updateCharacterStats(int health, int mana) {
lifeBar.setValue(health);
manaBar.setValue(mana);
}
}
Este es un ejemplo de cómo integrar las barras de vida y maná en un panel de personaje. En este panel, también hemos añadido un campo de texto para el nombre del personaje. Puedes personalizar el diseño y la disposición de los componentes según tus necesidades, utilizando diferentes layouts o añadiendo más elementos como iconos, habilidades, etc. La función updateCharacterStats te permite actualizar los valores de salud y maná en tiempo real, lo que es útil para reflejar los cambios durante el juego.
Recuerda que al final, tu interfaz de usuario debe ser intuitiva y fácil de entender para los jugadores, así que no dudes en experimentar con diferentes diseños y estilos para encontrar el que mejor se adapte a tu juego.
Conclusión
En esta sección, hemos creado un sistema de barras de progreso personalizadas para representar la salud y el maná de un personaje en un juego RPG. Hemos utilizado Java Swing para diseñar estas barras con un estilo único, utilizando degradados de colores y bordes redondeados para mejorar su apariencia. Además, hemos integrado estas barras en un panel de personaje que también incluye un campo de texto para el nombre del personaje. Este enfoque modular te permite reutilizar los componentes y personalizarlos según las necesidades de tu juego, lo que facilita la creación de una interfaz de usuario atractiva y funcional para tus jugadores.
Archivo tipo Objeto
En este capítulo se explica cómo manejar archivos de tipo objeto en Java, utilizando las clases ObjectInputStream y ObjectOutputStream para leer y escribir objetos completos en archivos.
UI para nuestro RPG: Parte 4
En esta cuarta parte de la serie sobre la creación de una interfaz de usuario para nuestro RPG, se profundiza en la implementación de características avanzadas y mejoras en la experiencia del usuario.