Grafiken laden (Verhalten)

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Grafiken laden (Verhalten)

Beitrag von BeRsErKeR »

Hallo ich arbeite gerade an einem kleinen Spielchen mit Items und so Sachen. Nun ist es so, dass jede Iteminstanz (von mir aus auch andere Instanzen die Grafiken nutzen wie GUI-Elemente etc) eine bestimmte Grafik haben. Instanzen gleichen Typs natürlich auch die gleichen Grafiken. Nun will man ja nicht Grafiken doppelt im Speicher haben.

Nun bieten sich mir folgende 3 Möglichkeiten.

1. Ich lade ALLE Grafiken zu Beginn und lege sie irgendwo zentral ab. Items und andere Objekte können sich dann über eine ID oder einen Namen ihre Grafik holen oder die jeweilige Grafik anzeigen lassen.

Vorteile:

- Man lädt nur einmal (am besten beim Programmstart) und vermeidet so das Laden zwischendurch.

Nachteile:

- Man lädt eventuell zu viel (vielleicht werden im Spiel nicht alle Items benutzt/angezeigt)
- Man muss irgendwie festhalten welche Grafiken existieren bzw. nötig sind (mit IDs). Könnte man vielleicht auch über Dateinamen und eine Art FindFirstFile/FindNextFile lösen.
- Viel Speicherverbrauch bei vielen Grafiken


2. Ich lade die jeweilige Grafik dann wenn ich sie das erste mal benötige und lasse sie dann im Speicher. Bei späterer Benutzung wird einfach wieder auf die gleiche Grafik verwiesen.

Vorteile:

- Man lädt nur die Grafiken die man wirklich benutzt
- Man lädt beim Programmstart nicht so lange

Nachteile:

- Man muss zwischendurch Laden
- Viel Speicherverbrauch bei langen Spielen und vielen Grafiken


3. Ich lade die jeweilige Grafik dann wenn ich sie benötige und gebe sie frei sobald ich sie nicht mehr benötige. Bei späterer Benutzung lade ich sie erneut.


Vorteile:

- Man lädt nur die Grafiken die man wirklich benutzt
- Man minimiert den Speicherverbrauch
- Man lädt beim Programmstart nicht so lange

Nachteile:

- Man muss feststellen wann eine Grafik nicht mehr gebraucht wird (ReferenceCounting etc)
- Man muss im worst-case dennoch oft zwischendurch nachladen



Ich würde gern eure Meinungen dazu hören. Ich tendiere eher zu Variante 1 oder 2.

In meinem konkreten Fall sollten die Daten nicht sonderlich groß werden allerdings kann man das ganze ja auch auf andere Daten übertragen (Sounds, etc).

Zu Bedenken ist auch noch dass ich einen Mod-Support anbieten möchte. Modder können dann beliebig viele eigene Grafiken nutzen. Ggf. müssten sie bei Variante 1 dann z.B. eine Grafikdatenbank etc mitpflegen.


Danke schonmal.
Ohne Input kein Output.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Grafiken laden (Verhalten)

Beitrag von dot »

Ich würde mal sagen das hängt von der konkreten Anwendung ab. Kannst du denn mit dem Speicherverbrauch leben? Du könntest auch dein Design so auslegen, dass du Variante 3 nachrüsten kannst wenn es sich als notwendig erweisen sollte...
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Grafiken laden (Verhalten)

Beitrag von BeRsErKeR »

Nun ja für das Basisspiel wird es wohl nicht all zu viele Grafiken und andere Daten geben. Wobei man ja nicht unbedingt weiß wie man das ganze in ferner Zukunft noch erweitern wird. Allerdings handelt es sich nur um 32x32 Pixel PNGs, daher sollte es auch mit einigen hundert Grafiken keine Probleme geben. Wie gesagt hat das Spiel Mod-Support. Wieviele Daten ein Mod hat ist also nicht vorhersehbar. Allerdings gehe ich auch nicht unbedingt von langen Ladezeiten bei solch kleinen Grafiken aus, wobei wohl er der Zugriff auf die Festplatte im Allgemeinen das Problem (wenn es eins sein sollte) ist. Prinzipiell sollten also eigentlich alle 3 Varianten aus Performancesicht machbar sein.

