在SFML中无法获得平滑的运动

时间:2016-12-12 05:32:22

标签: c++ c++11 sfml frame-rate game-loop

我搜索了这个主题,发现使用sf::Clock实现独立于帧的更新(使用deltaTime)可以帮助解决它。然而,即使在添加它之后,桨叶运动也会停顿一些。另一方面,当我将整个Playing案例移至event polling loop而不使用deltatime时,游戏似乎运行顺畅。

如何在我的代码中正确使用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();
}

游戏循环:

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();
    }   
}

划分更新逻辑:

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);
}

1 个答案:

答案 0 :(得分: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/60秒)更新游戏并尽可能渲染(您可以使用setFramerateLimit()来限制FPS;这不会影响固定更新间隔,所以没问题有)。

您现在将sf::Time传递给manager.updateAllLayers,其elapsedTime就像.asSeconds()一样使用(它的功能类似于speed所以基本没什么变化,但您显然已经有了调整sum(v."Surface")::double precision

的值
相关问题