//tips
//オフラインとオンラインは別物と考える
今までオフラインの技術を中心に取り扱ってきたがマルチプレイヤーの仕組みを取り入れる際にはどうしてもオンライン特有の通信技術が必要になる。
例えば、マルチプレイゲームで全員のキー入力の通信が完了するまで、キャラクターを操作することができないため画面がかくつくという現象が発生する。
それは各通信端末の処理スピードの差であり、一般的に多様なデバイスが使われている現在では避けられない問題となっている。
また、データを送信する際には、受け取るまでの遅延時間が発生し、0.001秒から0.1秒程度かかる。
ゲームでの動作は60FPS(1秒間に60フレーム描画される)が基準で、そう考えると1フレームに対し、0.016秒程度の処理時間がかけられる。
もし0.1秒の通信遅延が発生していた場合、7フレーム前の画面を相手が見て操作することになる。
データの流れを考える際には、常に時間も考慮し、各端末での送受信の時間のズレやデータの反映タイミングをデータの流れと時間の経過で見て検討する必要がある。
さらに、通信のエラーも当然起こり得るのでそちらへの対応も事前に仕様に組み込む。
//通信の仕組み
2台の端末で通信を行う時データがどのように届くかを確認する。
PCなどの端末内のデータは、パケットと呼ばれる入れ物に入れられて通信相手に送られる。
パケットは接続されているケーブルやルータを通して、バケツリレーのように送信データがなくなるまで一定量ずつ延々と運ばれる。
バケツリレーを行う際に分岐がある場合は、最初の段階で届け先の指示がされており、これがパケットに入れられる配達住所IPアドレスの役目となる。
もっと細かく、端末のどのアプリケーション向けに情報が送られるのかを判断するために、パケットにIPアドレスだけでなく、ポート番号も記載して送る。
バケツリレー形式のため、途中でデータがこぼれて破損することもあり、その場合の対処がどうなされているかも知っておく必要がある。
データ送受信プロトコルがデータを安全の届ける役割をになっており、代表的なプロトコルTCPとUDPについて見ていく。
TCP(TCP/IP)の場合は、配達先の確認(どの端末のどのアプリケーションか)、受領証の取得、データロストの場合の再配達を行うが、その分利用コストも高くなる。
流れとして、送信元の接続処理→送信先確認応答→送信要求+データ→データ到着+確認応答→送信元の確認応答受信となる。
最初の接続処理の応答の中に送信先の受信バッファサイズが入っており、データがそのバッファサイズより小さければ、送信を行える。送信中にデータを消失してしまうと、送信端末に一定時間確認応答が届かなくなるため、再度同じデータを送信することになる。
TCPはデータの到達保証や順序保証があるため、HTTPやFTP(File Transfer Protocol)で用いられているプロトコルである。
送信するデータが大きい場合、TCPは送信データを分割し、通信で扱えるサイズにする。受け取り先で分割データをバッファに格納・結合し、宛先のアプリケーションに配達する。
一方、UDPは応答確認を省き、データの配達のみを行う。そのため送信先のバッファサイズの情報がなくてもデータを送信することになる。
オンラインの場合は、UDPを使われることが多く、これはTCPの再送信などの便利機能が逆に時間のロスにつながってくるからである。
通信量についても別途考える必要がある。
リアルタイムで通信相手に即座に情報を反映させるためには高頻度でデータを送受信しなければならない。大量のデータを高頻度で送ると、通信帯域(回線の太さ)を圧迫し、遅延が大きくなったり、パケットロストが発生して再送信しなければならなくなる。
通信帯域を圧迫するとルーターなどのバッファにパケットが溜まり、送信の順番待ちが発生することになる。送信するデータは相手に届くまでにいくつかのルータやハブを通過する。
つまり、データの通信はできるだけ、少ない回数で、少量のデータで行うようにパフォーマンスと相談しながら工夫する必要がある。
通信するデータの仕様が決まったら、必要な通信量を計算して、どれくらいの帯域まで処理が快適に行われるかを確認し、通信帯域の値を超える場合は、見直しを行う必要がある。
//ソケットプログラミング
TCPやUDPを簡単に扱うための通信APIソケットを使用する。
これは、IPアドレスとポート番号を1組にし、通信相手を指定して通信を行う。ソケットを使用するためにはソケット生成、使用ポートの割当、接続待ち受け開始の順に準備を整えていくことになる。
ソケットで通信を始めるためにはソケットを操作するSocketクラスを利用してプログラミングを行う。
void StartListener(int port)
{
//ソケット生成
m_listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
//使用するポート番号割り当て
m_listener.Bind(new IPEndPoint(IPAddress.Any,port));
//待受開始
m_listener.Listen(1);
m_state = State.AcceptClient;
}
https://docs.microsoft.com/ja-jp/dotnet/api/system.net.sockets.socket?view=netcore-3.1
などのようにプログラミングで処理を設定することができる。
//マルチプレイヤーゲーム作成補足
Unityから最新のマルチプレイ情報が出ていたので下記に記載する。
https://www.youtube.com/results?search_query=unity+%E3%83%9E%E3%83%AB%E3%83%81%E3%83%97%E3%83%AC%E3%82%A4+%E4%BD%9C%E3%82%8A%E6%96%B9&pbjreload=102