本地主机

时间:2019-12-01 00:33:40

标签: sockets network-programming udp sfml

我目前正在使用SFML创建一个游戏,该游戏将允许客户端连接并观看玩家的游戏玩法。自UDP以来,此操作目前正在本地主机127.0.0.1的同一端口上完成。

我正在启动两个可执行文件-一个将是客户端,另一个将是主要播放器[udpserver]。

我注意到在客户端,飞船移动时会出现抖动,并且子弹在向上移动之前在实例化位置被拉动了2到3次。 (当生成子弹时,将其渲染为向上,代码将同时为客户端和服务器执行)。这就是我所拥有的-

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
                    if (bulletPtr->isAlive())
                    bulletPtr->setLocation(clientXPosition - 13.f, clientYPosition - 24.f);
                    //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

}

让我知道是否可以提供其他信息。这是从main开始执行的顺序-

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

0 个答案:

没有答案
相关问题