私が以前ちょっと試したリアルタイム性の高いアクションゲームのオンライン対戦プログラムでの通信は
ゲームが開始してから経過したフレーム数+そのときのプレイヤーのキー入力情報
の情報を毎フレーム「現在のフレーム+それ以前の60フレーム分」を通信相手とお互いに送信しあって、
相手のキー入力情報が届いてから初めてゲーム内時間を進める、という処理を行ったところ、それっぽく動きました
ただ、ゲーム内時間は相手のキー入力情報が届くまで進めませんが、こちらのキー入力は相手に
送るためにガンガン先行して採取するので、相手からキー入力情報が届くまでの時間が長くなれば
なるほど「自分が入力したキー入力が画面に反映されるまでの時間」が長くなります
あと、DXライブラリのリファレンスに載っている通信機能はTCP/IPという通信プロトコルを
使用しているのですが、リアルタイム性の高いゲームではTCP/IPは遅くて実用に耐えないので、
UDPという通信プロトコルを使用します、こちらは
・相手に届かないかもしれない
送信したデータが途中で行方不明になって相手に届かないことがあります( TCP/IP では自動的に再送信してくれます )
・送った順番で相手に届くとは限らない
1・2・3という順番でデータを送信しても、相手には2・1・3という順番で届く可能性があります
なので、送信データはどの順番で届いても処理に問題が発生しないような内容にしておく必要があります
・一度に送信できるデータサイズは 65507byte
ただ、データのサイズが大きいと送信時間が長くなるので、1フレーム辺りの送信データのサイズは
数百バイトに抑えた方が良いです
という欠点がありますが、高速です
DXライブラリのリファレンスには載っていませんが、以下のようなUDP通信用の関数があります
// UDPを使用した通信を行うソケットハンドルを作成する( RecvPort を -1 にすると送信専用のソケットハンドルになります )
int MakeUDPSocket( int RecvPort ) ;
// UDPを使用した通信を行うソケットハンドルを削除する
int DeleteUDPSocket( int NetUDPHandle ) ;
// UDPを使用した通信で指定のIPにデータを送信する、Length は最大65507、SendPort を -1 にすると MakeUDPSocket に RecvPort で渡したポートが使用されます
// 戻り値 0以上;送信できたデータサイズ -1:エラー -2:送信データが大きすぎる -3:送信準備ができていない
int NetWorkSendUDP( int NetUDPHandle, IPDATA SendIP, int SendPort, void *Buffer, int Length ) ;
// UDPを使用した通信でデータを受信する、Peek に TRUE を渡すと受信に成功してもデータを受信キューから削除しません
//
// 引数補足
//
// RecvIP : 送信してきた相手のIPを保存する IPDATA 構造体のアドレス( NULL でも大丈夫 )
// RecvPort : 受信に使用したポート番号( NULL でも大丈夫 )
//
// 戻り値 0以上:受信したデータのサイズ -1:エラー -2:バッファのサイズが足りない -3:受信データがない
int NetWorkRecvUDP( int NetUDPHandle, IPDATA *RecvIP, int *RecvPort, void *Buffer, int Length, int Peek ) ;
// UDPを使用した通信で新たな受信データが存在するかどうかを調べる
// 戻り値 -1:エラー TRUE:受信データあり FALSE:受信データなし
int CheckNetWorkRecvUDP( int NetUDPHandle ) ;
UDPはTCPと違い「相手に接続する」という過程がありません、なので、「接続を切る」という関数もなく
データを送信するときも NetWorkSendUDP で相手のIPアドレスとポート番号をその都度、直接指定します
( 受信するときは相手に MakeUDPSocket の RecvPort で指定したポートに NetWorkSendUDP してもらい、
それを NetWorkRecvUDP で受信します )
例えばポート番号 9876 に送信されたUDPパケットをひたすら受信して、受信したデータの総量を表示するだけのプログラムは
次のようになります
#include "DxLib.h"
BYTE Data[ 65500 ] ;
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
int UDPNetHandle ;
int RecvSize, TotalRecvSize ;
ChangeWindowMode( TRUE ) ;
if( DxLib_Init() < 0 ) return -1 ;
// 受信用UDPソケットハンドルの作成
UDPNetHandle = MakeUDPSocket( 9876 ) ;
SetDrawScreen( DX_SCREEN_BACK ) ;
// パケット受信
TotalRecvSize = 0 ;
while( ProcessMessage() == 0 )
{
ClearDrawScreen() ;
// データを受信
RecvSize = NetWorkRecvUDP( UDPNetHandle, NULL, NULL, Data, sizeof( Data ), FALSE );
if( RecvSize >= 0 )
{
TotalRecvSize += RecvSize;
}
DrawFormatString( 0, 0, GetColor( 255,255,255 ), "TotalRecvSize:%d", TotalRecvSize ) ;
ScreenFlip() ;
}
DxLib_End() ;
return -1 ;
}
アクションゲームの通信ではUDPは必須、ということと、それを使ってそれっぽい処理を実現することはできましたが、
完成形のものを作った経験は無いのでそれが正しい方法かはわかりません
また、UDPに関しては上記以外にも注意することがありますので、よろしければ「UDP WinSock」などのキーワードで
検索して調べてみてください( WinSock は Windows上で TCP/IP通信や UDP通信を行うための機能で、DXライブラリも
WinSock を使用して通信機能を作成しています )