我搜索了这个主题,发现使用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);
}
答案 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
)