Du bist nicht angemeldet.

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

buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

11

07.12.2014, 20:35

Schau doch einfach mal, wie anderes das machen. Es gibt ja genug open source Engines. Außerdem verstehe ich das Problem mit Gottobjekten nicht.
Was spricht denn gegen globale Variablen? Ist doch in C eine ganz normale Variante. Auch in C++ ist das nicht ungewöhnlich und man sieht das
in einigen Engines. Einfaches Beispiel:
Header:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
namespace resources {
  struct Texture {
    float width;
    float height:
    LPDIRECT3DTEXTURE9 texture;
  }
  int loadTexture(const char* name);
  LPDIRECT3DTEXTURE9 getTexture(int index);
}

CPP Datei:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace resources {
  static std::vector<Texture> Textures;
  int loadTexture(const char* name) {
    Texture t;
    // load texture somehow
    int ret = Textures.size();
    Textures.push_back(t);
    return ret;
  }
  LPDIRECT3DTEXTURE9 getTexture(int index) {
    assert(index >= 0 && index < Textures.size());
    return Textures[index].tex;
  }
}

Die globale Variable ist für andere nicht sichtbar, weil sie ganz einfach in der CPP Datei definiert ist. Das ist eine absolut übliche Praxis.

12

09.12.2014, 16:30

Außerdem verstehe ich das Problem mit Gottobjekten nicht.

Das Problem mit Gott-Objekten ist, dass Klassen prinzipiell dem Single-Responsibility-Principle folgen sollten, ein Gott-Objekt aber klassischerweise mehrere Zuständigkeiten aufweist.

Was spricht denn gegen globale Variablen?

Lose Kopplung und Testbarkeit.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
namespace resources {
  struct Texture {
    float width;
    float height:
    LPDIRECT3DTEXTURE9 texture;
  }
  int loadTexture(const char* name);
  LPDIRECT3DTEXTURE9 getTexture(int index);
}

CPP Datei:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace resources {
  static std::vector<Texture> Textures;
  int loadTexture(const char* name) {
    Texture t;
    // load texture somehow
    int ret = Textures.size();
    Textures.push_back(t);
    return ret;
  }
  LPDIRECT3DTEXTURE9 getTexture(int index) {
    assert(index >= 0 && index < Textures.size());
    return Textures[index].tex;
  }
}

Mal abgesehen von mangelnder Testbarkeit .. sobald ich einen zweiten ResourceCache brauche, war's das mit er globalen Variable.
  • Warum sollte man zwei ResourceCaches brauchen? Wenn ich einen Cache für GUI-spezifische Ressourcen (Buttongrafiken etc.) und einen für Session-spezifische Ressourcen (Tiles die in der aktuellen Spielsession aber möglicherweise nicht in der nächsten gebraucht werden) möchte.
  • Wozu sollte ich dazwischen unterscheiden wollen? Im Laufe einer Session können verschiedenste Orte der Spielwelt besucht werden. Wenn ich dann eine neue Session starte, brauche ich die alten Spieldaten ggf. nicht mehr - ich muss ja nicht zwangsläufig in der gleichen Ecke des Spiels landen. Analoges beim Laden.. ich denke es gibt einige Negativbeispiele bei größeren Spielen, wo über Stunden der Speicherbedarf enorm wächst weil vermutlich alte Spieldaten noch im Arbeitsspeicher verweilen.
    Ich finde so ein Spiel sollte die Möglichkeit haben sich selbst zur Laufzeit zu entmüllen.
  • Ja das kann ich auch machen indem ich eine dropTexture-Funktion in dein Beispiel integriere. Aber ich will mir nicht jede einzelne Textur - die zur Session gehört - merken um sie danach explizit "fallen zu lassen" :)
  • usw.
Die globale Variable ist für andere nicht sichtbar, weil sie ganz einfach in der CPP Datei definiert ist. Das ist eine absolut übliche Praxis.

Sorry, aber da stellen sich mir sämtliche Fußnägel und Nackenhaare auf! Eine (normale) Funktion um den Zugriff auf eine globale Variable zu verstecken? Also wenn das übliche Praxis sein soll :dash: Sorry ^^

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

