Skip to content

Custom Panes (Dutch)

stefvanschie edited this page Sep 4, 2021 · 6 revisions

Talen: Engels (English)

Je kan ook je eigen panelen maken als je denkt dat de bestaande panelen niet goed werken voor de inventaris die jij wilt maken. Je eigen panelen maken kan lastig zijn, dus hier wordt dit stap voor stap uitgelegd. Je kan ook kijken hoe de ingebouwde panelen in dit framework werken.

Als voorbeeld ga ik laten zien hoe je een RandomPane maakt. Je kan aan dit paneel items toevoegen en dan worden ze op een willekeurige plek getoond. We maken eerst een class genaamd RandomPane en zorgen dat deze Pane, de standaard klasse voor elk paneel, extends.

class RandomPane extends Pane {}

Nu moet je een aantal functies en een constructor toevoegen. Laat je IDE de functies en de constructor met de prioriteit genereren. Voor nu kan je alles zo laten als het is.

We zullen ergens de items moeten bewaren wanneer je ze aan het paneel toevoegd, dus hier gaan we een array voor maken.

final GuiItem[] items;

Nu moeten we het paneel initialiseren wanneer we een nieuw RandomPane maken, dus ga naar de constructor onder de super aanroep (als je IDE deze niet heeft gemaakt moet je deze zelf toevoegen, deze moet er zijn) initialiseer de array met de grootte van het paneel. De grootte van het paneel is de lengte vermenigvuldigt met de hoogte.

items = new GuiItem[lengte * hoogte];

Nu maken we een functie om een item toe te voegen die op een willekeurige plek in onze array wordt geplaatst.

void itemToevoegen(GuiItem item) {
    items[ThreadLocalRandom.current().nextInt(items.length)] = item;
}

Dit voegt het item op een willekeurige plek in ons paneel toe (het is mogelijk dat een item een ander overschrijft, maar dat laten we zo in deze tutorial). We laten het hierbij voor onze eigen functionaliteit voor deze tutorial, maar je kan natuurlijk meer functies hier aan toevoegen om te doen wat je wilt.

Nu moeten we aangeven hoe we deze array van items gaan tonen. Ga naar je display method en haal de super aanroep weg. Nu gaan we items toevoegen in de juiste plek in de inventaris. Houd er rekening mee dat items die onzichtbaar zijn en items die buiten de GUI zijn, niet getoond moeten worden.

We beginnen met door onze array heen te gaan en bij te houden op welke plek in de array we zijn.

for (int index = 0; index < items.length; index++) {

}

Hierin willen we het item nemen waar we zijn en kijken of het bestaat en niet onzichtbaar is.

GuiItem item = items[index];

if (item == null || !item.isVisible()) {
    continue;
}

Nu moeten we de juiste x en y coordinaten bereken gebaseerd op onze index. Dit kunnen we doen met behulp van de deel- en modulusoperator.

int x = index % inventarisComponent.getLength();
int y = index / inventarisComponent.getLength();

Nu willen we kijken of deze locatie binnen de GUI is. Houd er rekening mee dat je de paneel-offset moet toevoegen voor elk item.

if (x + paneelOffsetX > Math.min(lengte, maximumLengte) || y + paneelOffsetY > Math.max(hoogte, maximumHoogte)) {
    continue;
}

Nu we aan alle criteria voldoen kunnen we het item in het paneel plaatsen.

inventory.setItem(item, getX() + x + paneelOffsetX, getY() + y + paneelOffsetY);

Nu zijn we klaar met het display-gedeelte dus nu moeten we naar het uitvoeren van klikken gaan. Ga naar de click functie en verwijder de super aanroep. De click-functie is makkelijker, omdat we al gegevens van de item hebben die we kunnen gebruiken.

Eerst kijken we of we wel op een item hebben geklikt.

ItemStack item = event.getCurrentItem();

if (item == null) {
    return false;
}

Bij het aangeven van false wordt aangegeven dat jij het gewenste item niet hebt gevonden, zodat de code die deze functie heeft aangeroepen kan zoeken naar het volgende item. Bij het aangeven van true wordt ervan uitgegaan dat jij het item hebt gevonden en wordt gestopt met zoeken.

Nu moeten we het item vinden op basis van interne gegevens. Dit kan gemakkelijk met findMatchingItem.

GuiItem item = findMatchingItem(Arrays.asList(items), itemStack);

Nu gaan we kijken of ons item ook daadwerkelijk was gevonden.

if (item == null) {
    return false;
}

Nu we het juiste item hebben gevonden, kunnen we de code die hier aan vast hangt aanroepen.

item.callAction(event);

return true;

Nu zijn we klaar met de click-functie, maar we hebben nog twee functies waar we nog niets mee hebben gedaan: getItems and getPanes. Voor getPanes kan je een lege lijst teruggeven, aangezien we geen panelen hebben.

return new ArrayList<>();

Voor getItems wil je van je item array een lijst maken.

