初心者でもわかる！「オンラインゲームにおける仕組み」を学んでみよう【後編】

# 最初に
本記事では、非エンジニアな方でも理解しやすいように「オンラインアクションゲームを開発するにあたって知っておきたい仕組み」について、丁寧に解説していきます。


対象読者は以下の通りです。
- ゲームサーバーを運営したり、シンプルなオンラインゲームを構築した経験があり、実際の開発ではどういった仕組みを用いているのか興味がある方
- プログラムやゲームエンジンを触ったことがあり、オンラインゲーム開発の基礎について学びたい方
- なんもわからんけど知見として持っておきたい方

<br>
今回記事の中で紹介する内容は以下の通りとなります。

- **同期型について**
- **同期型におけるフルメッシュ型とスター型の違い**
- **C/SやP2Pの簡単な概要について**
- **グローバルIPアドレスとプライベートIPアドレスについて**
- **NAT問題について**
- **リレーサーバ方式について**

<br>

[初心者でもわかる！「オンラインゲームにおける仕組み」を学んでみよう【前編】](https://qiita.com/4_mio_11/items/45f7ea6df34bec8e86c1)

前編もありますので、興味がある方はご一読頂けますと嬉しいです、励みになります。
前編では以下の内容を記載しています。


- **ゲーム開発における基本用語**
- **非同期型について**
- **非同期型における「アイテムデュープ」などの問題**

<br>

逆に今回解説しない項目は以下の通りです。

- MMO型とMO型の違い
- 非同期型のフルメッシュ型やスター型における概要
- TCPやUDP、RUDPに関する詳細な説明
- 非同期型における「アイテムデュープ」などの問題に対しての説明

TCPやUDP、RUDPに関する詳細な説明は以下の記事を参考頂ければと思います。
(ﾁｮｯﾄﾌﾙｲので、最新の記事もチェックしてみてください)
➡[ネトゲや配信で使い分けられてるTCPとUDP、RUDPの概念から勉強し直してみた](https://qiita.com/4_mio_11/items/cd3efe0345eee75c3ae2)

<br>

## リアルタイム対戦格闘ゲームや対戦ゲームの公式戦

前編では、非同期式の説明として格闘ゲームを例に出しましたが、「どちらかの結果を採用する」という解決方法では、実際のシビアな1フレームで勝敗を決するようなゲームでは、辻褄の合わない結果が発生するために使えません。高度な判断を求められるゲームでは、1フレーム単位で完全に端末同士を同期させる必要があるのです。

これを **「完全同期式」** と呼びます。

完全同期式とは、**対戦しているプレイヤー全員が全く同じ画面を見ることができる形式**です。この方式でゲーム中に通信されるデータは、プレイヤーの移動・攻撃・防御などの操作情報です。通信方式は**UDP**を使うことで、リアルタイム性を重視したデータのやりとりを行うことができるようになります。

UDPとは、データ受信確認などの返答を必要せず、データを送ったら送りっぱなしという、信頼性や確実性よりもリアルタイム性を重視した遅延の少ない通信方式のことです。

:::note
UDPの詳しい説明はこちらから。
[ネトゲや配信で使い分けられてるTCPとUDP、RUDPの概念から勉強し直してみた #UDPとは？](https://qiita.com/4_mio_11/items/cd3efe0345eee75c3ae2#udp%E3%81%A8%E3%81%AF)
:::

同期の仕組みは、**「相手の操作情報が届いたら、そのフレームの処理を実行する」** という考え方に基づいています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36899/5fd5f7f3-3853-06d8-6314-5beff5e018f1.png)

この高速なやり取りを実現するためには、プレイヤー同士でのデータの流れ方も重要となってきます。

<br>

# 完全同期式を実現するフルメッシュ型やスター型とは？

**プレイヤーの端末同士を直接接続する方式** を用いて完全同期式を実装する場合に、基本となる、**「フルメッシュ型」**と**「スター型」** について説明します。

## フルメッシュ型

**「フルメッシュ型」** とは、**プレイヤーの端末が他の全プレイヤーの端末と直接通信する方法**です（端末とはPCやスマートフォン、ゲーム機を指します）。

つまり全てのプレイヤーの端末同士が相互に接続されている状態となります。これにより、各端末が直接情報をやり取りできるため、通信の遅延が少なくなり、セキュリティも向上します。

例えばプレイヤー数が3人いた場合は以下のようなデータのやり取りが行われます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36899/f5bd36ab-ee9c-69b4-5c71-b86fd753f6dc.png)

この場合、プレイヤーのコントローラ操作（十字キーやAボタンを押した、など）の入力情報のみを通信し合います。この情報は全ての端末が、自分を除く全ての他プレイヤーの端末に送るので、図では合計６本の矢印が存在しています。


時間の流れを図にすると以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36899/9ac84f04-583c-95ec-2620-2f4db60b9796.png)

