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

Author Topic: UDP code laggy on localhost  (Read 1119 times)

0 Members and 1 Guest are viewing this topic.

firepro20

  • Newbie
  • *
  • Posts: 22
    • View Profile
UDP code laggy on localhost
« on: December 01, 2019, 01:40:27 am »
I am trying to understand why the spaceship moves really jittery on screen on client on same machine using localhost as IP.

This is the code I have, followed by the order of execution -

Quote
void createUdpServer(unsigned short port) { // send data to client
   
   // Create a socket to receive a message from anyone
   sf::UdpSocket socket;
   sf::IpAddress local = sf::IpAddress::getLocalAddress(); // Currently 127.0.0.1 localhost
   sf::IpAddress receiver = sf::IpAddress::getLocalAddress();
   
   socket.setBlocking(false);
   // I was figuring out and arranging according to example.. set socket non blocking

   // Listen to messages on the specified port
   if (socket.bind(port) != sf::Socket::Done && !portBound) // You bind once
      return; // error
   else {
      portBound = true;
   }
   std::cout << "Server is listening to port " << port << ", waiting for a connection... " << std::endl;
   
   // Wait for a message
   char in[128];
   std::size_t received;
   sf::IpAddress sender;
   //unsigned short senderPort; we will be receiving and sending data on sa,e port
   
   sf::SocketSelector selector;
   selector.add(socket);

   if (selector.wait(sf::milliseconds(10.f))) { // times out after 10ms
      if (selector.isReady(socket)) {
         if (socket.receive(in, sizeof(in), received, sender, port) != sf::Socket::Done) // blocking
            return;
         std::cout << "Message received from client " << sender << ": \"" << in << "\"" << std::endl;
      }
   }
   
   // Sends connection established to client
   /*
   const char out[] = "Connection with server established!";
   if (socket.send(out, sizeof(out), sender, port) != sf::Socket::Done)
      return;
   */
   // acknowledgement of packets
   float playerXPosition = player->getPosition().x;
   float playerYPosition = player->getPosition().y;
   sf::Packet playerData;
   sf::Packet bulletData;
   playerData << playerXPosition << playerYPosition << bulletPtr->isAlive() << bulletPtr->getLocation().x << bulletPtr->getLocation().y;
   //bulletData << bulletPtr->isAlive() << bulletPtr->getLocation().x << bulletPtr->getLocation().y;
   socket.send(playerData, sender, port);
   //socket.send(bulletData, sender, port);
   //const char out[] = "";
   //if (socket.send(out, sizeof(out), sender, port) != sf::Socket::Done)
   //   return;
   
}

void runUdpClient(unsigned short port) { // receive data from server

   // Ask for the server address
   server = "127.0.0.1";
   /*
   if (server == sf::IpAddress::None)
   do
   {
      std::cout << "Type the address or name of the server to connect to: ";
      std::cin >> server;
      
   } while (server != sf::IpAddress::None);
   */
   // Create a socket for communicating with the server
   sf::UdpSocket socket;

   sf::IpAddress recipient = sf::IpAddress::getLocalAddress();
   char data[100] = "Connection with client established!";

   if (socket.send(data, 100, server, port) != sf::Socket::Done && !sendInitialToServer) // if send once dont't send again
   {
      // added up top send this only once
      // error...
   }
   else{
      sendInitialToServer = true;
   }
   
   // Think about putting this globally
   sf::SocketSelector selector;
   selector.add(socket);
   
   if (selector.wait(sf::milliseconds(10.f))) { // not enough time for server to be created with 0.1f

      // received something
      if (selector.isReady(socket)) {

         // Wait for a message
         char in[128];
         std::size_t received; // am I using this?
         sf::IpAddress sender;
         sf::Packet playerData;
         sf::Packet bulletData;
         float playerXPosition;
         float playerYPosition;
         float clientXPosition;
         float clientYPosition;
         float clientBulletX;
         float clientBulletY;
         bool bulletShot;
         
         socket.receive(playerData, sender, port);
         //socket.receive(bulletData, sender, port);

         if (playerData >> playerXPosition >> playerYPosition >> bulletShot >> clientBulletX >> clientBulletY) { // if you are able to read
            clientXPosition = playerXPosition;
            clientYPosition = playerYPosition;
            
            player->setPosition(clientXPosition, clientYPosition);
            if (bulletShot) {
                // - might not need this
               bulletPtr->spawn(true); // once bullet spawned, should be taken care of both sides
               //
               bulletPtr->setLocation(clientXPosition - 13.f, clientYPosition - 24.f);
               if (!bulletPtr->isAlive())
               {
                  bulletPtr->kill();
               }
               //else
               // clientbulletx and clientbullety

               //bulletPtr->draw(window); // client window handled from both client and server what to do if bullet is alive
            }
            
         }

         /*
         if (bulletData >> bulletShot >> clientBulletX >> clientBulletY) {
            if (bulletShot) {
               bulletPtr->spawn(true); // once bullet spawned, should be taken care of both sides
               bulletPtr->setLocation(player->getPosition().x - 13.f, player->getPosition().y - 24.f);
                              
               //bulletPtr->draw(window); // client window handled from both client and server what to do if bullet is alive
            }
         }*/
         else {
            // Handle error / packet loss // else simulate?
            std::cout << "Error - failed to read from player data packet!" << std::endl; // this is normal when packet is lost
            // I think I am getting several packet drops as I am receiving and sending from the same PC same port, localhost
         }
         
         //unsigned short senderPort;
         //if (socket.receive(in, sizeof(in), received, sender, port) != sf::Socket::Done)
         //   return;
         //std::cout << "Message received from server " << sender << ": \"" << in << "\"" << std::endl;
      }
      // this shouldn't be here, receive stuff should go on client, server just sends
   }
   else {

      // timeout reached, nothing was received

   }
   // prediction
   // bullet

}

