2014-03-02 5 views
6

Ich arbeite derzeit an einem Jump'n'Run und versuche, einen Zeitschritt zu implementieren, aber für Framerate Grenzen mehr als 60 die CPU-Auslastung steigt von 1% bis 25% und mehr.Einfaches C++ SFML Programm hohe CPU-Auslastung

Ich habe dieses Minimalprogramm, das Problem zu demonstrieren. Es gibt zwei Kommentare (Zeilen 10-13, Zeilen 26-30) im Code, die das Problem beschreiben und was ich getestet habe.

Beachten Sie, dass die FPS Sachen nicht relevant für das Problem ist (glaube ich).

Ich habe versucht, den Code kurz und einfach zu halten:

#include <memory> 
#include <sstream> 
#include <iomanip> 
#include <SFML\Graphics.hpp> 

int main() { 
    // Window 
    std::shared_ptr<sf::RenderWindow> window; 
    window = std::make_shared<sf::RenderWindow>(sf::VideoMode(640, 480, 32), "Test", sf::Style::Close); 
    /* 
    When I use the setFramerateLimit() function below, the CPU usage is only 1% instead of 25%+ 
    (And only if I set the limit to 60 or less. For example 120 increases CPU usage to 25%+ again.) 
    */ 
    //window->setFramerateLimit(60); 

    // FPS text 
    sf::Font font; 
    font.loadFromFile("font.ttf"); 
    sf::Text fpsText("", font, 30); 
    fpsText.setColor(sf::Color(0, 0, 0)); 

    // FPS 
    float fps; 
    sf::Clock fpsTimer; 
    sf::Time fpsElapsedTime; 
    /* 
    When I set framerateLimit to 60 (or anything less than 60) 
    instead of 120, CPU usage goes down to 1%. 
    When the limit is greater, in this case 120, CPU usage is 25%+ 
    */ 
    unsigned int framerateLimit = 120; 
    sf::Time fpsStep = sf::milliseconds(1000/framerateLimit); 
    sf::Time fpsSleep; 
    fpsTimer.restart(); 

    while (window->isOpen()) { 
    // Update timer 
    fpsElapsedTime = fpsTimer.restart(); 
    fps = 1000.0f/fpsElapsedTime.asMilliseconds(); 

    // Update FPS text 
    std::stringstream ss; 
    ss << "FPS: " << std::fixed << std::setprecision(0) << fps; 
    fpsText.setString(ss.str()); 

    // Get events 
    sf::Event evt; 
    while (window->pollEvent(evt)) { 
     switch (evt.type) { 
     case sf::Event::Closed: 
     window->close(); 
     break; 
     default: 
     break; 
     } 
    } 

    // Draw 
    window->clear(sf::Color(255, 255, 255)); 
    window->draw(fpsText); 
    window->display(); 

    // Sleep 
    fpsSleep = fpsStep - fpsTimer.getElapsedTime(); 
    if (fpsSleep.asMilliseconds() > 0) { 
     sf::sleep(fpsSleep); 
    } 

    } 

    return 0; 
} 

Ich will nicht SFML der setFramerateLimit(), aber meine eigene Implementierung mit dem Schlaf verwenden, weil ich die fps Daten verwenden, wird mein zu aktualisieren Physik und so.

Gibt es einen logischen Fehler in meinem Code? Ich sehe es nicht, da es mit einer Framerate-Grenze von beispielsweise 60 (oder weniger) arbeitet. Liegt es daran, dass ich einen 60 Hz Monitor habe?

PS: Mit SFML des Window-> setVerticalSync() ändert sich nicht die Ergebnisse

Antwort

4

ich antwortete eine andere similar question mit diesem answer.

Die Sache ist, es ist nicht gerade hilft Ihnen bei der CPU-Nutzung, aber ich habe Ihren Code versucht und es funktioniert gut unter 1% CPU-Nutzung bei 120 FPS (und vieles mehr). Wenn Sie ein Spiel oder ein interaktives Medium mit einer "Game-Loop" erstellen, möchten Sie nicht die Leistung durch das Schlafen verlieren, Sie möchten so viel CPU-Zeit verwenden, wie der Computer Ihnen geben kann. Anstatt zu schlafen, können Sie andere Daten verarbeiten, wie das Laden von Material, Pfadfindungsalgorithmen, etc., oder legen Sie einfach keine Grenzen für das Rendering.

ich einige nützlichen Links und Code bereitstellen, hier ist es:


ähnliche Frage: Movement Without Framerate Limit C++ SFML.

Was Sie wirklich brauchen, ist fester Zeitschritt. Werfen Sie einen Blick auf das SFML-Spiel Entwicklungsbuch source code. Hier ist der interessante Schnipsel aus Application.cpp:

const sf::Time Game::TimePerFrame = sf::seconds(1.f/60.f); 

// ... 

sf::Clock clock; 
sf::Time timeSinceLastUpdate = sf::Time::Zero; 
while (mWindow.isOpen()) 
{ 
    sf::Time elapsedTime = clock.restart(); 
    timeSinceLastUpdate += elapsedTime; 
    while (timeSinceLastUpdate > TimePerFrame) 
    { 
     timeSinceLastUpdate -= TimePerFrame; 

     processEvents(); 
     update(TimePerFrame); 

    } 

    updateStatistics(elapsedTime); 
    render(); 
} 

Ist dies nicht wirklich das, was Sie wollen, finden Sie unter „Fix your timestep!“ , die Laurent selbst Gomila im SFML Forum verlinkt sind.

+0

Vielen Dank dafür!(Entschuldigung für die späte Antwort). Eine Frage zu deinem Code: Verstehe ich richtig, dass die Update-Funktion jetzt einen festen Zeitschritt verwendet, aber es gibt kein Framerate-Limit für das Rendering? Wenn ja, genau das will ich. –

+0

Genau das macht es. –

1

Ich schlage vor, die setFrameRate Grenze zu verwenden, da es in SFML nativ implementiert ist und wird viel besser funktionieren. Für die verstrichene Zeit immer Sie tun müssen:

fpsElapsedTime = fpsTimer.getElapsedTime(); 

Wenn ich, etwas ähnliches zu implementieren hätte, würde ich tun:

/* in the main loop */ 
fpsElapsedTime = fpsTimer.getElapsedTime(); 
if(fpsElapsedTime.asMillisecond() >= (1000/framerateLimit)) 
{ 
    fpsTimer.restart(); 
    // All your content 
} 

Andere Sache, verwenden sf :: Farbe :: Weiß oder sf: : Farbe :: Schwarz statt (sf :: Farbe (255.255.255))

Hope this Hilfe :)