return Arrays.asList(items);

Als je wilt dat je paneel eigenschappen heeft voor bijvoorbeeld oriëntatie of draaien kan je jouw klasse de juiste interface laten implementeren.

En dan ben je nu klaar. Als je je paneel met XML wilt laten werken kan je nog de stappen hieronder volgen.

Bekijk volledige code
class WillekeurigPaneel extends Pane {

  private final GuiItem[] items;

  public WillekeurigPaneel(int x, int y, int lengte, int hoogte, Priority prioriteit) {
    super(x, y, lengte, hoogte, prioriteit);

    items = new GuiItem[lengte * hoogte];
  }

  @Override
  public void display(InventoryComponent inventariscomponent, int paneelOffsetX, int paneelOffsetY, int maximumLengte, int maximumHoogte) {
    for (int index = 0; index < items.length; index++) {
      GuiItem item = items[i];

      if (item == null || !item.isVisible()) {
        continue;
      }

      int x = index % Math.min(lengte, maximumLengte);
      int y = index / Math.min(lengte, maximumLengte);

      if (x + paneelOffsetX > Math.min(lengte, maximumLengte) || y + paneelOffsetY > Math.min(hoogte, maximumHoogte)) {
        continue;
      }

      inventariscomponent.setItem(item.getItem(), getX() + x + paneelOffsetX, getY() + y + paneelOffsetY);
    }
  }

  @Override
  public boolean click(Gui gui, InventoryClickEvent event, int slot, int paneelOffsetX, int paneelOffsetY, int maximumLengte, int maximumHoogte) {
    ItemStack itemStack = event.getCurrentItem();

    if (itemStack == null) {
      return false;
    }

    GuiItem item = findMatchingItem(Arrays.asList(items), itemStack);

    if (item == null) {
      return false;
    }

    item.callAction(event);

    return true;
  }

  public void itemToevoegen(GuiItem item) {
    items[ThreadLocalRandom.current().nextInt(items.length)] = item;
  }

  @Override
  public Collection<GuiItem> getItems() {
    return Arrays.asList(items);
  }

  @Override
  public Collection<Pane> getPanes() {
    return new ArrayList<>();
  }

  @Override
  public void clear() {}
}

XML

Om je paneel te laten werken met XML moeten we deze eerst registreren. Je kan je paneel als volgt registreren.

Gui.registerPane("randompaneel", (instance, element) -> {});

De naam is gespecificeerd is de naam die je gaat gebruiken in het XML-bestand, in dit geval randompaneel. Nu moeten we dit paneel laden. Ik raad je aan om een losse functie te maken in je klasse hiervoor, omdat dit snel chaotisch wordt in een lambda.

static RandomPane load(Object instance, Element element) {

}

Nu moeten we dit eerst in een try/catch-blok stoppen met een NumberFormatException (we gaan niet kijken voor de juiste getallen, maar je kan dit doen in je echte functie).

try {

} catch (NumberFormatException exceptie) {
    exceptie.printStackTrace();
    return null;
}

In het try-blok moeten we eerst ons RandomPane maken gebaseerd op de attributen in het XML-bestand. Een attribuut opvragen is heel makkelijk, roep gewoon getAttribute aan op je element.

RandomPane paneel = new RandomPane(
    Integer.parseInt(element.getAttribute("lengte")),
    Integer.parseInt(element.getAttribute("hoogte"))
);

Er is een makkelijke functie die een aantal standaardwaarden voor je inlaadt dus die gaan we nu aanroepen.

Pane.load(paneel, instance, element);

Als je Orientable, Flippable of Rotatable hebt geïmplementeerd kan je voor deze hun respectieve load-functie aanroepen om die attributen in te laden.

Het grootste gedeelte is gedaan, maar in het geval dat we een populate-attribuut hebben moeten we alles negeren dat we hierna gaan doen, dus we gaan het paneel teruggeven als dat zo is.

if (element.hasAttribute("populate")) {
    return paneel;
}

Nu moeten we alle items in dit paneel inladen, dus gaan we een lijst van de kinderen nemen en hier doorheen gaan.

NodeList kinderNodes = element.getChildNodes();

for (int index = 0; index < kinderNodes.getLength(); index++) {
    Node item = kinderNodes.item(index);
}

Nu we dat hebben moeten we eerst kijken of ons element inderdaad een element is (nodes en elementen zijn iets anders, maar wij zijn alleen geïnteresseerd in de elementen).

if (item.getNodeType() != Node.ELEMENT_NODE) {
    continue;
}

Element kind = (Element) item;

Dit element kunnen we aan ons paneel toevoegen. Het item kunnen we inladen met een interne functie, dus daar hoeven we geen rekening mee te houden.

paneel.itemToevoegen(Pane.loadItem(instance, kind));

En nu buiten het for-blok kan je het paneel teruggeven en ben je klaar.

return paneel;
Clone this wiki locally