60FPSのゲームの場合は、入力情報のやり取りを1秒間に60回繰り返します。自分以外の全ての端末から、入力情報がもらうまでは、単純に待ち続けます。ゲーム進行の情報はデジタルデータなので、初期状態とそれに対する変更分を漏れなく送れば、全員の状態は常に一致するという考え方です。上の図では変更分の入力を全端末に送り、全員が情報を受け取り終わったら次の状態へと進んでいます。

<br>

これを成立させるためには、以下の条件が満たされている必要があります。

1. **全プレイヤーの初期状態が厳密に同じである**
2. **全てのプレイヤーの入力情報パケットが、全てのプレイヤーの端末に確実に漏れなく届く**
3. ゲーム進行用のデータが乱数で変化しない（結果が同じになる擬似乱数ならOK）
4. ゲーム進行用のデータが、タイミングによって異なる結果にならない

一見、この方式で問題ないように見えますが、このフルメッシュ型には2つほど問題点が存在します。

#### 1. **人数が増えると、送受信の完全性が急激に崩れやすくなる。**

例えば50人や、100人がフルメッシュ型で接続しようとした場合、非常に複雑なネットワーク構成となり、通信量が膨大になります。これにより、ネットワークの遅延や混雑が発生し、情報の送受信に遅れが生じやすくなります。

#### 2. ユーザーがお互いの入力を待つ必要があるため、遅延の大きいプレイヤーがいた場合に、他のプレイヤーが足を引っ張られてしまう。

先ほどの図で、Cさんの通信環境が悪く、AさんとBさんのデータをなかなか受け取れなかった場合、Cさんの遅延にAさんとBさんも引っ張られてしまうことになります。


これらの問題点があることから、フルメッシュ型で**人数や規模を大きくさせるのは難しい**です。

## スター型

メッシュ型よりも同時プレイ数を増やすことができる通信方式、それが**スター型**です。
先ほどと同じように、プレイヤーが3人いた場合は、以下のようなデータのやり取りが行われます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36899/ac59e876-8e93-2a71-bd7a-20b4cd027012.png)

上記の図では、Aがサーバーの役割を担っています。

サーバーという単語が出てきたので、今後は「端末」という言葉を「クライアント」と言い換えていきましょう。

<details><summary>なぜクライアントという言葉を使うのか？</summary><div>

1. サーバーとの対比：クライアントという用語は、サーバーに対する対比として使用されます。サーバーは情報などを提供する中心的な機器/役割を果たします。それに対して、情報などを要求する側をクライアントと呼びます。
1. リクエストと応答の関係：クライアントは、通常、サーバーにリクエストを送信して情報などを要求し、その結果としてサーバーから応答を受け取ります。このリクエストと応答の関係を強調するために、クライアントという用語が使用されます。

</div></details>

<br>

スター型の中心がサーバー、それ以外をクライアントと呼びます。

クライアントから入力情報がサーバに送信されて、サーバー側では全員分の入力データが揃うまで待ちます。その後、サーバーは集めた入力情報を、全てのクライアントに対して送ります。

これをシーケンス図にすると、以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36899/e76b1ed2-cde6-166d-27d3-19b8bb8182ad.png)


この方式の最大の利点は、メッシュ型と違い、プレイヤーの数が増えても必要な通信経路が一定の割合でしか増えないという点です。つまり、プレイヤーが増えても通信の複雑さが急激に増すことがないため、ゲームの情報の一貫性が保ちやすくなります。

ただし、この型には4つの問題点があります。

#### **レスポンス性が落ちる**
 
スター型では、全ての通信がサーバーを介して行われるため、データの送受信で遅延する可能性があります。

####  **サーバの役割を担うプレイヤーが途中で離脱した場合、ゲーム全体が回復不能になり、強制中止となる。**

スター型では、サーバー役が全体の通信の中心となっています。そのため、サーバーの役割を担うプレイヤーが途中で離脱した場合、他のプレイヤーがその役割を代替することができず、ゲーム全体が停止してしまうことがあります。

