Jump to content
Unity Insider Forum

Referenz auf ScriptableObjects / Datenbank


RiseBasti

Recommended Posts

Hallo Community

Seit einer Weile beschäftige ich mich damit, wie ich meine Items organisieren möchte. Bisher habe ich jedoch noch keine Variante gefunden, die meinen Erwartungen entspricht.

Mein Ziel dabei wäre, dass ich über ein Editor Window Items erstellen und bearbeiten kann. Diese sollten dann irgendwie als Referenz in z.B. einem Dictionary abrufbar sein damit ich im Spiel darauf zugreifen kann.

Bisher habe ich dies über ScriptableObjects versucht, was soweit auch ganz gut funktioniert. Dazu hab ich bereits ein Editor Window erstellt, in welchem neue Items erstellt und bearbeitet werden können. Ich scheitere jedoch beim letzten Punkt mit der Referenz in einem Dictionary. Natürlich könnte ich die Items per Drag&Drop im Inspector referenzieren, allerdings scheint mir das für eine grosse Sammlung an Items eine sehr unpraktische und nicht nachhaltige Lösung zu sein.

Weiss da jemand vielleicht bescheid, wie diese generierten SOs direkt beim erstellen referenziert werden können?

Oder gibt es allenfalls andere, bessere Lösungen als mein Ansatz?

 

Des weiteren würde mich auch interessieren wie das funktionieren würde, wenn man eine Online Datenbank verwenden würde. (MySQL oder ähnlich?)
Ich kenne mich da kaum aus und weiss auch nicht ob man da überhaupt Prefabs oder SOs speichern könnte oder dies dann komplett anders lösen müsste.

 

Schonmal danke für eure Antworten. 🙂

Link zu diesem Kommentar
Auf anderen Seiten teilen

Moin!

Die Möglichkeit zu haben, SOs irgendwo reinzuziehen ist schon super. Einfach ein Lootkisten-Script bauen, den Loot reinziehen und schon hat man definiert, was einem die Kiste gibt. Ich meine jetzt aber, aus deinem Post herauszulesen, dass du das gar nicht so machst? Du hast die Dinger nicht einfach nur rumliegen, sondern in einem Dictionary - heißt das, dass du in einem (hypothetischen) Loot-Script einen Identifier (z.B. einen String) benutzt, um zu definieren, von welchem Item du redest?

Ich gebe dir Recht, dass ScriptableObjects bei größerer Anzal erstmal nicht mehr nach einer gut skalierenden Lösung aussehen, aber das könnte unter Umständen an deiner Art der Verwendung liegen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

 SOs rumziehen ist oftmals wirklich sehr praktisch und bisher ist das auch meine Lösung aktuell. Problematisch dabei ist bei mir eher die Anzahl an Items die mit der Zeit existieren werden und teilweise hab ich auch, dass bei Änderungen an den SOs oder am Datenbank Script die Items verloren gehen. Zudem hätte ich es auch gerne automatisiert.

Ich möchte die Items so nutzen können, dass ich jederzeit auf alle Items von überall zugreifen kann. Diese werden dann über einen Store zum Kauf zur Verfügung stehen. Die Items selber beinhalten effektiv nur die benötigten Daten der Items (diverse Werte, ein Icon und Prefabs).

Diese Daten werden anschliessend im UI (Store, Inventar) von den UI Elementen und in der Scene von den GameObjects verwendet, damit sie die Werte und Prefabs der Items verwenden können. (Alles als Referenz zum SO)

