Inventar Widgets (Gegenstände)

  • Hallo zusammen!


    Ich habe derzeit ein sehr verwirrendes Problem mit meinem Inventar.

    Da ich aktuell 5 Structs (Gegenstandsarten) habe, habe ich auch 5 Inventar-Arrays. Eben für jedes eines, da ich leider nicht alle Structs gemeinsam in ein Array packen kann (das ist auch soweit OK!).


    Die Gegenstände im Inventar, landen alle im "Inventar-Menü-Widget" gemeinsam in der "InventarScrollBox", denn von dort aus, soll man entsprechend das Item anklicken und benutzen können.

    Das funktioniert auch alles richtig.


    Nun ist das leider so das alle Arrays (wenn 3 Gegenstände drinnen sind) mit der Anzahl von 0,1,2 beginnen.


    Habe ich also von jeder Sorte (5 unterschiedliche Gegenstandsarten) 3 Gegenstände von der Art im Inventar ist Reihenfolge für jedes Array wie folgt:

    0,1,2 Konsumgegestände

    0,1,2 Handwerksgegenstände

    0,1,2 Waffengegenstände

    0,1,2 Einrichtungsgegenstände

    0,1,2 Munitionsgegenstände


    Das ist auch alles logisch!


    Jedes Widget in der "InventarScrollBox" hat eine eigene "IndexZahl" bekommen, welches beim erstellt der Widgets für die "InventarScrollBox" erstellt wird.

    Sozusagen als Identifikation welche IndexZahl dieses Widget hat.


    Da nun alle Arrays mit ihrer Reihenfolge immer bei 0,1,2 beginnen, haben die Widgets in der "InventarScrollBox" als "IndexZahl" auch leider immer 0,1,2... ist ja auch logisch!

    Aber wie kann ich das umändern?



    Habe zig fach das Inventar umgestellt... egal wie ich komme immer auf den gleichen Fehler hinaus, das alle Gegenstände in jedem Array von 0,1,2 anfangen und somit die Idenfitikation als IndexZahl bei den Widgets entsprechend identisch sind.



    Hierzu ein paar Bilder:

    Hier wird die IndexZahl für das Widget eingelesen. (Jede Gegenstandsart hat eine eigene)



    ---


    Hier möchte ich den ausgewählten Gegenstand wegwerfen.



    Das funktioniert alles perfekt wenn ich NUR eine Gegenstandsart im Inventar habe, aber bei 2 verschiedenen kommt das zu Fehlern, ist auch logisch weil 2x 0 und 1 von Gegenständen führt natürlich zu fehlern. Ich weiss nur leider nicht wie ich das ändern kann.


    InventarIndexAuswahl wird gesetzt, wenn man entsprechend ein Widget in der "InventarScrollBox" anklickt.


    Das ist echt zum Mäusemelken!


    Danke für eure Antworten.

  • Theoretisch (wenn ein Index größer 0 als erster erlaubt ist) kannst du die Item-Art als suffix verwenden und den Item-Index um 1 erhöhen, umsowas wie 01 zu vermeiden.


    Also 11 wäre das erste Item der ersten Art, 12 das erste der zweiten und so weiter 101 wäre dann das zehnte der ersten Art etc.


    Ich weiß nicht, was du noch alles geplant hast, oder ob du schon fast am Ziel mit deinem Inventarsystem bist: Wenn du noch viel vorhast, solltest du vielleicht von Structs noch auf Classes umsteigen, der einzige Unterschied in C++ und damit defacto auch in Blueprints ist das standardmäßige Zugriffslevel auf Member und Funktionen. Bei Structs halt Public und bei Classes private. Aber dann könntest du z.B. auch anstelle von 5 Arrays für dein Inventar 1 verwenden und so . Nur so als Gedanke

  • da ich leider nicht alle Structs gemeinsam in ein Array packen kann

    Das geht schon, du musst nur in einer Structure, die anderen Structures hinzufügen^^


    Hab das in meinem letzten Game so gemacht:


    Ich weiss nur leider nicht wie ich das ändern kann.

    Du könntest verschiedene Inventare machen, die mit nem Widget-Switcher, gewechselt werden, eins für Rüstung, eins für Waffen, eins für Resourcen, usw.^^



    Eine direkte Lösung hab ich für dich leider nicht...

  • Da ich aktuell 5 Structs (Gegenstandsarten) habe, habe ich auch 5 Inventar-Arrays.

    Da ist doch schon der Fehler. Gegenstände müssen immer eindeutig identifizierbar sein. 5 Structs für Gegenstandsarten mögen noch okay sein, aber dein Inventar besteht nur aus einem einzigen Array.


    Wenn ich mich recht entsinne, hat das schonmal jemand gefragt und das selbe oder ein ähnliches Problem aufgezeigt.


    Letztlich schnappst du die Excel oder etwas vergleichbares und erst wenn alle Gegenstände in einer einzigen Tabelle stehen, dann klappt das auch.


    Fehlern kommt es immer, wenn etwas nicht eindeutig identifiziert werden kann, wie du das anstellst, ist dir überlassen, dass muss nicht über die Indexzahl erfolgen oder kann auch eine gemischte Identifizierung sein, nur muss sie eben eindeutig ablaufen.


    Hast du schonmal versucht mit Tag zu arbeiten? viele kommen damit besser zurecht als mit Indexzahlen.


    Deine Gegenstände haben Eigenschaften, die meisten erstellen mehrere Listen, weil sie meinen, dass das übersichtlicher ist. Bspw Waffen, Nahrung, Rüstung, Baumaterial, Rohstoffe.


    Dieses System halte ich persönlich für möglich aber eben auch extrem anfällig. Besser ist es, wenn alle Items in einer Liste stehen und neben der Indexzahl einen Tag erhalten. bspw Nahrung.


    Eigenschaften einer Sache müssen nicht ausgefüllt werden und erhalten dann auch keinen Wert. Viele Werte sind also für verschiedene Items überhaupt nicht auszufüllen, aber über Tag kannst du schnell und einfach filtern.


    Größtes Problem für mich war es damals, wenn du später Gegenstände individualisierst.

  • Ich habe die Structs extra voneinander getrennt, damit die Performance erhalten bleibt.

    Bei kleinen Projekten mag das sehr sinnvoll sein, ich möchte jedoch etwas größeres machen, weshalb es besser ist das eine Vielzahl von Gegenständen separiert werden.


    Angenommen es gibt in dem Projekt:

    ca. 1000 Waffen (Bauteile, Zielfernrohr, Magazine, usw.)

    2000 Rüstungen

    3000 Fahrzeugteile (Waffen, Bewegungsteile, Panzerung, Bauelemente)

    5000 Bauteile für Gebäude (Mauern, Pflaster, Steine, Hölzteile usw.)

    1000 Nahrungssachen (Heiltränke, diverse Tränke, Nahrung usw.)

    10000 Materialien (Diverse Metalle, Erze, unzähliche Legierungen, Edelsteine usw.)


    Wenn man das alles über eine Datenbank und ein Struct laufen lassen würde, das würde doch komplett die ganze Struktur sprengen?

    Alle Teile sollen im Spiel noch modifizierbar und färbbar sein, sowie anpassbar. Auch die Bauteile für Fahrzeuge und Gebäude (bei den Gebäuden eher weniger, ausgenommen Verteidigungsanlagen).


    Bei Conan Exiles meine ich das alles über ein Struct läuft und wenn ihr mal die Datenbank im Spiel durchschaut, hat das extreme Performance Probleme.

    Ich kenne das auch aus diversen anderen Spielen die das über eine Datenbank gemacht haben (ja es ist bequemer) aber bis das System die ganze Datenbank durchgeschaut hat und abgespeichert... das kann richtig übel werden.

  • Theoretisch (wenn ein Index größer 0 als erster erlaubt ist) kannst du die Item-Art als suffix verwenden und den Item-Index um 1 erhöhen, umsowas wie 01 zu vermeiden.


    Also 11 wäre das erste Item der ersten Art, 12 das erste der zweiten und so weiter 101 wäre dann das zehnte der ersten Art etc.


    Ich weiß nicht, was du noch alles geplant hast, oder ob du schon fast am Ziel mit deinem Inventarsystem bist: Wenn du noch viel vorhast, solltest du vielleicht von Structs noch auf Classes umsteigen, der einzige Unterschied in C++ und damit defacto auch in Blueprints ist das standardmäßige Zugriffslevel auf Member und Funktionen. Bei Structs halt Public und bei Classes private. Aber dann könntest du z.B. auch anstelle von 5 Arrays für dein Inventar 1 verwenden und so . Nur so als Gedanke

    Ja das ist der Fehler den ich auch sehe, eben das jedes Array von 0,1,2 anfängt.

    Da aber 0+0 = 0 ist, komme ich ständig auf das gleiche Problem (die Arrays vom Inhalt her zusammen zu ziehen habe ich mir schon überlegt gehabt).

    Auch ein Fake-Array konnte mir da nicht weiterhelfen (in dem ich die Anzahl einfach darin gepackt habe, um das entsprechend weiterzuleiten).



    Ich bin davon ausgegangen das Struct + Actor-Class Blueprint + Child Actor System das beste sei?

    Was genau meinst du mit Classes System?


    Ich habe das derzeit so, das ein Struct (etwa für Waffen), in einem Actor Blueprint (Master) ist und ich erzeuge für die Waffe dann ein Child Actor vom Actor Blueprint (Master).

    Das ChildActor hat dann die Funktionen und Informationen des Master, also muss ich diese nur in ein Datatable packen und dort die Werte eintragen.

    Damit kann ich dann die Sache im Spiel frei verwenden (so wie ich das brauche).

    Anstatt 10 gleiche Schwerter mit unterschiedlichen Werten, wie es in diversen anderen Spielen gibt. Gibt es nun ein Schwert mit unterschiedlichen Möglichkeiten. Die auch optisch und inhaltlich verändert werden können.

  • Glaube die Frage habe ich schon mal früher gestellt, nur wusste ich bis dato nicht welche Ausmaße das ganze bei mir annimmt, weshalb ich in dem ganzen System ein paar Dinge umändern musste damit das besser harmoniert.


    Alle Structs haben ein TAG, das habe ich ganz vergessen... das könnte ich neben dem Index als Filter nehmen.

    Den TAG benutze ich bereits für die Kampfanimationen, damit ich weiss mit welcher Waffe, welche Animation erfolgt.


    Die Gegenstände sollen auch frei individualisierbar sein, was aktuell auch im Test sehr gut funktioniert. Nur ziemlich aufwändig ist.

    Vor allem bei den Schusswaffen, wenn man Zielfernrohr, Magazin, fordere Laufgriff usw, einbauen möchte.



    Warum ich 5 Arrays habe ist der Zugriff darauf. Spieler sollen in das Inventar der anderen Spieler zugriff haben (entsprechend mit rechten), weshalb es einfacher ist wenn es mehrere Arrays/Inventare gibt das ganze zu limitieren.

    Waffen/Rüstungen, Nahrung/Materialien sollen frei lootbar bzw. verwaltbar sein, während Bauteile für Gebäude, Fahrzeuge und mehr das nicht sein soll, oder entsprechend vorbehalten.

    Das alles nur über Filter zu machen wird schwer, das die Arrays nach einem Gewichts/Volumen System limitiert sind. Was wiederum das eine mit dem anderen zu Problemen führt.


    Ich dachte ursprünglich auch das EIN Array/Inventar prima wäre, aber dann ist mir aufgefallen das je größer das Projekt wird (inhalt), um so mehr Probleme kann das verursachen.


    Ähnlich wie bei einem LKW mit Unterschiedlichen Ladeflächen, eines für Flüssigkeiten, eines für Pulver/Sand, schwere Bauteile mit spezial Halterungen... natürlich ist das eine Digital (Inventar) und die Ladeflächen physisch aber das beides getrennte Plätze hat, halte ich für einen guten Vorteil.

  • Hier mal 2 Bilder wie das aktuell aussieht im Spiel:

    Die Stapelbaren Gegenstände habe vorher eine Zahl bekommen die entsprechend die Anzahl der Stück zeigt. Darin enthalten auch die Stapelgröße.


    Also 1x9mm = 1x9mm (10/10 Schuss) oder (5/10) usw.

    Innerhalb der Stapelgrößen gibt es noch eine Stapelmenge.




    ---


    Oben beginnt es bei INDEX 0 und unten (1 x 5mm ) = INDEX 5, (eigentlich index 6, weil ja 0 schon 1 ist).




    ---


    Die Inhalte sollen später bis zu einem gewissen Grad, veränderbar sein

  • Ich glaube das könnte schon die Lösung sein.


    Set Index für die Position des Gegenstandes und Set Widget-Reference für das Widget selber.



    Bei allen Widgets in der ScrollBox mache ich dann einfach eine Überprüfung ob gleich ist und fertig.

    Aber ob das wirklich die beste Lösung ist?

    Was ist wenn ich in dem Inventar eines anderen Spielers bin und dort etwas hinaus oder reinpacken möchte?


  • Das ist ziemlich unrealistisch, außer du willst erst in 100 Jahren damit fertig sein, aber egal...


    Ob du jetzt 25k Items in nem DataTable hast oder 5k, ist ziemlich egal, die Übersicht (für dich als Dev) ist so oder so verloren^^


    Du kannst auch für jeden Typ ein eigenes DataTable machen, macht die Umsetzung aber auch nicht einfacher.


    Ob das mit 25k Actors übersichtlicher ist, glaub ich kaum...



    Wenn es dir um die Multiplayer-Performance geht, brauchst ja nicht alles was im DataTable drin steht, auch dem Item im Inventar geben, das meiste davon ist nur fürs Widget interessant, welches nicht replicated ist.


    In der Structure vom Inventar brauchst eigentlich nur die ID, Amount und evtl. Health^^



    Zum Details aus nem DT abzufragen, brauchst auch kein ForEachLoop:

  • Geloscht


    Die Gegenstandsmengen häufen sich sehr schnell an!

    24 Teile hat eine Rüstung.

    9 Gewichtsklassen x 24 = 216 Rüstungsteile und damit habe ich gerade mal nur eine Rüstung pro Gewichtsklasse.

    Eine Schusswaffe ca. 6-x Teile.

    Bei ca. 30 Waffen x 6 Komponenten = ca. 180 Teile

    (5 Pistolen, 5 Sturmgewehre, 5 SMGs, 5 Sniper, 5 Schrotflinten, 5 Raketenwerfer/Bogen/Armbrust usw.)

    Das sind schon für den Anfang ca. 396 Teile.


    Davon ist noch keine Kleidung oder sonstiges...




    Für die Datenbank anfrage mache ich bisher immer das hier:


    Eine ID verwende ich nicht da ich den Actor Class benutze.

  • Nicht zwangsläufig, man kann auch einfach ein leeres Array anfangen und alles bis z.B. Index 10 ist dann ein nullptr bzw. NULL in Blueprints. Ich habe mich nur gefragt, ob das auch alle UI-Elemente mit Indizies das so sehen :)

    Ich hatte ein Fake-Array für die Widgets gemacht.

    Sprich die ganzen Widgets von der ScrollBox (im Inventar) in das Fake-Array packen (weil dort ist ja alles geordnet von 0,1,2,3,4 usw.).


    Das hat leider nicht so funktioniert, weil er Inhalt der Widgets unterschiedliche Structs hat, die Information ist zwar enthalten aber das muss entsprechend auch wieder aus dem Original-Array entfernt werden und wenn da ein Lag oder anderes ist, macht der das nicht :(



    Kannst du mir bitte mal zeigen wie das mit dem Index 10 und NullPtr aussieht?

    Ich finde oder komme nicht darauf wie das Bauteil dafür ist.




    Danke an alle Antworten von euch :)

  • 22.000 verschiedene Items? Ich hoffe du kommst noch zum Spiel an sich...


    Performance ist relativ - Geschwindigekeit ist bei UE4 struct/array kein Thema - aber klar das ganze muss im RAM stehen. Habe schon mal ein struct mit über 400.000 Items gesehen - sowas kostet dich dann je nach Inhalt auch mal über 1 GB RAM zusätzlich. Wobei man sagen muß daß man heute eh keinen PC mehr unter 8GB RAM bekommt - von daher...


    Wenn du die performance sehen willst teste es doch mal. Füll es mal zur Laufzeit prozedural mit 30.000 "Müll" Einträgen und guck mal auf RAM und performance. Wie gesagt - fps dürfte es nicht kosten aber RAM natürlich schon etwas. Aber mit so ner Anzahl an Items hast du kaum Alternativen.

  • Das ist jetzt etwas unrealistisch/utopisch in der aktuellen Situation aber um das ganze mal in einen Vergleich zu setzen, wie es im Idealfall laufen könnte! Natürlich über die Jahre hinweg, jedoch möchte man ja jetzt schon den Grundweg für alles weitere setzen. Schlechte wäre es wenn man ständig die Datenbank erneuern/umändern muss weil man merkt das es zu Fehlern oder performance Problemen führt.

    Daher meine Frage wie die Unreal Engine damit so umgehen kann... mit diesen gewaltigen Massen an Gegenständen.


    Beispiel ist World of Warcraft.

    Ersterscheinung: 2004

    Sagen wir mal (um das leichter zu rechnen) WoW existiert seit dem Jahr 2000 (da gab es dann schon die ersten Gegenstände).

    Das macht ca. 7300 Tage bis zum Jahr 2020.


    Aktuell gibt es laut der "WoWHead Datenbank":

    125.681 Gegenstände gefunden


    125.681 Gegenstände durch 7300 Tage = ca. 17 Gegenstände pro Tag. Pro Jahr ca. 6205 Gegenstände!

    Bei ungefähr 100 Mitarbeitern (einfach mal als Beispiel), wäre das nicht so viel pro Tag an Gegenständen die in das Spiel hinein kommen könnten/würden.


    Die ganzen Gegenstände müssen irgendwo hin, aber was passiert wenn man im Spiel nach einem Gegenstand suchen will und die Engine müsste die ganzen 125k Gegenstände durchsuchen. Geht das wirklich ohne Performance Verlust?


    The Elder Scrolls Online musste ihre Datenbank umstellen da diese durch die Engine am Limit war.

    In diversen anderen Spielen gibt es auch häufig Performance Probleme mit der Datenbank (siehe Conan Exiles Admin-Menü).

  • Die ganzen Gegenstände müssen irgendwo hin, aber was passiert wenn man im Spiel nach einem Gegenstand suchen will und die Engine müsste die ganzen 125k Gegenstände durchsuchen. Geht das wirklich ohne Performance Verlust?

    Das kommt ja immer auf den Suchalgorithmus an.


    Es gibt Algorithmen, die durchsuchen stumpf von oben nach unten bis es einen Treffer gibt. Diese sind in Datenbanken notwendig wo nicht nach dem Suchbegriff sortiert werden kann.


    Wenn du aber nach dem Suchbegriff sortieren kannst, zum Beispiel Alphabetisch, dann gibt es jede Menge andere Möglichkeiten. Ein Algorithmus, den ich noch von früher her kenne, ist zum Beispiel so vorgegangen, dass er die Datenbank immer halbierte. Nehmen wir mal an du hast eine Datenbank von A bis Z alles drin, sagen wir mal 2000 Einträge. Dann ist er auf den Eintrag 1000 gesprungen und hat halt geschaut, ob der Buchstabe des Eintrags größer, bzw. höher ist als da wo er gerade steht. War er jetzt zum Beispiel höher hat er die ersten 1000 Einträge vergessen und hat sich um die nächsten 1000 Einträge gekümmert. Dann ist er auf 500 gesprungen und dasselbe Spiel ging von vorne los. Dadurch hattest du auch bei sehr großen Datenbanken relativ wenige Sprünge, eben halt weil immer sofort ein sehr großer Teil, nämlich die Hälfte, schon beim ersten Durchgang weggefallen ist.


    Wie gesagt, das ist jetzt ein sehr alter Algorithmus, den ich noch aus den 90er Jahren kenne. Ich denke mal, dass da inzwischen schon optimiertere Wege zum Ziel führen. Aber dieser Weg war damals schon, auf recht langsamen Systemen, die es ja in der Zeit nun mal gab, sehr effektiv.

  • Probiers doch einfach aus. Lass über nen Loop rnd zahlen einfüllen und auch 1 oder 2 "echte" mit nem namen oder wert nach dem du dann suchst. Dann weisst du es.

  • Für was gibts ne Item-ID?

    Ach stimmt ja, benutzt du ja nicht^^


    Wäre vielleicht ne Überlegung wert, wenn man schon ein Data-Table benutzt, denn die ID ist da schon drin (automatisch), siehe Sleepy ´s Thread DataTable (Struct) fortlaufende ID.

    Ich verstehe nicht was eine ID für einen Sinn hat, warum braucht man das und wofür?


    Man sucht Gegenstand X in der Datenkbank mit ID Y (unbekannt).

    Wenn ich X kenne, wieso brauche ich dann ID Y?

    X hat einen ActorClass/ActorReference was auch immer, was ich direkt für den Spawn benutzen kann.


    Wenn ich im Spiel ein Langschwert erzeugen möchte, weiss ich doch nicht welche ID das Langschwert hat also muss ich nach dem Langschwert in der Datenbank schauen und da wäre die ID z.B. 5232.

    Da man vorher nicht weiss welche ID das Langschwert hat, wieso also die ID nehmen nach der man sucht obwohl man das Langschwert schon gefunden hat?


    Warum nutze ich nicht gleich den Namen anstatt der ID?

    Der Name als ActorClass anstatt einer ID.

    SpawnActor from Class = der ActorClass welchen ich gesucht habe (ohne ID).