:::note
今回は詳しく説明しませんが、「ホストマイグレーション」という手法でサーバーの役割を別のクライアントに引き継ぐ方法もあります。
:::

#### **整理するロジックが増える分、プログラムの構造がフルメッシュ型よりも少々複雑になる。**

スター型では、サーバーとクライアントの間にデータの中継が必要となります。この中継の処理を追加することで、プログラムの複雑さが増します。一方、フルメッシュ型では各プレイヤーが直接通信するため、中継処理が不要です。

#### **サーバの役割を担うプレイヤーの端末の通信負荷が他よりも大幅に高くなる。**

スター型では、サーバー役を担うプレイヤーの端末が他のプレイヤーよりも多くのデータを処理する必要があります。そのため、サーバー役のプレイヤーのお家につながっている回線に負荷がかかり、データ転送速度が低下したり、サーバーからの応答が悪くなる可能性を持っています。

<br>

## 同期式全般の大きな問題

同期式全般で抱えている問題の一つに **「プレイヤーが途中参加しにくい」** というものが挙げられます。同期式では、ゲームの状態が各プレイヤーの入力に基づいて進行しており、途中参加するプレイヤーにはゲームの現在の状態を正確に伝える必要があります。そのため、途中参加するプレイヤーがいた場合、ゲームを一時停止して、現在のゲーム状態の情報を新規プレイヤーに送信する時間が発生します。

AとBが一緒にプレイしていたところに、Cが後から合流したパターンを考えてみます。
シーケンス図にすると以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36899/aee10465-5123-1088-1310-953f1dea0efd.png)


ゲームデータの初期化処理は通常1フレーム以内で終わることはありません。初期化処理には大量のデータが関わり、メモリ（HDDやSSDなど）からのゲーム自体のデータ取得も含まれます。そのため、実際の処理時間は数秒以上かかることもあります。

新しく参加してきたCは、まずはどのプレイヤーに対してでも良いので、現在のゲームの状態を要求します。

今回の例だとAが、その情報をCに返しています。もしこのデータが大きい場合、通信をするための時間だけでも数秒かかってしまいます。この間、ゲームを進行するわけにはいかないので、プレイヤーCだけではなく全プレイヤーのゲームの進行を一旦止める必要があります。

プレイヤーが途中参加できない問題以外にも、**データの送受信中に、その情報が途中で壊れたり、無くなったりする可能性**もあります。

それぞれの問題に対しての対応策を確認してみましょう。

### プレイヤーが途中参加しにくい問題

この問題は、非同期式の実装方法を選択することで回避できます。新しいプレイヤーが参加した場合、ゲームはそのプレイヤーの参加を待つことなく進行します。新しいプレイヤーのデータが準備されると、そのデータを処理してゲームの状態を更新します。このように、非同期方式では、プレイヤーの参加やデータの受信にかかる時間がゲームの進行に影響することはありません。

では、同期式を採用する場合の対応策は何もないのでしょうか？

実際には、同期式においても、いくつかの工夫を行うことで、途中参加の問題を軽減することが可能です。その代表的な例として、ゲーム状態の「スナップショット」を利用する方法があります。

**スナップショット方式**とは、定期的にゲームの現在の状態を記録し、途中参加したプレイヤーにその情報を送る仕組みです。この方式では、ゲーム内の全オブジェクトの位置や状態、プレイヤーのスコア、進行状況などを定期的に保存しておきます。新しいプレイヤーが参加した際には、最新のスナップショットを送信し、その時点から同期を開始します。これにより、途中参加時のゲーム停止時間を最小限に抑えることができます。

さらに、通信環境が不安定な状況でもプレイ体験を維持するために、「補間（Interpolation）」を用いることがあります。補間とは、スナップショット間の状態を推測して描画し、プレイヤーにスムーズな体験を提供する技術です。たとえば、キャラクターの移動を補間することで、途中参加したプレイヤーが画面上で突然キャラクターを目撃するような違和感を軽減します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36899/90f7e412-b064-f1d8-c7f5-070557a18167.png)

<br>

しかし、このアプローチにも限界があります。スナップショットを頻繁に保存しすぎると、サーバーやネットワークに負荷がかかり、全体のパフォーマンスに影響を及ぼす可能性があります。そのため、ゲームの設計段階で、スナップショットの保存間隔やデータ量を最適化することが求められます。

