Bewegung gleichmäßig darstellen



  • Hallo,

    ich versuche mit SDL ein sich bewegendes Bild unabhängig von der Framerate darstellen zu lassen. Dabei bewegt sich own.bmp (ein 5sec Paint Bild) von links nach rechts über den Screen. Ich habe dieses Testprogramm erstellt, um zu überprüfen, ob FPS-Unabhängige-Bewegung funktioniert, aber es klappt nicht und ich finde den Fehler nicht.

    Ich lasse das Programm zweimal starten: Einmal drücke ich SDLK_LEFT (linke Pfeiltaste), wodurch 300 mal cb.bmp auf den Bildschirm gezeichnet wird und einmal drücke ich es nicht, es ist also nur ein Bild (bzw. zwei) auf dem Bildschirm. Die FPS ist bei 300 Bildern ca. bei 10 und bei dem anderen ca. 350.

    Trotz meiner Berechnung des "Movement Value" (übrigens von diesem Tutorial: http://www.gamedev.net/reference/articles/article1604.asp ) bewegt sich ein own.bmp immer schneller.

    P.S.: Der nachfolgende Code ist der CodeBlocks Standard SDL Code mit ein paar Veränderungen von dem Tutorial.
    Wenn ihr es auch testen möchtet, braucht ihr zwei 5sec-Paint-Bilder namens "own.bmp" und "cb.bmp".

    P.P.S.: Bei Enter bewegt sich das Bild.

    #include <SDL/SDL.h>
    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    using namespace std;
    
    int main ( int argc, char *argv[] )
    {
        srand(time(0));
    
    	int count = 0, r = 0;
    
    	// initialize SDL video
        SDL_Init( SDL_INIT_VIDEO );
    
        // make sure SDL cleans up before exit
        atexit(SDL_Quit);
    
        // create a new window
        SDL_Surface* screen = SDL_SetVideoMode(640, 480, 16,
                                               SDL_HWSURFACE|SDL_DOUBLEBUF);
    
        // load an image
        SDL_Surface* bmp = SDL_LoadBMP("cb.bmp");
    	SDL_Surface* own = SDL_LoadBMP("own.bmp");
    
        // centre the bitmap on screen
        SDL_Rect dstrect, dst;
    	dst.x = 0;
    	dst.y = 0;
        dstrect.x = (screen->w - bmp->w) / 2;
        dstrect.y = (screen->h - bmp->h) / 2;
    
        // program main loop
        bool done = false;
    
    	/****************************************************/
    	int v = 0;
    	Uint32 timerdiff;
    	double secsperframe; //used to hold the value for how many seconds have elapsed between frames
    	const double desireddistance = 2.0f; //desired distance to move in a second
    	double movementvalue = 0.0f; //value to move by each frame
    	Uint32 timer = SDL_GetTicks(); //the last recorded time.
    	/****************************************************/
    
        while (!done)
    	{				
    		// message processing loop
            SDL_Event event;
            while (SDL_PollEvent(&event))
            {
                // check for messages
                switch (event.type)
                {
                    // exit if the window is closed
                case SDL_QUIT:
                    done = true;
                    break;
    
                    // check for keypresses
                case SDL_KEYDOWN:
                    {
    					if(event.key.keysym.sym == SDLK_LEFT)
    						count = 300;
    
    					if(event.key.keysym.sym == SDLK_RIGHT)
    						count = 0;
    
    					if(event.key.keysym.sym == SDLK_RETURN)
    						 v = 1;
    
    					if(event.key.keysym.sym == SDLK_BACKSPACE)
    						 v = 0;
    
    					// exit if ESCAPE is pressed
                        if (event.key.keysym.sym == SDLK_ESCAPE)
                            done = true;
    
                        break;
                    }
                } // end switch
            } // end of message processing
    
    		/****************************************************/
    		if(v == 1) // movement
    		{
    			double s = (double)1000.0f * movementvalue;
    			cout << "s = " << s << "\tr = " << r << "\tFPS: " << (int)(1.0f / secsperframe) << endl;
    
    			dst.x += s;
    			if(dst.x > 640-1){ dst.x = 0; r++; }
    		}
    		/****************************************************/
    
            // DRAWING STARTS HERE
    
            // clear screen
            SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
    
            // draw bitmap
    		SDL_BlitSurface(bmp, 0, screen, &dstrect);
    
    		for(int i = 0; i < count; ++i)
    		{
    			SDL_Rect temp;
    			temp.x = rand() % 640;
    			temp.y = rand() % 480;
    			SDL_BlitSurface(bmp, 0, screen, &temp);
    		}
    
    		SDL_BlitSurface(own, 0, screen, &dst);
    
            SDL_Flip(screen);
    
    		/****************************************************/
    		//first determine how many milliseconds elapsed
    		timerdiff = SDL_GetTicks() - timer;
    
    		//the function reads in milliseconds so convert to seconds by dividing by 1000
    		secsperframe=(double)((double)timerdiff/(double)1000.0f);
    
    		//now compute the movement value
    		movementvalue = desireddistance * secsperframe;
    
    		//get the new time
    		timer = SDL_GetTicks();
    		/****************************************************/
    
        } // end main loop
    
        // free loaded bitmap
        SDL_FreeSurface(bmp);
    
        // all is well ;)
        printf("Exited cleanly\n");
        return 0;
    }
    

    Danke für eure Hilfe!



  • Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum Spiele-/Grafikprogrammierung verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • baron schrieb:

    Hallo,

    Trotz meiner Berechnung des "Movement Value" (übrigens von diesem Tutorial: http://www.gamedev.net/reference/articles/article1604.asp ) bewegt sich ein own.bmp immer schneller.

    double movementvalue = 0.0f; //value to move by each frame
    

    Nur ein Anreiz, ohne den Source komplett gelesen oder gar kompiliert zu haben: "value to move by each frame" ist vielleicht unpraktisch, wenn die fps mal steigt und mal sinkt.

    Mach die Position Deiner Elemente von der Zeit abhängig, nicht von der Anzahl der schon ausgegebenen Bilder.



  • du musst alle geschwindigkeiten in px/sec angeben, oder etwas Äquivalentem. Dann für jeden Frame die vergangene Zeit in Sekunden, und diesen Faktor bei absolut jeder Berechnung, die die Geschwindig nutzt um eine neue Position zu berechnen als Faktor hinzunehmen. Das ist der mir einzig sinnvolle Ansatz. Mit den FPS die pro-Frame-Geschwindigkeit zu berechnen ist nicht unbedingt der richtige ansatz und weil unkonventionell auch sehr unübersichtlich.



  • Ich berechne doch die Zeitdifferenz und nutze die dann als Faktor.

    Könnt ihr mir das vielleicht ein wenig ausführlicher erklären? Ich verstehe nicht ganz recht, was ihr meint 🙂

    der baron



  • trenne am besten einfach gameticks und "realtime-ticks"

    while(meineschleifeläuftnoch)
    {
        //Irgendwo hier zeitmessen
    
        if(30ms vorbei)
        { //GAMETICK
          if(benutzer drückt "dies und das")
              bewege_futzi(x,y);
        }
    
         rendern(); 
    }
    

    edit: omg tags


Anmelden zum Antworten