✅ Qué se implementa


📁 Archivos modificados

Archivo Acción Propósito
UI.java Nuevo Controla todo el HUD (superpuesto al juego)
PanelJuego.java Modificación Instancia UI y llama a ui.draw() en el ciclo de renderizado
Jugador.java Modificación Notifica a la UI cuando ocurren eventos (recoger llave, abrir cofre, etc.)
Sound.java Ya corregido ✅ Usa dos instancias (musica, efectoSonido) para evitar conflictos entre loops y efectos puntuales

💡 ¿Por qué dos instancias de Sound?

Es análogo a tener dos reproductores: uno dedicado exclusivamente a música de fondo (loop), otro para efectos cortos. Así evitas que un stop() o setFramePosition(0) en un efecto interrumpa la música.


🛠️ Implementación paso a paso

1️⃣ Crear UI.java

Crea el archivo `src/main/UI.java`:

```java
package main;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.text.DecimalFormat;

import objetos.OBJ_llave;

/**
 * Clase que maneja la Interfaz de Usuario (HUD).
 * Dibuja información sobre el juego: llaves, tiempo, mensajes.
 */
public class UI {

    PanelJuego pj;
    
    // ⚠️ IMPORTANTE: Las fuentes se declaran AQUÍ, no dentro de draw()
    // Esto es por rendimiento - draw() se ejecuta 60 veces por segundo
    Font arial_40;
    Font arial_80B;  // B = Bold
    
    // Imagen de la llave para el HUD
    BufferedImage imagenLlave;
    
    // Sistema de mensajes temporales
    public boolean mensajeActivo = false;
    public String mensaje = "";
    int contadorMensaje = 0;
    
    // Estado del juego
    public boolean juegoTerminado = false;
    
    // Tiempo de juego
    double tiempoJuego;
    DecimalFormat formatoDecimal = new DecimalFormat("#0.00");
    
    /**
     * Constructor: Inicializa fuentes y carga recursos.
     */
    public UI(PanelJuego pj) {
        this.pj = pj;
        
        // Crear fuentes UNA sola vez (optimización)
        arial_40 = new Font("Arial", Font.PLAIN, 40);
        arial_80B = new Font("Arial", Font.BOLD, 80);
        
        // Cargar imagen de llave para mostrar en el HUD
        OBJ_llave llave = new OBJ_llave();
        imagenLlave = llave.imagen;
    }
    
    /**
     * Muestra un mensaje temporal en pantalla.
     * El mensaje desaparece después de ~2 segundos.
     */
    public void mostrarMensaje(String texto) {
        mensaje = texto;
        mensajeActivo = true;
    }
    
    /**
     * Método principal de dibujado del HUD.
     * Se llama desde paintComponent() de PanelJuego.
     */
    public void draw(Graphics2D g2) {
        
        if (juegoTerminado == true) {
            // Pantalla de victoria
            dibujarPantallaFin(g2);
        } else {
            // HUD normal durante el juego
            dibujarHUD(g2);
        }
    }
    
    /**
     * Dibuja el HUD normal: llaves, tiempo, mensajes.
     */
    private void dibujarHUD(Graphics2D g2) {
        
        g2.setFont(arial_40);
        g2.setColor(Color.WHITE);
        
        // === CONTADOR DE LLAVES ===
        // Dibujar icono de llave
        g2.drawImage(imagenLlave, pj.tamanioTile / 2, pj.tamanioTile / 2, 
                     pj.tamanioTile, pj.tamanioTile, null);
        
        // Dibujar número de llaves (x2, x3, etc.)
        g2.drawString("x " + pj.jugador.numeroLlaves, 74, 65);
        
        // === TIEMPO DE JUEGO ===
        tiempoJuego += (double) 1 / 60; // Incrementar cada frame
        g2.drawString("Tiempo: " + formatoDecimal.format(tiempoJuego), 
                      pj.tamanioTile * 11, 65);
        
        // === MENSAJES TEMPORALES ===
        if (mensajeActivo == true) {
            g2.setFont(g2.getFont().deriveFont(30F));
            g2.drawString(mensaje, pj.tamanioTile / 2, pj.tamanioTile * 5);
            
            contadorMensaje++;
            
            // Después de 120 frames (~2 segundos), ocultar mensaje
            if (contadorMensaje > 120) {
                contadorMensaje = 0;
                mensajeActivo = false;
            }
        }
    }
    
    /**
     * Dibuja la pantalla de fin del juego.
     */
    private void dibujarPantallaFin(Graphics2D g2) {
        
        g2.setFont(arial_40);
        g2.setColor(Color.WHITE);
        
        String texto;
        int x, y;
        int longitudTexto;
        
        // === MENSAJE DE FELICITACIONES ===
        texto = "¡Encontraste el tesoro!";
        g2.setFont(arial_80B);
        
        // Centrar texto horizontalmente
        longitudTexto = (int) g2.getFontMetrics().getStringBounds(texto, g2).getWidth();
        x = (pj.anchoPantalla / 2) - (longitudTexto / 2);
        y = pj.altoPantalla / 2 - (pj.tamanioTile * 2);
        
        // Sombra del texto (efecto visual)
        g2.setColor(Color.BLACK);
        g2.drawString(texto, x + 5, y + 5);
        
        // Texto principal
        g2.setColor(Color.YELLOW);
        g2.drawString(texto, x, y);
        
        // === TIEMPO FINAL ===
        g2.setFont(arial_40);
        g2.setColor(Color.WHITE);
        texto = "Tu tiempo fue: " + formatoDecimal.format(tiempoJuego) + " segundos";
        longitudTexto = (int) g2.getFontMetrics().getStringBounds(texto, g2).getWidth();
        x = (pj.anchoPantalla / 2) - (longitudTexto / 2);
        y = pj.altoPantalla / 2 + (pj.tamanioTile * 2);
        g2.drawString(texto, x, y);
        
        // === DETENER EL JUEGO ===
        pj.threadJuego = null;
    }
    
    /**
     * Método utilitario para obtener la posición X centrada de un texto.
     */
    public int obtenerXCentrado(String texto, Graphics2D g2) {
        int longitudTexto = (int) g2.getFontMetrics().getStringBounds(texto, g2).getWidth();
        return (pj.anchoPantalla / 2) - (longitudTexto / 2);
    }
}

### 🔍 Lógica clave:

- **Fuentes se inicializan una sola vez** en el constructor → evita creación repetida (60×/segundo), lo cual afecta rendimiento.
- **Mensajes temporales** usan un contador de frames (`contadorMensaje++`).
Como el juego corre a **60 FPS**, `120 frames = 2 segundos` → tiempo de visualización estándar.
- **Estado `juegoTerminado`** controla si se muestra el HUD normal o la pantalla de victoria.
- **`DecimalFormat("#0.00")`** garantiza `45.33` en lugar de `45.3333333`.

---

### 2️⃣ Modificar `PanelJuego.java`