Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Best Practice for using setFramerateLimit  (Read 1213 times)

0 Members and 1 Guest are viewing this topic.

firepro20

  • Newbie
  • *
  • Posts: 22
    • View Profile
Best Practice for using setFramerateLimit
« on: November 23, 2019, 01:37:27 am »
I currently follow the SFML Game Development example for checking the time frame update between the previous and the current frame, for frame per second in my main loop.

However, I want to set the limit to 60FPS, as in the moment it going to 1000s. I am setting the limit right after creating the window as written in the documentation, however I'm getting a jittery effect on my spaceships.

This is my current code. What would be the best practice to use setFramerateLimit with main loop calculations to update on each frame? (render, movement,input etc)

Quote
int main()
{
   sf::Texture            mPlayerTexture;
   sf::Sprite            mPlayer;
   sf::Texture            mBackgroundTexture;
   sf::Sprite            mBackground;
   
   sf::RenderWindow window(sf::VideoMode(game->getWindowWidth(), game->getWindowHeight()), "SFML Application");
   //static const sf::Time   TimePerFrame;

   window.setFramerateLimit(60);

   if (!mPlayerTexture.loadFromFile("Media/Textures/PixelSpaceships/blue_01.png"))
   {
      // Handle loading error
   }
   if (!mBackgroundTexture.loadFromFile("Media/Textures/Space.jpg")) {
      // Handle loading error
   }
   

   mBackground.setTexture(mBackgroundTexture);
   mBackground.setOrigin(game->getWindowWidth() / 2.f, game->getWindowHeight() / 2.f);
   mBackground.setPosition(game->getWindowWidth() / 2.f, game->getWindowHeight() / 2.f);

   // Set Texture and Position
   mPlayer.setTexture(mPlayerTexture);
   mPlayer.setOrigin(24.f, 24.f);
   mPlayer.setPosition(game->getWindowWidth() / 2.f, game->getWindowHeight() / 2.f);

   //enemy.enemyInstantiator(2, 100.f, 50.f);
   //enemyInstantiator(10, 100.f, 150.f);

   // Statistics Initialisation
   sf::Font            mFont;
   sf::Text            mStatisticsText;
   mFont.loadFromFile("Media/Sansation.ttf");
   mStatisticsText.setFont(mFont);
   mStatisticsText.setPosition(5.f, 5.f);
   mStatisticsText.setCharacterSize(10);

   // Enemy Creation // Separate method in main
      
   std::vector<Enemy> *enemyList = new std::vector<Enemy>();
   float xPosition = 100.f;
   float yPosition = 50.f;
   float yOffset = 50.f;
   float xOffset = 60.f;
   for (int i = 0; i < NUMBER_OF_ALIENS; i++) {
      Enemy alien(i, enemySpeed);
      alien.getSprite().setOrigin(24.f, 24.f);
      alien.setLocation(xPosition + (i * xOffset), yPosition);
      alien.getSprite().setRotation(180.f);
      enemyList->push_back(alien);

      //std::cout << "I have " << enemyList->size() << " spaceships" << std::endl;
   }
   //std::cout << "I have " << enemyList->size() << " spaceships";

   /*
   //create a an array of enemys
   Enemy alienArray = new Enemy[];
   for (int i = 0; i < NUMBER_OF_ALIENS; i++)
   {
      Enemy alien(i, enemySpeed);

      alien.setLocation(i * 50.f + 50.f, alien.getSprite().getGlobalBounds().height / 2);
      alienArray;
   }
   */

   //game->run();

   // Measure elapsed time
   sf::Clock clock;
   sf::Time timeSinceLastUpdate = sf::Time::Zero;
   while (window.isOpen())
   {
      // Puts the time counter back to zero and also returns the time elapsed since the clock was started
      sf::Time deltaTime = clock.restart();
      timeSinceLastUpdate += deltaTime;
      while (timeSinceLastUpdate > TimePerFrame) // fixed time steps
      {
         timeSinceLastUpdate -= TimePerFrame; // solves problem with variable delta time, each frame is unique

         processEvents(window);
         //update(TimePerFrame);

         // Player 1 movement
         sf::Vector2f movement(0.f, 0.f);
         if (mIsMovingUp)
            movement.y -= playerSpeed;
         if (mIsMovingDown)
            movement.y += playerSpeed;
         if (mIsMovingLeft)
            movement.x -= playerSpeed;
         if (mIsMovingRight)
            movement.x += playerSpeed;
         // shooting logic


         // Possibly this will be the data that needs to be sent to server
         mPlayer.move(movement * TimePerFrame.asSeconds()); // Time.deltaTime frame independent movement

         // for each player eventually
         screenBound(mPlayer);
         // screenbound enemies or else check that they do not go off bounds and change direction

         // Enemy Behaviour // Move to separate method

         sf::Vector2f enemyMovement(1.f, 0.f);
         float yOffset = 50.f;
         float xOffset = 60.f;
         // Be careful with iterators as when deleting it will automatically jump to the next item in vector
         for (std::vector<Enemy>::iterator i = enemyList->begin(); i != enemyList->end(); ++i) // CAUTION & solved everything again - lesson in C++, if we don't get address, we always create a copy and modify it, which is not what we want
         {
            std::cout << "Direction before working move " << direction << std::endl;
            i->getSprite().move(enemyMovement * direction); // Issue detected direction only changing sign if greater or less than screen bounds once
            if (i->getSprite().getPosition().x + i->getSprite().getLocalBounds().width / 2 > game->getWindowWidth() ||
               i->getSprite().getPosition().x - i->getSprite().getLocalBounds().width / 2 < game->getWindowWidth() - game->getWindowWidth()) { // this will be 0
               direction = -(direction);

               std::cout << "Direction inside if statement " << direction << std::endl;
               // another for loop move all down by yOffset
               for (std::vector<Enemy>::iterator i = enemyList->begin(); i != enemyList->end(); ++i) {
                  i->getSprite().setPosition(i->getSprite().getPosition().x, i->getSprite().getPosition().y + yOffset);
                  //enemy.move(0.f, enemy.getPosition().y + yOffset);
               }
               //enemy.setPosition(enemy.getPosition().x, enemy.getPosition().y + yOffset); // y axis is inverted in SFML
               //return 0; // move to separate method
            }

            if (i->getSprite().getPosition().y > game->getWindowHeight() - mPlayer.getLocalBounds().height) {
               //removeEnemy(enemy);
               // ALIVE is false, then draw based on whether alien is alive or not
               std::cout << "Everyone should be dead game over!" << std::endl;
               return 0; // change state to paused
            }
         }
      }

      updateStatistics(deltaTime, mStatisticsText);
      
      // Render All
      // Remember draw order is important
      window.clear();
      window.draw(mBackground);
      window.draw(mPlayer);
      window.draw(mStatisticsText);

      
      for (std::vector<Enemy>::iterator i = enemyList->begin(); i != enemyList->end(); ++i) {
         if (i->isAlive()) {
            i->draw(window);
            std::cout << "Enemy " << i->getID() << " position - " << i->getLocation().x << " " << i->getLocation().y << std::endl;
         }
            
      }

      

      //for (Enemy& enemy : enemyList) {
      //   if (enemy.isAlive()) {
      //      enemy.draw(window);
      //   }
      //}

      //enemy.render(alienArray, mWindow);
      /*
      for (int i = 0; i < mEnemies.size(); i++)
      {
         sf::Sprite temp = mEnemies.at(i);
         mWindow.draw(temp);
      }
      */

      window.display();

   }

   return 0;
}

firepro20

  • Newbie
  • *
  • Posts: 22
    • View Profile
Re: Best Practice for using setFramerateLimit
« Reply #1 on: November 23, 2019, 01:44:02 am »
I replaced the setFrameLimit with window.setVerticalSyncEnabled(true) and now I am getting constant 60, so smooth movement.

I think the issue was that setFrameLimit implies that it will ceil the value to 60, but if its lower it is also acceptable. So maybe that causes the weird issue.