2016-12-12 77 views
0

Я искал в этой теме и обнаружил, что с помощью sf::Clock для реализации независимого от кадра обновления (с использованием deltaTime) может помочь его решить. Однако даже после его добавления движение весла немного заикается. С другой стороны, когда я переношу весь случай Playing на event polling loop без использования deltatime, игра, кажется, работает плавно.Невозможно получить плавное движение в SFML

Как я могу идти об использовании sf::Clock правильно в моем коде и почему моя игра, кажется, бежит гладко, когда я сдвигать Playing случай события цикла бассейн даже без использования deltatime? Инициализация

игры:

void Game::start() { 
    if (_gameState != Uninitialized) { 
     return; 
    } 
    //Creating window 
    _mainWindow.create(sf::VideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32), "Pong"); 
    _gameState = ShowingMenu; 

    //Adding game entities to the manager  
    VisibleGameObject *paddle1 = new PlayerPaddle("Player1", 1.0f, sf::Keyboard::Key::Up, sf::Keyboard::Key::Down); 
    VisibleGameObject *paddle2 = new PlayerPaddle("Player2", 1.0f, sf::Keyboard::Key::W, sf::Keyboard::Key::S); 
    VisibleGameObject *background = new Background("Background", 0.0f); 
    paddle1 -> setPosition(SCREEN_WIDTH - (paddle1 -> getWidth()), 0); 
    paddle2->setPosition(0, 0); 
    manager.addObject(paddle1); 
    manager.addObject(paddle2); 
    manager.addObject(background); 

    //Starting Clock 
    deltaTime = 0.0f; 
    frameClock.restart(); 


    while (!isExiting()) {  
     gameLoop(); 
    } 
    _mainWindow.close(); 
} 

Game Loop:

void Game::gameLoop() 
{ 
    static bool firstPass = true; 
    sf::Event currentEvent; 

    //Event loop 
    while(_mainWindow.pollEvent(currentEvent) || firstPass) 
    { 

     if (firstPass) { 
      currentEvent = sf::Event(); 
      currentEvent.type = sf::Event::GainedFocus; 
      firstPass = false; 
     } 

     if (currentEvent.type == sf::Event::Closed) 
     { 
      _gameState = Exiting; 
     } 

     switch (_gameState) 
     { 
      case ShowingMenu: 
      { 
       showingMenu(); 
       break; 
      } 
      case Paused: 
      { 
       break; 
      } 


      default: 
       break; 
     } 

    } 

    //Extracting deltaTime to update game logic 

    deltaTime = frameClock.restart().asSeconds(); 
    if(_gameState == Playing) 
    { 
     manager.updateAllLayers(deltaTime); 
     manager.drawAllLayers(_mainWindow); 
     _mainWindow.display(); 
    } 
} 

Paddle Update Logic:

void PlayerPaddle::update(const float & elapsedTime) 
{ 
    sf::Vector2f currentPos = getPosition(); 
    float displacement = 0.0f; 

    if (sf::Keyboard::isKeyPressed(controls.up)) 
    { 
     displacement = -speed * elapsedTime;  
    } 
    else if (sf::Keyboard::isKeyPressed(controls.down)) 
    { 
     displacement = speed * elapsedTime; 
    } 

    if (displacement + currentPos.y < 0.0f) 
    { 
     setPosition(currentPos.x, 0.0f); 
     return; 
    } 
    else if (displacement + currentPos.y + getHeight() > Game::SCREEN_HEIGHT) 
    { 
     setPosition(currentPos.x, Game::SCREEN_HEIGHT - getHeight()); 
     return; 
    } 

    setPosition(currentPos.x, currentPos.y + displacement); 
} 
+0

Если не использовать прошедшее время, то какое значение вы передадите в функцию обновления? –

+0

@DenisErmolin 1 –

+0

@KaranJoisher как часто firstPass становится правдой? вы можете показывать коды? –

ответ

0

У меня недостаточно репутации, чтобы оставить комментарий, поэтому я должен буду ответить на этот вопрос ...

Вы обновляете (и рисуете) каждый кадр. Ваш игровой цикл не имеет смысла, если вы хотите реализовать фиксированный шаг времени обновления.

Вот как должен выглядеть ваш игровой цикл. Я использую свои имена переменных для вашего удобства:

// ... 

sf::Clock frameClock; 
const sf::Time timePerFrame = sf::seconds(1.0f/60.0f); 
sf::Time timeSinceLastUpdate = sf::Time::Zero; 

while (_mainWindow.isOpen()) { 
    timeSinceLastUpdate += frameClock.restart(); 

    // events 
    { 
    sf::Event evt; 
    while (_mainWindow.pollEvent(evt)) { 
     //... 
    } 
    } 

    // update 
    { 
    while (timeSinceLastUpdate > timePerFrame) { 
     timeSinceLastUpdate -= timePerFrame; 
     manager.updateAllLayers(timePerFrame); 
    } 
    } 

    // render 
    { 
    _mainWindow.clear(); 
    // ... 
    _mainWindow.display(); 
    } 
} 

// ... 

Это обновляет игру по фиксированной ставке (1/60s) и делает это всякий раз, когда это возможно (вы можете использовать setFramerateLimit(), чтобы ограничить FPS, это не повлияет на фиксированный интервал обновления, поэтому проблем нет).

Теперь пройти sf::Time к вашему manager.updateAllLayers, который используется как ваш elapsedTime (он имеет такие функции, как .asSeconds() так по существу ничего не меняется, но вы, очевидно, придется изменить значения для speed)

+0

Ур ответ правильный для подхода с фиксированным обновлением, тогда как я пытаюсь найти решение, которое не зависит от количества обновлений в секунду. Я знаю, что это не имеет значения для игр, таких как понг, но я делаю это, чтобы изучить новые концепции. –