无法获得SFML的平稳运动

Cannot get smooth movement in SFML

本文关键字:运动 SFML      更新时间:2023-10-16

我搜索了此主题,发现使用sf::Clock实现帧独立更新(使用deltaTime)可以帮助解决它。但是,即使在添加后,桨动作也有点结束。另一方面,当我在不使用deltatime的情况下将整个Playing情况转移到event polling loop时,游戏似乎会顺利运行。

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

我没有足够的声誉来发表评论,所以我必须给这个答案...

您更新(并绘制)每个帧。如果要实现固定的更新时间步骤,则您的游戏循环是没有意义的。

这就是您的游戏循环的外观。为了您的方便,我使用您的变量名称:

// ...
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的值)