SDL 2D Shooter + Gegner/Sternobjekte?



  • Hallo!

    Ich will derzeitig einen einfachen 2D-Shooter schreiben.

    Derzeitig ist der Code wie folgt:

    #include <stdlib.h>
    #include <SDL/SDL.h>
    #include <SDL/SDL_TTF.h>
    #include <windows.h>
    #include <string>
    
    using namespace std;
    
    SDL_Surface *bildschirm;
    TTF_Font *schriftart;
    SDL_Surface *sternbild;
    SDL_Surface *gegbild;
    int xbeschg;
    
    void anz_bmp(int x, int y, SDL_Surface* bildanz)
    {
         SDL_Rect rechteck;
    
         rechteck.x=x;
         rechteck.y=y;
    
         SDL_BlitSurface(bildanz, NULL, bildschirm, &rechteck);}
    
    int anz_txt(int x, int y, char* text)
    {
        SDL_Color farbe;
        farbe.r=255;
        farbe.b=255;
        farbe.g=255;
        SDL_Surface *tempsurf;
        SDL_Rect rechteck;
    
        tempsurf=TTF_RenderText_Blended(schriftart, text, farbe);
    
        rechteck.x=x;
        rechteck.y=y;
    
        SDL_BlitSurface(tempsurf, NULL, bildschirm, &rechteck);
    
        SDL_FreeSurface(tempsurf);}
    
    class sterne{
          public:
                 int x;
                 sterne();
                 ~sterne();
                 void anzeige();
          private:
                  int lkraft, y;
                  SDL_Surface *bild;
                  };
    
    sterne::sterne()
    {
                    x=640+rand()%640;
                    y=rand()%480;
                    bild=sternbild;}
    
    void sterne::anzeige()
    {
                    x-=xbeschg;
                    anz_bmp(x,y,bild);
                    }
    
    sterne::~sterne()
    {
                     }
    
    class spieler{
          public:
                 int x, punkte,xbesch, ybesch, energie,y;
                 void aktuell();
                 spieler();
                 ~spieler();
          private:
                  SDL_Surface *bild;
                  };
    
    void spieler::aktuell()
    {
                      x+=xbesch/30;
                      y+=ybesch/32;
                      x-=xbeschg;
                      if (x<0){x=0;}
                      if (x>630){x=630;}
                      if (y<0){y=0;}
                      if (y>470){y=470;}
                      anz_bmp(x,y,bild);}  
    
    spieler::spieler()
    {
                      int test;
                      bild=SDL_LoadBMP("Daten/rs.bmp");
                      test=SDL_SetColorKey(bild, SDL_SRCCOLORKEY, SDL_MapRGB(bildschirm->format,0,255,0));
                      if (test==-1){
                                    anz_txt(10,10,"Fehler");
                                    SDL_Delay(1000);}
                      xbesch=30;ybesch=0;
                      x=10;y=210;punkte=100;energie=100;};
    
    spieler::~spieler()
    {
                        SDL_FreeSurface(bild);};
    
    class gegner
    {
          public:
                 int x;
                 gegner();
                 ~gegner();
                 void berech(int xs, int ys);
          private:
                  int schuss, schussx, schussy,y;
                  SDL_Surface *bild;};
    
    gegner::gegner()
    {
                    bild=gegbild;
                    x=bildschirm->w+rand()%200;
                    y=rand()%bildschirm->h;}
    
    void gegner::berech(int xs, int ys)
    {
         anz_bmp(x,y,bild);
         x-=xbeschg;}
    
    gegner::~gegner()
    {
                     }
    int main(int argc, char* argv[])
    {
        if (SDL_Init(SDL_INIT_VIDEO)!=0){
                                         MessageBox(NULL, "Leider wird SDL nicht unterstützt","Fehler", 
                                         MB_ICONINFORMATION|MB_OK);
                                         return(0);}
        if (TTF_Init()!=0){
                                         MessageBox(NULL, "Leider wird SDL_TTF nicht unterstützt","Fehler", 
                                         MB_ICONINFORMATION|MB_OK);
                                         return(0);}
    
        char fehler;
        bildschirm=SDL_SetVideoMode(640,480,16,SDL_DOUBLEBUF);
        if (bildschirm==NULL){fehler=*SDL_GetError();
                              MessageBox(NULL, "Leider wird SDL nicht unterstützt"+fehler,"Fehler", 
                                         MB_ICONINFORMATION|MB_OK);
                              return(0);}
    
        SDL_WM_SetCaption("Return To Earth - RTE","");
    
        schriftart=TTF_OpenFont("Daten/Vera.ttf",16);
        if (schriftart==NULL){MessageBox(NULL, 
                                         "Leider wird SDL_TTF nicht unterstützt oder ihre Schriftdatei fehlt"
                                         ,"Fehler", MB_ICONINFORMATION|MB_OK);
                                         return(0);}
    
        sternbild=SDL_LoadBMP("Daten/stern.bmp");
        SDL_SetColorKey(sternbild, SDL_SRCCOLORKEY, SDL_MapRGB(bildschirm->format,0,0,30));
        gegbild=SDL_LoadBMP("Daten/geg.bmp");
        SDL_SetColorKey(gegbild, SDL_SRCCOLORKEY, SDL_MapRGB(bildschirm->format,0,0,30));
        bool ende;
        SDL_Event ereigniss;
        ende=false;
        sterne *stern[30];
        spieler *sp;
        gegner *gegi[20];
        sp=new spieler;
        char buffer[12];
        int tasten[10], i;
        for (i=1; i<29; i+=1)
        {
            stern[i]=new sterne;}
        for (i=1;i<19;i+=1)
        {
            gegi[i]=new gegner;}
        while (ende==false)
        {
              while (SDL_PollEvent(&ereigniss))
              {
                    if (ereigniss.type==SDL_QUIT){return(0);}
                    if (ereigniss.type==SDL_KEYDOWN){
                                                     if (ereigniss.key.keysym.sym==SDLK_ESCAPE){return(0);}
                                                     if (ereigniss.key.keysym.sym==SDLK_UP){tasten[1]=1;}
                                                     if (ereigniss.key.keysym.sym==SDLK_DOWN){tasten[2]=1;}
                                                     if (ereigniss.key.keysym.sym==SDLK_LEFT){tasten[3]=1;}
                                                     if (ereigniss.key.keysym.sym==SDLK_RIGHT){tasten[4]=1;}
                                                     }
                    if (ereigniss.type==SDL_KEYUP){
                                                     if (ereigniss.key.keysym.sym==SDLK_UP){tasten[1]=0;}
                                                     if (ereigniss.key.keysym.sym==SDLK_DOWN){tasten[2]=0;}
                                                     if (ereigniss.key.keysym.sym==SDLK_LEFT){tasten[3]=0;}
                                                     if (ereigniss.key.keysym.sym==SDLK_RIGHT){tasten[4]=0;}   
                                                     }                                        
               }
    
               if (tasten[1]==1 && sp->ybesch>-150){
                                sp->ybesch-=1;
                                if (sp->ybesch<0 && sp->ybesch>-50){sp->ybesch=-50;}
                                if (sp->ybesch>0){sp->ybesch-=1;}
                                }
               if (tasten[2]==1 && sp->ybesch<150){
                                sp->ybesch+=1;
                                if (sp->ybesch>0 && sp->ybesch<50){sp->ybesch=50;}
                                if (sp->ybesch<0){sp->ybesch+=1;}
                                }
               if (tasten[3]==1 && sp->xbesch>-100){
                                sp->xbesch-=1;
                                if (sp->xbesch<0 && sp->xbesch>-60){sp->xbesch=-60;}
                                if (sp->xbesch>0){sp->xbesch-=1;}
                                }
               if (tasten[4]==1 && sp->xbesch<150){
                                sp->xbesch+=1;
                                if (sp->xbesch>0 && sp->xbesch<100){sp->xbesch=100;}
                                if (sp->xbesch<0){sp->xbesch+=1;}
                                }
    
               xbeschg=1;
               if (sp->x>400){xbeschg=2;}
               if (sp->x>450){xbeschg=3;}
               if (sp->x>500){xbeschg=5;}
    
               SDL_FillRect(bildschirm, NULL, SDL_MapRGB(bildschirm->format, 0,0,30));
    
               for (i=1;i<29;i+=1)
               {
                   stern[i]->anzeige();
                   delete stern[i];
                   if (stern[i]->x<-50){stern[i]=new sterne();}}
    
               for (i=1;i<19;i+=1)
               {
                   gegi[i]->berech(sp->x, sp->y);
                   if (gegi[i]->x<(-50)){
                                         delete gegi[i];
                                         gegi[i]=new gegner();
                                         }
                   }
    
               sp->aktuell();
    
               sprintf(buffer, "Punkte: %d Energie: %d", sp->punkte, sp->energie);
               anz_txt(150,1,buffer);
    
               SDL_Flip(bildschirm);
    
        }
        SDL_Delay(1000);         
        SDL_Quit();
    }
    

    Das Problem: er stürzt grundlos ab.

    Wenn ich allerdings

    for (i=1;i<29;i+=1)
               {
                   stern[i]->anzeige();
                   delete stern[i];
                   if (stern[i]->x<-50){stern[i]=new sterne();}}
    
               for (i=1;i<19;i+=1)
               {
                   gegi[i]->berech(sp->x, sp->y);
                   if (gegi[i]->x<(-50)){
                                         delete gegi[i];
                                         gegi[i]=new gegner();
                                         }
                   }
    

    lösche, dann funktioniert es.

    Ein weiteres Problem ist, das SDL_SetColorKey bei allen Objekten nicht geht(die eine angegebene Farbe wird nicht transparent). Kann mir jemand bei diesen beiden Problemen Helfen?



  • Hi!

    Also, pass mal auf: Ein Programm stürzt nicht grundlos ab, sondern das hängt meist an der doofheit des Programmierers. Ich würde mal sagen das du ein Problem hast wenn du Objekte löschst, die ggf nichtmehr erzeugt werden, aber trotzdem stets zur Verfügung stehen sollen.
    Das ist nur eine Vermutung, genaueres solltest du im Umgang mit dem Debugger herausfinden!

    Was mir noch aufgefallen ist:

    for (i=1;i<29;i+=1)
    for (i=1;i<19;i+=1)
    

    Warum fängst du nicht bei Index 0 an? Hat das einen tieferen Sinn?

    grüße


  • Mod

    DaGeRe schrieb:

    delete stern[i];
                   if (stern[i]->x<-50)
    

    😮



  • rapso schrieb:

    DaGeRe schrieb:

    delete stern[i];
                   if (stern[i]->x<-50)
    

    😮

    hier wird die 50 derefernziert - der linke derefernzierungsoperator ist natürlich stärker :p



  • Vertexwahn schrieb:

    rapso schrieb:

    DaGeRe schrieb:

    delete stern[i];
                   if (stern[i]->x<-50)
    

    😮

    hier wird die 50 derefernziert - der linke derefernzierungsoperator ist natürlich stärker :p

    Ja, man munkelt! 🙂 😃



  • @DaGeRe: um dich nicht zu verwirren

    delete stern[i];   // hier gibts du den Speicher stern[i] frei
     if (stern[i]->x < -50) // hier greifst du auf den freigegebenen Speicher zu -> bum!
    


  • Hallo!

    Danke für eure Hilfe. 🙂

    Das mit den Sternen ist mir nun klar, natürlich darf der Stern nur gelöscht werden, wenn er danach neu erstellt wird:

    for (i=1;i<29;i+=1)
               {
                   stern[i]->anzeige();
                   if (stern[i]->x<-50){delete stern[i];
                                        stern[i]=new sterne();}}
    

    Das mit den Gegnern ist mir noch nicht klar.

    Selbst wenn ich einfach nur die Gegener neu erstelle, wenn x<-50 ist,:

    for (i=1;i<19;i+=1)
               {
                   //gegi[i]->berech(sp->x, sp->y);
                   if (gegi[i]->x< (-50)){
                                         //delete gegi[i];
                                         gegi[i]=new gegner();
                                         }
                   }
    

    stürzt es ab.

    Wenn ich jedoch immer Gegner neu erstelle, dann bleibt das abstürzten aus. Und wenn ich einfach nur die if-Abfrage drinne lasse, ohne in der Abfrage was zu machen, stürzt es nicht ab.

    Zu dem mit 1 beginnen: Tut mir leid, ich hab früher mit basic programmiert und steige auf C++ um...und dort gings immer mit 1 los.

    Ach ja, und kann mir jemand zufällig auch bei dem 2. Problem helfen?
    www.dagere.de/RTE-Daten.zip
    Dort sind meine Graphikdateien, das Problem ist: die Farbe 0,0,30 wird nicht transparent dargestellt.

    /EDIT: was ev. noch interresant ist:
    wenn ich gegi[i]->berech; reinmache, und den Rest weg kommentiere, gibt es nur eine interresante Möglichkeit, bei der es abstürzt:

    void gegner::berech(int xs, int ys)
    {
         //anz_bmp(x,y,gegbild);
         x=x;//xbeschg;
         }
    

    Kommentiere ich hingegen das x=x; noch weg, bleibt es. Ich verstehs net... 😕



  • void gegner::berech(int xs, int ys)      //hier hast du xs und ys...
    {
         anz_bmp(x,y,gegbild);                    //hier ist es aber nur x und y...
         x=x;//xbeschg;
    }
    

    mir ist gerdae auch noch aufgefallen, dass deine gegner gar keine y-koordiante haben.. nur x...

    noch eine frage: gibst du den speicher auch irgendwo wieder frei?



  • Hallo!

    Nein, xs und ys sind nicht die Anzeigekoordinaten, das sind die Spielerkoordinaten. Die sollen dann für Koollisionsabfragen gebraucht werden(z.Zt. bedeutungslos).

    Doch, die haben ne y Koordinate, die ist nur private:

    class gegner
    {
          public:
                 int x;
                 char buffer[15];
                 gegner();
                 ~gegner();
                 void berech(int xs, int ys);
          private:
                  int y;//<----
                  SDL_Surface *bild;};
    

    Na, ich mache delete auf den gegner, speicher freigeben ist aber net nötig, weil ich ja das globale gegbild verwende(irgendwann änder ich das - aber erstmal muss es mal so laufen, und da weder Transparenzfarben noch Gegner funzen..)



  • DaGeRe schrieb:

    Na, ich mache delete auf den gegner, speicher freigeben ist aber net nötig, weil ich ja das globale gegbild verwende(irgendwann änder ich das - aber erstmal muss es mal so laufen, und da weder Transparenzfarben noch Gegner funzen..)

    ähmm.. diesen speicher musst du natürlich auch freigeben... es ist egal, ob es global ist oder nicht...

    P.S.: Warum ist die X-Koordinate public, aber die Y-Koordinate private?



  • Wie, freigeben? Ich dachte, der wird am schluss mit SDL_Quit sowieso freigegeben.

    Weil die x Koordinate mit xbeschg(Globale Beschleunigung in X-Richtung^^) verglichen werden muss und so. Derzeitig hat das keinen Grund - bloß für spätere abfragen von der Hauptschleife.

    Angenommen, ich verändere den Gegnerkonstruktor so:

    gegner::gegner()
    {
                    //bild=gegbild;
                    x=500;
                    SDL_FillRect(bildschirm, NULL, SDL_MapRGB(bildschirm->format,0,0,0));
                    printf(buffer,"X: %d", x);
                    anz_txt(10,10,buffer);
                    SDL_Flip(bildschirm);
                    SDL_Delay(1000);
                    //y=rand()%bildschirm->h;
                    }
    

    dann werden so komische Vierecke angezeigt, aber nicht X: 500.



  • Nein mit SDL_Quit wird nur der von SDL allokierte Speicher (insbesondere Screen-Surface etc.) freigegeben.

    Um deine eigenen Objekte musst du schön selbst kümmern.



  • Hm...ja schon....aber ich mein, das hat doch nichts damit zu tun, weshalb es abstürzt und die Transparente Farbe nicht klappt?

    Ich kann das schon noch am schluss rein machen...aber es wird wahrscheinlich den absturz nicht verhindern.



  • also zum thema speicher freigeben aka "reservieren" und speicher verwerfen oder löschen /sperren /kicken /eraz0rn oder was auch immer

    int *b=new int; //speicher für b wird reserviert
    *b=1;     //b ist jetzt 1 !
    cout<<b; //computer wird hier 1 ausgeben
    delete b; //speicher wird gelöscht (verweise werden verworfen)
    cout<<b; //halt!stop! hier wird das programm abstürzen, denn
            //du versuchst b auszugeben, obwohl keine verweise auf b mehr vorhanden 
             //sind, das heisst, der pc weiss nicht wo er b finden kann und gibt 
             //entweder nen error aus oder es passiert etwas undefiniertes(z.b gibt
            //er eine willkürliche zahl aus)
    
    b=new int;
    b=1;
    cout<<b; //ja, dass hat geklappt! neuer speicher ist angeschafft und du kannst
            //auf b zugreifen
    


  • Ok. Danke erstmal, ich glaube, das habe ich jetzt verstanden.

    Es ist demzufolge anzunehmen, das die Objekte falsch initiallisiert/wieder gelöscht wurden.
    Ich habe weiterhin herausgefunden, das das Problem eigentlich bei den Koordinaten ist.

    Das ist die Klasse:

    class gegner
    {
          public:
                 int x;
                 gegner();
                 ~gegner();
                 void berech(int xs, int ys);
          private:
                  int y;};
    
    gegner::gegner()
    {
                    x=500;
                    y=rand()%bildschirm->h;
                    }
    
    void gegner::berech(int xs, int ys)
    {
         anz_bmp(1,1,gegbild);
         //x=x;//xbeschg;
         }
    
    gegner::~gegner()
    {
                     //x=0;
                     //y=0;
                     }
    

    Wenn ich beim Desturktor x=0 oder y=0 setze kommt es zum absturz. Bei dem void berech funktioniert es nur, wenn ich Zahlen eingebe, benutze ich x oder y kommt es zum Absturz.

    Vor der Hauptschleife ist nun:

    gegner *gegi[20];
    for (i=1;i<19;i+=1)
        {
            gegi[i]=new gegner();}
    

    zur Intiallisierung der Variablen(hier kommt es zu keinen Problemen).

    Jedoch bei:

    for (i=1;i<19;i+=1)
               {
                   gegi[i]->berech(sp->x, sp->y);
                   //if (gegi[i]->x< (-50)){
                                         delete gegi[i];
                                         gegi[i]=new gegner();
                                         //}
                   }
    

    kommt es wieder zu Problemen, wenn ich das if dingens nicht kommentiert habe.
    Ach ja, am Rande: deshalb ist x global: das man das Objekt zerstören und neu erstellen kann, wenn es am Bildschirmrand verschwunden ist.

    Leider verstehe ich eins noch nicht: wieso ist x/y falsch initiallisiert? Es ist doch genau so wie bei sterne int x und int y vorhanden.



  • Hi!

    @TravisG:
    Das stimmt nich so ganz, es muss heisen:

    *b = 1;
    

    @DaGeRe:
    Warum verwendest du nicht einfach Vektoren? Du würdest dir massig Arbeit sparen und (an dieser Stelle) um das erlernen des Debuggens herumkommen, da du das ja anscheinend sowiso nicht für notwendig hältst...

    grüße



  • Na, wie debugge ich denn?

    Ich benutze Dev C++, falls das wichtig ist.

    /EDIT: ES KLAAAAAAAPT! Ich hab mir gedacht, x und y werden nicht aktuallisiert, der Fehler ist im Konstruktor oder so(von daher hätte nen Debugger nicht soo viel geholfen) - also nehm ich in die Klasse mal einfach xg und yg als Koordinaten(für xgegner und ygegner). Und jetzt KLAPPT es. Ich weiß zwar nicht wieso es mit x und y nicht geklappt hat, aber es geht :-). Wenn mir jemand noch sagen könnte, wieso x bzw. y nicht geklappt hat, wäre ich restlos glücklich.



  • DaGeRe schrieb:

    der Fehler ist im Konstruktor oder so(von daher hätte nen Debugger nicht soo viel geholfen)

    Wieso hilft dir da kein Debugger weiter? Ich hege die Befürchtung das du nichtmal weist was genau das ist! 🙂

    grüße



  • Richtig befürchtet...
    Im ICQ hat mir jemand gesagt, damit kriege ich die Programmzeile raus, wo es abstürzt. Und so weit war ich ja schon 😉

    Ist jetzt aber auch egal...
    Kann mir jemand eventuell nach sagen, wieso die Farbe 0,0,30 nicht transparent angezeigt wird?


Anmelden zum Antworten