Ich mache mir also nicht so viel Sorgen um Speichermangel. Ich bin mir ziemlich sicher, dass selbst wenn alle Grafiken im Speicher sind maximal ein paar MB Arbeitsspeicher gefressen werden. Daher tendiere ich schon fast zu Variante 1. Wie gesagt brauche ich dann aber auch eine Art Zuordnung. Klar kennen Items etc mindestens die ID oder den (Datei-)Namen der Grafik aber ich muss sie ja zu Beginn schon laden und da gibt es noch keine Items bzw. ich will nicht unbedingt irgendwen bei allen Items nach den Dateinamen nachfragen lassen. Eine Datenbank mit Zuordnungen von ID zu Dateiname, Name zu Dateiname oder Item (etc) zu Dateiname muss also in irgendeiner Form schon vorhanden sein. Und da befürchte ich, dass es einfach für Modder zu aufwendig wird da noch sowas mit zu pflegen.

Man könnte natürlich auch erstmal alle Daten, die Refernzen auf Grafiken besitzen laden und davon abhängig die Grafiken laden. Allerdings muss da wieder ein "Objekt" alle Objekte kennen, die solche Referenzen haben könnten oder jedes dieser Objekte eine Instanz des Grafikverwaltungs-Objekts mitführen. Wobei das bei den anderen Varianten wahrscheinlich auch irgendwie sein müsste.

Vielleicht einfach eine globale std::map<std::string, InsertGraphicClassHere>? Und einfach die Zuordnung Dateiname -> Grafik? Dann wäre Variante 2 ziemlich bequem und ohne zusätzliche Logik realisiertbar.

Beim Vergleich von Variante 2 und 3 denke ich fast, dass Variante 3 nicht wirklich sinnvoll ist, wenn man mal davon ausgeht, dass einem der Speicher nicht ausgeht. Und davon gehe ich aus. Da brauch ich auch kein Referenzcounting oder ähnliches.

Mich würde übrigens auch interessieren wie ihr das bei euren Projekten so handhabt. Dann sehe ich vielleicht auch wo die einzelnen Varianten sinnvoll sind oder ihr könnt mir sogar andere Varianten aufzeigen.

dot hat geschrieben:Du könntest auch dein Design so auslegen, dass du Variante 3 nachrüsten kannst wenn es sich als notwendig erweisen sollte...
Du meinst ich nutze Variant 2 und wenn der Platz knapp wird bzw. ein Limit überschreitet gebe ich ungenutze Grafiken frei? Klingt ja fast wie ein Cache. Das ist interessant. In gewissen Grenzen kann ich gut voraussagen, welche Grafiken oft benötigt werden (z.B. Tilegrafiken, die immer fest und in begrenzter Anzahl vorhanden sind). Bei Item-Grafiken ist das schon schwieriger, gerade auch weil Modder beliebige eigene Items erstellen können. Ich werde über diese Idee aber mal weiter nachdenken.

Allerdings löst sie nicht unbedingt die Tatsache, die mich eigentlich an Variante 2 und 3 stört bzw. wo ich mir ein wenig Sorgen mache. Und das sind halt kleinere Wartezeiten beim Laden der Grafiken zur Laufzeit des Spiels. Das hätte man bei Variante 1 halt nicht, weshalb ich sie in all meinen bisherigen Projekten verwendet habe. Da hatte ich allerdings mitunter auch recht große Datenbanken die ich pflegen musste und das ist irgendwie auch nicht das Wahre.
Zuletzt geändert von BeRsErKeR am 22.12.2011, 00:47, insgesamt 1-mal geändert.
Ohne Input kein Output.
EyDu
Establishment
Beiträge: 101
Registriert: 24.08.2002, 18:52
Wohnort: Berlin
Kontaktdaten:

Re: Grafiken laden (Verhalten)

Beitrag von EyDu »

Hallo,

warum bist du dir "ziemlich sicher", dass alle Daten in den Speicher passen? Das kann man doch leicht ausrechnen. Bei 32x32 Pixeln mit 4 Bytes pro Pixel brauchst du pro Grafik 4096 Bytes. Selbst wenn du nur 128 MB zur Verfügung hättest, dann könntest du dort locker über 30000 Grafiken reinschubsen.