以上のような工夫を行うことで、同期式においても途中参加の問題をある程度克服することが可能です。ただし、非同期式と比較すると負荷や複雑さが増すため、ゲームの特性に応じて慎重に選択することが重要です。

<br>

### データの送受信中にトラブルが起きた場合

この問題は、オンラインゲームにおいて特に避けられない課題の一つです。通信中にデータが破損したり、パケットが損失することで、ゲームプレイが中断したり、意図しない挙動を引き起こす可能性があります。

では、これを防ぐための手法にはどのようなものがあるのでしょうか？

ここで「バーチャファイター」が行っている対策を見ていきましょう。

「バーチャファイター」では「情報の多重化」という工夫を行なっています。これは1回に送るデータの中に、過去10フレーム分の操作情報を詰め込み、毎フレーム送信するという手法です。こうすれば通信中に、情報のロスが数回発生しても、次に情報が届いた時点で、現在のフレームまで処理を進めるための情報を穴埋めすることができます。


## 同期式全般のメリットと問題解消のための工夫

同期式を用いると、プログラムの内容を単純に保つことができます。

そのメリットがとても大きいため、様々な工夫をして問題を回避しつつ同期式を採用する、という事例も多く見られます。

例えば以下のような工夫が挙げられます。

### 予測と補間

先ほども少し触れた、スナップショットを用いてプレイヤーの操作情報を予測し、通信遅延を補間することで、ゲームの滑らかなプレイを実現する対応です。例えば、プレイヤーの次の動きを予測し、その動きに合わせてキャラクターを移動させることで、遅延を感じさせずに操作を反映させることができます。

### 遅延の最小化

ネットワーク通信やデバイス間での遅延を極力減らすことで、ゲームのレスポンスを向上させます。他にも、プレイヤーマッチングシステムを工夫して、地理的に近くにいるプレイヤーを優先的にマッチングするのも良いでしょう。

### 同期手法の最適化

同期手法自体の改善によって、通信の効率性や正確性を向上させます。例えば、通信で送る情報を極力少なくすることで、通信のデータ量を減らすことができます。また、通信部分を担当するコードロジックの改善を行うことで通信の効率性が上がって、ラグを減らすことも可能です。

### ゲームの設計を変更する

レースゲームや格闘ゲームのように、**一回のゲーム自体（レースや試合）が数分以内で終わるようにして、途中参加の必要性自体をなくす**、というのも一つの手ではあります。

## P2P接続での問題

これまでに、プレイヤーのクライアント同士を直接接続してデータのやり取りを行う、**P2P**(peer-to-peerの略称)接続を前提に同期式の説明を行ってきました。

一般的な接続方法としてはパソコンやゲーム機を、ルーターなどを経由してネットに繋げるモデルが挙げられます。これを　**C/S(クライアント/サーバー)**　と呼びます。

この方式は高性能なサーバを使用して全ての処理を行なっているため、セキュリティ面でも優位に立ちます。ただし、端末に負荷をかけませんが、遅延はP2Pよりも大きくなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36899/06fe5b90-e688-a717-65b5-544324ab3e21.png)


P2P接続は、端末に直接グローバルIPアドレス（ネットに接続するための一意のIPアドレス(後述)）を割り当てて、端末同士を接続します。そのため、遅延がとても小さく、帯域負荷自体も非常に低いものとなっています。

しかし、最近だと、ほとんどのプレイヤーが使用している端末はNAT機能(後述)を持つルータで守られたネットワークに接続されているため、直接通信ができません。この部分に関して、より詳しく見ていきましょう。

#### グローバルIPアドレス？ルーター？

一般的には、「プロパイダー」経由で割り振ってもらう、ネットワークに繋ぐための一意なIPアドレスを **「グローバルIPアドレス」** と呼びます。

<details><summary>「プロパイダー」とは？</summary><div>

プロパイダーは、「インターネットサービスプロバイダー」の略称で、一般的にはインターネット接続サービスを提供する事業者を指します。
例えば有名なところだと、以下のものがあります。

- NTTドコモ
- So-net
- KDDI

:::note
ちなみに私はSo-netを使ってます。
:::

</div></details>

このグローバルIPアドレスは、基本的にはルーターへ割り当てます。

つまり実質、インターネットへ直接通信しているのは、このルーターのみとなります。

