GUI e Screen Custom
Introduzione alle GUI in Fabric
Le GUI (Graphical User Interfaces) in Minecraft permettono di creare schermate personalizzate per interagire con il giocatore. Fabric offre un sistema flessibile per creare sia screen semplici (menu, configurazioni) che screen complessi con inventari (chest custom, macchine, ecc.).
Tipi di GUI
1. Screen Semplici (senza inventario)
Perfetti per menu, configurazioni, dialoghi. Estendono Screen.
2. Handled Screen (con inventario)
Per GUI che interagiscono con inventari (chest, fornaci, macchine). Richiedono un ScreenHandler per gestire la logica server-side.
Creare uno Screen Semplice
```java public class CustomScreen extends Screen { private ButtonWidget myButton;
public CustomScreen() {
super(Text.literal("Custom Screen"));
}
@Override
protected void init() {
super.init();
// Aggiungi un bottone centrato
this.myButton = ButtonWidget.builder(
Text.literal("Click Me!"),
button -> {
// Azione quando cliccato
this.client.player.sendMessage(Text.literal("Button clicked!"), false);
this.close();
})
.dimensions(this.width / 2 - 100, this.height / 2 - 10, 200, 20)
.build();
this.addDrawableChild(myButton);
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
// Sfondo scuro
this.renderBackground(context);
// Titolo centrato
context.drawCenteredTextWithShadow(
this.textRenderer,
this.title,
this.width / 2,
20,
0xFFFFFF
);
// Renderizza i widget (bottoni, ecc.)
super.render(context, mouseX, mouseY, delta);
}
@Override
public boolean shouldPause() {
return false; // Non mette in pausa il gioco
}
} ```
Aprire lo Screen
```java // Client-side MinecraftClient.getInstance().setScreen(new CustomScreen()); ```
Creare una GUI con Inventario
Per GUI più complesse (chest custom, macchine), serve un ScreenHandler per gestire la sincronizzazione client-server.
1. Definire il ScreenHandler Type
```java
public class ModScreenHandlers {
public static final ScreenHandlerType
public static void register() {
// Chiamato nell'inizializzazione della mod
}
} ```
2. Creare il ScreenHandler
```java public class CustomScreenHandler extends ScreenHandler { private final Inventory inventory;
// Costruttore client-side
public CustomScreenHandler(int syncId, PlayerInventory playerInventory) {
this(syncId, playerInventory, new SimpleInventory(9));
}
// Costruttore server-side
public CustomScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory) {
super(ModScreenHandlers.CUSTOM_SCREEN_HANDLER, syncId);
this.inventory = inventory;
checkSize(inventory, 9);
inventory.onOpen(playerInventory.player);
// Aggiungi slot della GUI custom (3x3)
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
this.addSlot(new Slot(inventory, col + row * 3, 62 + col * 18, 17 + row * 18));
}
}
// Aggiungi slot dell'inventario del giocatore
addPlayerInventory(playerInventory);
addPlayerHotbar(playerInventory);
}
@Override
public boolean canUse(PlayerEntity player) {
return this.inventory.canPlayerUse(player);
}
@Override
public ItemStack quickMove(PlayerEntity player, int slot) {
// Logica shift-click
ItemStack stack = ItemStack.EMPTY;
Slot clickedSlot = this.slots.get(slot);
if (clickedSlot.hasStack()) {
ItemStack originalStack = clickedSlot.getStack();
stack = originalStack.copy();
if (slot < 9) {
// Dalla GUI all'inventario
if (!this.insertItem(originalStack, 9, this.slots.size(), true)) {
return ItemStack.EMPTY;
}
} else {
// Dall'inventario alla GUI
if (!this.insertItem(originalStack, 0, 9, false)) {
return ItemStack.EMPTY;
}
}
if (originalStack.isEmpty()) {
clickedSlot.setStack(ItemStack.EMPTY);
} else {
clickedSlot.markDirty();
}
}
return stack;
}
private void addPlayerInventory(PlayerInventory playerInventory) {
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 9; col++) {
this.addSlot(new Slot(playerInventory, col + row * 9 + 9, 8 + col * 18, 84 + row * 18));
}
}
}
private void addPlayerHotbar(PlayerInventory playerInventory) {
for (int col = 0; col < 9; col++) {
this.addSlot(new Slot(playerInventory, col, 8 + col * 18, 142));
}
}
} ```
3. Creare lo Screen
```java
public class CustomHandledScreen extends HandledScreen
public CustomHandledScreen(CustomScreenHandler handler, PlayerInventory inventory, Text title) {
super(handler, inventory, title);
this.backgroundHeight = 166;
this.playerInventoryTitleY = this.backgroundHeight - 94;
}
@Override
protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) {
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
int x = (width - backgroundWidth) / 2;
int y = (height - backgroundHeight) / 2;
context.drawTexture(TEXTURE, x, y, 0, 0, backgroundWidth, backgroundHeight);
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
renderBackground(context);
super.render(context, mouseX, mouseY, delta);
drawMouseoverTooltip(context, mouseX, mouseY);
}
} ```
4. Registrare lo Screen (Client-side)
```java @Environment(EnvType.CLIENT) public class ModClient implements ClientModInitializer { @Override public void onInitializeClient() { HandledScreens.register( ModScreenHandlers.CUSTOM_SCREEN_HANDLER, CustomHandledScreen::new ); } } ```
Texture della GUI
Crea una texture PNG (176x166 pixel per dimensioni standard) in:
src/main/resources/assets/mymod/textures/gui/custom_gui.png
Usa strumenti come Blockbench o template esistenti per creare la texture.
Best Practices
- Separa logica client/server: Il
ScreenHandlergestisce la logica, loScreensolo il rendering - Usa
DrawContext: Nelle versioni recenti di Minecraft, usaDrawContextinvece diMatrixStackdirettamente - Testa la sincronizzazione: Verifica che gli item si sincronizzino correttamente tra client e server
- Gestisci lo shift-click: Implementa
quickMove()per permettere lo shift-click negli slot
Conclusione
Le GUI in Fabric permettono di creare interfacce personalizzate per arricchire l’esperienza di gioco. Gli screen semplici sono perfetti per menu e configurazioni, mentre gli handled screen con inventari sono ideali per macchine e container custom.