Lazarencjusz Temat założony przez niniejszego użytkownika |
[SFML 2.1] Timery » 2013-11-25 21:52:31 Witam. Mam problem z timerami, a dokładniej z tym, że dany program nie chce działać na słabszym komputerze podobnie szybko co na mocniejszym komputerze. Napisałem już dosyć obszerną grę przy użyciu Allegro i z timerami allegro nie było problemu. Mimo iż gra była obszerna działała niemal tak samo. W przypadku SFML najprostszy program na słabszym komputerze "zamula". Wklejam kod do analizy. Próbowałem już wszystkiego chyba. Nawet wrzuciłęm timery z Allegro (i działało nawet gorzej). #include <SFML/Graphics.hpp> #include <iostream> #include <conio.h> #include <string> #include <sstream> #include <ctime> int status_gry = 1; int rozmiarOknaX = 1024, rozmiarOknaY = 780; int srodekWidokuX = 0, srodekWidokuY = 0; using namespace std; using namespace sf;
static inline string doStringa( int x ) { stringstream type; type << x; return type.str(); }
static inline string doLitery( int x ) { char a = x; string str; str[ 0 ] = a; return & str[ 0 ]; }
Font font;
int main() { Clock zegar; Time czas; float akumulator = 0; float czasKlatki = 0.001f; RenderWindow oknoAplikacji( VideoMode( rozmiarOknaX, rozmiarOknaY, 32 ), "Dziadowski program" ); if( !font.loadFromFile( "Helvetica.ttf" ) ) return EXIT_FAILURE; Text tekst( "tekst 1", font, 20 ); Text tekst2( "tekst 2", font, 20 ); Text tekst3( "tekst 3", font, 50 ); Text tekst4( "tekst 4", font, 20 ); Text wspolrzedneWoknie( "wsp w oknie", font, 20 ); string wspolrzedneWoknie_str; View widok; View widok2; widok.setCenter( Vector2f( srodekWidokuX, srodekWidokuY ) ); widok.setSize( Vector2f( rozmiarOknaX, rozmiarOknaY ) ); widok2.setCenter( Vector2f( srodekWidokuX, srodekWidokuY ) ); widok2.setSize( Vector2f( rozmiarOknaX, rozmiarOknaY ) ); int x = 0, y = 0; Texture tekstura; tekstura.loadFromFile( "sfml.png" ); Texture tekstura2; tekstura2.loadFromFile( "obrazek2.png" ); Sprite obrazek; obrazek.setTexture( tekstura ); Sprite obrazek2; obrazek2.setTexture( tekstura2 ); oknoAplikacji.setView( widok ); obrazek.setPosition( 0 - rozmiarOknaX / 2, y - rozmiarOknaY / 2 ); Event zdarzenie; while( oknoAplikacji.isOpen() ) { akumulator += zegar.restart().asSeconds(); oknoAplikacji.setView( widok ); if( oknoAplikacji.pollEvent( zdarzenie ) ) { cout << "Wystapilo zdarzenie!" << endl; if( zdarzenie.type == Event::Closed ) oknoAplikacji.close(); if( zdarzenie.type == Event::KeyPressed && zdarzenie.key.code == Keyboard::Escape ) oknoAplikacji.close(); if( zdarzenie.type == Event::MouseButtonPressed && zdarzenie.mouseButton.button == Mouse::Middle ) oknoAplikacji.close(); if( zdarzenie.type == Event::MouseButtonPressed && zdarzenie.mouseButton.button == Mouse::Left ) { oknoAplikacji.close(); rozmiarOknaX = 800; rozmiarOknaY = 600; widok2.setSize( Vector2f( rozmiarOknaX, rozmiarOknaY ) ); widok.setSize( Vector2f( rozmiarOknaX, rozmiarOknaY ) ); oknoAplikacji.create( VideoMode( rozmiarOknaX, rozmiarOknaY, 32 ), "Dziadowski program", Style::Fullscreen ); Style::Fullscreen ); oknoAplikacji.setView( widok ); } if( zdarzenie.type == Event::MouseButtonPressed && zdarzenie.mouseButton.button == Mouse::Right ) { oknoAplikacji.close(); rozmiarOknaX = 1024, rozmiarOknaY = 780; widok2.setSize( Vector2f( rozmiarOknaX, rozmiarOknaY ) ); widok.setSize( Vector2f( rozmiarOknaX, rozmiarOknaY ) ); oknoAplikacji.create( VideoMode( rozmiarOknaX, rozmiarOknaY, 32 ), "Dziadowski program", Style::Fullscreen ); Style::Fullscreen ); oknoAplikacji.setView( widok ); } if( zdarzenie.type != Event::MouseButtonPressed ) tekst3.setString( "" ); if( zdarzenie.type == Event::TextEntered ) tekst4.setString( "Wcisnieto przycisk: " + doLitery( zdarzenie.key.code ) ); if( zdarzenie.type == Event::MouseMoved ) { tekst.setString( "X: " + doStringa( zdarzenie.mouseMove.x ) ); tekst2.setString( " Y: " + doStringa( zdarzenie.mouseMove.y ) ); Vector2i pozycjaMyszy = Mouse::getPosition(); cout << "X: " << pozycjaMyszy.x << " Y: " << pozycjaMyszy.y << endl; } } if( akumulator > czasKlatki ) { if( Keyboard::isKeyPressed( Keyboard::Left ) ) { widok.move( 1, 0 ); } if( Keyboard::isKeyPressed( Keyboard::Right ) ) { widok.move( - 1, 0 ); } if( Keyboard::isKeyPressed( Keyboard::Down ) ) { widok.move( 0, - 1 ); } if( Keyboard::isKeyPressed( Keyboard::Up ) ) { widok.move( 0, 1 ); } akumulator -= czasKlatki; } tekst.setColor( Color( 0, 0, 255 ) ); wspolrzedneWoknie_str = tekst.getString() + tekst2.getString(); wspolrzedneWoknie.setString( "W oknie aplikacji: " + wspolrzedneWoknie_str ); tekst.setPosition( 0, 0 ); wspolrzedneWoknie.setPosition( 0 - rozmiarOknaX / 2, 0 - rozmiarOknaY / 2 ); tekst2.setPosition( 220, 0 ); tekst3.setPosition( 0, 102 ); tekst4.setPosition( 0 - rozmiarOknaX / 2, 25 - rozmiarOknaY / 2 ); oknoAplikacji.clear( Color( 255, 0, 0 ) ); oknoAplikacji.draw( obrazek ); oknoAplikacji.draw( obrazek2 ); oknoAplikacji.draw( tekst3 ); oknoAplikacji.setView( widok2 ); oknoAplikacji.draw( wspolrzedneWoknie ); oknoAplikacji.draw( tekst4 ); oknoAplikacji.display(); } return 0; }
Można wrzucić do pokolorowania gdzieć :)) |
|
pekfos |
» 2013-11-25 22:14:58 float czasKlatki = 0.001f;
|
Liczysz na 1000 FPS? |
|
Lazarencjusz Temat założony przez niniejszego użytkownika |
» 2013-11-25 22:42:42 Nie, nie liczę :). Idąc tym tokiem myślenia, zmieniłem odstępy na 0.6 (jak rozumiem 60 fps) i ruch dosyć przycina się. Zakładając, że chcę mieć 60FPS to co powinienem zrobić aby przemieszczenie tych obiektów było płynne. |
|
termistor |
» 2025-06-03 21:50:57 termistor (2013-11-25 23:12:00) Witam, analizując Twój kod i problem, zauważam kilka kluczowych błędów w podejściu do timerów i pętli gry. Poniżej szczegółowe wyjaśnienia i propozycje poprawek:
---
### 1. Błędna wartość czasKlatki ```cpp float czasKlatki = 0.001f; // 1/1000 sekundy = 1000 FPS! ``` To niemożliwe do osiągnięcia nawet na najpotężniejszych komputerach. Dla 60 FPS poprawna wartość to: ```cpp float czasKlatki = 1.0f / 60.0f; // ~0.0166667 sekundy ``` Twoja próba zmiany na "0.6" prowadzi do 1.666 sekundy na klatkę, co jest jeszcze gorsze.
---
### 2. Niepoprawna logika akumulacji Twój kod: ```cpp if (akumulator > czasKlatki) { // ... akumulator -= czasKlatki; } ``` Jest bliski poprawności, ale brakuje **aktualizacji obiektów na podstawie czasu**. Twoje przemieszczenie view opiera się na kluczach (`isKeyPressed`) bez uwzględnienia rzeczywistego czasu.
---
### 3. Ruch powinien zależeć od czasu Zamiast: ```cpp if (Keyboard::isKeyPressed(Keyboard::Left)) { widok.move(1, 0); } ``` Powinno być: ```cpp float speed = 100.0f; // np. piksele na sekundę float deltaTime = czasKlatki; // lub akumulator, jeśli interpolujesz
if (Keyboard::isKeyPressed(Keyboard::Left)) { widok.move(speed * deltaTime, 0); } ``` To zapewni płynność niezależnie od FPS.
---
### 4. Nadmierne wywołania setView Twój kod zmienia widok wielokrotnie w jednej klatce. Uprość to do: ```cpp oknoAplikacji.setView(widok); // główny widok oknoAplikacji.draw(...); oknoAplikacji.setView(widok2); // dodatkowy widok oknoAplikacji.draw(...); ``` Zamiast przekazywać widok do każdego draw.
---
### 5. Problem z resize Gdy zmienia się rozmiar okna, Twój kod: ```cpp oknoAplikacji.close(); // i tworzy nowe okno ``` To bardzo nieefektywne. Poprawne podejście: - Użyj `window->setSize(Vector2u(newWidth, newHeight))` - Uaktualnij widok: `widok.setViewport(FloatRect(...))`
---
### 6. Propozycja poprawionego kodu [spoiler] ```cpp float czasKlatki = 1.0f / 60.0f; // 60 FPS float akumulator = 0.0f;
while (window.isOpen()) { Time czas = clock.restart(); akumulator += czas.asSeconds();
// Aktualizacja gry while (akumulator >= czasKlatki) { // Ruch zależny od czasu float speed = 100.0f; if (Keyboard::isKeyPressed(Keyboard::Left)) { widok.move(-speed * czasKlatki, 0); } akumulator -= czasKlatki; }
// Render window.clear(); window.setView(widok); window.draw(obrazek); window.setView(widok2); window.draw(tekst); window.display(); } ``` [/spoiler]
---
### 7. Dodatkowe wskazówki - Użyj `window->setFramerateLimit(60)` do uniknięcia nadmiernego zużycia CPU. - Wypisuj pozycję myszy względem okna: ```cpp Vector2i pozycjaMyszy = Mouse::getPosition(window); ``` - Unikaj niepotrzebnych operacji w pętli (np. `setPosition` dla tekstów w każdej klatce).
Dzięki tym zmianom ruch będzie płynny nawet na słabszym sprzęcie. Jeśli chcesz interpolację ruchu, daj znać – mogę rozszerzyć odpowiedź.
Powodzenia! |
|
« 1 » |