Widgets richtig erstellen (+Multiplayer)

  • Hallo Leute!


    Ich bin mir nicht sicher ob diese Frage sinn ergibt... es geht darum ob es besser ist, wenn man 1x ein Widget erstellt und dieses speichert, oder ob man jedes mal ein neues erstellt.


    Es geht um "Create Widget" und den daraus folgenden Funktionen, im allgemeinen betrachtet (egal wo man Widgets braucht).


    Gibt es irgend einen Unterschied, wenn ich jedes mal das Inventar öffne, das dieses ständig neu erstellt wird?

    Sozusagen:

    Input -> i (für Inventar), dann Create Widget... usw.

    Wenn ich die Reference davon an ein "Print String" hänge, dann sind das nach ca. 50x Inventar öffnen, 49x Inventar Widgets.

    Bei 10 Spielern wären das schon 490 usw... falls man das so einfach sagen kann.


    Was passiert mit den alten Widgets die nicht genutzt sind und trotzdem erstellt wurden?



    Wie macht ihr eure Widgets, einmal permanent und dann in einer Variable speichern?

    Oder so wie ich, jedes mal ein neues Widget erstellen und das in einer Variable speichern?


    Was gibt mehr performance, was ist so gesehen besser für die Engine oder allgemein?

  • Natürlich macht das Sinn. Allerdings nur, wenn du das Widget nach dem Schließen auch wieder killst.



    Hier habe ich dir auch mal ein Beispiel reingestellt wo man mit der Taste I das Inventar öffnen und schließen kann. Hier wird dann nach dem Drücken der Taste abgefragt, ob das Inventar geöffnet/vorhanden ist, Ich nehme hier bewusst kein FlipFlop, weil die Stupide den Zustand wechseln, ohne das abgefragt wird, ob das Inventar geöffnet ist oder nicht. Dies ist halt einfach eine etwas sicherere Methode.

  • Was passiert denn im schlimmsten Fall wenn man irgendwann mal zig tausende Widgets erstellt hat?

    Ehrlich gesagt hatte ich noch nicht das Bedürfnis es auszuprobieren und zig tausende Male das Inventar, oder ähnliches, zu öffnen, um das auszuprobieren. :D


    Ich kann mir aber vorstellen, dass das Inventar eventuell anders reagiert als man denkt, je nach Programmierung halt. Und wenn es gaaaanz schlimm läuft, und Unreal nicht irgendwelche Abfangroutinen hat, dann kann es natürlich auch zu Speicher und/oder Variablenüberläufen kommen.


    Allerdings müsstest du es bei einem signed Integer schon 32.768 mal öffnen, und bei einem unsigned Integer 65.536 mal, um es zu einem Fehler kommen lassen zu können.

  • Was passiert denn im schlimmsten Fall wenn man irgendwann mal zig tausende Widgets erstellt hat? ^^

    Fehler passieren ja oftmals so:

    Du hast zb am Anfang eine Karte im Invetar mit der du Startest.

    Inventar auf und zu und irgend wann nimmst du die Karte aus dem Inventar zb in eine Kiste.


    Nun gibt im Inventar eine Veränderung die im laufe des Spiels auftritt die aber beim Start nicht gegeben war. Deswegen ist abfragen sicherlich besser.

    You may love to play games, but that doesn’t make you a developer.
    I love to eat dinner, but that doesn’t make me a chef.

  • Sieht mir dank FlipFlop aber doch etwas unsicher aus. Zudem, wozu in einer Variablen erstellen und es vorher doch anders machen müssen?


    Wobei wir uns darauf einigen sollten was eigentlich erstellen ist. Denn die Logik des Inventars, also Speichern des Inhaltes und ablegen usw., das ist ja nicht direkt im Widget hinterlegt. Also ich zumindest habe dazu noch ein extra BP, welches die ganze Logik dahinter übernimmt. Widgets sind ja vorzugsweise dazu da dem Spieler Inhalte anzuzeigen und zu interagieren.


    Warum ich ein Flipflop in diesem Falle als unsicher empfinde ist also eher relativer Natur. Wenn das Widget jetzt aus irgendeinem Grund schon angezeigt wird, also irgend ein logischer Fehler den man irgendwo gemacht hat, und man drückt auf Inventar öffnen, dann könnten sich zufällig zwei Inventare überlagern. Wenn es jetzt ganz blöd läuft, veränderst du in dem einen Inventar etwas und in dem Anderen halt nicht. Deswegen immer die sichere Abfrage, ob das Inventar bereits angezeigt wird oder nicht.


    Ist natürlich ein klein wenig Mehraufwand. Aber halt auch nicht so viel. Und man spart sich unter Umständen eine Fehlersuche, die nicht hätte sein müssen.

  • Zudem, wozu in einer Variablen erstellen und es vorher doch anders machen müssen?

    Das verstehe ich nicht.


    Um denn FlipFlop geht es ja nicht, auch wenn ich da keine Probleme sehe. So viele stellen wo man das Inventar öffnet/schließt gibt es ja in der regel nicht.


    Im Grunde besteht mein Inventar aus drei Teilen, das Ui, die Logik in einer Komponente und den reinen Daten.

  • Ganz einfach. Diese Variable ist unnötig und suboptimal. Sie nimmt wahrscheinlich nicht viel Platz weg. Aber jetzt stell dir mal vor, ich weiß ja nicht wie du ihr einen Wert zuweist, aber nehme wir mal an du machst es beim Spielstart. Jetzt lass sie aus irgendeinem Grund mal gelöscht werden, also den Inhalt, dann kannst du dein Inventory schon mal nicht mehr öffnen.


    Da wo es möglich ist, da würde ich auch so gut wie es geht immer auf Sicherheit gehen. Das Öffnen und Anzeigen eines Inventars ist keine Zeitkritische Aktion in einem Spiel. Es ist ja nicht so, dass das Inventar in einer bestimmten Zeit geöffnet sein muss, also innerhalb einer bestimmten Bildwiederholung oder so. Es ist nicht wie die anderen Berechnungen, wie zum Beispiel das Rendern und Berechnen von Licht und Schatten oder so, was alles sehr Zeitkritische Berechnungen sind, die auch den Spielfluss stören können, wenn da zu viel Zeit benötigt wird.


    Ich meine, ich gehöre ja nun nicht zu den Personen, die dir sagen wollen, wie du etwas zu machen hast. Das sind halt nur Tipps die eventuelle Fehler vermeiden kannst die dann wieder Zeit kosten sie zu finden. Letztendlich kannst du es ja umsetzen wie du es möchtest. Es gibt, wie immer in der Programmierung, zig Wege zur Lösung. Der von mir aufgezeigte Weg dient halt nur dazu aufzuzeigen wie man auch eine Abfrage integriert. Und ich versuche solche Abfragen, wenn möglich und wenn ich daran denke, immer einzubauen. Und sogar diese Abfrage ist ja auch in verschiedenen Varianten umsetzbar.

  • Ich geb dir ja recht das man schauen sollte ob die Variable ein Objekt enthält, das ist ja schnell gemacht.


    Mein Inventar ist dafür ausgelegt verschiedene Widgets anzuzeigen.

    Den Luxus eines für Maus+Tastatur und eines für Controller gönne ich mir schon, dann brauche ich keine faulen Kompromisse eingehen.


    War ja auch nur meine Variante, kann ja jeder machen was er will.

  • Ich habe das halt so gemacht, das Grundprinzip ist bei allen Widgets die ich verwende, identisch.

    Probleme hatte ich nur am Anfang mit dem Flip Flop, aber das ist echt perfekt.



    Ich erstelle jedes mal wenn ich das Inventar aufrufe, ein neues Inventar und wenn es geschlossen wird, wird die Variable dafür gelöscht.

    Im Widget oder sonst wo, überprüfe ich mit "IsValid?" ob die Variable für das Inventar Widget vorhanden ist oder nicht.



    Ist das jetzt so richtig oder falsch?

    Auf längere Sicht hin.

    Das verwende ich auch im Multiplayer und funktioniert prima (liegt daran das es nur beim Client ausgeführt wird), aber das wichtige (InventarArray) ist ja eh im MyCharacter und replicated, damit dann andere Spieler mit entsprechender Berechtigung auch auf das Inventar eines anderen Spielers zugreife kann.

    Z.B. wenn ein Spieler-Dieb etwas aus dem Rucksack eines anderen Spielers klauen möchte.

  • Ich bin ja kein Freund von FlipFlop wo es nicht notwendig ist. Eben halt aus dem Grund, weil du nicht unbedingt den Anfangswert kennst unter bestimmten Umständen. Derartiges habe ich aber schon in "normalen" Programmiersprachen immer versucht zu verhindern, wo es nur geht.


    Was ich nicht ganz verstehe ist, warum du die Abfrage ob der Spieler gerade am Schreiben ist, negierst und dann auf den Truezweig springst. Vom denken her würde ich ja einfach in den Falsezweig gehen, was vom Kopf her logischer zu lesen ist.


    Und was machst du mit der Inventoryvariablen? Laut dem Screenshot machst du damit nichts anderes, als sie mit Inhalt zu füllen und wieder zu leeren.


    Das CastToOnlinePlayerController kommt mir auch etwas suspekt vor. Ich habe noch nie irgendwo im Widget ein CastTo setzen müssen, was ich immer für sehr unglücklich halte. Ich weiß zwar nicht genau was dies CastTo in C++ darstellen soll, aber es scheint mir immer ein Kunstgriff zu sein um auf Klassen zugreifen zu können, bzw. deren Inhalte, auf die man in der regulären Programmierung nicht zugreifen können sollte.

  • Bei FlipFlop gibts ja den Bool "IsA", damit kann man prüfen ob A bereits verwendet wurde oder nicht.


    Das benutze ich z.B. beim Crafting Menü, dort kann ich es über den Input aufrufen oder an der Handwerker Station und da frage ich dann ab ob "IsA" schon aufgerufen wurde oder nicht.

    A ist ja automatisch beginnend.


    Das mit dem "Schreibt?" ist, wenn man im Chat etwas schreibt, sonst würde bei jedem "i" das Inventar aufgehen.

    Ob NEIN = True oder JA = False ist ja egal, reine Geschmackssache ^^.



    CastTo... kann man überall verwenden, wo man keine Variable benutzen möchte, etwa um von etwas Informationen zu beziehen.


    CastToMyCharacter ist genau so, als wenn ich im Blueprint eine Variable mit "MyCharacter" mache.

    Weil in dem Blueprint muss der MyCharacter in die MyCharacter Variable eingelesen werden und da verwendet man auch den CastToMyCharacter um den MyCharacter nach dem ConstructionScript zu ermitteln.

    Das klingt sehr verwirrend, aber sonst würde man nur eine leere MyCharacter Variable erstellen, die muss ja noch befüllt werden.



    Also anstatt:

    CastToMyCharacter -> Set MyCharacter (neue Variable) -> Get MyCharacter -> Lebenspunkte.

    eben

    CastToMyCharacter -> Get Lebenspunkte.

  • Naja, kann man ja so machen. Bleibt trotzdem die Frage warum du eine Invetory Menu Variable füllst, ohne diese zu benutzen. Weil alle weiteren Stränge gehen von der Create-Node ab.


    Auch das schreiben brauchst du eigentlich nicht abfragen. Bei mir geht es auch so. Mag sein das es daran liegt, weil ich die I-Taste in den Projekteinstellungen hinterlegt habe und eben halt ein Event zum öffnen benutze.

  • Mit Create Widget sparsam umgehen. Nur nutzen wenn damit ein widget erstellt werden soll, weil es noch nicht existiert. Danach den Widget in eine Variable setzen um diesen Widget zu bearbeiten.

    Mit AddToViewport anzeigen lassen und RemoveFromParent vom Bildschirm entfernen lassen.

    Man muss bedenken, man kann kein Widget einzeln entfernen, oder zerstören. RemoveFromParent ist nur das entfernen von VIewport. Es ist immer noch vorhanden. Nur RemoveAllWidgets zerstört die Widgets und können nicht mehr angesprochen werden.

    Das bedeutet, Sehr viel mit Hide, oder visible arbeiten. Weis jetzt nicht welches davon relevant ist. Wenn ein Widget sich mit vielen schnickschnack sich aufbaut, kann das Spiel auch schon mal kurz einfriehren. Damit nicht permanent sich alles wieder neu aufbauen muss, muss das Widget vorhanden sein. Mit einer Variable findet man diesen Widget schnell wieder, desswegen immer in eine Variable setzen.

    Noch ein Beispiel ist, manche bauen ihr Widget mit html auf. html kann sehr langsam aufbauen, wenn diese vom Internet abgerufen wird. Damit das nicht immer wieder so langsam aufbaut, wird das Widget versteckt, oder sichtbar gemacht, anstatt immer wieder create widget zu nutzen.

  • Na im Programm löschst du sie ja auch nicht, warum auch? Vor allem zur Laufzeit. Nein, ob sie bereits einmal geöffnet ist oder nicht. Solche Sicherheitsabfragen sind eigentlich recht wichtig und üblich beim Programme schreiben. Auch wenn sich viele aus Faulheit solche Abfragen sparen. Aber wir wollen doch hier zumindest das saubere Programmieren vorschlagen. Was die Leser daraus machen ist dann ja deren Sache.