SDL : Geschiwindigkeitsverlust



  • Hallo, ich hab mir ein kleines Snake-Grundgerüst gebaut.
    Dabei besteht die Schlange aus einzelnen Pixeln, deren Position in einem Array gespeichert ist.Bei 200 Pixeln läuft das ganze normal. Wenn ich die Länge der Schlange auf 1000 erhöhe, dann spielt sich das ganze Programm in einem Zeitlupentempo ab.
    Komisch ist aber, dass das Spiel auch mit 1000 Pixeln flüssig läuft, wenn das Spielfenster Inaktiv ist. Sobald das Fenster wieder aktiv ist, spielt sich das ganze wieder in einem langsamen Tempo ab.

    Weiß jemand , an was es liegen könnte ?

    Wer sich den Code anschauen will , hier :

    #include <SDL.h>
    
    void DrawPixel(SDL_Surface *screen, int x, int y,Uint8 R, Uint8 G,Uint8 B);  //Zeichnet ein Pixel
    
    SDL_Surface *screen;
    
      SDL_Event event;
    
     int i;
    
      const int SnakeLen = 1000;
      int snakeX=300,snakeY=300;    //Die Position des erste Pixels der Schlange
      int xPlus=1,yPlus=0;          //Die Richtung
    
      int snakex[SnakeLen+1]={0},snakey[SnakeLen+1]={0};   //Die restlichen Positionen der Pixel 
    
       Uint8 *keys;   //Speichert die gedrückte Taste
    
      bool done = false;   //prüft, ob die hauptschleife weiterläuft
    
    int main(int argc, char *argv[])
    {
    
      atexit(SDL_Quit);
    
      screen = SDL_SetVideoMode(800,600,32,SDL_HWSURFACE | SDL_DOUBLEBUF);
    
        while(!done)
        {
    
            while(SDL_PollEvent(&event)) //Prüfen, ob das Programm verlassen wird 
            {
                switch(event.type)
    			{
    				case SDL_QUIT:
    				done = true;
    				break;
    
    			}
            }
    
    	 SDL_FillRect(screen,NULL,SDL_MapRGB(screen->format,255,255,255)); //Bildschirm löschen
    
    	snakeX+=xPlus;                                  //Die Schlange bewegt sich in die aktuelle Richtung weiter
    	snakeY+=yPlus;
    
    	for (i=0;i<=SnakeLen;i++)
    	{
    		DrawPixel(screen,snakex[i],snakey[i],0,0,0);  //Jedes Pixel zeichnen
    	}
    
    	for(i=SnakeLen;i>=0;i--)
    	{
    		snakex[i]=snakex[i-1];           //Jedes Pixel erhält die Position des Pixels vor ihm
    		snakey[i]=snakey[i-1];
    	}
    
    	snakex[0] = snakeX;             //Die Hauptkoordinaten
    	snakey[0] = snakeY;
    
    	keys = SDL_GetKeyState(NULL);   //Tasten Prüfen
    		if(keys[SDLK_UP])
    		{
    			xPlus = 0;
    			yPlus = -1;
    		}
    		if(keys[SDLK_DOWN])
    		{
    			xPlus= 0;
    			yPlus= 1;
    		}
    		if(keys[SDLK_RIGHT])
    		{
    		    xPlus= 1;
    			yPlus= 0;
    		}
    		if(keys[SDLK_LEFT])
    		{
    			xPlus=-1;
    			yPlus =0;
    		}	
    
    		SDL_Flip(screen); 
        }
    
        return 0;
    }
    
    void DrawPixel(SDL_Surface *screen, int x, int y,Uint8 R, Uint8 G,Uint8 B)
    {
        Uint32 color = SDL_MapRGB(screen->format, R, G, B);
    
        if ( SDL_MUSTLOCK(screen) ) {
            if ( SDL_LockSurface(screen) < 0 ) {
                return;
            }
        }
        switch (screen->format->BytesPerPixel) {
            case 1: { /* vermutlich 8 Bit */
                Uint8 *bufp;
    
                bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
                *bufp = color;
            }
            break;
    
            case 2: { /* vermutlich 15 Bit oder 16 Bit */
                Uint16 *bufp;
    
                bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
                *bufp = color;
            }
            break;
    
            case 3: { /* langsamer 24-Bit-Modus, selten verwendet */
                Uint8 *bufp;
    
                bufp = (Uint8 *)screen->pixels + y*screen->pitch + x * 3;
                if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {
                    bufp[0] = color;
                    bufp[1] = color >> 8;
                    bufp[2] = color >> 16;
                } else {
                    bufp[2] = color;
                    bufp[1] = color >> 8;
                    bufp[0] = color >> 16;
                }
            }
            break;
    
            case 4: { /* vermutlich 32 Bit */
                Uint32 *bufp;
    
                bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
                *bufp = color;
            }
            break;
        }
        if ( SDL_MUSTLOCK(screen) ) {
            SDL_UnlockSurface(screen);
        }
        SDL_UpdateRect(screen, x, y, 1, 1);
    }
    


  • Heutzutage ist Videospeicher nicht dafür gemacht, um darin einzelne Pixel zu setzen.

    Bye, TGGC (NP Intelligenz)



  • Ist es dann besser wenn ich ein 1*1 großes Bild lade und es zeichne ?



  • In deinem Programm werden für jeden einzelnen Pixel dir Lock/Unlock Methoden in der DrawPixel-Funktion aufgerufen.

    Wie wärs, wenn du die SDL_Lock(...) und SDL_Unlock(...)- Aufrufe aus der Funktion DrawPixel(...) nimmst und um die for-Schleife mit dem DrawPixel-Aufruf setzt:

    if ( SDL_MUSTLOCK(screen) ) 
    {
       if ( SDL_LockSurface(screen) < 0 ) 
           return;
    }
    
    for (i=0;i<=SnakeLen;i++)
       DrawPixel(screen,snakex[i],snakey[i],0,0,0);  //Jedes Pixel zeichnen
    
    if ( SDL_MUSTLOCK(screen) ) 
       SDL_UnlockSurface(screen);
    

    Und wozu brauchst du

    SDL_UpdateRect(screen, x, y, 1, 1);
    

    , wenn du doch Doublebuffering verwendest?

    Mal hoffen, dass nun dein Programm schneller läuft.



  • Na dann 🙂 Danke

    Die funktion habe ich aus einem Beispiel kopiert, ohne sie näher anzuschauen.



  • Falls du HW Support hast wäre eine dritte Idee nur die Eckpunkte zu speichern und dann mit einem Linestrip zu zeichnen.

    Bye, TGGC (Denken, und gut ist.)



  • Diese PutPixel-Funktion aus der SDL-Doku war vermutlich auch eher nur als Beispiel gedacht... Da du dich bei SDL_SetVideoMode eh auf 32Bit festlegst, ist der case-Block recht überflüssig.

    (achso, mehr Performance würde die fehlende Abfrage aber auch nicht wirklich bringen)


Anmelden zum Antworten