Ich würde das Laden erstmal so einfach wie möglich machen. Wenn du das Interface dazu flexibel genug hälts, dann kannst du später immer noch optimieren.

Sebastian
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Grafiken laden (Verhalten)

Beitrag von BeRsErKeR »

Die beiden hauptsächlichen Sachen, die mich zur Zeit schwanken lassen sind eigentlich folgende:

- Delays durch Laden der Grafiken während des Spiels (Variante 2 und 3)
- Aufwand durch feste Zuordnung von Grafiken (Variante 1)

Beim Speicherbedarf hast du natürlich recht. Das sehe ich nicht wirklich kritisch. Bei der aktuellen Version beträgt die Gesamtgröße aller Bilder knapp 1 MB (allerdings komprimiert). Aber selbst unkomprimiert wird das nicht wirklich was ausmachen. 5 Grafiken a 48x48 Pixel, 34 Grafiken a 32x32 Pixel und bislang 5 GUI-Grafiken, die geringfügig größer sind. Den Speicherverbrauch können wir also außen vor lassen. Ich hatte ihn auch eher der Vollständigkeit halber angegeben.


Ich halte für mich wohl erstmal Variante 2 fest. Die Cache-Variante ist laut oben genannten Tatsachen nicht wirklich nötig, aber die Idee finde ich recht interessant.


Danke erstmal für die Antworten. Aber schreibt ruhig noch weitere Anmerkungen wenn euch was dazu einfällt. Z.B. würde mich interessieren wie man Variante 1 ohne eine Datenbank (welcher Form auch immer) recht einfach realisieren könnte. Heute bau ich eh nicht mehr am Code rum. ;)

Das Thema interessiert mich übrigens auch im Allgemeinen, also nicht nur auf mein Projekt bezogen. Wie gesagt habe ich bislang immer Variante 1 genutzt aber war nicht wirklich glücklich damit. Ich würde für die Zukunft gern ein schönes Verfahren haben, was ich nutzen kann. Wir könnten es allerdings auf kleinere Hobbyprojekte mit 2D-Pixelgrafik beschränken.


EDIT: Ah ich habe etwas ganz vergessen. Und zwar einen weiteren entscheidenen Nachteil von Variante 2 und 3. Und zwar stellen diese beiden Verfahren erst während des Spiels fest wenn z.B. eine Grafik fehlt. Variante 1 kann das beim Programmstart bereits prüfen. Eine Fehlermeldung mit resultierendem Spielende oder der Anzeige einer Dummy-Grafik ist auch nicht unbedingt eine schöne Sache. Und ein separater Check für die Grafiken am Anfang würde ja dann schon genauso viel Aufwand bedeuten wie Variante 1 mit sich bringt.

Hierbei wären auch Ideen interessant, wie man sowas elegant abfangen könnte, anstatt einer "Aus die Maus. Das Licht geht aus!"-MessageBox.
Ohne Input kein Output.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Grafiken laden (Verhalten)

Beitrag von dot »

