Statische Klassenvariablen oder doch globale?


  • Administrator

    Nexus schrieb:

    Naja, bei meinem Spiel gibt es für die einzelnen Klassen (Gegner, Tiles, ...) eben Attribute, die für alle Instanzen gelten. Das sind meistens Konstanten. Teilweise habe ich auch kleine Datensätze für die Eigenschaften unterschiedlicher Typen (z.B. Geschwindigkeit, Feuerrate, Grafik-Rechteck der Gegner) in einem statisch-konstanten tr1::array , also eine Art Tabelle.

    Solche Daten lege ich in eine Managerklasse. Diese Klasse ist dann für die Verwaltung der Attribute verantwortlich. Die anderen Objekte referenzieren dann über Zeiger oder IDs auf die entsprechenden Attribute. So kann ich jederzeit auf einfache Art und Weise die Attribute von anderen Orten holen und/oder modifizieren. Meistens ist diese Managerklasse dann auch ein Singleton.

    Das praktische daran ist zum Beispiel das Laden (und teilweise Speichern) der Attribute. Für diese Aufgabe gibt es eine weitere Klasse, welche dann die geladenen Attribute der Managerklasse übergibt. So kann man zum Beispiel Attribute aus einem XML File laden lassen oder allenfalls auch andere Formate zulassen.

    Grüssli



  • Mit der Zeit könnte ich das auch überlegen, aber momentan habe ich die Daten sowieso hardcoded im Code (es sind nicht allzu viele, und ein Auslagern in Dateien würde nur zu mehr Aufwand, unnötigen Fehlerquellen und einer Flexibilität, die man nicht braucht, führen). Diese Daten sind auch in einer gemeinsamen .cpp-Datei definiert - die Frage ist also nur, wo die Deklaration hin soll.


  • Administrator

    Nexus schrieb:

    Mit der Zeit könnte ich das auch überlegen, aber momentan habe ich die Daten sowieso hardcoded im Code (es sind nicht allzu viele, und ein Auslagern in Dateien würde nur zu mehr Aufwand, unnötigen Fehlerquellen und einer Flexibilität, die man nicht braucht, führen). Diese Daten sind auch in einer gemeinsamen .cpp-Datei definiert - die Frage ist also nur, wo die Deklaration hin soll.

    Ich drück dir die Daumen, dass dir nicht sowas passiert wie bei mir:
    3 Leute und ich haben ein Netzwerkspiel entwickelt für die Uni. Die Einheiten waren auch Hardcoded. Das war auch kein Problem, da wir nur 4 Einheiten reingesetzt haben. Dies reichte völlig aus für das Uniprojekt.
    Später wollte ich die Sache weiterentwickeln. Also mehr Einheiten reintun und die ganze Sache ausbalancieren. Dies resultierte in den folgenden Zyklus:
    - Server starten, spiel eröffnen (was einige Eingaben und Klicks benötigte)
    - Client starten, mit Server verbinden (localhost, Spielername, usw. usf.)
    - Testen und Notizen machen
    - Client beenden
    - Server beenden
    - Code ändern
    - Neu kompilieren (Server und Client)
    - Server starten, spiel eröffnen
    - Client starten, mit Server verbinden
    - usw.

    Ein Zyklus hat wohl ca. 5 bis 10 Minuten benötigt. Da kam man einfach nicht mehr vom Fleck. Habe dann die Sache neuprogrammieren müssen und dann eben ein Managersystem eingeführt mit externem File. Zusätzlich eine Debugfunktion, welche die Files zur Laufzeit neu lädt. Dann war der Zyklus:
    - Server starten, spiel eröffnen
    - Client starten, Server beitreten
    - Testen
    - XML ändern
    - neu einlesen
    - Testen
    - XML ändern
    - usw.

    Zyklus von 30 Sekunden 😃
    Wirkliche Daten, welche Hardcoded sind, sind ein Graus.

    Grüssli



  • Wirkliche Daten, welche Hardcoded sind, sind ein Graus.

    Hehe. Oh ja.. 🙂
    Ich liebe es ja, wenn ich die Daten Online ändern kann. Editoren für alles mögliche beschleunigt den Workflow und den Spass extrem. 🙂



  • - Server starten, spiel eröffnen (was einige Eingaben und Klicks benötigte)
    //kommandozeilenparameter hätten hier geholfen. die will der user eh haben.

    - Client starten, mit Server verbinden (localhost, Spielername, usw. usf.)
    //kommandozeilenparameter hätten hier geholfen. die will der user eh haben.

    - Testen und Notizen machen
    //sollte möglich sein, gleich den code anzufassen und compilieren zu lassen

    - Client beenden
    //darf sich selber beenden, wenn der server sich beendet

    - Server beenden
    //kann auf strg+c beenden oder auf signal, das wegen codeänderung kommt

    - Code ändern
    //hab ich schon

    - Neu kompilieren (Server und Client)
    //macht makefile

    - Server starten, spiel eröffnen
    //siehe oben

    - Client starten, mit Server verbinden
    //siehe oben
    - usw.

    Ein Zyklus hat wohl ca. 5 bis 10 Minuten benötigt. Da kam man einfach nicht mehr vom Fleck.
    [/quote]
    das geht alles auch hardcoded. du hättest nur makefiles einsetzen müssen und tricks wie exe-dateien, die sich selber beenden, wenn eine steuerdatei verändert wurde oder sowas. hättest du mal die symptome einzeln und entschieden bekämpft, wäre xml gar nicht ins spiel gekommen.
    aber xml hat nen vorteil für mich als zocker: ich kann dran rumbasteln.


  • Administrator

    volkard schrieb:

    - Server starten, spiel eröffnen (was einige Eingaben und Klicks benötigte)
    //kommandozeilenparameter hätten hier geholfen. die will der user eh haben.

    Da der Server auch der Client war, war sowas nicht geplant. Und wieso sowas nicht geplant war, siehe danach:

    volkard schrieb:

    - Client starten, mit Server verbinden (localhost, Spielername, usw. usf.)
    //kommandozeilenparameter hätten hier geholfen. die will der user eh haben.

    Ich habe bisher noch kaum ein Spiel gesehen, dass Kommandozeilenparameter hatte, bzw. wo der User welche verlangt oder eingesetzt hat. Viele von den Spielern wissen ja nicht einmal, was ein Kommandozeilenparameter sein soll.

    volkard schrieb:

    - Testen und Notizen machen
    //sollte möglich sein, gleich den code anzufassen und compilieren zu lassen

    Klar kannst du das, nur ob es sinnvoll ist? Ich mache mir meisten lieber zuerst mehrere Notizen, bevor ich anfange im Code was zu ändern. Du kannst auch die Sache kompilieren lassen. Nur ist es dann irgendwie blöd, wenn du plötzlich merkst, dass du noch was ändern/testen willst -> nochmals kompilieren.
    Bevor man Code ändert, sollte man wissen, was man tut.

    volkard schrieb:

    - Client beenden
    //darf sich selber beenden, wenn der server sich beendet

    Ging nicht, da die Sache so aufgebaut war, dass ein Client automatisch die Funktion des Server übernommen hat, sobald dieser ausfiel. Sehr praktisches Feature, wenn man das Spiel zu Ende spielen möchte.

    volkard schrieb:

    - Server beenden
    //kann auf strg+c beenden oder auf signal, das wegen codeänderung kommt

    Siehe oben.

    volkard schrieb:

    - Code ändern
    //hab ich schon

    Ja, aber die Zeit hast du trotzdem verbraten. Nur halt in einer anderen Reihenfolge.

    volkard schrieb:

    - Neu kompilieren (Server und Client)
    //macht makefile

    Wie bitte? Bei mir macht das sogar die IDE. Trotzdem muss kompiliert werden.

    volkard schrieb:

    - Server starten, spiel eröffnen
    //siehe oben
    - Client starten, mit Server verbinden
    //siehe oben
    - usw.

    siehe oben ...

    volkard schrieb:

    das geht alles auch hardcoded. du hättest nur makefiles einsetzen müssen und tricks wie exe-dateien, die sich selber beenden, wenn eine steuerdatei verändert wurde oder sowas. hättest du mal die symptome einzeln und entschieden bekämpft, wäre xml gar nicht ins spiel gekommen.

    Muss ich wohl nix mehr dazu sagen, da alles schon oben steht.
    Und auch wenn mein Spiel anders aufgebaut gewesen wäre, mit all den Beschleunigungen, welche du aufzeigst, würde es trotzdem noch länger dauern, als ein einfaches externes XML File, wo man dann die Clients gar nicht mal beenden oder neustarten muss. Wo man eine Situation nicht wieder bis zu einem Punkt hinarbeiten muss, um die den Test durchzuführen, usw. usf.

    volkard schrieb:

    aber xml hat nen vorteil für mich als zocker: ich kann dran rumbasteln.

    Und das wollte ich dann auch. Für Mods ist das der Himmel auf Erden.

    Grüssli



  • Dravere schrieb:

    Ich drück dir die Daumen, dass dir nicht sowas passiert wie bei mir:

    Wird es nicht, zumindest nicht vorläufig. 😉

    Ich habe weder Netzwerk noch das von dir beschriebene Vorgehen. Eine Änderung ist bei nicht annähernd so aufwändig wie in deinem Fall.

    volkard schrieb:

    aber xml hat nen vorteil für mich als zocker: ich kann dran rumbasteln.

    Genau. Ich muss bereits Leveldateien und Highscores absichern, damit nicht jeder daran manipulieren kann. (Wer jetzt sagen will, so gut könne ich das eh nicht absichern, ein 1337-Hacker würde es knacken - okay, von mir aus. Der könnte auch in den Arbeitsspeicher schauen oder das Programm disassembeln, aber darum gehts nicht. Tatsache ist, dass der normale Benutzer so nicht in Versuchung gerät, sich das Spiel zu einfach zu machen.)

    Das meinte ich auch mit zusätzlichen Fehlerquellen: Ich habe wieder einen Ort mehr, bei dem ich prüfen muss, ob die Datei vorhanden ist, ob sämtliche Einträge das richtige Format haben, ob die Einträge realistisch und spielbar sind. Das ist einfach unnötig, wenn ich das gleiche im Code erreiche und keine Nachteile dadurch habe bzw. diese gut tragbar sind. Wenn es jetzt so wäre, dass ich zuerst das Spiel fertigstelle und dann eine separate Balancing-Phase durchführe, sähe das auch wieder anders aus. Aber während des Testens muss ich so oder so dauernd Code ändern, sei es aufgrund von Bugs oder Details, die mir noch nicht gefallen.

    Soviel dazu. Aber grundsätzlich geht diese Diskussion am Thema vorbei. Selbst wenn man die Daten in jenem spezifischen Fall auslagern könnte, bleibt es ein allgemeines Problem, wie es um statische private Variablen steht. Wäre gut, wenn noch jemand dazu etwas sagen könnte. Hauptsächlich fragte ich mich, welche Vorteile solche Variablen hätten und was ein anonymer Namespace/ static in der .cpp-Datei bringen würde.



  • Nexus schrieb:

    Hauptsächlich fragte ich mich, welche Vorteile solche Variablen hätten und was ein anonymer Namespace/ static in der .cpp-Datei bringen würde.

    Du verhinderst damit "multiple definition", wenn du alles zusammenlinkst.



  • Aquae schrieb:

    Du verhinderst damit "multiple definition", wenn du alles zusammenlinkst.

    Aber nicht, wenn die Definition nur in einem Modul vorkommt...



  • Nexus schrieb:

    Aquae schrieb:

    Du verhinderst damit "multiple definition", wenn du alles zusammenlinkst.

    Aber nicht, wenn die Definition nur in einem Modul vorkommt...

    Naja, so kannst du das Kollisions-Risiko ausschließen, ist an sich ziemlich praktisch 😉



  • Badestrand schrieb:

    Naja, so kannst du das Kollisions-Risiko ausschließen, ist an sich ziemlich praktisch 😉

    Du meinst, falls in einem anderen Modul eine Definition mit dem gleichen Bezeichner vorkommt? Oder wie ist das zu verstehen?



  • Nexus schrieb:

    Badestrand schrieb:

    Naja, so kannst du das Kollisions-Risiko ausschließen, ist an sich ziemlich praktisch 😉

    Du meinst, falls in einem anderen Modul eine Definition mit dem gleichen Bezeichner vorkommt? Oder wie ist das zu verstehen?

    Ja, genau. Zur Vermeidung kann man natürlich auch kryptische Bezeichner oder fiese Prefixe vergeben, ist bei dem einfachen anonymer-namespace-Workaround aber imo ziemlich unnötig.



  • Gut, danke. Hat ein anonymer Namensraum eigentlich gewisse Vorteile gegenüber static ? Beide führen ja zu interner Linkage, oder worin besteht der Unterschied?



  • Ich kenne keinen Unterschied, verwende aber immer anonyme Namensräume um mir static für die "normalen" static-Fälle freizuhalten. Dass static internal Linkage bewirkt, hab ich auch erst vor etwa einem Jahr erfahren, da war ich gut überrascht 🙂



  • Nexus schrieb:

    Gut, danke. Hat ein anonymer Namensraum eigentlich gewisse Vorteile gegenüber static ? Beide führen ja zu interner Linkage, oder worin besteht der Unterschied?

    der nameless namespace (der richtig glaub ich unnamed heisst, aber ich mag nameless mehr weil es sich reimt 🙂 ) hat NICHT internal linkage. was auch gut so ist. denn dadurch kann man klassen, die man in einem unnamed namespace definiert, als template parameter einsetzen.

    der vorteil von unnamed namespaces ist ganz klar dass man alles reinstecken kann, also auch klassen. mit static kann man bloss variablen und funktionen machen, aber keine klassen. unnamed namespaces sind der "c++ way of doing it". static für globale variablen/funktionen gibt's im prinzip nurnoch zwecks kompatibilität mit C und mit älteren C++ versionen.



  • Vielen Dank für die Erläuterungen. Stimmt, ein anonymer Namensraum sollte sich bezüglich Linkage eigentlich gleich wie ein benannter verhalten. Dass man da alles reinpacken kann (auch Klassen), habe ich auch nicht bedacht, ist aber gut zu wissen. 🙂

    Möchte nun noch jemand bestätigen, dass private statische Klassenvariablen im Normalfall sinnlos sind? Oder hat jemand ein Gegenargument? Mir fällt nämlich gerade echt keines ein... 😉



  • Nexus schrieb:

    Möchte nun noch jemand bestätigen, dass private statische Klassenvariablen im Normalfall sinnlos sind? Oder hat jemand ein Gegenargument? Mir fällt nämlich gerade echt keines ein... 😉

    Naja wa sis mit statischen Konstanten? Oder anderen internen Werten die nur die Klasse selbst braucht die aber nur einmal gebraucht werden und damit Platzsparender weise static intern abgelegt werden?



  • Xebov schrieb:

    Naja wa sis mit statischen Konstanten? Oder anderen internen Werten die nur die Klasse selbst braucht die aber nur einmal gebraucht werden und damit Platzsparender weise static intern abgelegt werden?

    Das ist alles auch mit globalen Variablen möglich, die in den entsprechenden .cpp-Dateien deklariert werden. Darum ging es ja die ganze Zeit... 😉



  • Naja ... einzige Ausnahme die mir jetzt einfällt ist integrale private statische Konstanten (puh!), welche von friend Klassen verwendet werden.



  • Gut, danke. friend kommt bei mir eher selten vor (in meinem jetzigen Projekt gar nicht). Hmm, ich glaube, in nächster Zeit werde ich eher globale Variablen in .cpp-Dateien innerhalb anonymer Namensräume nutzen. Bis ich mir vielleicht eines Tages mal sage, es wäre halt doch schöner, die Variable würde zur Klasse gehören... 🙂

    P.S.:

    hustbaer schrieb:

    (puh!)

    Warum hast du nicht "integrale private statische konstante Variablen" hingeschrieben? (Wegen des "Widerspruchs" konstante Variable? Oder hat dich das bereits genügend Schnauf gekostet?)... 😉


Anmelden zum Antworten