Wie lasse ich ein Objekt korrekt von SDL_Rect erben?
-
Hi, ich bin kein erfahrener Programmierer und das ist das erste Mal, dass ich eine Klasse von mir von einer Klasse erben lasse, die ich nicht selbst geschrieben habe. Und ja, ich benutzte deutsche Variablennamen und weiß, dass viele meinen, dass man das nicht sollte.
Mein Quelltext sieht so aus:
class Spieler : public SDL_Rect { public: Spieler(int* SpielfeldversatzX, int* SpielfeldX, int* SpielfeldversatzY, int* SpielfeldY, int AILevel) : x(SpielfeldversatzX + SpielfeldX/7 - SpielfeldX/40), y(SpielfeldversatzY + SpielfeldY/2 - SpielfeldX/8), w(SpielfeldX/82.6), h(SpielfeldX/16.5), Punkte(0), AILevel(AILevel), dSpeedY(0), dPosY(y){}
Das funktioniert nicht. Eigentlich müsste ich ja den Konstruktor von SDL_Rect aufrufen, aber ich weiß gar nicht ob SDL_Rect einen Konstruktor hat.
Was ich nicht verstehe ist, dass der Compiler meint:
C:\...\Spieler.h|11|error: class `Spieler' does not have any field named `x'|
Wenn Spieler von SDL_Rect erbt, muss es dann nicht eigentlich auch die Variablen erben? Sorry wenn das ne doofe Frage ist, aber ich dachte bisher, das ist so, das Variablen auch vererbt werden.
-
Ist SDL_Rect nicht eine Variable?
-
Nein, es muss eine Klasse sein, denn du kannst:
SDL_Rect Variable; Variable.x = 10; Variable.y = 5; Variable.w = 20; Variable.h = 40;
Ich habs jetzt geändert und meine Klassen erben nicht mehr. Doch jetzt spinnt der Compiler völlig:
Ein Ausschnitt einer meiner Klassen:
class Ball { public: Ball(int* SpielfeldversatzX, int* SpielfeldX, int* SpielfeldversatzY, int* SpielfeldY) : dPosX(*SpielfeldversatzX + *SpielfeldX/2), dPosY(*SpielfeldversatzY + *SpielfeldY/2), w(*SpielfeldX/82.6), h(*SpielfeldX/82.6) { ... protected: //w, h, x und y als int sind schon vererbt vorhanden int w; int h; double dPosX; double dPosY; double dSpeedX; double dSpeedY; };
Der Compiler spuckt für alle Variablen aus:
C:\...\Ball.h|21|error: class `Ball' does not have any field named `dPosX'|
Wie kann es denn zu dem Fehler kommen?
-
SDL_Rect ist ein type, keine klasse:
typedef struct{ Sint16 x, y; Uint16 w, h; } SDL_Rect;
-
Hi,
Little Programmer schrieb:
Nein, es muss eine Klasse sein, denn du kannst:
SDL_Rect Variable; Variable.x = 10; Variable.y = 5; Variable.w = 20; Variable.h = 40;
omg da fehlt aber einiges. Also zuerst solltest du dir Grundlagen aneignen, sonst wird das nix. Schon mal was von Unions oder Strukturen(is mir schon klar das in C++ Strukturen eig Klassen mit default public membern sind) gehoert!? Das koennte alles sein.
Desweiteren haste dich schon mal ueber SDL informiert!? Glaub ned oder, weil sonst haetteste das gelesen:
SDL is written in C, but works with C++ natively
SDL Doku schrieb:
1 typedef struct{ 2 Sint16 x, y; 3 Uint16 w, h; 4 } SDL_Rect;
Peace C0de4Fun
-
und wieso kann man von einem typedef-struct nicht erben?
und wieso kann man ihn nicht mit class Name; forwärtsdeklarieren?Ist ja nicht so, dass C++ großartig logisch ist :p
Little Programmer schrieb:
Hi, ich bin kein erfahrener Programmierer und das ist das erste Mal, dass ich eine Klasse von mir von einer Klasse erben lasse, die ich nicht selbst geschrieben habe.
dann am besten mal über Vererbung an sich nachlesen. Da ist vor allem falsch, dass Player überhaupt von Rect erbt. Die Position+Größe ist doch bestimmt nur eine Eigenschaft des Players?
-
Das Erben von Rect hätte des Umstand erspart die x, y, w und h Werte des players erst in ein SDL_Rect eintragen zu müssen, bevor ich ihn in SDL zeichnen kann. (Ja, der Spieler soll ein Viereck sein
) Ich hab jetzt einfach den Umstand eingebaut, dass nun für jeden Frame eine temporäres SDL_Rect erzeugt wird, aber so funktioniert es. Danke für eure Erklärungen.
-
Little Programmer schrieb:
Das Erben von Rect hätte des Umstand erspart die x, y, w und h Werte des players erst in ein SDL_Rect eintragen zu müssen, bevor ich ihn in SDL zeichnen kann. (Ja, der Spieler soll ein Viereck sein
) Ich hab jetzt einfach den Umstand eingebaut, dass nun für jeden Frame eine temporäres SDL_Rect erzeugt wird, aber so funktioniert es. Danke für eure Erklärungen.
Deine Vorgehensweise ist alles andere als empfehlenswert. Und das Eintragen der Daten in ein SDL_Rect, kann eigentlich kein Problem sein. Du brauchst zum Zeichnen ja sowieso ein SDL_Rect. Sogesehen solltest du ein SDL_Rect als Member in deiner Klasse haben. Das ständige neuerstellen ist jedenfalls keine gute Idee.
Und wenn du unbedingt von einer Klasse erben willst, dann schreib dir eine Sprite-Klasse, von der deine Spieler-Klasse erben kann. Das wäre dann sogar sinnvoll. Eventuell kann ich dir später ein Beispiel machen.
-
Hier mal ein Beispiel, wie man es machen könnte. Ich habe ein paar Spielerein eingebaut, damit du das ganze mal in Action sehen kannst. Auch habe ich die Initialisierung ein wenig gekapselt. Um Aufräumarbeiten muss man sich hier jedenfalls nicht mehr kümmern:
#include <iostream> #include <string> #include <ctime> #include <SDL.h> #undef main // Fix für Visual Studio... Bei mir linkt es sonst nicht... class Sprite { protected: SDL_Surface *myScreen; SDL_Surface *mySurface; SDL_Rect myRect; public: Sprite(SDL_Surface *screen) : myScreen(screen), mySurface(NULL) { myRect.x = 0; myRect.y = 0; } Sprite(Sprite& spr) { myScreen = spr.getScreen(); mySurface = spr.copySurface(); } Sprite &Sprite::operator=(Sprite &spr) { cleanup(); myScreen = spr.getScreen(); mySurface = spr.copySurface(); return *this; } ~Sprite() { cleanup(); } bool loadSprite(const std::string& filename) { cleanup(); mySurface = SDL_LoadBMP(filename.c_str()); if (!isValid()) { std::cerr << "Could not load " << filename << std::endl; return false; } return true; } void render() { SDL_BlitSurface(mySurface, NULL, myScreen, &myRect); } SDL_Surface *getScreen() { return myScreen; } SDL_Surface *copySurface() { return SDL_ConvertSurface(mySurface, mySurface->format, SDL_SWSURFACE); } SDL_Surface *getSurface() { return mySurface; } int getW() const { return mySurface->w; } int getH() const { return mySurface->h; } int getX() const { return myRect.x; } int getY() const { return myRect.y; } void setX(int x) { myRect.x = x; } void setY(int y) { myRect.y = y; } bool isValid() const { return mySurface != NULL; } private: void cleanup() { if (isValid()) { SDL_FreeSurface(mySurface); } } }; class Spieler : public Sprite // Wir erben von Sprite { private: int speedX; int speedY; public: Spieler(SDL_Surface *screen) : Sprite(screen), speedX(4), speedY(4) { if (!loadSprite("Sprite.bmp")) // wir brauchen nur das Sprite laden, den Rest macht die Basisklasse { // Exception oder sonst was... Liegt an dir. } } void move(int x = 1, int y = 1) { setX(getX() + (x * speedX)); setY(getY() + (y * speedY)); } void invertSpeedX() { speedX = speedX * -1; } void invertSpeedY() { speedY = speedY * -1; } void setSpeedX(int x) { speedX = x; } void setSpeedY(int y) { speedY = y; } int getSpeedX() const { return speedX; } int getSpeedY() const { return speedY; } }; class Context { private: SDL_Surface *myScreen; public: Context() { srand((unsigned int) time(NULL)); } ~Context() { SDL_Quit(); } bool init(int w, int h, int bpp) { if (SDL_Init(SDL_INIT_VIDEO) == -1) { std::cerr << "Can't init SDL: " << SDL_GetError() << std::endl; return false; } myScreen = SDL_SetVideoMode(w, h, bpp, SDL_HWSURFACE); if (myScreen == NULL) { std::cerr << "Can't set video mode: " << SDL_GetError() << std::endl; return false; } return true; } void wait(int ms) { SDL_Delay(ms); } void update() { SDL_UpdateRect(myScreen, 0, 0, 0, 0); } void clear(int r = 0, int g = 0, int b = 0) { SDL_FillRect(myScreen, 0, SDL_MapRGB(myScreen->format, r, g, b)); } SDL_Surface *getScreen() const { return myScreen; } }; const int SCREEN_W = 800; const int SCREEN_H = 600; int main() { Context ctx; if (!ctx.init(SCREEN_W, SCREEN_H, 16)) { std::cerr << "init() failed" << std::endl; return 1; } Spieler spieler1(ctx.getScreen()); spieler1.setX(rand() % (SCREEN_W - spieler1.getW())); spieler1.setY(rand() % (SCREEN_H - spieler1.getH())); SDL_Event ev; bool running = true; while (running) { while (SDL_PollEvent(&ev)) { switch(ev.type) { case SDL_QUIT: running = false; break; } } ctx.clear(); // Oder für die hartnäckigen: ctx.clear(rand() % 255, rand() % 255, rand() % 255); spieler1.render(); spieler1.move(); if (spieler1.getX() + spieler1.getW() >= SCREEN_W) { spieler1.invertSpeedX(); } else if (spieler1.getX() <= 0) { spieler1.invertSpeedX(); } if (spieler1.getY() + spieler1.getH() >= SCREEN_H) { spieler1.invertSpeedY(); } else if (spieler1.getY() <= 0) { spieler1.invertSpeedY(); } ctx.update(); } return 0; }
Wäre jedenfalls ein simpler Bildschirmschoner
-
Wow, danke für die ganze Arbeit. Soweit, dass man ein SDL_Rect usw. auch in eine Klasse als Variable reinschreiben kann hab ich gar nicht gedacht. Vielen Dank für den Hinweis!