BeRsErKeR hat geschrieben:Allerdings gehe ich auch nicht unbedingt von langen Ladezeiten bei solch kleinen Grafiken aus, wobei wohl er der Zugriff auf die Festplatte im Allgemeinen das Problem (wenn es eins sein sollte) ist.
Der Zugriff auf die Platte ist wohl in der Regel das Problem. Ich kann dazu jetzt keine konkreten Erfahrungswerte nennen, aber ich denk ein Atlas wäre hier wohl, auch was das Laden angeht, effizienter als viele kleine Dateien. Denn bei vielen derart kleinen Dateien würd ich mir erwarten, dass der ganze Overhead durch das viele Öffnen, Schließen, Dekomprimieren sehr wesentlich werden kann. Ist natürlich die Frage inwiefern das eine Rolle spielt.
Ein Atlas wäre auf jeden Fall auch potentiell wesentlich besser was die Performance beim Rendern anbelangt.
BeRsErKeR hat geschrieben:Eine Datenbank mit Zuordnungen von ID zu Dateiname, Name zu Dateiname oder Item (etc) zu Dateiname muss also in irgendeiner Form schon vorhanden sein. Und da befürchte ich, dass es einfach für Modder zu aufwendig wird da noch sowas mit zu pflegen.
Mir ist immer noch etwas schleierhaft was genau eigentlich das Problem mit dem Modding sein soll.
BeRsErKeR hat geschrieben:Man könnte natürlich auch erstmal alle Daten, die Refernzen auf Grafiken besitzen laden und davon abhängig die Grafiken laden. Allerdings muss da wieder ein "Objekt" alle Objekte kennen, die solche Referenzen haben könnten oder jedes dieser Objekte eine Instanz des Grafikverwaltungs-Objekts mitführen. Wobei das bei den anderen Varianten wahrscheinlich auch irgendwie sein müsste.
Wieso muss da jedes Objekt alle anderen kennen? Und die "Grafikverwaltung" muss doch nur dort, wo die Objekte erzeugt werden, bekannt sein!?
BeRsErKeR hat geschrieben:Vielleicht einfach eine globale std::map<std::string, InsertGraphicClassHere>? Und einfach die Zuordnung Dateiname -> Grafik? Dann wäre Variante 2 ziemlich bequem und ohne zusätzliche Logik realisiertbar.
Prinzipiell eine Lösung, wobei ich sowas auf jeden Fall in einer Klasse kapseln und auf keinen Fall global machen würde.
BeRsErKeR hat geschrieben:Beim Vergleich von Variante 2 und 3 denke ich fast, dass Variante 3 nicht wirklich sinnvoll ist, wenn man mal davon ausgeht, dass einem der Speicher nicht ausgeht. Und davon gehe ich aus. Da brauch ich auch kein Referenzcounting oder ähnliches.
Naja, das Problem ist nur eben, dass Variante 3 nachrüsten, sollte einem irgendwann mal doch der Speicher ausgehn, extrem viel Aufwand sein kann. Auf jeden Fall wesentlich mehr als es jetzt gleich vorzusehen...
BeRsErKeR hat geschrieben:
dot hat geschrieben:Du könntest auch dein Design so auslegen, dass du Variante 3 nachrüsten kannst wenn es sich als notwendig erweisen sollte...
Du meinst ich nutze Variant 2 und wenn der Platz knapp wird bzw. ein Limit überschreitet gebe ich ungenutze Grafiken frei? Klingt ja fast wie ein Cache. Das ist interessant. In gewissen Grenzen kann ich gut voraussagen, welche Grafiken oft benötigt werden (z.B. Tilegrafiken, die immer fest und in begrenzter Anzahl vorhanden sind). Bei Item-Grafiken ist das schon schwieriger, gerade auch weil Modder beliebige eigene Items erstellen können. Ich werde über diese Idee aber mal weiter nachdenken.
Ich dachte unter anderem auch an eine Art Cache, ja, denn Variante 3 muss nicht unbedingt Reference-Counting bedeuten.
Vor allem dachte ich daran, das Interface der jeweiligen "Grafikverwaltung" einfach mal so zu bauen als wäre Variante 3 Implementiert, auch wenn dies noch nicht tatsächlich der Fall ist. Dann kann man es nämlich einfach nachrüsten, sollte mal der Bedarf gegeben sein, denn der ganze restliche Code tut bereits so als wär es da.
Aber wie du selbst schon bemerkt hast, zeichnet sich eines ab und das ist imo der wesentlichste Punkt von allen: Es gibt keinen "one size fits all approach". Je nachdem von welcher Komponente wir reden, wollen wir andere Strategien, die mehr spezielle Information benötigen, als ein einzelner globaler Manager haben kann. Ich würde mich also nicht darauf fixieren, dass es unbedingt genau nur eine Stelle geben muss die sämtliche Grafiken verwaltet. Und spätestens an diesem Punkt sind wir heilfroh, das dass Grafikmanagement doch keine globale Variable ist :P
BeRsErKeR hat geschrieben:Allerdings löst sie nicht unbedingt die Tatsache, die mich eigentlich an Variante 2 und 3 stört bzw. wo ich mir ein wenig Sorgen mache. Und das sind halt kleinere Wartezeiten beim Laden der Grafiken zur Laufzeit des Spiels. Das hätte man bei Variante 1 halt nicht, weshalb ich sie in all meinen bisherigen Projekten verwendet habe. Da hatte ich allerdings mitunter auch recht große Datenbanken die ich pflegen musste und das ist irgendwie auch nicht das Wahre.
Naja, große Datenbanken sind jetzt eine Folge einer großen Anzahl an Grafiken und haben jetzt nicht wirklich was damit zu tun, nach welcher Strategie das Laden der Grafiken ablauft, oder?
Was die Wartezeiten angeht: Du darfst eine Grafik natürlich nicht immer erst dann laden wenn sie schon benötigt wird. Du wirst eine Heuristik brauchen die dir sagt, was für Grafiken demnächst potentiell benötigt werden und kannst dann schonmal anfangen die nebenher zu laden, damit sie dann, wenn sie wirklich benötigt werden, verfügbar sind.
Dabei könnte nun auch eine Art Cache interessant werden. Man könnte eine oder mehrere große Surfaces allokieren, in denen dann einfach dynamisch Platz reserviert und wieder freigegeben wird um die jeweils gerade benötigten Grafiken unterzubringen. Eine Art Heap für Grafiken sozusagen. Hat den Vorteil, dass man auch automatisch eine Art Atlas erhält. Ich hab sowas im Moment in meinem Font-Rendering im Einsatz und es funktioniert ganz wunderbar.
Anstatt es voll dynamisch zu machen, könnte man sich auch überlegen, einfach für jede Region der Map so einen Atlas vorzuberechnen und in der Map zu speichern...
BeRsErKeR hat geschrieben:EDIT: Ah ich habe etwas ganz vergessen. Und zwar einen weiteren entscheidenen Nachteil von Variante 2 und 3. Und zwar stellen diese beiden Verfahren erst während des Spiels fest wenn z.B. eine Grafik fehlt. Variante 1 kann das beim Programmstart bereits prüfen.
Stimmt. Aber:
BeRsErKeR hat geschrieben:Eine Fehlermeldung mit resultierendem Spielende oder der Anzeige einer Dummy-Grafik ist auch nicht unbedingt eine schöne Sache.
Also mir ist eine dummy Grafik lieber als ich kann den Level überhaupt nicht spielen ;)
BeRsErKeR hat geschrieben:Und ein separater Check für die Grafiken am Anfang würde ja dann schon genauso viel Aufwand bedeuten wie Variante 1 mit sich bringt.
Wieso, du musst ja nur checken ob alle referenzierten Grafiken voraussichtlich geladen werden können und sie nicht schon tatsächlich alle laden.

