Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[SFML] Trzęsienie się sf::Sprite gdy powinien tkwić w bezruchu.

Ostatnio zmodyfikowano 2013-09-18 16:33
Autor Wiadomość
akwes
Temat założony przez niniejszego użytkownika
[SFML] Trzęsienie się sf::Sprite gdy powinien tkwić w bezruchu.
» 2013-09-17 21:07:32
Witam :)

Problem wygląda tak: mam klasę, która porusza sobie sf::Spritem ale co 32 piksele starając się robić płynną animację przejścia z jednego miejsca do drugiego. Można założyć, że porusza się po szachownicy o polach 32x32 piksele. Animacja faktycznie wychodzi z grubsza płynnie.

Jednak kiedy włączę pauzę w trakcie trwania animacji to sf::Sprite trzęsie się.

Klasa
C/C++
class GridSprite {
    sf::Texture myTexture;
    sf::Sprite mySprite;
   
    sf::Vector2f delta;
    sf::Vector2f nextPosition;
    sf::Vector2f oldPosition;
   
    bool animation;
    float animationProgress;
    float animationSpeed;
   
    void startAnimation() {
        animation = true;
        animationProgress = 0;
        oldPosition = mySprite.getPosition();
        delta = nextPosition - oldPosition;
    }
   
public:
    GridSprite()
        : animation( false )
        , animationSpeed( 3.f )
    {
        myTexture.loadFromFile( "sprite.png" );
        mySprite.setTexture( myTexture );
    }
   
    void logic( float time ) {
        if( animation ) {
            // Przesuń mySprite o % całego przesunięcia
            mySprite.setPosition( oldPosition +( delta * animationProgress ) );
            animationProgress += time * animationSpeed;
           
            if( animationProgress > 1.f ) {
                animation = false;
                mySprite.setPosition( nextPosition );
            }
            return;
        }
       
        // Jeżeli brak animacji, wykonaj poruszanie
        // Dla uproszczenia, ruch tylko w prawo
        if( sf::Keyboard::isKeyPressed( sf::Keyboard::Key::D ) ) {
            nextPosition.x = mySprite.getPosition().x + 32;
            startAnimation();
        }
    }
   
    void draw( sf::RenderWindow & app ) {
        app.draw( mySprite );
    }
};

Kod:
C/C++
int main() {
    sf::RenderWindow app( sf::VideoMode( 800, 600, 32 ), "Testing" );
    app.setFramerateLimit( 60 );
   
    GridSprite gs;
    sf::Clock clock;
   
    bool gameRunning = true;
    while( app.isOpen() ) {
       
        sf::Event ev;
        while( app.pollEvent( ev ) ) {
           
            if( ev.type == sf::Event::Closed )
                 app.close();
           
            if( ev.type == sf::Event::KeyPressed && ev.key.code == sf::Keyboard::P )
                 gameRunning = !gameRunning;
           
        }
       
        if( gameRunning ) {
            app.clear( sf::Color::Black );
            gs.logic( clock.restart().asSeconds() );
            gs.draw( app );
        }
        app.display();
    }
    return 0;
}

Efekt działania na video: download.
(chciałem wrzucić na YT ale tamtejsza kompresja sprawia, że tego efektu nie widać na filmie)
(martwi mnie rozmiar pliku, bo ma tylko 88 kB, w każdym razie kodek użyty do kompresji tego avi to Xvid MPREG-4 Codec)

Co przegapiłem? Gdzie walnąłem byka?
P-92271
pekfos
» 2013-09-17 21:24:56
Spróbuj wciągnąć app.display() do warunku if(gameRunning).
P-92272
Wasilek
» 2013-09-17 21:29:14
Nie wiem co jest bezpośrednią przyczyną tego drgania, ale warto kilka rzeczy zmienić/dodać.
1.
C/C++
if( ev.type == sf::Event::KeyPressed && ev.key.code == sf::Keyboard::P )
{
    gameRunning = !gameRunning;
    clock.restart(); // Aby po wyłączeniu pauzy sprite nie leciał od razu do końcowej pozycji (chyba, że tak chciałeś :P)
}
2.
C/C++
animationProgress += time * animationSpeed; // Najpierw wypada policzyć zmianę
mySprite.setPosition( oldPosition +( delta * animationProgress ) ); // A dopiero później ją wyświetlić :)
3.
C/C++
if( animationProgress >= 1.f ) // Wydaje mi się, że jednak większe bądź równe tutaj powinno być (gdy będzie 1>1 to jeszcze raz się wykona niepotrzebnie animacja) :)
P-92273
akwes
Temat założony przez niniejszego użytkownika
» 2013-09-17 21:38:49
@Wasilek, to tylko kod pokazujący problem mający niewiele wspólnego z projektem, także nie warto się rozdrabniać nad niczym takim :P