スマートフォンやPCなどの端末は、ルーターを経由してネットに繋ぐ形となります。この時ルーターは、どの端末からネット接続の要求をされて、どの端末に結果を返せばいいのかを、　**「プライベートIPアドレス」**　を用いて端末の識別を行ないます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36899/db9dbae0-9642-2b07-5ecf-45854fa56482.png)


<details><summary>「プライベートIPアドレス」とは？</summary><div>

プライベートIPアドレスとは、自分の家や会社の中の小さなネットワーク内だけで使われる特別な番号です。この番号は、家の中や会社の中のデバイス同士がお互い通信するために使います。例えば、あなたの家でWi-Fiに接続しているスマートフォンやパソコンは、それぞれ異なるプライベートIPアドレスを持っています。

一方で、 **グローバルIPアドレス（公共のIPアドレス）** は、インターネット全体で使われるユニークな番号です。家や会社においてあるルーターは、このグローバルIPアドレスを持っており、インターネット上であなたが使用しているネットワークの代表として機能しています。

インターネットに接続するとき、ルーターは **ネットワークアドレス変換（NAT）** という技術を使って、家や会社の中で使われているプライベートIPアドレスを、ルーターのグローバルIPアドレスに変換します。これによって、家の中のデバイスがインターネット上で通信するとき、外の世界からは家全体が一つのIPアドレス（グローバルIPアドレス）を使っているように見えます。

この仕組みにより、複数のデバイスが同時にインターネットを使用できるだけでなく、プライベートIPアドレスが繰り返し使用されることで、IPアドレスの節約にもなります。また、プライベートIPアドレスを使うことで、外部からの直接的なアクセスを防ぎ、セキュリティを向上させる効果もあります。

</div></details>

端末から受け取ったデータリクエストをインターネットへ送信する前に、ルーターは「データリクエスト情報に書かれてあるプライベートIPアドレスを、自身が持つグローバルIPアドレスに変換してから、インターネットへと送信する」という処理を行います。これが **「NAT（Network Address Translation : ネットワークアドレス変換）機能」** と呼ばれるものです。

NAT機能は、グローバルIPアドレスがネット上で足りないという問題に対応するほか、インターネット上にあるウイルスなどの対策へも対応してくれます。

### NAT問題

P2Pではプレイヤーの端末同士が直接通信するためにグローバルIPアドレスが使用されます。しかし、多くのプレイヤーがNAT機能を持つルーターを使ってインターネットに接続しているため、実際の端末のIPアドレスが外部には見えません。

例えば、あるゲームがスター型のネットワーク構造を採用しているとします。Aさんがホスト役をやろうとした時、もしAさんがNATを使っていた場合、Aさんはホストになることができません。

これを回避するためにオンラインゲーム業界では **「NAT越え」「NATトラバーサル」** と呼ばれる技術が必要になってきます。

#### NATトラバーサル

NATを超えて通信路を確立する技術の事を、**NATトラバーサル**と呼びます。

NATには６つの段階に分かれた制限の強さが存在します。

1. **オープンインターネット**：
端末がグローバルIPアドレスを持っており、直接インターネットに接続されています。テスト用の開発環境などに使用されます。
2. **制限なしNAT**：
特定のポートの通信が、ルータからLAN上の特定のパソコンのポートへと固定的に変換されるため、どんな通信相手からのパケットも転送可能です。家庭用や、小規模オフィスのルーターで使用されることが多いです。
3. **アドレス制限つきNAT**（アドレス制限コーン）：
NATの内側にある端末から、以前通信を行ったことのある端末からのパケットのみを受け入れます。これにより、新しいIPアドレスからの通信は受け付けません。中小規模オフィスや、セキュリティと柔軟性のバランスが必要なプロジェクトで使用されます。
4. **ポート制限付きNAT**：
アドレス制限つきNATの特性に加え、ポート番号でも制限をかけ、より厳密な通信制限を実現します。セキュリティ重視の企業ネットワークなどで使用されます。
5. **シンメトリックNAT**：
通信を行うたびに異なるポート番号を利用し、アドレス変換も毎回異なるため、通信の追跡が難しくなります。複数の亜種が存在します。銀行など、セキュリティが最優先されるサービスを持つ環境で使用されます。
6. **UDPブロックド**：
UDPプロトコル（データ受信確認などの返答を必要としない送信形式）を用いた通信が完全に禁止されています。官公庁や金融機関のような秘匿情報を保管する環境で使用されます。

