Framerate...



  • Warum benutzt du goto, wenn eine einfache while Schleife auch geht?
    Warum fragst du einen boolschen Wert auf true ab?

    if (running == true) ...;
    

    Das ist doch redundant.

    Ich würde es ja ungefähr so aufbauen:

    while (running)
    {
        fps++; 
        currenttick=GetTickCount(); 
        if((currenttick-lasttick)>1000) 
        { 
            fpstoshow=fps; 
            lasttick=currenttick; 
            fps=0; 
        } 
        ////////////////////// 
        //szene rendern usw // 
        ////////////////////// 
    }
    

    Gruß
    Don06



  • Don06 schrieb:

    Warum benutzt du goto, wenn eine einfache while Schleife auch geht?
    Warum fragst du einen boolschen Wert auf true ab?
    ....
    Gruß
    Don06

    Angewohnheit xD



  • @ Don06:
    Ich finde, deine Methode sieht meiner 3. Möglichkeit recht ähnlich... Du benötigst doch fpstoshow für deine Spielgeschwindigkeit, oder irre ich mich?
    Und wie ist das mit GetTickCount()? Gibt es den gleichen Rückgabewert wie SDL_GetTicks()?
    Und dafür muss man doch time.h inkludieren, oder?



  • Es ist besser Grafik-Frames von GameTicks zu trennen, wie prim0 schon sagte.
    Hier mal ein Beispiel (Pseudo-Code):

    int lastTime = GetTickCount();
    // Game-Loop
    while (true)
    {
        int currentTime = GetTickCount();
        if ( (currentTime - lastTime) > 40 ) // alle 40ms: Game-Logik
        {
             lastTime = currentTime;
             // Hier: Spiel-Logik wie Bewegungen, Kollisionen, usw.
             // Dieser Block hat eine konstante "Framerate" von 25 FPS
             // Spielbewegungen sind daher immer gleichmäßig außer die
             // Framerate sinkt unter 25 FPS.
        }
        // FPS berechnen,
        // Szene rendern,
        // ...
    }
    

    Es ist wichtig Grafik und Logik zu trennen. Bewegungen sollten unabhängig von der Leistung der Grafikkarte durchgeführt werden.
    Ausserdem ist es unnötig 100-150 mal in der Sekunde zu überprüfen, ob der Spieler gerade Esc gedrückt hat, da niemand eine Taste sooft in der Sekunde drücken kann. Genauso mit Kollisionen: Wieso sollte man 100-150 mal in der Sekunde überprüfen, ob zwei Gegenstände kollisiert sind?
    Die unnötigen Überprüfungen würde auch noch Performance kosten.

    Achja: Benutze lieber deine SDL_GetTicks()-Funktion. GetTickCount ist glaube ich OS-abhängig.

    Gruß
    Don06



  • Ok, danke für die Hilfe 😉



  • Sorry, aber einige Dinge versteh ich nicht ganz:
    Die Szene zu rendern braucht ja ziemlich viel Rechenzeit, wieso also ausserhalb des 40-ms-Abfrageblocks? Und das Aktualisieren und Neu Zeichnen geschieht sowieso nur auf Ereignisse der Spiellogik... Ich hab es mal so implementiert (bestimmt falsch xD), dass beide im Innenblock sind, es hat jedoch visuell nichts geändert, als ich die Renderingsfunktion in die Hauptschleife verschoben habe. Dazu kommt, dass bei mir ein leichtes Flackern etwa jede halbe Sekunde auftritt (auch mit Double Buffering).

    Ausserdem finde ich 40 ms viel zu lang, ich habs mit 5 gemacht, weil sonst das Game extrem stockt... zwar hat 5ms keine grosse Wirkung mehr, aber ja...

    Hier mal der Code:

    SDL_Event event;    
    bool running = true;
    int LastTime = SDL_GetTicks();    
    while (running)
    {
        int CurrentTime = SDL_GetTicks();
        if (CurrentTime - LastTime > 5)
        {
            LastTime = CurrentTime;
            SDL_PollEvent(&event);
            if (event.type == SDL_QUIT || key[SDLK_ESCAPE])
                running = false;
            player->Think(); // Funktion, die alle Eingaben, Bewegung und Kollisionsabfragen übernimmt
            player->Display(background); // Funktion, die die Figur neu zeichnet (momentan noch nur die Figur)
        }
        // ***
    }
    

    Bei den drei Sternchen hast du geschrieben, da käme FPS berechnen, Szene rendern etc. Wieso ist denn die FPS-Rate noch zu berechnen?



  • Es flackert, weil die Szene ausserhalb des Blocks berechnet werden sollte.

    Das, was du gebaut hast ist eine Frame-Bremse. Sie reduziert auf guten Rechnern die Frame-Rate -> Grafik ist schlechter als möglich. Ausserdem bietet das auch für schlechtere Rechner keinen Vorteil -> ruckelige Grafik.
    Die Grafik-Frames konstant zu machen, ist ein Parade-Beispiel für "An-der-falschen-Stelle-Optimieren". (Ausnahme bildet hier natürlich VSync, oder änliches)

    Und zu der Frame-Rate: Es gibt zwei unterschidliche Dinge: Grafik-Frames und Logik-Ticks. Während die Logik-Ticks in einem gewissen Grade konstant sind (40ms -> 25 Ticks pro Sekunde), sind es die Grafik-Frames keinesfalls. Bei aufwendigen Szenen, viel KI oder Ragdoll-Effekten sinkt die Frame-Rate, bei weniger steigt sie. Das kennt man ja aus fast jedem 3D-Spiel (Bei zig Gegner und viel Spezial-Effekten ruckelts halt mal).

    Ich hoffe das hilft dir ein bisschen.

    Gruß
    Don06



  • ich sag mal, auch für die darstellung von grafischen spielen lässt sich das model-view-controller konzept durchaus gut verwenden.

    der view ist hier die grafikengine, die sich um das berechnen der darzustellenden entitäten kümmert. das model ist der zustand der aktuellen szene.
    der view kann unabhängig vom model agieren, da es sich nur der daten aus dem model bedient.
    wichtigstes element ist der controller. dieser hat wissen über die nötigen ticks und "füttert" das model mit den nötigen daten. soll also beispielsweise eine animation dargestellt werden (die spielfigur springt), dann weiss der controller, dass diese animation z.b. 20 ticks dauern soll.

    ist es nun möglich, diese 20 animationsstufen innerhalb von 20 ticks zu berechnen, ist alles in butter (sozusagen). der controller kann die animationsschritte durchaus auch schneller berechnen (alle 20) und aktualisiert das model dann halt entsprechend den ticks. so ist die gesamte animation möglicherweise schon nach 3 ticks berechnet und der controller ist wieder frei, sich um weitere aufgaben zu kümmern. denn das model um die bereits fertig berechneten zustände zu aktualisieren, sollte sogut wie keine rechnenzeit beanspruchen.



  • Aber was ist nun an meinem Programm konkret falsch? Liegt der einzige Fehler darin, dass das Rendern ausserhalb des 40-ms-Blockes sein sollte (ich hab es auch probiert, es flackerte weiterhin)?
    Und wenn bei mir die Spiellogik nur alle 40 ms berechnet wird, ist das Game zu langsam, bzw. es gibt zu harte Übergänge (die Figur verschiebt sich um 5 Pixel auf einmal etc.) Und damit wir uns nicht missverstehen: Die Spiellogik (Model) umfasst schon alles zum Berechnen (also Ändern der Koordinaten, Eingaben, Kollisionsabfragen) und mit dem View (Grafischen) wird nur das Blitten und Updaten des Screens bezeichnet?

    Sorry wenn ich mich wie ein Noob anstelle, doch ich kann es mir zum Teil noch nicht richtig vorstellen...



  • Das Problem besteht weiterhin, könntet ihr mir konkrete Korrekturvorschläge machen? Was muss den genau geändert werden? Ausserdem stockt das Spiel zum Teil enorm, also sieht man z.B. die Figur, wie sie stehen bleibt, und plötzlich ist sie um 20 Pixel auf einmal verschoben...

    Hier ist der Code (ich hab die Display-Funktion aus dem 40-ms-Block herausgenommen), die oben erwähnten Probleme treten immer noch auf; bitte konkrete Verbesserungsvorschläge! Danke im Voraus!

    SDL_Event event;    
    bool running = true;
    int LastTime = SDL_GetTicks();    
    while (running)
    {
        int CurrentTime = SDL_GetTicks();
        if (CurrentTime - LastTime > 5)
        {
            LastTime = CurrentTime;
            SDL_PollEvent(&event);
            if (event.type == SDL_QUIT || key[SDLK_ESCAPE])
                running = false;
            player->Think(); // Funktion, die alle Eingaben, Bewegung und Kollisionsabfragen übernimmt
            }
        player->Display(background); // Funktion, die die Figur neu zeichnet (momentan noch nur die Figur)
    
    }
    

Anmelden zum Antworten