+0

Crear un Menú (GUI) en Minecraft con Spigot



Vamos a ver que son las GUIs en Minecraft, y como crearlas en Spigot.

¿Qué es una GUI?

Una interfaz de usuario gráfica, o GUI, es una interfaz que se muestra en pantalla en la cual hay diferentes botones que permiten realizar acciones.

Supongamos que queremos hacer una forma sencilla y accesible de teletransportarse, la solución sería usar una GUI.

Ejemplo de GUI de Minecraft de Hypixel

Ejemplo de GUI de Minecraft de Hypixel

¿Cómo crear una GUI en Spigot?

Crear una GUI en Spigot es muy sencillo. No tiene más misterio que gestionar una instancia de Inventory.

Para crear un inventario, hemos de tener claro que nombre queremos ponerle y el tamaño que queremos que tenga. Una vez tengamos claro eso, llamaremos al método estático createInventory de la clase Bukkit y le pasaremos tres argumentos. El primero, nulo. El segundo, el tamaño del inventario. Y el tercero, el componente del nombre que le queramos poner al inventario.

¡Ojo! El tamaño del inventario ha de ser múltiple de 9, que significa que si queremos dos filas hemos de poner el tamaño 9 por 2, en este caso sería 18. Aquí dejo una imagen de referencia

Imagen con la posición de los slots de un cofre doble en Minecraft

Imagen con la posición de los slots de un cofre doble en Minecraft

Inventory inventory = Bukkit.createInventory(null, 9*6, Component.text("Título del inventario"));

Ya tenemos el inventario creado, ahora solo hace falta añadir los objetos, o en este caso, los ItemStacks. Como hemos visto anteriormente, un objeto inventario tiene diferentes métodos para manipular los ItemStacks dentro. En mi caso, voy a añadir unos cuantos de ejemplo.

Inventory inventory = Bukkit.createInventory(null, 9*6, Component.text("Título del inventario"));  
  
// Item de hierro  
ItemStack hierro = new ItemStack(Material.IRON_INGOT);  
ItemMeta ironMeta = hierro.getItemMeta();  
  
ironMeta.displayName(Component.text("Hierro").color(NamedTextColor.GRAY));  
ironMeta.lore(  
        List.of(  
                Component.text("Esto en un lingote").color(NamedTextColor.RED),  
                Component.text("de hierro").color(NamedTextColor.RED)  
        )  
);  
hierro.setItemMeta(ironMeta);  
  
// Item de oro  
ItemStack oro = new ItemStack(Material.GOLD_INGOT);  
ItemMeta goldMeta = oro.getItemMeta();  
  
goldMeta.displayName(Component.text("Oro").color(NamedTextColor.GOLD));  
goldMeta.lore(  
        List.of(  
                Component.text("Esto en un lingote").color(NamedTextColor.RED),  
                Component.text("de oro").color(NamedTextColor.RED)  
        )  
);  
oro.setItemMeta(goldMeta);  
  
// Item de diamante  
ItemStack diamante = new ItemStack(Material.DIAMOND);  
ItemMeta diamondMeta = diamante.getItemMeta();  
  
diamondMeta.displayName(Component.text("Diamante").color(NamedTextColor.BLUE));  
diamondMeta.lore(  
        List.of(  
                Component.text("Esto en un diamante").color(NamedTextColor.RED)  
        )  
);  
diamante.setItemMeta(goldMeta);  
  
// Añadimos los items en el inventario  
inventory.setItem(11, hierro);  
inventory.setItem(13, oro);  
inventory.setItem(15, diamante);

Como último, queda mostrar el inventario al jugador con el método openInventory de Player.

player.openInventory(inventory);

Si ahora corremos el código dentro del juego, veremos como aparece un inventario abierto con los ítems que hemos creado. Ahora veremos como hacer un inventario interactuable.

¿Cómo interactuar con una GUI o Inventario en Spigot?

Hay muchas formas de registrar acciones hechas en un inventario, pero yo os voy a enseñar la que es más simple y fácil de entender.

Para registrar las acciones dentro de tu inventario, vamos a separarlo en dos partes:

  • Detectar que el jugador tiene el nuestro inventario abierto (no otro).
  • Detectar qué acción ha hecho en el inventario.

Para continuar necesitaremos crear un Listener y registrarlo. En este Listener voy a añadir una lista de UUIDs para registrar que jugadores han abierto el inventario. Así cuando abra el inventario algún jugador lo guardaré ahí y cuando el jugador lo cierre lo sacaré de ahí.

Para detectar cuando un jugador cierra un inventario podemos escuchar el evento InventaryCloseEvent y el evento de cuando un jugador se va del servidor (PlayerQuitEvent). Cuando un jugador se va del servidor también hemos de registrarlo como inventario cerrado.

public class GUIListener implements Listener {  
  
    public static final List<UUID> openedInventory = new ArrayList<>();  
  
    @EventHandler  
    public void onInventoryClick(InventoryCloseEvent event) {  
        openedInventory.remove(event.getPlayer().getUniqueId());  
    }  
  
    @EventHandler  
    public void onPlayerQuit(PlayerQuitEvent event) {  
        openedInventory.remove(event.getPlayer().getUniqueId());  
    }  
  
}

Ahora solo queda registrar los clicks. Para registrar los clics dentro del inventario, usaremos el evento InventoryClickEvent. Este evento también nos ayudará a cancelar cualquier acción que haga el jugador dentro del inventario, como por ejemplo, mover ítems.

Aprovechando que nuestra interfaz tiene 3 ítems, (un diamante, un lingote de hierro y un lingote de oro), haré que al hacer click te rellene el inventario de ese material.

Primero de todo, comprobaremos que el jugador esté en la lista de jugadores con nuestro menú abierto. Si el jugador no está en la lista, no vamos a correr más código del evento. Si el evento sigue, significa que el jugador sí que tiene el inventario abierto, con lo cual vamos a cancelar la acción y vamos a conseguir el ítem que ha clicado.

Luego haremos una comprobación de que el ítem que ha clicado es válido, que no sea nulo

Para terminar haremos un switch para realizar una acción determinada dependiendo de que item ha clicado el jugador. Si ningún item coincide con una acción, reproducirá un sonido.

@EventHandler  
public void onInventoryClick(InventoryClickEvent event) {  
    if (!openedInventory.contains(event.getWhoClicked().getUniqueId())) {  
        return;  
    }  
      
    event.setCancelled(true);  
  
    ItemStack clickedItem = event.getCurrentItem();  
      
    if (clickedItem == null) {  
        return;  
    }  
      
    Player player = (Player) event.getWhoClicked();   
      
    switch (clickedItem.getType()) {  
        case IRON_INGOT -> {  
            player.getInventory().addItem(new ItemStack(Material.IRON_INGOT));  
            player.closeInventory();  
        }  
        case GOLD_INGOT -> {  
            player.getInventory().addItem(new ItemStack(Material.GOLD_INGOT));  
            player.closeInventory();  
        }  
        case DIAMOND -> {  
            player.getInventory().addItem(new ItemStack(Material.DIAMOND));  
            player.closeInventory();  
        }  
        default -> player.playSound(player, Sound.ENTITY_VILLAGER_NO, 10f, 1f);  
    }  
}