00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

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 CUSTOM_SCREEN_HANDLER = ScreenHandlerRegistry.registerSimple( new Identifier(“mymod”, “custom”), CustomScreenHandler::new );

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 { private static final Identifier TEXTURE = new Identifier(“mymod”, “textures/gui/custom_gui.png”);

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 ScreenHandler gestisce la logica, lo Screen solo il rendering
  • Usa DrawContext: Nelle versioni recenti di Minecraft, usa DrawContext invece di MatrixStack direttamente
  • 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.