Ich würde mir, wie gesagt, allerdings überlegen ob ich wirklich alle Grafiken gleich behandeln kann oder nicht doch je nach Art der Grafik verschiedene Strategien brauch. Die GUI Grafiken sind z.B. sicherlich essentiell für die Funktion des Spiels an sich, die werden die ganze Zeit über gebraucht und wenn die fehlen bzw. nicht geladen werden können, dann ist Beenden mit Fehlermeldung imo die einzige sinnvolle Reaktion. Aber von den Texturen in nem Level, brauch ich immer nur die, die gerade potentiell irgendwo zu sehen sind und wenn irgendwo mal eine Textur fehlt, dann ist die dummy Grafik durchaus ein gangbarer Weg. Wenn du mich fragst hat die sogar wesentliche Vorteile: Ich kann eben spielen auch wenn was fehlt. Das kann vor allem auch bei der Entwicklung des Spiels von Vorteil sein. Denn es werden nicht schon von Anfang an sämtliche Grafiken verfügbar sein. Trotzdem kann ich den Level schon bauen und spielen und ich seh an den Platzhaltern auch sofort wo noch was fehlt...

Fazit: Es gibt nicht die eine Strategie für alle Grafiken im Programm, verschiedene Komponenten werden ihre Grafiken selbst auf verschiedene Art managen wollen. Die GUI kann ohne ihre Grafiken nicht funktionieren, aber ein Level kommt ganz gut auch ohne die ein oder andere Textur zurecht. Ganz große Maps werden ihre Assets entsprechend einer Heuristik dynamisch laden und wieder freigeben wollen, während es für kleine Maps ausreichend sein wird, zu Beginn einfach alles zu laden.
Man muss sich eben von vornherein darüber im Klaren sein, was man will.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4878
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Grafiken laden (Verhalten)

