2 Stimmen

Das Festlegen einer festen Bildrate (FPS) funktioniert nicht.

Ich arbeite an einem 2D-Spiel für ein Schulprojekt. Die Vorlage, die mein Lehrer gegeben hat, funktioniert gut, aber ich wollte eine sehr, sehr dumme Sache im Code ersetzen. Im Code ruft er eine schwere Methode 20 Mal auf, um das Spiel zu verlangsamen. Anstatt das zu tun, möchte ich überprüfen, ob der nächste Frame verarbeitet werden soll.

Das Spiel ist ein Objekt im Vorlagen-Namespace. Dieser Namespace hatte eine Endlosschleife, die die Spiel-Tick-Methode aufruft und die Frame-Puffer austauscht.

In dieser Vorlage habe ich das Game->Tick() durch eine einfache if-Anweisung ersetzt:

if (game->Ready(lastftime)) {
    game->Tick();
}

lastframe ist die Zeitdifferenz in Sekunden zwischen dem letzten Aufruf und jetzt. Ich weiß, dass ich diese Zeit verwenden könnte, um Bewegungen innerhalb des Spiel-Ticks zu berechnen, aber das ist nicht das, was ich jetzt tun will!

Dies ist die Ready Methode:

bool Game::Ready(float timedif) {
    // Zeit zum Framezähler hinzufügen
    framecounter += timedif;

    // Überprüfen, ob der Zähler die fps überschreitet
    if (framecounter > fps) {
        // Falls ja, subtrahiere die fps vom Zähler
        while (framecounter > fps) {
            framecounter -= fps;
        }
        m_Screen->Clear(0);
        Draw();

        return true;
    }

    // Frame liegt immer noch innerhalb des fps-Bereichs
    return false;
}

fps wird wie folgt berechnet: fps = 1000.0f/60

Ich habe keine Ahnung, warum es nicht mit 60 Frames pro Sekunde läuft, und ich bin zu 100% sicher, dass es öfter aufgerufen wird als das (getestet mit einem printf). Jede Hilfe wäre willkommen.

4voto

Aleksander Fular Punkte 693

Was ist timedif?
Sie sollten einige Informationen darüber haben, wann in Echtzeit - zum Beispiel in ms - der letzte Frame war.
Mir scheint, dass Sie davon ausgehen, dass jede Iteration Ihrer while-Schleife eine ms dauert.

bool Game::Ready(float msSeitLetztemFrame)
{
    if(msSeitLetztemFrame > fps)
    {
        m_Screen->Clear();
        Draw();
        return true;
    }       
    return false
}

// rufen Sie dies mit einer Art von while-Schleife auf, in der Sie msSeitLetztemFrame aktualisieren  
if(game->Ready(msSeitLetztemFrame)
{
    msSeitLetztemFrame = 0;
    game->Tick();
}

aber, wenn Sie diesen Ansatz verwenden möchten, müssen Sie die game::ready-Schleife mit while() aufrufen;

Ich würde einen anderen Ansatz vorschlagen.

void Game::gameLoop()
{
    auto letzterFrameZeitstempel = GetTickCount(); // wenn Sie sich auf Windows befinden
    auto frameLänge = 1000/fps;
    while(true) // true oder irgendeine Art von Bedingung
    {
        auto aktuellerZeitstempel = GetTickCount();
        if( aktuellerZeitstempel - letzterFrameZeitstempel >= frameLänge)
        {
            // Mach deine Arbeit;
            letzterFrameZeitstempel = aktuellerZeitstempel;
        }
        Sleep(1); // Sie können hier schlafen, wenn Sie Ihren PC nicht überhitzen möchten =)
    }
}

2voto

Paddyd Punkte 1860

Warum ziehst du fps von framecounter ab? Du musst framecounter zurücksetzen, wenn es fps überschreitet.

Versuche Folgendes:

bool Game::Ready(float timedif) {
    // Füge Zeit zu framecounter hinzu
    framecounter += timedif;

    // Überprüfe, ob der Zähler das fps überschreitet
    if (framecounter > fps) {
        framecounter = 0;
        m_Screen->Clear(0);
        Draw();

        return true;
    }

    // Frame liegt immer noch innerhalb der fps-Spanne
    return false;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X