@pekfos, no tak, to by pomogło, tylko że jeżeli chciałbym wyświetlić napis "Pauza" albo cokolwiek innego (np. przeźroczyste menu), to już nie będę mógł.

Zastanawia mnie czemu sf::Sprite zmienia swoją pozycję w trakcie pauzy mimo, że żaden kod się do niego nie odwołuje (oczywiście pozycja sf::Sprite::getPosition również jest stała).
P-92274
Wasilek
» 2013-09-17 22:08:29
Skompilowałem u siebie i nie mam żadnych problemów po włączeniu pauzy. Może to nie jest problem z kodem, lecz z komputerem.
P-92275
MrPoxipol
» 2013-09-17 22:12:33
Zaokrąglaj ustawianą pozycję (niby pozycja na liczbie rzeczywistej nie powinna robić problemu, ale na niektórych komputerach tak się dzieje). Miałem tak w swoim toolbarze, podczas wysuwania grafika drgała. IMO to wygląda na bug w SFML, ale nie jestem tego pewnien.

Najlepszy sposób na błędy w rysowaniu?
...
Ustawić sprajta na niecałkowitej pozycji np. 245.5, 10.1..Objawem są najczęściej zdeformowane grafiki (a również drgania).

Wszystko przez niezaokrąglanie wyliczonych współrzędnych obiektu ;)
..
Grafika na różnych komputerach była zdeformowana w innym miejscu, może to zależne od karty graficznej i może trochę od systemu (co jest zresztą bardzo ciekawe). Dla przykładu: notebook Win7 karta ATI Radeon - wszystko jest OK (i to właśnie było zwodnicze), starszy komputer z kartą starego typu Win XP - grafika w jednym miejscu jest zdeformowana i przy jej animacji (interpolacja liniowa dla płynnego wejścia) grafika się trzęsie, zaś na tym samym komputerze pod Linuksem - zdeformowana grafika w tym samym miejscu co wcześniej, ale brak trzęsień. Co ciekawe na dużo mocniejszym komputerze od wcześniejszych (nie pytałem jakie GPU) grafika posiada skazę w całkiem randomowym miejscu. Tak, więc moja rada: Stawiajcie swoje sprajty na całkowitych pozycjach! :D jak będę miał czas to napisze temat z rozwiązaniem jakby ktoś, kiedyś miał podobny problem :)
http://cpp0x.pl/forum/temat/​?id=4756&p=456
P-92276
DejaVu
» 2013-09-17 23:04:41
Zapewne implementacja metody display może sporo powiedzieć dlaczego występują drgania. Scena w końcu się nie zmienia, ale być może położenie kamery jest ponownie obliczane i pojawiają się małe niedokładności w obliczeniach związane z precyzją floatów.
P-92278
akwes
Temat założony przez niniejszego użytkownika
» 2013-09-17 23:19:26
Ciekawe, przed wysłaniem kilka razy sprawdzałem czy zaokrąglanie jednostek cokolwiek zmienia i nie zmieniało. Jednak wygląda na to, że w przykładzie, który podałem zaokrąglanie jednostek naprawia problem.

Nigdy wcześniej nie było też z tym problemu. Wyczuwam światowy spisek.

// Hm... Co ciekawe, w głównym projekcie faktycznie zmiana pozycji sprajta na całkowitą nie pomaga. No nic, będę musiał pogrzebać dalej.
P-92279
« 1 » 2
  Strona 1 z 2 Następna strona