Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!
Werbeanzeige
Zitat von »"Laguna"«
Jedoch möchte/kann ich für die organisation nicht die std-Container benutzen, da ich mir einige zusätzliche Funktionen wünsche. So z.B. dass jedes Spielobjekt über seinen Bezeichner identifizierbar ist oder dass Objekte serialisiert werden können, für Speichern/Laden (und einige andere Sachen)
Zitat von »"Laguna"«
Mir erscheinen gerade zwei Wege sinnvoll: Entweder ich baue mir einer Vererbungshierarchie auf: "GameObject" und dies als Interface für eine Speicherung.
Alternativ eine Templateklasse, die diese Objekte verwaltet.
Gibt es darüber hinaus einen anderen Weg? Wie stehen die Meinungen zu diesen zwei Möglichkeiten? Wo seht ihr Vor- und Nachteile bzw Stolperfallen?
Zitat von »"Laguna"«
Meine Meinung dazu: Eine saubere Vererbungshierarchie incl Interfaces ist schön zu lesen. Auch lassen sich mit Factoryklassen alle Aspekte sehr schön verpacken und von Aussen sieht man nurnoch das, was man sehen soll.
Allerdings kann man sich damit auch recht schnell in Sackgassen manövrieren. Zusätzlich kommt einiges an Tipparbeit auf einen zu, sowie die Performanceeinbußen durch VTables.
Zitat von »"Laguna"«
Templates glänzen durch ihre Schlichtheit, eine gute Performance (durch Instancing zu Compilezeit, usw.), jedoch ist der Syntax oft kryptisch und für aussenstehende deutlich schwerer zu verstehen als ein Interface - Factory zusammenhang. Zusätzlich ist die Sichtbarkeit nicht so schön gelöst, wie bei Interfaces.
Zitat von »"Nexus"«
Was mich stört, ist der verbreitete Irrglaube, dass Objektorientierung und Abstraktion schlechtere Laufzeitverhältnisse implizieren. Virtuelle Funktionen sind zum Beispiel ein weiteres Schlagwort für Langsamkeit. Sehr selten denkt dabei jemand daran, dass auch auf tieferer Abstraktionsebene eine Auswahl zwischen verschiedenen Ablaufpfaden realisiert werden muss - ob das schlussendlich if, switch, selbst gebaute Funktionszeiger-Sprungtabellen oder gleich "richtige" virtuelle Funktionen sind, spielt im Allgemeinen keine grosser Rolle mehr.
Zitat von »"dot"«
Mit std::map kannst du deine Objekte über Bezeichner ansprechen und das Serialisieren müssen sowieso die Objekte implementieren...
Zitat von »"dot"«
Wie schon gesagt wurde: Templates und Vererbung schließen sich nicht aus. ...
Wie gesagt, es wird so oder so auf eine Wrapper-klasse hinauslaufen. Wie diese jedoch am geschicktesten aufzubauen ist, ist meine Frage. Also, ob ich Interfaceklassen speichere oder eben eine Templateklasse erstelle, die mir die entsprechenden Objekte hält.Zitat von »"dot"«
Du kannst dir z.B. auch einen Objektcontainer als template basteln der intern eine std::map verwendet und dir ein paar Komfortfunktionen wie du sie haben willst bietet...
Zitat von »"Laguna"«
Eine Map möchte ich deshalb nicht verwenden, da die Objekte selbst schon die Bezeichner enthalten, was meiner Meinung nach in einer OOP-Umgebung auch Sinn macht.
Zitat von »"Laguna"«
Wie gesagt, es wird so oder so auf eine Wrapper-klasse hinauslaufen. Wie diese jedoch am geschicktesten aufzubauen ist, ist meine Frage. Also, ob ich Interfaceklassen speichere oder eben eine Templateklasse erstelle, die mir die entsprechenden Objekte hält.
Zitat von »"Laguna"«
Ich persönlich stelle mir "prüfe alle Elemente in Liste 1 gegen alle Elemente in Liste 2" deutlich einfacher vor, als "Prüfe alle Elemente in einer Liste auf ihren typ und rückwirkend auf sämtliche Kombinationen mit möglichen anderen Typen"
Siehe hier
Gut, genau so habe ich mir das vorgestellt. Es scheint so, als ob mein Entwurf gar nicht so schlecht passen würde. Sowas wie "Objekt" könntest du als Basisklasse nehmen, von dem du dann z.B. kollidierbare Objekte ableitest, diese werden wiederum in Gegner, Spieler, Projektile unterteilt (so habe ich das in einem Jump'n'Run gemacht).Zitat von »"Laguna"«
Ich möchte Listen folgender Objekte anlegen (Auswahl):
- Einfache graphische Details, wie Grasbüschel oder Flares
- Hindernisse, Mauern, Steine, die mit bestimmten Objekten Kollision verursachen
- Schüsse (Kugeln), die Spieler wie Gegner verletzen können
- Charaktere
* Den Spieler
* NPCs (laufen, reden, handeln, simple AI)
* Gegner (laufen, schiessen, sterben, AI)
Das sehen zwar nicht alle gleich, aber ich persönlich finde es wichtig, Grafik und Logik zu trennen. Das bedeutet, ein Gegner weiss nicht, zu welchem Fenster er gehört oder wie er gezeichnet wird. Für jene Aktionen wären separate Klassen zuständig. Einerseits werden dann grafik-spezifische Dinge an einem Ort geregelt, andererseits erhältst du durch die Unabhängigkeit beider Komponenten zusätzliche Flexibilität. Du kannst eine davon austauschen, ohne die andere anzutasten. Auch die Zentralität hat einen Vorteil: Du kannst zum Beispiel an einem Ort alle Grafikaufrufe unterbrechen, oder irgendeine spezielle Operation für alle grafischen Objekte einführen.Zitat von »"Laguna"«
Im Grunde sähe die Schnittstelle (Interface oder Template) wie folgt aus:
- Fester und eindeutiger Name, zusätzlich evtl. Typ des Objekts (wahlweise Typetraits, String, ClassID, UUID)
- Input
- Update
- Draw
Da hast du absolut Recht. Wenn du bereits zur Compilezeit Typen trennen kannst und dadurch Vorteile erhältst, dann nutze die Möglichkeit! Denn Abstraktion dient dazu, mehrere ähnliche Objekte einheitlich zu behandeln. Wenn diese darauf hinausläuft, dass wieder Fallunterscheidungen ins Spiel kommen, hat man das Prinzip nicht ganz verstanden.Zitat von »"Laguna"«
Ich persönlich stelle mir "prüfe alle Elemente in Liste 1 gegen alle Elemente in Liste 2" deutlich einfacher vor, als "Prüfe alle Elemente in einer Liste auf ihren typ und rückwirkend auf sämtliche Kombinationen mit möglichen anderen Typen"
Werbeanzeige