Окно перестает обновляться при нажатии клавиши

Всякий раз, когда я нажимаю клавишу для перемещения спрайта, экран не будет обновляться, пока я не отпущу клавишу. Единственный способ исправить это - очистить, нарисовать и отобразить окно в каждом цикле KeyPressed.

Гораздо разумнее сделать каждую из этих вещей один раз, независимо от каких-либо нажатий клавиш. Я не знаю, почему это не работает, или как лучше всего это исправить.

В приведенной ниже программе я разместил код очистки/отрисовки/отображения в нескольких разных местах, надеясь, что размещение его в нужном месте сработает. До сих пор это не так. В противном случае избыточность бессмысленна.

#include <SFML/Window.hpp>
#include <iostream>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>

using namespace std;

int main()
{
int windowx = 800;
int windowy = 600;

float playerx = 400.0;
float playery = 300.0;

sf::Sprite playersprite;
sf::Sprite enemysprite;

float playerspeedx = 0;
float playerspeedy = 0;

float playerspeedx2 = 0;
float playerspeedy2 = 0;

float accelerationx = 50.0;
float accelerationy = 50.0;
float deccelerationx = 50.0;
float deccelerationy = 50.0;
float frictionx = 25.0;
float frictiony = 25.0;
float playermaxspeedx = 500.0;
float playermaxspeedy = 200.0;

sf::Texture hoverdrone; //player's sprite
if (!hoverdrone.loadFromFile("hoverdrone.png"))
    {
        cout << "error loading image";
    }
sf::Texture floatdrone; //for sprite enemysprite
    if (!floatdrone.loadFromFile("floatdrone.png"))
    {
        cout << "error loading image";
    }

    playersprite.setTexture(hoverdrone);
    enemysprite.setTexture(floatdrone);
    enemysprite.setPosition(sf::Vector2f(400, 400));
    playersprite.setPosition(sf::Vector2f(400, 300));


sf::RenderWindow mywindow(sf::VideoMode(windowx, windowy), "FishTank");

//sf::Clock clock; //Begin clock.
//sf::Int32 baseclock = clock.getElapsedTime().asMilliseconds();

// run the program as long as the window is open
while (mywindow.isOpen())
{
    // check all the window's events that were triggered since the last iteration of the loop
    sf::Event event;

    while (mywindow.pollEvent(event))
    {
        // "close requested" event: we close the window
        if (event.type == sf::Event::Closed)
            {
                cout <<"You have closed the window."<<endl;
                mywindow.close();
            }
        mywindow.clear(sf::Color::Black);
        mywindow.draw(playersprite);
        mywindow.draw(enemysprite);
        playersprite.setPosition(sf::Vector2f(playerx, playery));
        mywindow.display();
        sf::sleep(sf::microseconds(5));

        // left key is pressed: move our character
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
            {
                sf::Clock leftclock;

                while (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
                {
                    playerx -= 0.01; //will replace later with time based movement
                    sf::Int32 leftclock1 = leftclock.getElapsedTime().asMilliseconds();
                    cout << leftclock1 << endl;

                    /*mywindow.clear(sf::Color::Black);
                    mywindow.draw(playersprite);
                    mywindow.draw(enemysprite);
                    playersprite.setPosition(sf::Vector2f(playerx, playery));
                    mywindow.display();*/

                }

            }
        // right key is pressed: move our character
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
            {
                sf::Clock rightclock;

                while (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
                {
                    playerx += 0.01; //will replace later with time based movement
                    sf::Int32 rightclock1 = rightclock.getElapsedTime().asMilliseconds();
                    cout << rightclock1 << endl;

                    /*mywindow.clear(sf::Color::Black);
                    mywindow.draw(playersprite);
                    mywindow.draw(enemysprite);
                    playersprite.setPosition(sf::Vector2f(playerx, playery));
                    mywindow.display();*/

                }
            }
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
            {
                // up key is pressed: move our character
                //will replace later with time based movement
                (playery--);
            }
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
            {
                // down key is pressed: move our character
                // currently just resets sprite position for testing purposes
                    playerx = 400.0;
                    playery = 300.0;
            }
        if (playerx < 0) //Player cannot leave screen x left boundary
            {
                playerx = 0;
            }
        if (playerx > windowx) //Player cannot leave screen x right boundary
            {
                playerx = windowx - 10;
            }
    }
    mywindow.clear(sf::Color::Black);
    mywindow.draw(playersprite);
    mywindow.draw(enemysprite);
    playersprite.setPosition(sf::Vector2f(playerx, playery));
    mywindow.display();
    sf::sleep(sf::microseconds(5));
}
mywindow.clear(sf::Color::Black);
mywindow.draw(playersprite);
mywindow.draw(enemysprite);
playersprite.setPosition(sf::Vector2f(playerx, playery));
mywindow.display();
sf::sleep(sf::microseconds(5));
return 0;

}


person Jager57    schedule 31.08.2015    source источник
comment
Для фона: вы уже понимаете, почему окна не обновляются, или вам нужно это объяснить?   -  person user253751    schedule 31.08.2015
comment
Я не знаю, почему он не будет обновляться.   -  person Jager57    schedule 31.08.2015


Ответы (1)


Компьютер выполняет инструкции в том порядке, в котором он должен. Этот код:

mywindow.clear(sf::Color::Black);
mywindow.draw(playersprite);
mywindow.draw(enemysprite);
playersprite.setPosition(sf::Vector2f(playerx, playery));
mywindow.display();
sf::sleep(sf::microseconds(5));

обновляет окно. Если код обновления окна не запускается, то, конечно, окно не обновляется.

Если нажата левая клавиша, то компьютер запустит такой цикл:

while (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
    playerx -= 0.01; //will replace later with time based movement
    sf::Int32 leftclock1 = leftclock.getElapsedTime().asMilliseconds();
    cout << leftclock1 << endl;
    // there was commented-out code here; I removed it to save space in this answer
}

Он проверит, нажата ли левая клавиша. Если это так, он немного сдвинет игрока влево, напечатает время и повторит. Таким образом, он снова проверит, нажата ли левая клавиша. Если это так, он снова переместит игрока немного влево, снова напечатает время и повторит снова. И так далее. Это никогда не будет сделано с этим циклом, пока игрок не отпустит левую клавишу - он просто будет сидеть там, перемещая игрока влево (не то, чтобы вы могли это видеть) и спамить вашу консоль временем.

Типичное решение этой проблемы — просто удалить те циклы, которые проверяют нажатия клавиш. Сохраните if, но переместите их за пределы цикла обработки событий. Итак, у вас есть что-то вроде этого: (не фактический код)

while(window is open)
{
    while(have an event to process)
    {
        process event
    }
    if(left key pressed)
    {
        move player left
    }
    if(right key pressed)
    {
        move player right
    }
    // and so on
    update window
}

Кстати, вам не нужно обновлять окно внутри цикла событий - если событие не требует очень много времени для обработки (чего они не должны), тогда вы быстро закончите цикл событий.

person user253751    schedule 31.08.2015
comment
Значит ли это, что в моем коде не может быть цикла while, если я хочу, чтобы экран продолжал обновляться? - person Jager57; 31.08.2015
comment
@ Jager57 У вас могут быть циклы while, если они быстро заканчиваются. - person user253751; 31.08.2015