1〜4のNATタイプ（オープンインターネット、制限なしNAT、アドレス制限つきNAT、ポート制限付きNAT）では、NAT越えが可能です。これらのタイプでは、端末間で直接通信を確立することが比較的容易です。

しかし、タイプ5のシンメトリックNATでは、事情が異なります。このタイプは通信ごとに異なるポート番号を使用するため、通信を確立するための技術（例えば「UDP Hole Punching」や「STUN」など）を使っても、必ずしも通信が成功するわけではありません。これらの技術を使っても全ての場合にNATを越えることができるわけではなく、成功率は100%ではないのです。

さらに、タイプ6のUDPブロックドでは、UDPプロトコルを完全にブロックしているため、NATトラバーサル技術を使っても、NAT超えをすることはほとんど不可能です。

これらの制限により、NATトラバーサル技術を使っても、全てのプレイヤーが通信できる状態になるわけではなく、一部のプレイヤーは通信が不可能な場合もあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36899/fe290409-94e8-6401-6370-7c65637f05ad.png)

これを100%のプレイヤーが接続可能な状態に近づける方法として挙げられるのが **「リレーサーバ」** です。

### リレーサーバ方式

では、このリレーサーバとは何者でしょうか？

リレーサーバは、クライアント/サーバ（C/S）方式を基盤として、NAT問題を回避しつつ通信を中継する仕組みです。
（C/Sについては[P2P接続での問題](#P2P接続での問題) で解説しています）

この方式では、すべてのデータ通信が一つのサーバを介して行われるため、NATの問題を効果的に回避し、通信の安定性を向上させることができます。

通常のクライアント/サーバ方式では、セキュリティ対策として送受信するデータの正当性をサーバがチェックし、通信の整合性を保ちます。リレーサーバ方式も同様に、端末間のデータを中継しながら、場合によってはセキュリティ強化やデータ管理を行います。ただし、中継するという特性上、直接通信（P2P方式）に比べると遅延が発生する場合があります。

この仕組みは、特にシンメトリックNATやUDPブロックド環境など、NAT越えが難しいシチュエーションで有効です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36899/f27317b3-6990-4bd5-a732-268726e70dcf.png)


リレーサーバ方式は、スター型と同様に同時プレイ数を増やすことが可能です。

ただし、スター型とは違い、一部の端末のみに通信負荷が集中することもなく、単にデータの交換を行うだけなのでプログラムもシンプルです。フルメッシュ型とスター型両方のメリットを持ち合わせているのがリレーサーバ方式なのです。

では、リレーサーバー以外にも似た形でNATの制約を超えて通信路を確保する技術はあるのでしょうか？

ここで、最近流行りのWebRTCについて見ていきましょう。

### WebRTC

オンラインゲーム開発において、プレイヤー間のリアルタイム通信周りは極めて重要な要素となります。

この要求に応えるための技術として、**WebRTC（Web Real-Time Communication）** が注目されています。WebRTCは、ブラウザ間で音声、映像、データをリアルタイムで交換できるオープンソースのAPIです。追加のプラグインを必要とせず、直接ブラウザ間でP2P通信することを可能にします。

#### WebRTCのゲームへの応用

オンラインゲーム開発において、以下のようなWebRTCの応用が期待されています。

- **ボイスチャット**：
WebRTCを使用すると、開発者は追加のサーバーサイドインフラストラクチャなしで、高品質のボイスチャットを簡単に実装できます。
- **リアルタイムデータ同期**：
WebRTCのデータチャンネルを利用して、プレイヤーのアクションやゲーム内イベントがリアルタイムで同期され、すべてのプレイヤーに対して一貫したゲーム体験を提供することができます。

#### WebRTCの技術的仕組み

WebRTCは、ブラウザ間での直接通信を実現するために、いくつかの技術要素を組み合わせています。その中でも、ICE, STUN, TURNについて注目してみましょう。

- **ICE（Interactive Connectivity Establishment）**：
端末間の通信経路を効率的に確立するための仕組みです。STUNやTURNを活用して、可能な限り直接通信を試みます。直接通信が困難な場合には、TURNを利用して中継サーバーを経由することで通信を確立します。

- **STUN（Session Traversal Utilities for NAT）**：
クライアントが、外部から見た自分のグローバルIPアドレスとポートを取得する技術です。NATの背後にある端末は、通常、自身のIPアドレスやポート番号がどのように変換されているかを知ることができません。STUNを利用すると、NATルーターを介して外部に見えるアドレス情報を取得し、直接通信を試す際に利用します。