Order of Execution from main -

Quote
   while (window.isOpen())
   {
      
      if (userChoice == NULL){
         do {

            std::cout << "User Choice - " << userChoice << std::endl;
            std::cout << "Server or client? (s/c)" << std::endl;
            std::cin >> userChoice;
            
         } while (userChoice != 's' && userChoice != 'c');
         // The game clock will keep on restarting until the user makes a decision
         clock.restart(); // This solved issue to start movements and updates at same time once user chooses an option
      }
      if (userChoice == 's' || userChoice == 'c') { // start of main if  // else start the whole program
         
         // game time over here once game starts // frame independent

         // Binding of ports for both client or server
         /*

         // bind the socket to a port
         if (socket.bind(54000) != sf::Socket::Done)
         {
            // Using UDP starts listening on this port
            // whatever happens, bind for both -> will work with two executables running on same network with two different local IPs
         }

         */

         // 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 // userchoice != NULL otherwise it will start immeadiately
         {
            timeSinceLastUpdate -= TimePerFrame; // solves problem with variable delta time, each frame is unique

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

            // Start of if server
            if (userChoice == 's'){

               //if(!serverCreated){ // if problems of continous connection, this needs to place outside of bind
                  // create connection
                  createUdpServer(SERVER_PORT); // over here its happening every frame
                  //serverCreated = true; // is server actually created though?
               //}

               // 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
               if (mIsShooting) {
                  if (!bullet.isAlive()) // && !gameOver
                  {
                     bullet.spawn(true);
                     bullet.setLocation(mPlayer.getPosition().x - 13.f, mPlayer.getPosition().y - 24.f); // mPlayer.getPosition().x + 24 (offset) if origin is not set to center
                  }
               }
         
               // ** These two parts need to be put in an if statement, if server, direct movement, if client, move needs to happen with data received
               // from server (Server - main player streamer; Client - viewer)

               // 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

               // **

            } // end of if server
            else {
               // Handle control through incoming network data
               // vector x = datacoming in
               // Hypothetically mPlayer.move(data coming in);

               // bullet spawn
               // setlocation from data packet
               
               runUdpClient(SERVER_PORT);
            }

            // Enemy Behaviour // Ideally move to separate method

            sf::Vector2f enemyMovement(1.f, 0.f);
            float yOffset = 30.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);
                  // Time stamp over here for network calculations
                  //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
               }

               // This takes care of everything on both sides
               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);
            
         // ** Start of if server
         if (userChoice == 's'){
            for (std::vector<Enemy>::iterator i = enemyList->begin(); i != enemyList->end(); ++i) {
         
               // Test player and alien collision
               if (CollisionManager::collidesWith(mPlayer, *i) && i->isAlive()) { // *i it points to the enemy, and will give me an enemy
                  std::cout << "You're dead!" << std::endl;
                  mPlayerIsAlive = false;
                  
                  return 0; //-> I'm dead gameOver = true;
               }

               // Test collision between bullets and aliens
               if (CollisionManager::collidesWith(bullet, *i) && i->isAlive())
               {
                  i->kill();
                  //enemyList->erase(i); // issue here, we are trying to do this in order to get rid of rendering problems .. shit just move it out of way
                  //i->setLocation(700.f, 10.f);
                  bullet.kill();
                  bullet.setLocation(700.f, 0.f); // temporary solution for dealing with not actually killing but stop drawing bullet
                  // without above line, the bullet will not be drawn but still exist on screen
               }
         
               /*
               v.erase(std::remove_if(v.begin(), v.end(), //erase returns it, so it = erase
                  [](int i) { return i < 10; }), v.end());
               */
            }
         }
         // ** end of if server

         int deadEnemies = 0;
         for (std::vector<Enemy>::iterator i = enemyList->begin(); i != enemyList->end(); ++i) {
         
            if (!(i->isAlive())) {
               deadEnemies++;
            }
            if (deadEnemies >= NUMBER_OF_ALIENS) {
               std::cout << "You win!" << std::endl;
               
               
               return 0; // Set state win
            }
         
         }
         //std::cout << "Total Dead Enemies - " << deadEnemies << 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);
         }
         */

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

         if (bullet.isAlive()) // && !gameOver // for game state and win / lose screen representation
         {
            //draw bullet
            bullet.draw(window);
            //move bullet
            bullet.getSprite().move(0.f, -20);
         }

         //test collision with bullet and boundary
         if (bullet.getSprite().getPosition().y < 0)
            bullet.kill();

         window.display();
      } // end of main second if
   }

   return 0;
}

firepro20

  • Newbie
  • *
  • Posts: 22
    • View Profile
Re: UDP code laggy on localhost
« Reply #1 on: December 01, 2019, 05:14:38 pm »
I fixed this by setting wait time out on udp client selector.wait(sf::milliseconds(10.f) and wait time out on server
selector.wait(sf::milliseconds(20.f)

 

anything