Organisation von Spielobjekten
-
dot schrieb:
Mehrere Objekte verwenden die selbe Textur bzw. den selben Animator. Das wäre unter Umständen vielleicht eine notwendige, aber ganz sicher keine hinreichende Bedingung für shared Ownership.
Überleg dir nochmal, ob dir das tatsächlich als die richtige Lösung, oder nicht doch nur als die einfache Lösung erscheint...
Hint: Wieso genau sollte bei der Zerstörung eines GameObject auch dessen Textur oder Animator zerstört werden?
Naja, da ich mir offen halten will etwas Programmiertes auch mal auf einem Smartphone oä. mit wenig RAM laufen zu lassen, versuche ich im vorhinein die Möglichkeit offen zu halten oft ungenutzte Resourcen freizugeben.
So wie es jetzt ist kann ich meinen ganzen Texturencache bzw einzelne Texturenklassen mit einer einzigen Zeile Code freigeben ohne dass es irgendwo dangling ponter gibt. Würde ich normale Referenzen auf das geladene Texturobjekt haben, müsste ich beim Löschen jeder Textur aus dem Cache eine Garantie geben, dass sie nirgendwo sonst verwendet wird. Und da nicht nur die Spielobjekte die Texturen verwenden ist das unglaublich umständlich und gewinnen würde ich dabei auch nichts. (shared_ptr ist in diesem Kontext ja praktisch kostenlos)Deswegen gefällt mir die Logik: Ist eine Textur nicht mehr im Cache und wird sie von keinem Objekt mehr verwendet => Ab in die Tonne damit.
....
Ansonsten bin ich durch diesen Blogpost ( http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/ ) mittlerweile auch der Meinung dass soetwas eine recht sinnvolle Sache ist. Vor allem gefällt mir die Idee dass so der Renderer sehr leicht austauschbar ist.
Jetzt heißt es brainstormen wie ich das einigermaßen performant und mit möglichst wenig dynamisch angefordertem Speicher hinbekomme.
-
Ethon schrieb:
Naja, da ich mir offen halten will etwas Programmiertes auch mal auf einem Smartphone oä. mit wenig RAM laufen zu lassen, versuche ich im vorhinein die Möglichkeit offen zu halten oft ungenutzte Resourcen freizugeben.
Wenn du das willst, machst du dir mit std::shard_ptr das Leben schwer, denn:
Ethon schrieb:
So wie es jetzt ist kann ich meinen ganzen Texturencache bzw einzelne Texturenklassen mit einer einzigen Zeile Code freigeben [...]
Nope, kannst du nicht. Deine Ressource wird erst freigegeben, wenn der letzte shared_ptr darauf zerstört wird...
Ethon schrieb:
[...] ohne dass es irgendwo dangling ponter gibt.
Wie genau funktioniert das? Wenn du deinen "Texturenchace" "freigibst", sind die Texturen immer noch alle da, du weißt lediglich nicht mehr wirklich, dass sie da sind. Wenn dann einer kommt und eine Textur, die eigentlich noch da wäre, anfordert, dann lädst du sie gleich noch ein zweites Mal. Man könnte drüber Diskutieren, ob da nicht gerade eine völlig neue Art zu Leaken entdeckt hast, shared_ptr macht's möglich...
Ethon schrieb:
Würde ich normale Referenzen auf das geladene Texturobjekt haben, müsste ich beim Löschen jeder Textur aus dem Cache eine Garantie geben, dass sie nirgendwo sonst verwendet wird.
Jap, oder mit anderen Worten: Du müsstest dafür sorgen, dass Texturen erst aus dem Cache verschwinden, wenn sie nirgendwo mehr verwendet werden. Mit shared_ptr dagegen, müsstest du genau das Gleiche tun...
Shared Ownership führt schnell zu einem extrem komplizierten, undurchsichtigen, unvorhersehbaren und nur schwer beherrschbaren System...
-
Okay, danke, ich verstehe. Ich denke ein Smartpointer, der mir verrät wie viele Referenzen existieren, wäre die Lösung? Dann könnte ich im Cache auf das Löschen verzichten falls der größer 1 ist ...
Hab mal ein bischen Grundlegend herumgespielt, hier mal heruntergebrochen wie ich das mit dem Entitysystem umsetzen würde ... okay, oder hab ich da etwas falsch verstanden?
struct Component { inline virtual std::type_index id() { return std::type_index(typeid(*this)); } }; struct Position : public Component { static std::type_index const ID = std::type_index(typeid(Position)); float x, y; }; Component* findComponent(std::type_index const& component) { auto result = components.find(component); if(result == components.end()) return nullptr; return result->second; } void MovementSystem::move() { for(Entity : entities) { Component* component = findComponentInEntity(entity, Position.ID); if(component) doStuff(static_cast<Position*>(component)); } }
-
Ich habe das bei mir so geregelt, dass der shared_ptr einen deleter bekommt, der die Ressource beim Manager austrägt und der Manager hat nur einen weak_ptr auf die Ressource. So bestimmen die Clients über die Lebenszeit, aber wenn die Ressource "lebt", kann der Manager drankommen.