Korrekte Spielgeschwindigkeit (Framebremse)



  • Servus! Ich programmier mir grad ein Spiel und habe bisher immer
    die Framebremse verwendet, damit auf jedem System eine korrekte
    Spielgeschwindigkeit sichergestellt ist...

    Aber mitlerweile frage ich mich, wie professionele Programmierer
    das machen.. Wenn jetzt der Rechner zu lahm ist, und selbst
    bei einer Framebremse nicht mehr hinterher kommt, wird das Spiel
    ja langsamer... Ich könnte mir vorstellen, das das bei Multiplayer
    Spielen ganz schön blöd werden könnte *g*

    Bei modernen Spielen lassen sich ja FPS anzeigen. Diese sind dann
    variabel und trotzdem läuft das Spiel überall gleich schnell.

    Wie machen die Programmierer das? Ich hatte schon an sowas wie
    den Windows-Timer gedacht, der in bestimmten Abständen dann
    die eigentliche Spiel-Routine aufruft und im Hintergrund
    läuft ständig die Grafik-Routine durch... Aber der Windows-Timer
    ist immer so eine Sache...

    Vielleicht ginge das mit Threads? Damit kenne ich mich nicht so
    aus, kann von daher auch nicht beurteilen, wie brauchbar die
    in diesem Fall sind...

    Wer kann mir helfen? Wie macht ihr das? Dank im *******!



  • Man bremst Frames nicht aus...nein...nix da !

    Die verstrichene Zeit zwischen zwei Frames kann als Faktor (sinnvollerweise noch irgendwie passend skaliert) dienen. Sollen sich irgendwelche Objekte bewegen, dann multiplizier diesen Faktor dazu.

    Schneller Rechner -> viele Frames -> wenig verstrichene Zeit zwischen 2 Frames -> kleinerer Faktor -> Objekt bewegt sich nur wenig.

    Langsamer Rechner -> wenig Frames -> viel verstrichene Zeit -> großer Faktor -> Objekt bewegt sich nen größeres Stück in die gewünschte Richtung.



  • Mmh... naja...

    Also Framebremse... Weiss nicht was daran so schlimm sein soll...
    (Außer, dass es vielleicht stillos ist *g*)

    Das mit dem Faktor ist ne gute Idee, aber wie soll man das realisieren?
    Zumal die Framegeschwindigkeit ja nicht immer konstant ist. Wenn jetzt
    mehr objekte auf dem Bildschirm sind, und ich evtl. sogar mit
    Transparenz arbeite, wird das ganze ja langsamer, als wenn ich ein
    ganz leeres Spielfeld habe... Das müsste man ja sozusagen in Echtzeit
    kompensieren... Oder hab ich da jetzt was falsch verstanden?

    Mmh vielleicht sollte ich noch sagen, dass ich das Spiel nicht
    mit OpenGL oÄ. machen will, sondern es soll ein reines 2D-Spiel
    (ja ernsthaft *g*) werden. Ich benutze dazu LibSDL



  • Ja du hast es falsch verstanden.
    Den Faktor musst du natürlich in jedem Frame neu ermitteln.
    Deshalb schwankt er je nachdem ob die Geometrie komplex oder einfach ist und die Bewegungen bleiben konstant.



  • OK... Danke erstmal für die Antworten, aber ich hab immer noch
    Fragen *g*

    Wie gesagt habe ich vor, das ganze als reines 2D-Spiel zu machen.
    Angenommen, ich bekomme bei 40 fps eine Geschwindigkeit von
    1 px/frame. Bei 50 fps bekomme ich dann zB. 1,25 px/frame. Wie soll
    ich das machen? Ich könnte das ganze ja als komma-zahl abspeichern
    und für die eigentlichen Bewegungen die Zahlen hinterm Komma weglassen,
    aber ob das so ne gute Idee ist? 😉
    Immerhin gehts bei Spielen um Speed! Bei jedem Frame und jedem Objekt
    eine Multiplikation mit ner Fließkommazahl?

    Bei OpenGL geht das mit den Bewegungen um 0,25 Einheiten vielleicht,
    aber bei Surfaces?



  • Wenn Du bei 40 FPS 1 Pixel pro Frame hast, hast Du bei 50 FPS weniger als 1 Pixel pro Frame, nicht mehr!
    Es ist völlig wurscht, womit Du arbeitest. Du speicherst einfach alle Positionen als float oder double ab und dann - beim Zeichnen - wandelst Du intern in eine Ganzzahl um.

    Dass es um Speed geht, ist klar. Aber selbst wenn Du eine Million Multiplikationen machst, merkt man das so gut wie gar nicht! Überleg' doch mal, was wirklich Zeit kostet! Bestimmt nicht eine Fließkommamultiplikation, sondern eine Wurzel ziehen, oder eine Division oder das eigentliche Zeichnen! Hier würdest Du am völlig falschen Ende sparen.

    [ Dieser Beitrag wurde am 01.06.2002 um 18:34 Uhr von TomasRiker editiert. ]



  • @TomasRiker

    Nur damit ich das auch richtig verstanden habe 😉 😃 🙂 . Die neue errechnete Zahl wird dann mal der Bewegung gerechnet richtig ???
    Und daraus folgt für mich schon die zweite Frage, wie errechne ich die Differenz zwischen den Frames (mit welchem Counter ) ?

    Ein bißchen Code wäre echt nett 🙂 .

    MfG Unwissender



  • ...

    hast Du bei 50 FPS weniger als 1 Pixel pro Frame, nicht mehr!

    Stimmt.. hast ja Recht... Mmh. Ja das müsste ich mal ausprobieren *g*

    Aber meine unüberlegt gewählte Einheit war auch falsch 🙄
    1 pixel pro frame... Das ist ja gerade das Problem... Die bewegung
    soll unabhängig von den Frames sein... Wie wäre es also mit
    1 pixel / sekunde = 1 px/s

    Aber wie ist das mit Timern? Kennt sich da eiener aus? Das wäre ja
    noch leichter 😃

    Mal überlegen...

    **Am Anfang der Schleife hole ich einen möglichst
    genauen Millisekunden-Ticker.

    Dann lasse ich erstmal das Bild rendern und KI und sonen
    Kram erledigen.

    Jetzt rechne ich die Zeit aus, die das gedauert hat.
    Jetzige Zeit - Startzeit = Differenz

    Jetzt brauche ich den Faktor, mit dem alle Positionsänderungen
    multipliziert werden... Angenommen ich habe 20 ms Differenz...
    1000 / 20 = 50
    Aha ich habe also 50 fps. Müsste also die Geschwindigkeit meines
    Objektes mit 1/50 multiplizieren...

    Mist! Das sind ja gleich 2 Divisionen. 1 pro frame + 1 pro objekt

    Aber:
    *
    (1000/20) ^-1 = 1/50
    bzw: 20/1000 = 1/50
    *

    hehe!

    Mmmh. Ich weiss zwar nicht, ob das hilft, aber:
    20 / 1000 = 0.001 * 20 Jetzt sind alle
    Divisionen weg *g*

    So jetzt multiplizieren wir unsere geschwindigkeit in px/s
    mit dem errechneten Faktor (zb. 1/50)

    Das ergebnis wird zu einer Fließkomma-Variable mit unserer
    Position hinzuaddiert.

    Für unsere Zeichenaktionen wird das ganze dann auf bzw. abgerundet
    und fertig !!!

    **

    Wegen dem Code... Ich versuchs einfach mal: (Achtung, Pseudocode)

    long  position_x = 0;
    long  zeit;
    float unterschied;
    float position_x_rechnen = 0;
    float faktor;
    
    for(;;)
    {
        zeit = Hole_Millisekunden();
        Rendere_das_Bild();
        unterschied = Hole_Millisekunden() - zeit;
        // Beispiel für 10 px/s nach rechts...
        faktor = 0.001 * unterschied;
        position_x_rechnen += 10 * faktor;
        position_x = Runde_auf_oder_ab(position_x_rechnen);
    }
    


  • Na also, Du kannst es doch! Oder hast Du das irgendwoher kopiert?



  • Oder hast Du das irgendwoher kopiert?

    Ho ho ho!!!

    Wenn ich das irgendwo gefunden hätte, hätte ich doch nicht
    dieses Forum hier zugepostet, oder? *g*

    Trotzdem meine Fragen:

    - Stimmt der Code so?
    - Was ist mit Threads?
    - Was ist mit Timern?

    Danke...

    PS: Warum wird V_O_R_R_A_U_S eigentlich zensiert?



  • Original erstellt von Shinji Ikari:
    **Ho ho ho!!!

    Wenn ich das irgendwo gefunden hätte, hätte ich doch nicht
    dieses Forum hier zugepostet, oder? *g*

    Trotzdem meine Fragen:

    - Stimmt der Code so?
    - Was ist mit Threads?
    - Was ist mit Timern?

    Danke...

    PS: Warum wird V_O_R_R_A_U_S eigentlich zensiert?**

    Im ******* wird zensiert, weil es falsch ist. Es heißt "im Voraus".
    Also der Code sieht gut aus, ich mache es fast genauso.
    Der Windows-Timer ist zu ungenau und außerdem würde dann wahrscheinlich bei zu langsamen Szenen der Stack überlaufen oder es würde genauso langsam laufen wie normalerweise auch.
    Threads zu benutzen halte ich für übertrieben.



  • Also ich hab das mal vor kurzem Programmiert, aber mit einer Basic Sprache (BlitzBasic3D), hat prima gefunzt, hier der Pseudocode dazu:

    // erstmal die differenz zwischen den Frames bilden
    aktuelleZeit = GetCurrentTime()
    Differenz = aktuelleZeit - ZeitDesVergangenenFrame
    ZeitDesVergangenenFrame = aktuelleZeit
    // So, jetzt hast du die die Differenz gebildet, willst du jetzt ein Objekt in x richtung 30 pixel/sec fahren lassen so musst du einfach folgendes machen:

    x= x + 30*Differenz
    DrawObject(x,y)

    // Das wars. Wie du mit C++ die aktuelle Zeit herbekommst weis ich auch nicht, da ich gerade erst mit C++ angefangen hab und bei einfachen Konsolenanwendungen gerade bin (mit BlitzBasic3D war es sehr einfach, der Code sah fast so aus)....



  • Jo, BlitzBasic kenn ich. Is eigentlich ganz lustig, hab aber damit
    aufgehört...

    Ähm. Wenn du 30 px/s geschwindigkeit haben willst, und du zB. eine
    Differenz von 20 ms hast. dann bewegt sich dein Objekt nach deinem
    Code mit 30000 px/s !!!

    Naja..
    Obiges gilt natürlich nur für den Fall, dass GetCurrentTime()
    Millisekunden wiedergibt.. Wenns zB. Sekunden wiedergibt, ginge
    das ganze... aber dann müssten die Sekunden bis auf die 3te Nachkomma-
    stelle genau zurückgegeben werden... Dass eine Funktion einen Wert
    wie zB. 5,025 sek. zurückgibt kann ich mir nur schwer vorstellen...
    Was machst du denn dann, wenn die sekunden von 59 wieder auf 0
    umspringen??? wenn du in dem Moment die Differenz ausrechnest, hast
    du ein Problem *g*

    Beim Timer, wie ich ihn verwendet habe wird die Zeit wiedergegeben,
    die der PC schon an ist. und zwar in Millisekunden... Das ist IMHO
    genauer und praktischer 🙂



  • Die Zeit bekommt man z.b. mit dem XGamesSDK mit der Klasse "XTimer" ;).

    Bye, TGGC



  • Du hast schon recht, GetCurrentTime müsste sekunden widergeben, BlitzBasic3D gibt es in millisecunden wider, die funktion GetCurrentTime() rechnet bei mir halt das ganze in sekunden um, naja ob millisec. oder nur sec. ist eigentlich egal. Das mit dem Timer ist auch eine Lösung obs genauer ist, weis ich nicht, jedenfalls gibts da verschiedene wege die Zeit zu bekommen, der Lösungsansatz bleibt aber der gleiche...



  • Hi !
    Bei www.gamedev.net gibts nen netten Artikel darüber...
    Und ab ins FAQ !


Anmelden zum Antworten