Beitrag von Schrompf »

Bei den lächerlich kleinen Datenmengen halte ich jede Art von Laufzeit-Management für verschwendet. Da Du nach Erfahrungen gefragt hast:

Alle Grafiken von Splatter, abgesehen von Bildern in Zwischensequenzen, passen auf eine einzige 2048er. Nicht ganz "eine", weil es ja immer noch eine Normal Map und eine Relief/Specular-Map dazu gibt. Es gibt ein Rudel XML-Dateien, die Objekteigenschaften, Partikeleffekte, Tiles und sowas beschreiben. Und in diesen Beschreibungen werden die Grafiken oder Animations-Frames mittels <grafik quelle="bla.png" x="48" y="64" br="22" ho="22" /> spezifiziert. Die Verwaltung lädt alle so verwiesenen Grafiken, packt sie in einen Texturatlas und merkt sich alle Grafiken in einem vector. Doppelte Verweise werden über eine zusätzliche std::map beim Laden gefiltert, nach dem Laden reicht dann der vector und die Indizes, um hinein zu greifen.

Dinge, die zur Laufzeit ihre Grafik ändern müssen, können Einzelbilder und Animationssequenzen außerdem per Namen ansprechen. Es gibt z.B. pro Objekt eine Beschreibungsstruktur, die angelehnt an boost::property_tree beliebige Variablen enthalten kann. Ein Objekt besorgt sich seine Beschreibung im Konstruktor und zieht seine Parameter dann aus den Variablen in dieser Objektbeschreibung. Auch die Anims eines Objekts sind dann nur noch Variablen in der Beschreibungsstruktur, im Code enden sie als schlichte Vektoren aus Grafik-Indizes.

Das System klappt wie gesagt prima. Alle Grafiken, Partikel, Monster-Anims, Waffen usw. passen aktuell auf eine 2048er, die momentan zur Hälfte gefüllt ist. Und wenn das Ganze dann final ist, schreibe ich mir ein Binär-Format, um den Texturinhalt und alle Daten in einer Datei zu haben. Damit reduzieren sich die drei vier Sekunden aktuell auf eine Zehntel Sekunde vielleicht. Man könnte daraus auch ein cooles Abhängigkeitssystem basteln, was die Datei-Änderungszeitpunkte prüft, aber das war mir bisher zuviel Arbeit.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Grafiken laden (Verhalten)

Beitrag von BeRsErKeR »

dot hat geschrieben:
BeRsErKeR hat geschrieben:Allerdings gehe ich auch nicht unbedingt von langen Ladezeiten bei solch kleinen Grafiken aus, wobei wohl er der Zugriff auf die Festplatte im Allgemeinen das Problem (wenn es eins sein sollte) ist.
Der Zugriff auf die Platte ist wohl in der Regel das Problem. Ich kann dazu jetzt keine konkreten Erfahrungswerte nennen, aber ich denk ein Atlas wäre hier wohl, auch was das Laden angeht, effizienter als viele kleine Dateien. Denn bei vielen derart kleinen Dateien würd ich mir erwarten, dass der ganze Overhead durch das viele Öffnen, Schließen, Dekomprimieren sehr wesentlich werden kann. Ist natürlich die Frage inwiefern das eine Rolle spielt.
Ein Atlas wäre auf jeden Fall auch potentiell wesentlich besser was die Performance beim Rendern anbelangt.
Prinzipiell eine gute Idee. Für Tile-Grafiken und Item-Grafiken ist das definitiv eine gute Lösung.

dot hat geschrieben:
BeRsErKeR hat geschrieben:Eine Datenbank mit Zuordnungen von ID zu Dateiname, Name zu Dateiname oder Item (etc) zu Dateiname muss also in irgendeiner Form schon vorhanden sein. Und da befürchte ich, dass es einfach für Modder zu aufwendig wird da noch sowas mit zu pflegen.
Mir ist immer noch etwas schleierhaft was genau eigentlich das Problem mit dem Modding sein soll.
Bislang ist es so, dass man Items in einem simplen Scriptfile beschreibt. Eigentlich auch eine Art Datenbank. Dabei gibt man für einen ItemTyp auch eine Grafik an. Ich möchte einfach nicht, dass ein Modder nun noch eine weitere Datenbank für Grafiken anlegen muss und dann in der Item-Datenbank eventuell mit IDs oder Grafiknamen rumhantieren muss.