Daher hab ich mein Datenbank Scirpt, welches alle SOs in einem Dictionary enthalten (Ich wollte keine Liste da ich auf die Items über klar definierte IDs zugreifen können möchte. Falls ich dann aus versehen ein SO lösche kann ich jederzeit über die ID das SO wieder finden.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 4 Stunden schrieb RiseBasti:

rumziehen ist [...] auch meine Lösung aktuell.

vor 4 Stunden schrieb RiseBasti:

da ich auf die Items über klar definierte IDs zugreifen können möchte

Das heißt, du hast eine Hybridlösung? Da könnte u.U. schon ein Problem drin liegen.

Was meinst du mit

vor 4 Stunden schrieb RiseBasti:

Falls ich dann aus versehen ein SO lösche kann ich jederzeit über die ID das SO wieder finden.

Wenn das SO gelöscht ist, kannst du es doch nicht wiederfinden?

Generell würde ich empfehlen, dass du dich für eine von beiden Varianten entscheidest und die auch durchziehst. ScriptableObjects funktionieren am besten dezentral. Du hast sie (z.B.) in den Assets herumliegen und benutzt Unitys Project Window, um sie zu verwalten. Du kannst Label draufpacken und ihnen sprechende Namen geben. Mit der Suchleiste kannst du nach beidem und dazu noch nach dem Typ filtern. Wenn man die Suchleiste im Workflow drinhat, braucht man eigentlich keine zentrale Sammelstelle mehr. Und damit kriegst du auch größere Anzahlen von Items gut in den Griff. Genauso, wie du bei einer Datenbank nicht durch eine Liste oder eine Datei scrollst, bis du das richtige Ding gefunden hast, solltest du dich auch nicht durch deine Ordnerstruktur klicken.

vor 4 Stunden schrieb RiseBasti:

dass bei Änderungen an den SOs oder am Datenbank Script die Items verloren gehen.

Warum? Unity kann das einigermaßen, dass der Code eines ScriptableObjects oder eines MonoBehaviours sich ändert und neu kompiliert wird, ohne, dass die Instanzen kaputt gehen. Wenn du Felder umbenennst, versucht Unity auch, das festzustellen, kann das aber natürlich nur begrenzt gut entscheiden. Da kannst du aber mit dem [FormerlySerializedAs]-Attribut nachhelfen.

Mit solchen kleinen Tricks (Attribut, Suchleiste, und nicht die Label unterschätzen!) kann man ganz gut eine reine SO-Lösung aufbauen, die auch etwas größere Mengen an Objekten unterstützt. Ich würde wie gesagt auch von abraten, eine Hybridlösung zu bauen.

Aber was ich brauchbar finde, ist ein kompletter Umstieg auf eine Datenbankstruktur. Es ist in bestimmten Situationen keine schlechte Idee, SOs ganz sein zu lassen... z.B.

  • wenn jemand im Team keine Ahnung von Unity hat, aber an der Itemdatenbank fummeln soll,
  • wenn das Projekt nicht ausschließlich Unity-basiert ist, sondern z.B. noch ein Nicht-Unity-Backend hat, oder
  • man das Drag&Drop-Feature sowieso nicht so wirklich gebrauchen kann.

Ich habe z.B. mal mit einem Lokalisations-System auf SO-basis experimentiert und das wieder eingestampft. Es ist sinnvoller, wenn man einem Übersetzer eine standartisierte .po-Datei geben kann, anstatt die Daten in Unity-Land aufzubewahren. Und das Drag&Drop-Gedöns war auch eher anstrengend als hilfreich, da es kaum etwas mit Leveldesign zu tun hatte. Wenn man entscheidet, welche Kiste welchen Loot hat, ist das nice, aber in diesem Fall... dazu kommt noch, dass die meisten Strings nur einmal vorkommen, und dann hat man ein SO, das nur an einer Stelle gebraucht wird. Und eh nur einen String enthält. Also hab ich einfach den String direkt in der Komponente stehen und mit ein bisschen Editor-Scripting eine "Leuchte" daneben eingebaut, die anzeigt, ob man einen gültigen Schlüssel eingegeben hat.

Lanmge Rede, kurzer Sinn... Reine SO-Lösung gut, reine DB-Lösung gut, aber Hybridlösungen bringen meiner Erfahrung nach eher das schlechteste aus beiden Welten mit.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Erstmals Danke für deine Ausführlichen Antworten!

Ich merke, dass ich mich relativ unklar ausdrücke.

1. Aktuell ist meine Lösung so, dass ich ein Database Script habe mit einer Liste, welche SO Referenzen beinhaltet (Also per Drag&Drop in die Liste gezogen auf dem GO, SOs sind ja Ref-Type). Diese SOs sind irgendwo unter dem "Assets" Ordner abgelegt. Der Store lädt aus dieser Liste alle Items, welche gekauft werden können (Erstellt UI Elemente mit den daten der SOs). Auf meine Liste greift also nur der Store zu. Dieser gibt bei einem Kauf die Referenz des SOs weiter in die Inventarliste des Spielers.

2. Die Sache mit dem Dictionary ist mehr eine Idee dazu, wie z.B. gelöschte und wieder neu erstellte SOs über einen Key wieder referenziert werden könnten. (Die Items des Spielers werden gespeichert und falls ich was vergurke kann ein Item mit einer fehlenden Referenz diese wieder über den Key suchen.)

3. -> Nun der vermutlich in diesem Moment wichtigste Punkt.

Erstmals noch genauer zum Spiel. Ich möchte eine App entwickeln in welcher die Spieler sich im Store Items kaufen können. Dabei sollen neue Items der Datenbank hinzugefügt werden können, damit die Spieler entweder durch ein Update oder besser noch beim Start des Spieles die neuen Inhalte herunterladen können.

Dazu denke ich eignet sich eine "richtige" Datenbank vermutlich doch am besten so wie ich dich verstanden habe. Dabei frage ich mich was es dazu braucht, damit ich dann die Assets über eine solche Datenbank zur Verfügung stellen kann (Wie z.B. Bilder, 3D Modelle, Prefabs,...). Ich kenne nur ein wenig MySQL von früher, aber da ging es mehr darum Werte wie "Ints" oder "Strings" zu speichern.

 

Ich hoffe ich habe nicht wieder nur die hälfte an Infos geschrieben die gebraucht werden. 😅

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 23 Minuten schrieb RiseBasti:

mit einer Liste, welche SO Referenzen beinhaltet (Also per Drag&Drop in die Liste gezogen auf dem GO, SOs sind ja Ref-Type). Diese SOs sind irgendwo unter dem "Assets" Ordner abgelegt. Der Store lädt aus dieser Liste alle Items, welche gekauft werden können (Erstellt UI Elemente mit den daten der SOs). Auf meine Liste greift also nur der Store zu.

Ja, das ergibt Sinn. Und es ist genau dieser Fall, wo Drag&Drop eher nervig ist, als Vorteile zu bieten. Benutzt du Drag&Drop denn noch irgendwo zum Design (so wie "welche Kiste dropt welchen Loot") oder nur in dieser "Fleißarbeit"-Art? Wenn letzteres, würde ich tatsächlich eher von SOs weg gehen in diesem Fall.

Was ich jetzt als "Datenbank" bezeichnet habe, muss nicht unbedingt mit einer Datenbank-Engine sein. Da kann man sich jetzt über die Begrifflichkeiten streiten, aber an sich reicht da auch eine einfache XML/Json/YAML-Datei.

So könnte Json aussehen:

{
  "items":
  [
    "flask_red": { "name"="Red Flask", "price"="100" },
    "flask_green": { "name"="Green Flask", "price"="150" },
    "sword": { "name"="Sword", "price"="300" }
  ]
}

Das wäre dasselbe in XML:

<items>
  <item id="flask_red">
    <name>Red Flask</name>
    <price>100</price>
  </item>
  <item id="flask_green">
    <name>Green Flask</name>
    <price>150</price>
  </item>
  <item id="sword">
    <name>Sword</name>
    <price>300</price>
  </item>
</items>

Und dann packst du das in deine Assets und liest es irgendwie aus. XML kann C# von alleine, für Json hat Unity selber etwas rudimentäres, sonst gibt's auch immer fertige Bibliotheken für sowas. Du lässt das dann laden und kriegst ein Array voller Objekte zurück. Da ist also kein SQL oder so nötig, du kannst dann einfach direkt mit den deserialisierten Objekten arbeiten.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Zitat

Benutzt du Drag&Drop denn noch irgendwo zum Design (so wie "welche Kiste dropt welchen Loot") oder nur in dieser "Fleißarbeit"-Art?

Für den Loot in den Kisten denke ich eher an einen Algorithmus, welcher die Kisten befüllt. Somit kann ich Drag&Drop nicht mehr wirklich brauchen.

 

Wegen dem Speichern der Daten fehlt mir aber noch das "gewisse Etwas". Ich kann somit ja gewisse Variablen für Items abspeichern, aber wie mache ich das dann mit meinen Bildern, 3D-Modellen und Prefabs für die Items? Diese müsste ich irgendwie abspeichern und möglichst auch so, dass ich jederzeit neuen Content für die Items über einen Download hinzufügen kann. Und auf diese muss ich dann wiederum zugreifen können.

Ich glaube der Umgang und die Möglichkeiten mit Dateien zu arbeiten ist somit mein grösstes Problem momentan.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 8 Stunden schrieb RiseBasti:

Somit kann ich Drag&Drop nicht mehr wirklich brauchen.

Naja, man kann auch wunderbar Loot Tables mit Drag&Drop machen ;)

vor 8 Stunden schrieb RiseBasti:

Wegen dem Speichern der Daten fehlt mir aber noch das "gewisse Etwas". Ich kann somit ja gewisse Variablen für Items abspeichern, aber wie mache ich das dann mit meinen Bildern, 3D-Modellen und Prefabs für die Items?

Ja, das ist ein Problem. Sobald du zu irgendeinem Teil die Unity-Welt verlässt, musst du halt ein bisschen eklige Sachen machen. Für diese Brücke zwischen Test-Datei und Unity-Referenzen brauchst du leider halt Strings. Du kannst also in deine Datei zum Beispiel sowas packen:

<item id="flask_red">
  <name>Red Flask</name>
  <price>100</price>
  <prefab>flask</prefab>
 </item>

oder du nimmst direkt die Id - wie es halt besser passt. Dann kannst du deine Prefabs z.B. in den Resources-Ordner packen und dann wird halt dein Prefab-Id-String in Resources.Load geschmissen. Um das einzudämmen, dass da jederzeit was schief gehen kann, kannst du einen Edit Mode-Test schreiben, der einfach mal checkt, ob alle Prefabs, die in der Datei erwähnt werden, auch existieren.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...