wie am besten geschwindigkeiten umsetzen?



  • so ich hab folgenden code:
    SDL_Sprite.h

    // SDL_Sprite.h
    #include "SDL.h"
    #include <string>
    using namespace std;
    const int ciSpriteWidth =79;
    const int ciSpriteHeight=79;
    class SDL_Animation
    {
    private:
    	int iAnimState;
    	Uint32 curframe,lastframe,frametime;
    protected:
    		SDL_Surface *m_sprite, *m_target,*m_animTarget;
    		SDL_Rect dest;
    		SDL_Rect src;
    public:
    	SDL_Animation()
    	{
    		iAnimState=0;
    	}
    	void animWalk()
    	{
    		if(iAnimState==0) //Starting Animation
    		{
    			src.x=320;
    			iAnimState++;
    		}
    		else if(iAnimState==1)//first step
    		{
    			src.x+=80; //Set Bitmap Window which is showed to next animation state
    			iAnimState++;
    		}
    		else if(iAnimState>=1 && iAnimState <=3)//Second to 4th step
    		{
    			src.x+=80;
    			iAnimState++;
    		}
    		else if(iAnimState>=3 &&iAnimState <=5)//and back again
    		{
    			src.x-=80;
    			iAnimState++;
    		}
    		else if(iAnimState>5) 
    		{
    			src.x-=80;
    			iAnimState=1;
    		}
    	}
    };
    class SDL_Sprite:public SDL_Animation  //Sprites
    {
    private:
    
    public:
    	SDL_Sprite(SDL_Surface *target, SDL_Surface *newSurface)
    	{//target(i.e. screen), surface(i.e. "SDL_Surface testimage =SDL_LoadBMP(...),xpos,ypos
    		m_sprite = newSurface;
    		m_target = target;
    	};
    	SDL_Sprite();
    	void setImage()//Set Animationstate to 0,0
    	{
    		src.x=0;
    		src.y=0;
    	}
    	void draw(int x, int y)
    	{
    		dest.x=x;
    		dest.y = y;
    		dest.w=79;
    		dest.h=79;
    		src.w=79;
    		src.h=79;
    		SDL_BlitSurface(m_sprite, &src, m_target, &dest);
    	}
    	void move(int x, int y);
    };
    

    und main.cpp

    // main.cpp
    //LF XP Build 0001
    #ifdef WIN32
    #pragma comment(lib, "SDL.lib")
    #pragma comment(lib, "SDLmain.lib")
    #endif
    #include <stdlib.h>
    #include "SDL.h"
    #include <string>
    #include "SDL_Sprite.h"
    const int SCREEN_WIDTH = 800;
    const int SCREEN_HEIGHT = 600; // screen= Hingergrund, sGalaxy = galaxien.bmp
    
    int main(int argc, char **argv)
    {
    	SDL_Surface *screen; 
    	if(SDL_Init(SDL_INIT_VIDEO)<0)
    	{
    		printf("Error: Couldn initalize Video\n");
    		exit(1);
    	}
    	screen=SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT,32, SDL_DOUBLEBUF);
    	if(!screen)
    	{
    		printf("Error: No Screen found\n");
    		exit(1);
    	}
    
    	SDL_Surface *lol;
    	lol=SDL_LoadBMP("sprite/template1/0.bmp");
    	bool running=true; //Game continueing ? 8[ teh sucks
    	int state=0;
    	int bildpos=0;
    	int bildposy=0;
    	Uint8 *keys;
    	int mouseX=0, mouseY=0;
    	SDL_GetMouseState(&mouseX,&mouseY);
    	SDL_Event event;
    	SDL_Sprite bild(screen,lol);
    	while(running==true)
    	{
    		while(SDL_PollEvent(&event))
    		{
    			switch(event.type)
    			{
    			case SDL_QUIT: //teh quit sucks
    				running=false;
    				break;
    			case SDL_KEYDOWN: //Here keyboard input teh sucks
    				switch(event.key.keysym.sym)
    				{
    				case SDLK_ESCAPE:
    					running=false;
    					break;
    				}
    			case SDL_MOUSEMOTION: //everytime when mouse is moved, you can put conditions here
    				break;
    			}
    		}
    			keys=SDL_GetKeyState(NULL);
    			//Here the control options, not in switch(event.key.keysym.sym)
    			if(keys[SDLK_RIGHT])
    			{
    				if(state==1)
    				{
    					bild.animWalk();
    					bildpos+=70;
    					if(bildpos > (SCREEN_WIDTH-80))
    					{
    						bildpos=0;
    						bildposy+=80;
    					}
    					bild.draw(bildpos,bildposy);
    				}
    				else
    				{
    					bild.setImage();
    					bild.draw(bildpos,bildposy);
    					state ++;
    				}
    			}
    		SDL_Flip (screen);
    	}
    	atexit(SDL_Quit);
    	return 0;
    }
    

    bis jetzt macht der code folgendes:
    Er startet das programm, macht ein fenster auf und zeigt einen schwarzen bildschirm an.
    drückt der benutzer jetzt "pfeiltaste rechts" so wird die animationsreihenfolge "laufen" angemacht und die figur im bildschirm bewegt sich.

    soweit so gut.
    ich habe hier 2 testrechner zur verfügung. was auffält ist, das bei meinem hauptrechner(amd athlon 64 3200++,geforce 4 ti 4200,512 mb ddr ram[pc400])
    die figur ca doppelt so schnell animiert wird wie bei meinem
    zweitrechner(intel pentium 4 1,5 ghz, radeon 7500 , 256 mb ddr ram[pc233 wenn ich mcih nicht täusche).

    woher das kommt weis ich. mein hauptrechner berechnet alle daten einfach viel schneller. was her muss weiss ich auch: eine geschwindigkeitsberechnung.

    jedoch weiss ich nicht wie ich sie ansetze. solche sachen wie _sleep(100) oder SDL_Delay(300) will ich nicht verwenden, da dabei nicht nur die animation ne pause machen würde sondern auch z.b alle gegner im lvl stehen bleiben/langsamer laufen würden. und das will ich ja natürlich nicht.

    freue mich auf kommende hilfe

    mfg travisg



  • Dein Problem hatten hier auch schon andere Leute. Sicherlich gibt es dafür verschiedene Ansätze. Wichtig ist zB, dass du deine Logik vom Rendering trennst. Dann hängen deine Animationen auch nicht mehr von der Geschwindigkeit der Anzeige ab. Und Funktionen wie sleep sollte man möglichst auch nicht verwenden, das hast du ja schon richtig erkannt.
    Ich mach es zB so, dass ich mir in jedem Frame einen Zeitstempel hole. Mit diesem kannst du dann deine Animationen zeitlich immer gleich ablaufen lassen, egal ob da ein Schritt über 100 oder 1000 Frames erfolgt. Hier mal etwas Pseudocode zur Veranschaulichung:

    sprite s;
    //...
    zeitstempel z = hole_zeitstempel(); // in ms
    if (z >= s.letzter_zeitstempel + 50) // 50 ms fuer naechsten Animationsschritt
    {
        s.animate();
        s.letzter_zeitstempel += 50;
    }
    

    Ansonsten such mal im Forum, hier gab es schon genügend Beiträge dazu.



  • gibt es in standart c++ eine funktion zum messen der ms während des frames? oder weisst du eine von SDL ?



  • Hier in SDL:

    void Calc()
    {
        static int Last;
        const int Past = SDL_GetTicks() - Last;
    
        if(Past == 0.0f)
           mFps = 1000.0f;
         else
           mFps = (1000.0f / Past);
    
         Last = SDL_GetTicks();
    }
    

    Wenn du es genauer haben willst:

    //Variablen zum berechnen
    LONGLONG freq;
    LONGLONG lastFrame;
    LONGLONG CurrentFrame;
    
    //Muss im Konstruktor:
    QueryPerformanceFrequency((LARGE_INTEGER*)&m_Freq);
    
    //brechne die Frames per Seconds
    {
    
        QueryPerformanceCounter((LARGE_INTEGER*)&m_LastFrame);
    
        //Render
    
        QueryPerformanceCounter((LARGE_INTEGER*)&m_CurrentFrame);
        m_Elapsed = m_CurrentFrame - m_LastFrame;
        double m_FPS = (double)((double)m_Freq / (double)m_Elapsed);
        m_LastFrame = m_CurrentFrame;
    }
    

    Dieser Code ist aber nicht plattformabhänging, also funktioniert nur auf Windows Plattformen.

    MFG Lars



  • ChrisFehn3 schrieb:

    Hier in SDL:

    void Calc()
    {
        static int Last;
        const int Past = SDL_GetTicks() - Last;
    
        if(Past == 0.0f)
           mFps = 1000.0f;
         else
           mFps = (1000.0f / Past);
           
         Last = SDL_GetTicks();
    }
    

    1.öhm last hat keinen wert was soll dann von past abgezogen werde.
    2. wie implementiere ich das in meinen code.
    MFG Lars



  • int
    fps(void) {
       static int frames = 0;
       static int last = SDL_GetTicks();
       int f = 0, now = SDL_GetTicks();
    
       if (now-last>=1000) {
          last = now;
          f = frames;
          frames = 0;
       }
       frames++;
       return (f);
    }
    

    So, das implementiere muss du selbst machen. Hättes ja auch vorher mal Google.de fragen könne, der hätte dir sofort die Antwort auf deinen Problem gegeben.

    MFG Lars



  • könnntest du ma deinen code genauer beschreiben?^^ ist irgendwie sehr verwirrend. oder kannst du mir sagen wonach ich in google suche muss?



  • Wechsel doch einfach die Bildchen nicht nach jedem Frame, sondern nach 1/4 sec., oder nach 1 sec., oder nach 2 sec., oder nach...



  • // INIT:
    int StartZeit = HoleAktuelleZeit();  // Wieviel Uhr ist es jetzt? --> Z.B. 1000 Uhr
    int ZeitBisDerNaechsteFrameAbgespieltWerdenSoll = 500;  // Nach 500 Zeiteinheiten die Animation weiterschalten
    int AktuellesAnimationsBild = 15;  // Mit dem 15. Bild der Animation starten (Steh-Animation)
    
    // GAMELOOP:
    ...
    
    int ZeitDieFuerDenLetztenFrameGebrauchtWurde = HoleAktuelleZeit() - StartZeit;  // Wie lange hat der letzte Frame gedauert? --> Z.B. 1400 Uhr - 1000 Uhr = 400 Zeiteinheiten
    if(ZeitDieFuerDenLetztenFrameGebrauchtWurde >= ZeitBisDerNaechsteFrameAbgespieltWerdenSoll)  // Die Zeit ist rum, nächstes Animations-Bild abspielen -> z.B. 400 >= 500 ? Nein, also noch nicht wechseln!
    {
        AktuellesAnimationsBild += 1;  // Auf das nächste Bild schalten (Abfrage für MaxBilder fehlt!)
    }
    
    StartZeit = HoleAktuelleZeit();  // Die StartZeit auf die aktuelle Zeit zurücksetzen (StartZeit ist dann beim nächsten Aufruf 1400 Uhr statt 1000 Uhr)
    
    ...
    


  • Dann fehlt noch das droppen von Frames, falls die Grafikdarstellung zu langsam ist.



  • Ich mach es immer so, dass ich die Zeit-Differenz (in millisekunden) zwischen zwei Frames nehme und mit 0.001f multipliziere. Diesen Wert, den ich daraus bekomme, multipliziere ich mit jeden Geschwindigkeitsänderungen... also beispielhaft so:

    float faktor = (lastFrameTime - currentFrameTime) * 0.001f;
    ...
    obj.x += obj.speed_x * faktor;
    obj.y += obj.speed_y * faktor;
    

    (wobei speed_x die erwünschte geschwindigkeit in px pro sekunde darstellt
    und bei animationen das gleiche:

    float frame = 0;
    ...
    frame += ani_fps * faktor;
    showFrame( (int)frame );
    

    (ani_fps = gewünschte frames pro sekunde der animation)
    dann kommt man immer auf die selbe fps-zahl der animation oder die selbe geschwindigkeit ovn objekten, unabhängig von der frame-rate



  • Optimizer schrieb:

    Dann fehlt noch das droppen von Frames, falls die Grafikdarstellung zu langsam ist.

    Da fehlt noch so einiges... 😉 :xmas2:

    Aber für den Anfang sollte das wohl mal reichen... :xmas1:



  • Was fehlt mir denn noch? 😕 🤡 👍



  • Curved Surfaces z.B. ... 🤡 👍

    ...und 'ne dicke Wumme mit massiv BUMMS! :xmas2: 😃



  • Und ein Quarterpounder mit Käse. :xmas2:



  • ROFL

    Aber die haben doch das metrische System... :xmas1: 👍



  • Mein Hauptloop geht in etwa so (übertragbar auf andere Counter und Grafiklibs):

    int ticks;
    unsigned delay = 20; //So lang dauert ein Logikschritt. In diesem Beispiel haben wir 50 Logikschritte in der Sekunde
    bool drawn = false;
    int time = 0;
    while(!done)
    {
      ticks = SDL_GetTicks();
    
      if(time < delay)  //Grafiksachen erledigen
      {
        if(!drawn)  //Wenn im letzten Durchlauf nicht schonmal gerendert wurde
        {
          //Hier zeichnen!
          drawn = true;
        }
        else  //Ansonsten warten wir einfach, weil was bringt es, zweimal das selbe Bild zu zeichnen?
        {
          SDL_Delay(delay); //warten. evtl. auch nicht, SDL_Delay() frisst oft zu viel Zeit
        }
      }
      else //Spiellogik erledigen
      {
        //Hier Logik
        time -= delay;  //Die Logik bringt wieder Zeit rein, dh wir lassen im Spiel Zeit weitergehen, wenn wir die Logik ausführen
        drawn = false;  //Es hat sich was verändert, also sollten wir das Bild neu zeichnen
      }
    
      time += SDL_GetTicks() - ticks;
    }
    

    Das ganze kann problematisch werden. Bei sehr langsamen Computern (oder zu niedrigem delay) führt es zu einer Endlosschleife. Das kann man verhindern, indem man sagt, dass die Logik nicht zu oft hintereinander ausgeführt werden darf. Bei sehr schnellen Computern gibt es vielleicht auch ein Problem, wenn SDL_GetTicks() - ticks == 0 ist. Das habe ich mir noch nicht überlegt.
    Diese Variante funktioniert bei Pixelgrafik gut. :xmas2:
    geloescht


Anmelden zum Antworten