dot hat geschrieben:
BeRsErKeR hat geschrieben:Man könnte natürlich auch erstmal alle Daten, die Refernzen auf Grafiken besitzen laden und davon abhängig die Grafiken laden. Allerdings muss da wieder ein "Objekt" alle Objekte kennen, die solche Referenzen haben könnten oder jedes dieser Objekte eine Instanz des Grafikverwaltungs-Objekts mitführen. Wobei das bei den anderen Varianten wahrscheinlich auch irgendwie sein müsste.
Wieso muss da jedes Objekt alle anderen kennen? Und die "Grafikverwaltung" muss doch nur dort, wo die Objekte erzeugt werden, bekannt sein!?
Nicht jedes Objekt muss alle anderen kennen, sondern jedes Objekt muss die Grafikverwaltung kennen. Dein zweiter Satz stimmt nicht unbedingt. Für Items mag das stimmen, aber z.B. können Map-Tiles ihre Erscheinung ändern (Erde zu Gras z.B.). Da muss die Grafik dann gewechselt werden und woher weiß das Tile dann wo die Grafik im Speicher liegt wenn es keine Grafikverwaltung mehr gibt?

dot hat geschrieben:
BeRsErKeR hat geschrieben:Vielleicht einfach eine globale std::map<std::string, InsertGraphicClassHere>? Und einfach die Zuordnung Dateiname -> Grafik? Dann wäre Variante 2 ziemlich bequem und ohne zusätzliche Logik realisiertbar.
Prinzipiell eine Lösung, wobei ich sowas auf jeden Fall in einer Klasse kapseln und auf keinen Fall global machen würde.
Ob nun gekapselt oder nicht, um was globales komm ich nur drum rum, wenn ich die Grafikliste immer mit übergebe beim Erstellen von Objekten und auch bei Änderungen der Objekt-Grafik (wobei das auch irgendwo intern ausgelöst werden kann, also eine Referenz auf die Grafikliste auch in jedem Objekt speichern). Ob da was globales nicht einfacher und schneller ist? Zumal die Grafikliste nun mal was globales ist und vom logischen her nicht Teil eines anderen Objekts. Warum also nicht global? Diverse Fehlbenutzung könnte man ja durch die genannte Kapselung bzw. das Klasseninterface verhindern. Das Objekt als global anzulegen sehe ich aber nicht wirklich kritisch.

dot hat geschrieben:
BeRsErKeR hat geschrieben:
dot hat geschrieben:Du könntest auch dein Design so auslegen, dass du Variante 3 nachrüsten kannst wenn es sich als notwendig erweisen sollte...
Du meinst ich nutze Variant 2 und wenn der Platz knapp wird bzw. ein Limit überschreitet gebe ich ungenutze Grafiken frei? Klingt ja fast wie ein Cache. Das ist interessant. In gewissen Grenzen kann ich gut voraussagen, welche Grafiken oft benötigt werden (z.B. Tilegrafiken, die immer fest und in begrenzter Anzahl vorhanden sind). Bei Item-Grafiken ist das schon schwieriger, gerade auch weil Modder beliebige eigene Items erstellen können. Ich werde über diese Idee aber mal weiter nachdenken.
Ich dachte unter anderem auch an eine Art Cache, ja, denn Variante 3 muss nicht unbedingt Reference-Counting bedeuten.
Vor allem dachte ich daran, das Interface der jeweiligen "Grafikverwaltung" einfach mal so zu bauen als wäre Variante 3 Implementiert, auch wenn dies noch nicht tatsächlich der Fall ist. Dann kann man es nämlich einfach nachrüsten, sollte mal der Bedarf gegeben sein, denn der ganze restliche Code tut bereits so als wär es da.
Aber wie du selbst schon bemerkt hast, zeichnet sich eines ab und das ist imo der wesentlichste Punkt von allen: Es gibt keinen "one size fits all approach". Je nachdem von welcher Komponente wir reden, wollen wir andere Strategien, die mehr spezielle Information benötigen, als ein einzelner globaler Manager haben kann. Ich würde mich also nicht darauf fixieren, dass es unbedingt genau nur eine Stelle geben muss die sämtliche Grafiken verwaltet. Und spätestens an diesem Punkt sind wir heilfroh, das dass Grafikmanagement doch keine globale Variable ist :P
Wie gesagt denke ich dass Variante 1 für alle Grafiken durchaus möglich ist (was die Performance angeht). Daher würde ich mich auch auf wirklich einen Ansatz für all meine Grafiken beschränken. Das Projekt ist überschaubar und vom Design her können da keine neuen Grafikarten hinzukommen, die einen anderen Ansatz benötigen würden. Im Allgemeinen hast du natürlich recht.

