1

私はマルチプレイヤー ゲームを作成しています。すべてのフレームで、プレイヤーの位置をサーバーに送信する必要があります。サーバーでは、他のすべてのプレイヤーの位置を応答として受け取ります。

コードをノンブロッキングにするために、次の行を追加しました。

u_long one = 1; // Giggety
ioctlsocket(sock, FIONBIO, &one);

しかし、問題は、独自のブロック コード (while ループ) を有効にしない限り、サーバーから他のプレイヤーの位置を受信できないことです。

while(recvfrom(sock, receiveBuffer, 255, 0, (struct sockaddr *)&server, &sockaddr_in_sizePtr) <= 0) {
}
// Do stuff with response

しかし、私がこれを行うと、応答が得られるまでローカル ゲームが実行されないため、ゲームの遅延が非常に大きくなります。

解決策は、while ループで表示関数を呼び出すことだけだと思いましたが、何もしていないようです。

もう 1 つの問題は、UDP ソケットを使用していることです。これは、データが届かない可能性があることを意味し、その場合はタイムアウトする必要があります。だから私はこれを追加しました:

time_t timer;
time(&timer);
while(recvfrom(sock, receiveBuffer, 255, 0, (struct sockaddr *)&server, &sockaddr_in_sizePtr) < 0) {
    display(); // Doesn't stop lag
    if(timer != time(NULL)) return; 
}

しかし今では、文字通り 1 秒あたり 1 フレームの場合があります。これはひどいです。

ゲームを実行し続ける方法と、同時にソケットをリッスンする方法について、誰かが光を当てることができますか?

4

1 に答える 1

1

すべての対話型シミュレーション プログラムは、ノンブロッキング メイン ループを実行します。そのループのある時点で、外部から到着したすべてのデータを収集します。ネットワーク経由で新しいデータが到着した場合は、それを読み取り、プログラムの状態に処理します。何も到着しない場合は、通常どおりメイン ループを続行します。

ただし、このスキームが機能するには、SO 受信バッファーが十分に大きく、受信するために大量の着信パケットを蓄積できる必要があります。

だからあなたがすることは次のようなものです

while(running) {
    if( hasDataArrivedOn(socket) ) {
        receiveFrom(socket);
    }
    
    if( isThereUserInput(mouse) ) {
        processMouseMovement();
    }

    if( isThereUserInput(keyboard) ) {
        processKeypresses();
    }

    simulate();

    display();
}

その「hasDataArrivedOn」関数は、実際には別の ioctl です。つまり、FIONREAD最後のパケットで受信したオクテットの数を返すか、保留中のパケットがない場合は 0 を返します (また、最後に受信した UDP パケットにペイロードが含まれていない場合は 0 が返されます。プログラムはそうしないと、ペイロードを含まない UDP パケットでフラッディングされて DoS 攻撃を受ける可能性があります)。


更新 – GLUT アイドル コールバック バリアント

void idle()
{
    if( hasDataArrivedOn(socket) ) {
        receiveFrom(socket);
    }

    simulate();

    glutPostRedisplay();
}
于 2013-07-07T22:04:06.443 に答える