Liste mit Zeigern
-
hi, hab ein Problem, also ich hab eine Liste ind er Objekte gespeichert werden.
list<XXX> LISTE;
Was genau passiert da jetzt wenn ich wie folgt da was reinschiebe.
X *Variable; Variable =new X; // dann n paar Sachen was nicht wichtig sind LISTE.push_back(*Variable);Muss ich dann danach was mit delete() entfernen?
Oder wie wird da der Zeiger genau in der Liste gespeichet?Brauch das weil eigentlich wollt ich das so machen:
X Variable; LISTE.push_back(Variable);Nur da stürzt das bei mir dann ohne Kommentar ab.
Hoffe mal mir kann das wer erklären wie man am besten
mit Variablen, Listen und Zeiger arbeitet. Also wann man was wie am besten verwenden soll. Oder kann mir wer ein gutes Toturial sagen das sich um soetwas dreht?Danke schon mal im vorraus.
mfg Stefan
-
Am besten speicherst du gar keine Zeiger, sondern direkt Instanzen in Containern. Sobald du nämlich
neweinsetzt, musst du mitdeletewieder selber freigeben.Natürlich gibt es auch Gründe, weshalb man Zeiger verwenden muss (Polymorphie oder Nichtkopierbarkeit sind zum Beispiel solche). In diesen Fällen verwendet man allerdings eher speziell dafür konzipierte Container wie die Boost PointerContainer.
In deinem Fall wäre wahrscheinlich
std::list<X>passender alsstd::list<X*>(unter oben genannten Bedingungen). Lies vielleicht auch mal diesen Artikel.
-
ok, gut danke ersstmal. Hab jetzt bisschen weiterausprobiert und dann ist mir was aufgefallen was ich mir nicht erklären kann.
So jetzt mit meinem Orginalcode und nicht mehr nur so ein Bsp.
void Loop::CreateCreeps() { Creep Einheit; Einheit.LoadSprite("Media/Creeps/creep1.tga",0,0, 10, 10); Einheit.SetZ(10); m_CreepList.push_back(Einheit); }So das ist der Teil einer Klasse der Probleme macht.
hatte das dannn einfach mal , weil es nicht funktioniert hat sondern ohne Fehlermeldung einfach abgebrochen hat einfach so geschrieben:
void Loop::CreateCreeps() { Creep *Einheit; Einheit= new Creep; Einheit->LoadSprite("Media/Creeps/creep1.tga",0,0, 10, 10); Einheit->SetZ(10); m_CreepList.push_back(*Einheit); }aber da das anscheinend so auch nicht so praktisch ist hab ich es jetzt wieder wie da oben am anfang. Ah ja was ich noch sagen sollte so wie es hier steht geht es, also so mit den Zeigern.
Also gut dann hab ich mal einfach weiterprbiert und mir gedacht was passiert wenn ich das einfach mal nicht als Funktion schrieb sondern einfach so schriebe.
Also dann hab ichs einfach so gemacht:
void Loop::Run() { //... Andere Funktionen oder sonstiges unwichtig //CreateCreeps(); Den Funktionsausruf auskommentiert Creep Einheit; Einheit.LoadSprite("Media/Creeps/creep1.tga",0,0, 10, 10); Einheit.SetZ(10); m_CreepList.push_back(Einheit); //...Auch noch sonstiges unwichtiges Zeug. }Und so funktioniert das dann auf einmal..., kann mir das vielleicht einer erklären wie das gehen kann?
m_CreepList ist eine Membervariable von der Klasse Loop die wie folgt ausschaut.
list<Creep> m_CreepList;Hoffe mal mir kann dabei nochmal wer helfen. Fals noch fragen sind oder sonstiger Code gebraucht wird einfach sagen.
-
Nexus schrieb:
...
Natürlich gibt es auch Gründe, weshalb man Zeiger verwenden muss (Polymorphie oder Nichtkopierbarkeit sind zum Beispiel solche).Ich bin zwar noch nicht so weit mit meinen C++ Künsten, aber gehört dazu nicht auch der Fall, indem die Anzahl der zu erzeugenden Objekte unbekannt ist?
Wenn also die Objekte dynamisch erzeugt werden müssen, dann bleiben doch nur Zeiger oder?
-
stefan schrieb:
Und so funktioniert das dann auf einmal..., kann mir das vielleicht einer erklären wie das gehen kann?
Hm. Hat deine Creep-Klasse zum Beispiel Zeiger mit eigener Speicherverwaltung? Hast du einen eigenen Destruktor implementiert? Dann solltest du auch Kopierkonstruktor und Zuweisungsoperator bereitstellen.
stefan schrieb:
hatte das dannn einfach mal , weil es nicht funktioniert hat sondern ohne Fehlermeldung einfach abgebrochen hat einfach so geschrieben:
Ich würde mal mit dem Debugger durchgehen und genau überprüfen, wo es abbricht. Dabei immer schön die Variablen im Auge behalten und schauen, ob sie noch gültige Werte besitzen. Auf diese Weise kannst du den Fehler schnell eingrenzen. Alternativ kannst du auch Konsolenausgaben verwenden, allerdings rate ich zu einem Debugger, der ist manchmal unersetzlich.
beispiel0r schrieb:
Ich bin zwar noch nicht so weit mit meinen C++ Künsten, aber gehört dazu nicht auch der Fall, indem die Anzahl der zu erzeugenden Objekte unbekannt ist?
Wenn also die Objekte dynamisch erzeugt werden müssen, dann bleiben doch nur Zeiger oder?Was du meinst, ist (statisches) Array vs. Zeiger auf dynamisch allokiertes Array.
Bei Containern hat man dieses Problem nicht, da kann man die Grösse beliebig zur Laufzeit wählen. Das geht eben, weil hierfür der dynamische Speicherbereich (Heap) und nicht der automatische (Stack) verwendet wird.
-
Nexus schrieb:
Was du meinst, ist (statisches) Array vs. Zeiger auf dynamisch allokiertes Array.
Nein, ich meine, das zur Laufzeit die Anzahl unbekannt ist:
void test1( int n ) { string a[n]; } void test2( int n ) { string* a = new string [n]; // string-array bentutzen // ... delete [] a; } int main ( int argc, char* argv[] ) { int n; // ... und plötzlich fiel die 3 vom Himmel n = 3; // ... und zwar zur Laufzeit! test1(n); // error C2057: Konstanter Ausdruck erwartet test2(n); // Oki Doki //...In dem Fall wüsste ich mir nicht anders zu helfen, als mit der Funktion test2.
-
beispiel0r schrieb:
Nein, ich meine, das zur Laufzeit die Anzahl unbekannt ist:
Lies meinen Post nochmals. Das ist genau das, was ich gesagt habe.
beispiel0r schrieb:
In dem Fall wüsste ich mir nicht anders zu helfen, als mit der Funktion test2.
Wie wärs mit
test3?void test3(int n) { std::vector<std::string> vec(n); // mit vec arbeiten } // wird automatisch aufgeräumt!
-
beispiel0r schrieb:
In dem Fall wüsste ich mir nicht anders zu helfen, als mit der Funktion test2.
Das ist schade; denn std::vector sollte bekannt sein.
#include <vector> #include <string> using std::vector; using std::string; void test3( int n ) { vector<string> a (n); // ... }Gruß,
SP
-
Naja erstmal danke, hba bis auf jetzt noch nichts mit dem Debbuger gemacht und bei mir (CodeBlocks, MinGW, mit gdb.exe) was ich mir grad gedownloaded hab also den Debbuger funktioniert das auch nicht so wirklich, der Zeigt alles ögliche an bzw. so halbwegs an, da kommt dann ein Feld mit Hex-Werten das aber nur so halberts da ist, man kann damit nichts machen.
Naja werd mich wohl erst mal genauer mit dem Debbuger auseinander setzen müssen...
-
Hm. Hat deine Creep-Klasse zum Beispiel Zeiger mit eigener Speicherverwaltung? Hast du einen eigenen Destruktor implementiert? Dann solltest du auch Kopierkonstruktor und Zuweisungsoperator bereitstellen.
Ne das nicht, aber ich weiß jetzt glaub ich zuminderst woran das liegt.
class Sprite :public Anzeige { public: Sprite(); ~Sprite(); void LoadSprite(string filename, float PosX, float PosY,float w ,float h); void LoadSprite(string filename, int NumX,int NumY,float PosX, float PosY,float w ,float h); void Render(); void Render(int ClipX,int ClipY); void Render(int Clip); void SetPos(float x, float y); void AddPos(float x, float y); void SetSize(float w,float h); void AddSize(float w,float h); void SetWinkel(float Winkel); void AddWinkel(float Winkel); protected: void LoadTexture(string TexName); //Ladet die Texture GLuint Texture; //Speichert die Textur float m_Winkel; //Winkel (zum drehen von dem Sprite int m_MaxRowX; int m_MaxRowY; int m_MaxClips; };class Creep : public Sprite { public: Creep(); ~Creep(); void SetSpeed(float Wert); private: float m_Speed; };Und zwar glaub ich liegt das an der Variable (GLuint) Texture. Also bräuchte ich dafür normal einen Kopierkonstruktor, weil wenn ich das da dann erstelle über die Funktion
void Loop::CreateCreeps() { Creep Einheit; Einheit.LoadSprite("Media/Creeps/creep1.tga",0,0, 10, 10); Einheit.SetZ(10); m_CreepList.push_back(Einheit); }Dann wird da die danach doch gelöcht oder?
Aber wie müsst da der Kopierkonstruktor dann ausschauen?,
und in welches Klasse schreib ich denn dann am besten Sprite oder?Ich komm da irgentiwe mit dem GLuint nicht zurecht. Weil wenn ich mir das dann anschau heißt es das das GLuint selber schon en Zeiger oder sowas ist.
-
GLuint Texturespeichert doch die ID der Textur, die du über OpenGL allokiert hast (glGenTextures). Die Textur müsstest du überglDeleteTexturesauch wieder freigeben, wenn sie nicht mehr gebraucht wird.Als erstes solltest du Ressourcen, Sprites und Spiellogik-Objekte voneinander differenzieren. Nicht jedes Objekt braucht seine eigene Textur. Mach dafür am besten eine eigene Klasse, z.B.
Texture. In deinenCreep-Objekten speicherst du dann lediglich Zeiger auf die Texturen (=Instanzen vonTexture).Das erfordert bei deinem momentanen Design vielleicht ein Umkrempeln, aber dafür hast du das mal sauber gelöst. Denn was soll bei dir jetzt passieren, wenn eine
Creep-Instanz kopiert wird? Soll eine neue gleiche Textur angefordert werden? Soll die Kopie die gleiche Textur referenzieren? Wer gibt die Textur frei?
-
Als erstes solltest du Ressourcen, Sprites und Spiellogik-Objekte voneinander differenzieren. Nicht jedes Objekt braucht seine eigene Textur. Mach dafür am besten eine eigene Klasse, z.B. Texture. In deinen Creep-Objekten speicherst du dann lediglich Zeiger auf die Texturen (=Instanzen von Texture).Naja ich weiß jetzt nicht so ganz genau wie du das meinst, aber ich mach das momentan so.
Da ich momentan eignetlich nur TGAimages hernehm hab ich mir da eine Klasse mit hilfe vom Internet geschrieben die schaut so aus.
class TGAImg { public: TGAImg(); ~TGAImg(); int Load(char* szFilename); int Load(string szFilename); int GetBPP(); int GetWidth(); int GetHeight(); int GetPitch(); unsigned char* GetImg(); // Return a pointer to image data unsigned char* GetPalette(); // Return a pointer to VGA palette SDL_Surface *GetSurface(); //Gibt das SDL_Surface zurueck (Nur bei SDL Anwendungen private: short int iWidth,iHeight,iBPP; unsigned long lImageSize; char bEnc; unsigned char *pImage, *pPalette, *pData; // Internal workers int ReadHeader(); int LoadRawData(); int LoadTgaRLEData(); int LoadTgaPalette(); void BGRtoRGB(); void FlipImg(); };So und dann lad ich so die Texture:
Sprite.cpp
void Sprite::LoadSprite(string filename, float PosX, float PosY, float w, float h) { LoadTexture(filename); m_x=PosX; m_y=PosY; m_w=w; m_h=h; } /**Ladet ein Sprite mit Animation**/ void Sprite::LoadSprite(string filename, int NumX,int NumY,float PosX, float PosY,float w ,float h) { LoadSprite(filename,PosX,PosY,w,h); m_MaxRowX=NumX; m_MaxRowY=NumY; m_MaxClips=m_MaxRowX*m_MaxRowY; } /**Ladet die Texture**/ void Sprite::LoadTexture(string TexName) { TGAImg Img; // Image loader if(Img.Load(TexName)!=IMG_OK) { cout<<"Fehler beim laden der Textur: "<<TexName<<endl; } glGenTextures(1,&Texture); // Allocate space for texture glBindTexture(GL_TEXTURE_2D,Texture); // Set our Tex handle as current // Create the texture if(Img.GetBPP()==24) glTexImage2D(GL_TEXTURE_2D,0,3,Img.GetWidth(),Img.GetHeight(),0,GL_RGB,GL_UNSIGNED_BYTE,Img.GetImg()); else if(Img.GetBPP()==32) glTexImage2D(GL_TEXTURE_2D,0,4,Img.GetWidth(),Img.GetHeight(),0,GL_RGBA,GL_UNSIGNED_BYTE,Img.GetImg()); else { cout<<"Fehler: falsches Format von: "<<TexName<<endl; } // Specify filtering and edge actions glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); /* glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); */ }So und was meinst du jetzt?
Das ich das laden da Als extra Klasse mache oder wie? Und hast du dafür vielleicht ein paar Bsp.-Anwendungen oder Toturials dazu?Weil ich hab mir alles selbst über internet, Toturials beigebracht und hab da auch noch nicht so viel erfahrung wie man das am bestne schreibt. Also hab ich dann einfach mal mit SDL angefangen, dann bin ich damit zurechtgekommen und war dann soweit das die funktionen von SDL nicht mehr gereicht haben und bin dann auch SDL mit opengl umgestiegen, naja und da häng ich jetzt momentan und versuch mal wenigstens was halbwegs brauchbares hinzubekommen.
Eigentlich hätt ich auch nicht gedacht dass das dann solche probleme macht das in die Liste zu tun. Aber es muss an irgetnwas dadrinnen liegen. Weil Konstrukter und Destruktor werden aufgerufan und erst wenn die Funktion zu Ende ist stürzt das Programm ab.
-
Naja, als erstes würde ich mir nicht irgendwas vom Internet zusammenklicken. Das führt selten zu sinnvollem Code. Zudem scheinst du in C++ noch nicht allzu sicher zu sein; ich würde zuerst ein C++-Buch gut durcharbeiten, bevor ich mich mit Grafik beschäftigte.
Deine
TGAImg-Klasse hat zum Beispiel keinen benutzerdefinierten Kopierkonstruktor und Zuweisungsoperator, aber einen Destruktor. Das ist schon mal ein Hinweis auf eine mögliche Fehlerquelle. Implementiere entweder diese drei Memberfunktionen, oder verbiete sie (inprivatedeklarieren und nicht definieren). Ausserdem solltest du dich achten, Klassen wiestd::stringals Const-Referenz und nicht als Kopie zu übergeben. Oder Konstruktoren zu nutzen, um Instanzen zu initialisieren.Ich hätte grundsätzlich an sowas gedacht:
class Texture { public: Texture(const std::string& FileName); Texture(const Texture&); ~Texture(); void operator= (const Texture&); // hier deine Schnittstelle fürs Zeichnen private: GLuint MyTextureID; }; class TextureManager { public: TextureManager(); Texture& GetTexture(const std::string& Name); private: std::map<std::string, Texture> MyTextures; };Aber das ist nur mal ein grober Aufbau, ein möglicher Vorschlag. Du solltest schauen, dass du Texturen von den Sprites oder sogar Logikobjekten loslösen kannst, dann musst du nämlich auch nicht bei jedem neuen Objekt eine eigene Textur anlegen.
Entweder du implementierst für Texturen eine sinnvolle Kopiersemantik (z.B. neue Textur anlegen) oder du verbietest den Kopierkonstruktor und Zuweisungsoperator und verwendest Zeiger. Da musst du allerdings etwas aufpassen. Ich bin kein Fan von besitzenden Zeigern in STL-Containern. Boost würde sonst noch Pointer-Container anbieten...
-
So hab mich jetzt einfach mal hier angemeldet, finds hier recht gut und man bekommt gute Tipps.
Also naja aber ich find trotzdem das ich zuminderst die Grundlageen kann. Naja wegen Buch hab ich mir auch schon mal überlegt eins zu kaufen, aber irgendwie denk ich mir dann immer bzw. seh ich das in den Büchern nicht das drinnen steht was ich will, (brauch).
Naja ich bräucht halt dann ein Buch was über C++ und OpenGl und ggf. SDL geht.Momentan nehm ich so als hauptinformation die Seite her
http://wiki.delphigl.com/index.php/HauptseiteFind da sind die Funktionen recht gut beschrieben, zwar leider nicht in C++ aber ist eh fast gleich.
Aber anscheinend bau ich die Klassen immer ein bischen falsch auf.
Da musst du allerdings etwas aufpassen. Ich bin kein Fan von besitzenden Zeigern in STL-Containern. Boost würde sonst noch Pointer-Container anbieten...
zu dem noch, ist das aus eigener Erfahrung so oder kann man das irgendwie belegen, oder geht es da dann nur darum das man da dann den Speicher nicht bzw nicht gut oder leicht wieder freigeben kann?
EDIT:
Für was sollte da dann der Überladene Operator gut sein?
Um einer anderen Textur diese Textur zuzuweißen ode versteh ich das falsch?
-
stefan schrieb:
zu dem noch, ist das aus eigener Erfahrung so oder kann man das irgendwie belegen, oder geht es da dann nur darum das man da dann den Speicher nicht bzw nicht gut oder leicht wieder freigeben kann?
Ja, hauptsächlich wegen der Gefahr von Memory Leaks. Ein oder mehrere
deletes beierase()- bzw.clear()-Aufrufen können sehr schnell vergessen gehen. Die Sonderbehandlung ist auch hinderlich, wenn man generisch arbeitet (mit Templates). Ausserdem kann man den Container so nicht sinnvoll kopieren oder zuweisen, weil dann nur die Zeiger kopiert werden und somit mehrere Zeiger auf das Gleiche zeigen. Sich da immer zu merken, welcher Zeiger nun worauf zeigt und wie freizugeben ist, kann unter Umständen recht mühsam sein.Vielleicht bin ich aber auch nur ein bisschen verwöhnt von C++.

So tragisch sind Zeiger auch nicht, wenn du nicht viele Operationen auf dem Container anwendest. Sei einfach der Problematik bewusst, bevor du sowas exzessiv anwendest. Du kannst es also schon so versuchen (schreib dir fürs Löschen am besten eine Funktion, die zuerstdeleteund dannerase()aufruft).stefan schrieb:
Für was sollte da dann der Überladene Operator gut sein?
Um einer anderen Textur diese Textur zuzuweißen ode versteh ich das falsch?Ja, falls dies Sinn macht. Wenn nicht, verbiete den Zuweisungsoperator, sodass man ihn nicht aus Versehen benutzt (z.B. innerhalb von Containern). Dann kannst du allerdings wie gesagt keine Container mehr benutzen. Gleiches gilt für den Kopierkonstruktor.
-
Also du hast mich da jetzt auf jeden Fall mal überzeugt, werde mal das ganze neu machen und dann hier noch mal hertun. Kann aber sein das ich vielleicht dann beim Kopierkonstruktor noch mal hilfe brauch, da komm ich grad nicht ganz so mit wie der dann hinhauen soll...
Naja bis dahin erst mal danke.
EDIT:
class Texture { public: Texture(const std::string& FileName); Texture(const Texture&); ~Texture(); void operator= (const Texture&); // hier deine Schnittstelle fürs Zeichnen private: GLuint MyTextureID; }; class TextureManager { public: TextureManager(); Texture& GetTexture(const std::string& Name); private: std::map<std::string, Texture> MyTextures; };So jetzt hab ich mir mal den funktionsablauf ausgedacht.
Texture:
Texture(const std::string& FileName); :
Ladet die Textur mit dem FileName von dem String, wenn es schon eine Textur mit dem FileNamen im TexturManager gibt die nehmen.Texture(const Texture&); :
Ladet die Textur Textur (also wird auch von der Funktion Texture(const std::string& FileName)) aufgerufen, schätz ich mal).~Texture();
Gibt den Speicher wieder frei, naja da wird es aber dann shcon schwieriger,weil es kann ja sein das eine Textur auch noch in einer anderen Funktion genutzt wird oder? Oder wie müsste man die dann löschen (also aus dem TexturManager?
Das ist die Funktion was ich im Moment nicht weiß wie ich das anstellen soll.void operator= (const Texture&); :
Naja einfach n Zuweisungsoperatot der eine Textur zuweist.Texturmanager:
Texture& GetTexture(const std::string& Name); :
Gibt die Textur ID von der Textur zurück wenn es die Gibt.Naja braucht man dann nicht auch eingentlich ein SetTexture? oder wie bringt man die sonst in die Map rein? Naja muss aber dazu sagen das ich noch nicht wirklich mit Maps(MultiMaps) gearbeitet hab, hab eigentlich immer entweder Arrays,Vektoren oder Listen hergenommen.
-
stefan schrieb:
Kann aber sein das ich vielleicht dann beim Kopierkonstruktor noch mal hilfe brauch, da komm ich grad nicht ganz so mit wie der dann hinhauen soll...
Sicher, kein Problem, frag ruhig.

stefan schrieb:
Texture(const std::string& FileName); :
Ladet die Textur mit dem FileName von dem String, wenn es schon eine Textur mit dem FileNamen im TexturManager gibt die nehmen.Ja, wobei eine Textur eigentlich nichts über die anderen Texturen weiss. Zu schauen, dass keine Textur zweimal vorkommt, ist dann Aufgabe des Texturmanagers.
stefan schrieb:
Texture(const Texture&); :
Ladet die Textur Textur (also wird auch von der Funktion Texture(const std::string& FileName)) aufgerufen, schätz ich mal).Das ist der Kopierkonstruktor. Der wird aufgerufen, falls eine Textur kopiert wird. Hier weiss ich wie gesagt nicht, welches Verhalten von dir erwünscht ist — sollen Kopien überhaupt möglich sein? Soll dabei eine neue identische Textur entstehen, die eigenen Speicher belegt und separat handhabt? Oder ...?
stefan schrieb:
~Texture();
Gibt den Speicher wieder frei, naja da wird es aber dann shcon schwieriger,weil es kann ja sein das eine Textur auch noch in einer anderen Funktion genutzt wird oder? Oder wie müsste man die dann löschen (also aus dem TexturManager?
Das ist die Funktion was ich im Moment nicht weiß wie ich das anstellen soll.Das muss dich hier nicht kümmern. Der Destruktor soll lediglich dafür sorgen, dass eine Textur richtig aufgeräumt wird (also z.B.
glDeleteTextures()aufruft). Wann der Destruktor aufgerufen wird, bestimmt wiederum der Texturmanager.stefan schrieb:
void operator= (const Texture&); :
Naja einfach n Zuweisungsoperatot der eine Textur zuweist.Ja — hier stellt sich die gleiche Frage wie beim Kopierkonstruktor.
stefan schrieb:
Texture& GetTexture(const std::string& Name); :
Gibt die Textur ID von der Textur zurück wenn es die Gibt.Ja, kommt wieder ein wenig drauf an, wie du von aussen auf die Texturen zugreifen willst. Brauchst du die ID? Wer ist fürs Zeichnen zuständig? Könnte man das Zeichnen vielleicht sogar auch eine eigene Klasse übernehmen lassen, damit das zentral passiert?
Und was ist, wenn ein ungültiger Name übergeben wird? Mit einer Referenzrückgabe wäre eine Exception am besten geeignet. Sonst kannst du einen Zeiger zurückgeben, und im Falle eines fehlerhaften Namens den Nullzeiger zurückgeben.stefan schrieb:
Naja braucht man dann nicht auch eingentlich ein SetTexture? oder wie bringt man die sonst in die Map rein?
Doch, man braucht noch einige Methoden. Das sollte nur das Grundgerüst darstellen, damit du einen ungefähren Ansatz hast. Diese beiden Methoden wären auch eine Möglichkeit:
// Fügt eine Textur hinzu. 'Name' ist hierbei der Name, über den man die Textur anspricht // (bei GetTexture), 'FileName' der Name der Datei, von der die Textur geladen wird. void AddTexture(const std::string& Name, const std::string& FileName); // Gibt die Textur mit dem entsprechenden Namen frei. Ruft std::map::erase() auf. // Damit wäre auch das Problem mit dem Einsatzbereich des Texture-Destruktors geklärt. // Was passiert hier, wenn der Name nicht vorkommt? Exception? bool-Rückgabewert? void RemoveTexture(const std::string& Name);stefan schrieb:
Naja muss aber dazu sagen das ich noch nicht wirklich mit Maps(MultiMaps) gearbeitet hab, hab eigentlich immer entweder Arrays,Vektoren oder Listen hergenommen.
Das macht nichts, die hast du schnell begriffen, wenn du dich mit anderen Containern auskennst. Der primäre Unterschied besteht darin, dass die Elemente assoziativ statt sequenziell gespeichert werden. Das heisst, nicht du bestimmst die Reihenfolge, sondern ein zuvor festgelegtes Sortierkriterium (normalerweise der
operator<).Mehr Informationen findest du im Artikel über Container oder auf www.cplusplus.com.
-
So naje hab das jetzt mal angefangen und gleich mal auf ein Problem gekommen.
und zwar schaut das momentan so aus.
Texture::Texture(const string& FileName) { TGAImg Img; // Image loader if(Img.Load(FileName)!=IMG_OK) { cout<<"Fehler beim laden der Textur: "<<FileName<<endl; } glGenTextures(1,&m_TextureID); glBindTexture(GL_TEXTURE_2D,m_TextureID); // Create the texture if(Img.GetBPP()==24) glTexImage2D(GL_TEXTURE_2D,0,3,Img.GetWidth(),Img.GetHeight(),0,GL_RGB,GL_UNSIGNED_BYTE,Img.GetImg()); else if(Img.GetBPP()==32) glTexImage2D(GL_TEXTURE_2D,0,4,Img.GetWidth(),Img.GetHeight(),0,GL_RGBA,GL_UNSIGNED_BYTE,Img.GetImg()); else { cout<<"Fehler: falsches Format von: "<<m_TextureID<<endl; } glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); g_pTexturManager->AddTexture(FileName, //???); }Naja und dann muss ja die Textur in dem Textureditor gespeichert werden. Oder wäre es besser wenn die Texturen auch direkt im Textureditor erstellt werden?
Also das das nicht so ist sonderns das der Texturmanager dann die Funktionen zum erstellen von der Textur aufruft.
Das ist der Kopierkonstruktor. Der wird aufgerufen, falls eine Textur kopiert wird. Hier weiss ich wie gesagt nicht, welches Verhalten von dir erwünscht ist — sollen Kopien überhaupt möglich sein? Soll dabei eine neue identische Textur entstehen, die eigenen Speicher belegt und separat handhabt? Oder ...?
Naja gut wenn man das so mit dem TexturManager macht, braucht man Texturen eignetlich auch nicht mehr kopieren können. Weil man ja dann in dem Objekt (Sprite schon genau weiß welche Textur geladen wird und man sich die nur über die ID, Texturname holen braucht.
Naja bin jetzt echt schon am überlegen ob ich mit dem grafischen aufhören soll und noch mal alles genau in der Konsole machen soll. Wobei mir da das meiste dann wieder so einfach vorgekommen ist, bzw. es ist nie was größeres geworden weil ich nicht wusste was ich da machen sollte.
-
stefan schrieb:
Naja und dann muss ja die Textur in dem Textureditor gespeichert werden. Oder wäre es besser wenn die Texturen auch direkt im Textureditor erstellt werden?
Also das das nicht so ist sonderns das der Texturmanager dann die Funktionen zum erstellen von der Textur aufruft.
Ja. Du machst wieder den gleichen Fehler wie vorher: Du willt der Textur Aufgaben übergeben, für die sie nicht zuständig ist. Erstellung und Zerstörung erfolgt im Texturmanager. Implementiere die Textur als abgeschlossenes System, sodass sie nichts vom Manager weiss (dessen Header also auch nicht einbindet) und somit keine unnötigen Abhängigkeiten besitzt. Der Texturmanager muss dann die Texturen kennen, aber nicht umgekehrt.
stefan schrieb:
Naja bin jetzt echt schon am überlegen ob ich mit dem grafischen aufhören soll und noch mal alles genau in der Konsole machen soll. Wobei mir da das meiste dann wieder so einfach vorgekommen ist, bzw. es ist nie was größeres geworden weil ich nicht wusste was ich da machen sollte.
Um objektorientierte Konzepte und Designsaspekte zu verstärken, empfiehlt sich die Konsole sehr gut. Hier ist auch Erfahrung sehr wichtig - mit der Zeit merkst du wahrscheinlich selber, was sinnvoll ist und was nicht. Auch wenn du neue Sprachmittel oder Dinge aus der Standardbibliothek lernen willst, kannst du in der Konsole gut damit herumexperimentieren.
Ich würde das Projekt aber deswegen nicht über den Haufen werfen. Allerdings könnte es sich auszahlen, zuerst eine Pause mit Grafikprogrammierung einzulegen und andere Dinge zu vertiefen. Kennst du Polymorphie und Templates und kannst du sie gut anwenden? Diese Themen sind sehr wichtig, die würde ich unbedingt gut anschauen. Oder Operatorüberladung? Exception-Handling? Sagt dir RAII was? Weisst du, wie eine eigene Implementierung von
operator newundoperator deleteaussehen könnte? Hast du schon einmal einen eigenen Container geschrieben? Durch solche Projekte kannst du sehr schnell wichtige Dinge von C++ dazulernen, die meines Erachtens grösstenteils von fundamentaler Bedeutung für das weitere Programmieren sind.
-
Naja ich hab schon von dem meisten was gelesen, aber ich hab eigentlich nie was davon so richtig gebraucht außer einmal hab ich Templates gebraucht, wo ich mir ne Singleton-Klasse geschrieben hab.
Und dann halt vererbung grhört ja auch bei Polymorphie mit rein.Hmm ne eigenen Container hab ich mir noch nicht geschrieben. Aber ist das überhaupt so sinvoll sich da einen eigenne zu schreiben, gibts ja schon gute. Oder ist das mehr so zum verständnis dann gedacht? Nimmst du da einen selbstgeschriebenen her?
RAII sagt mir nichts werd ich mir heute aber dann mal anschauen.
Implementierung von operator new und operator delete
Muss ich auch sagen weiß ich nicht...
Naja werd mir wahrscheinlich doch auch mal ein Buch kaufen müssen. Was gibt es denn da gutes?
Hab mal so geschaut und hab dann das gefunden:
"C++ Für Spieele-Programmierer"Weißt wer ob das was ist oder gibt es da bessere Bücher?
EDIT: Oder gibt es Seiten wo Übunsaugaben gestellt werden (vielleicht dann auch mit möglichen Lösungen) wo eine feste Aufgaben stellung ist? Also die Aufgaben sollen aber shcon ein bisschen Sinn haben.
-
stefan schrieb:
Hmm ne eigenen Container hab ich mir noch nicht geschrieben. Aber ist das überhaupt so sinvoll sich da einen eigenne zu schreiben, gibts ja schon gute. Oder ist das mehr so zum verständnis dann gedacht? Nimmst du da einen selbstgeschriebenen her?
Nein, mehr fürs Verständnis. Ich hab das auch mal gemacht und dabei recht viel gelernt (vor allem, was
newunddeleteund Templates betrifft). Sollte nur so ein Beispiel sein, natürlich muss man das nicht zwingend einmal getan haben.
Momentan verwende ich eigentlich nur Standardcontainer und ab und zu solche von Boost, aber eigentlich nie selbstgeschriebene.stefan schrieb:
Naja werd mir wahrscheinlich doch auch mal ein Buch kaufen müssen. Was gibt es denn da gutes?
Hab mal so geschaut und hab dann das gefunden:
"C++ Für Spieele-Programmierer"Weißt wer ob das was ist oder gibt es da bessere Bücher?
Das Buch kenne ich nicht, allerdings würde ich eher zu einem "reinen" C++-Buch raten. Das Spieleprogrammierer-Buch bindet dich wahrscheinlich an eine API (wenns blöd kommt, SDL, was eher kontraproduktiv für das Lernen von C++ ist) und vernachlässigt C++-Teile eher. Aber das ist nur meine Vermutung.
Als C++-Buch wird oft der C++-Primer empfohlen. Ich habe sehr viel durch das C/C++-Kompendium von Dirk Louis gelernt. Wäre gut, wenn noch andere User ihre Empfehlungen abgeben könnten...