dot hat geschrieben:
BeRsErKeR hat geschrieben:Allerdings löst sie nicht unbedingt die Tatsache, die mich eigentlich an Variante 2 und 3 stört bzw. wo ich mir ein wenig Sorgen mache. Und das sind halt kleinere Wartezeiten beim Laden der Grafiken zur Laufzeit des Spiels. Das hätte man bei Variante 1 halt nicht, weshalb ich sie in all meinen bisherigen Projekten verwendet habe. Da hatte ich allerdings mitunter auch recht große Datenbanken die ich pflegen musste und das ist irgendwie auch nicht das Wahre.
Naja, große Datenbanken sind jetzt eine Folge einer großen Anzahl an Grafiken und haben jetzt nicht wirklich was damit zu tun, nach welcher Strategie das Laden der Grafiken ablauft, oder?
Nunja ich habe aber schon eine Art Datenbank für die Items. Und die wissen welche Grafik sie brauchen. Da noch eine Extra-Datenbank für Grafiken zu machen ist halt in meinen Augen nicht nur Zusatzaufwand sondern auch in gewisser Weise redundant.
dot hat geschrieben:Was die Wartezeiten angeht: Du darfst eine Grafik natürlich nicht immer erst dann laden wenn sie schon benötigt wird. Du wirst eine Heuristik brauchen die dir sagt, was für Grafiken demnächst potentiell benötigt werden und kannst dann schonmal anfangen die nebenher zu laden, damit sie dann, wenn sie wirklich benötigt werden, verfügbar sind.
Dabei könnte nun auch eine Art Cache interessant werden. Man könnte eine oder mehrere große Surfaces allokieren, in denen dann einfach dynamisch Platz reserviert und wieder freigegeben wird um die jeweils gerade benötigten Grafiken unterzubringen. Eine Art Heap für Grafiken sozusagen. Hat den Vorteil, dass man auch automatisch eine Art Atlas erhält. Ich hab sowas im Moment in meinem Font-Rendering im Einsatz und es funktioniert ganz wunderbar.
Anstatt es voll dynamisch zu machen, könnte man sich auch überlegen, einfach für jede Region der Map so einen Atlas vorzuberechnen und in der Map zu speichern...
So komplex wollte ich das nicht machen. Wenn dann würde ich sie wirklich genau dann laden, wenn ich sie das erste mal anzeigen will bzw. wenn ein Objekt erstellt wird, welches diese benötigt.

dot hat geschrieben:
BeRsErKeR hat geschrieben:Und ein separater Check für die Grafiken am Anfang würde ja dann schon genauso viel Aufwand bedeuten wie Variante 1 mit sich bringt.
Wieso, du musst ja nur checken ob alle referenzierten Grafiken voraussichtlich geladen werden können und sie nicht schon tatsächlich alle laden.
Die Ladezeit am Anfang (bei Variante 1) ist mir relativ egal. Da läuft das Spiel nicht und wenn der Spieler da 1-2 Sekunden warten muss ist das kein Problem. Ich rede bei Variante 1 halt mehr über den Aufwand das Dateisystem zu durchforsten und ggf. eine Datenbank dazu zu nutzen.



Danke für die Antworten
Ohne Input kein Output.
Antworten