13

09.12.2014, 18:10

Das ist wenn meine ich bei C Programmen nicht unübliche Praxis um wenigstens ein bisschen Data Hiding zu haben. Das ist ein Punkt wo ich sagen würde, das geht mit C++ definitiv sauberer. Oder mit anderen objektorientierten Sprachen.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

14

09.12.2014, 19:04

Also ich kann ja verstehen, wenn dir der Ansatz nicht gefällt. Es war ja auch nur ein Vorschlag. Aber ich muss schon sagen, dass deine Argumente alle arg konstruiert sind.
Lose Kopplung und Testbarkeit sind hier genauso gegeben wie mit einem OOP Ansatz.
Ich habe mich beispielsweise auf Doom3 und Quake und openGL und Unreal und andere bezogen.
Wenn du halt einen strengen OOP Ansatz verfolgen willst, dann ist das doch in Ordnung. Ich sehe die Welt halt anders. Darum poste ich auch immer wieder Code, auch wenn ich weiß das es den meisten nicht gefällt. Soll ja auch nur eine Anregung sein.

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

15

10.12.2014, 00:59

Mit "Testbarkeit" ist wohl nicht gemeint, dass dein Texturenvektor und der Zugriff darauf getestet werden kann, sondern dass davon abhängige Klassen getestet werden können. Da über eine globale Variable darauf zugegriffen wird, ist einerseits die Abhängigkeit verschleiert (man sieht sie nur, wenn man sich die konkrete Implementierung ansieht, nicht aber schon beim Betrachten der Schnittstelle), andererseits ist keine Austauschbarkeit gegeben, wodurch man die zu testende Klasse nicht oder nur mit sehr großen Umwegen mit Testdaten versorgen kann.

Hier im Forum gibt es auch noch einen anderen Thread, in dem ähnliche Dinge bereits genannt wurden.
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

kiba

Alter Hase

Beiträge: 327

Wohnort: NRW

Beruf: Azubi: Fach-Info. Anw.

  • Private Nachricht senden

16

19.12.2014, 23:29

Ich wollte noch etwas zu Evreys ansatzt mit den shared_ptr sagen, wenn man das tut sollte man auch weak_ptr verwenden.
Probleme kann es auch bei threads geben dann muss man gegebenenfalls den cache locken (was etwas unschön ist).
Und man sollte wenn man mit shared_ptr arbeitet auch mit weak_ptr arbeiten um z.b. ein cycles vermeide (shared_ptr erhalten sich gegenseiten am leben).
Mit expired() kann man auch z.b. die gültigkeit überprüfen ob irgetn jemand anders gerade die Texture verwendet(z.b. durch weitere shared_ptr) und wenn nicht die ggf. löschen.
Das Aufräumen und managen des caches beim multithread is auch so eine sache.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
std::shared_ptr<Texture> loadTexture(std::string filename) {    
       static std::vector<std::weak_ptr<Texture>> cache; // lieber vector statt map verwenden .... oder nicht ?
       static std::mutex m;     
       std::lock_guard<mutex> hold (m); 
       auto find_cache_func = [&](const std::weak_ptr<Texture>& tex){       
             return !tex.expired() && tex.lock()->getFilename() == filename;     
        };  
        auto cache_it = std::find_if(std::begin(cache), std::end(cache), find_cache_func);  
        std::shared_ptr<Texture> ret;   
        if (cache_it != std::end(cache) && !cache_it->expired()) {          
             ret = cache_it->lock();    
       } else {     
            ret = loadRealTexture(filename);            
            if(ret) cache.push_back(ret);   
       }        
      return ret;
}


Das static cache und mutex ist jetzt wieder global, könnte das auch in ein Manager rein packen.
Soll nur ein denk anstoß mit shared_ptr sein.

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

17

20.12.2014, 00:27

Ich habe zwar nicht den ganzen Thread gelesen. Aber ich kann dir ein Openbook zum Thema empfehlen: http://openbook.galileo-press.de/oop/
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »NachoMan« (20.12.2014, 00:32)


Werbeanzeige