0

I searched on this topic and found that using sf::Clock to implement frame independent update(using deltaTime) can help to solve it. However even after adding it the paddle movement stutters a bit. On the other hand when I shift the entire Playing case to the event polling loop without using deltatime the game seems to run smoothly.

How do I go about using sf::Clock properly in my code and why does my game seems to run smoothly when I shift the Playing case in event pool loop without even using deltatime?

Game initialization:

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);
}
Karan Joisher
  • 331
  • 1
  • 9

1 Answers1

0

I don't have enough reputation to post a comment so I'll have to make this an answer...

You update (and draw) every frame. Your game loop doesn't make sense if you want to implement a fixed update time step.

This is how your game loop should look like. I use your variable names for your convenience:

// ...

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

// ...

This updates your game at a fixed rate (1/60s) and renders it whenever possible (you can use setFramerateLimit() to limit the FPS; this won't affect the fixed update interval, so no problem there).

You now pass sf::Time to your manager.updateAllLayers which is used like your elapsedTime (it has functions like .asSeconds() so essentially nothing changes but you'll obviously have to adjust the values for speed)

user3881815
  • 103
  • 7
  • Ur answer is correct for fixed update approach, whereas I am trying to achieve a solution which is independent of the number of updates per second. I know it doesn't matter for games like pong but am doing so to learn new concepts. – Karan Joisher Dec 13 '16 at 04:45