- **TURN（Traversal Using Relays around NAT）**：
NAT越えが難しい場合に、TURNサーバーを介してデータを中継します。通信を中継するため、遅延が増加しますが、リレーサーバーのように、ほぼすべての環境で通信を可能にします。

<br>
ということで、TURNやSTUNを活用することでもNAT超えを実現できます。

以下の表は、リレーサーバー、STUN、TURNの主な違いを比較したものです。

|  | **リレーサーバー** | **STUN** | **TURN** |
| --- | --- | --- | --- |
| **通信方式** | クライアント-サーバー（C/S）方式 | 直接通信（P2P） | 中継通信 |
| **データ転送方法** | すべての通信がサーバーを経由 | 直接通信のためのIPとポートを提供 | TURNサーバーを介してデータを中継 |
| **遅延** | 中程度（地理的距離やサーバー負荷に依存） | 非常に低い | 中程度 |
| **セキュリティ** | 高い（サーバーでデータチェック可能） | STUN自体はセキュリティ機能を提供しない（アプリケーション側で補完が必要） | TURN自体はセキュリティ機能を提供しない（暗号化はアプリケーションに依存） |
| **コスト** | 高い（サーバー運用コストが大きい） | 非常に低い | 中程度（中継データ量に応じて増加） |
| **使用環境** | NAT制約の厳しい環境、企業向け、秘匿通信など | NAT制約が緩い環境 | シンメトリックNATやUDPブロックされた環境 |
| **成功率（NAT越え）** | 高い | NATの種類に依存 | 高い（サーバーの正しい設定が前提） |
| **メリット** | 安定性・信頼性が高い、セキュリティを確保可能 | 遅延が少ない、直接通信が可能 | ほぼすべてのNAT環境で通信可能 |
| **デメリット** | 運用コストが高い | 制約の厳しいNATでは利用不可 | 遅延が増加、TURNサーバー運用が必要 |


# まとめ

後編では、同期型通信を支える「フルメッシュ型」と「スター型」、通信を円滑にするための「リレーサーバー」、「STUN」、「TURN」の役割と特徴、用途などを見てきました。それぞれの技術にはメリットとデメリットがあり、どれを採用するかはゲームの特性やターゲットとするプレイヤーの環境によって異なります。

- **同期型通信**は、ゲーム内の正確な状態を維持するために有効ですが、途中参加や遅延の影響を受けやすい点に注意が必要です。
- **リレーサーバー**は、NATの制約が厳しい環境でも確実に通信を成立させる手段ですが、運用コストが高くなる傾向があります。
- **STUN**は直接通信が可能で、遅延が少ないのが魅力ですが、NATの種類によっては通信が成立しない場合もあります。
- **TURN**は、ほぼすべてのNAT環境に対応可能ですが、遅延が発生しやすく、サーバー運用の手間がかかります。

最終的に、オンラインゲーム開発においては、これらの技術的な挑戦にどう対応するかが、プレイヤーに提供する経験の質を左右します。開発者は、これらの情報を理解し、適切な技術選択を行うことで、より良いゲーム環境を構築することが可能です。

技術は常に進化しており、新しい解決策が日々開発されているため、最新のトレンドと更新を追い続けることが重要です（今回に限ったことではないですが…）。

読んで頂き、有難うございました！

# 参考

- 「オンラインゲームを支える技術」（技術書）
- [通信同期の技術について](http://blog.opuwr.ganbarion.co.jp/?eid=6)
- [セガ節政氏、オンラインゲームの実装テクニックをレクチャー「バーチャファイター」から「PSU」まで、ネットワークプログラムの実例を紹介](https://game.watch.impress.co.jp/docs/news/391007.html)
- [ラグの対策【基本編】](https://squid-ink-cafe.com/lag/basic/003.html)
- [オンラインゲームの仕組みと工夫](https://www.slideshare.net/imaifactory/ss-48388661)
- [[CEDEC 2010]ネットゲームの裏で何が起こっているのか。ネットワークエンジニアから見た，ゲームデザインの大原則](https://www.4gamer.net/games/105/G010549/20100905002/)
- [Photon Fusion for Unityの新機能　描画補間、ラグ補償、同期範囲設定](https://qiita.com/nimushiki/items/c82763817a8c7c4f2278)