ネットワーク部分の抽象化
MMOを作る場合に、まず初めに考えるのはサーバークライアント間の通信です。そのためにsocketクラスを誰もが作成すると思います。
フルスクラッチでも他のライブラリの薄いラッパーでもかまわないと思いますが仮にそのsocketクラスができたとしましょう。
で、次にどうすべきか・・。通信はできるようになったんだけど、どうしていいか分からない。
たくさんのキャラクターがいて、送るべき情報がいろいろあって、考え出すとなかなかカオスです。
特にサーバー側の構成をどうするのか。ここをどうするかはMMOの開発での第一の関門かもしれません。
前回のときもここの部分は悩みましたので、この辺のわたしなりの考え方を書いてみたいと思います。
ネットワークのゲームを作成する場合にその設計をややこしくしているのは
『同期のための通信はアプリケーション(ソケット)同士がする』
という考え方です。
考え方というよりは、あまり深く考えずに開発していくと考えてなくてもそうなっていきます。
ですので、これについて考えない場合もここに含まれるかもしれません。
もちろん現実は最終的にサーバーアプリケーションとクライアントアプリケーション同士の通信になるのですが
あるキャラクターの情報の同期をとるということと、アプリケーションの通信という二つの間には大きな乖離があります。
これまたどうしたらいいか分からない主要な部分になってしまっています。
通常アプリケーションごとにソケットは存在しますから、アプリケーションのところはソケットとも置き換えられます。
通信は普通ソケット同士でしますし、当たり前なのに、どうしてソケット同士の通信という考え方がいけないのでしょうか。
それは同期するための情報と通信の窓口であるソケットいうのは別次元の違うものだからです。
ちょっと分かりにくいですね。もうすこし分かりやすくいきましょう。
たとえばサーバー側での話なのですが、あるキャラクターがキャラクタークラスのオブジェクトcharacter1として存在したとします。
そしてサーバー側のソケットクラスserver_socket1とクライアントのソケットクラスclient_socket1があります。
このcharacter1が[右にちょっとだけ動きました]というパケットをserver_socket1が受信したとします。
というわけで、サーバーではcharacter1の情報を更新するわけです。
まぁcharacter1.move(character1.x()+1,character.y())のイメージですね。
サーバーではこのclient_socket1の情報が更新されたことをクライアント側に送らなければなりません。
送らないと他のプレイヤーさんにはこのキャラクターが止まったままですからね。
送るパケットの内容は[character1のオブジェクトのid,xが更新されました,新しいxは30です]といった簡単な情報でしょう。
さて、このパケットはいつ誰に対して送ったらいいのでしょうか?
まさにこれが同期をするための情報です。いつ誰に対して送るべきか。
MMOの場合、キャラクターが動いていたら、そのキャラクターが同期すべき情報っていうのは
・そのキャラクターをプレイしているクライアントの画面に描画されている別のクライアントのキャラクター
になるわけです。
もっと簡単に、チャットソフトを作っていて、チャットルームという機能をつけましょうとなったときに
同期すべき情報ってのは
・そのチャットしている人が入ったチャットルームにいる別のチャットしてる人
になるわけですね。
一応ここで役者が3つそろいました。キャラクターと同期をするための情報とソケットです。
ということはCharacterクラスと同期クラスとSocketクラスの3つが必要になりそうです。
同期クラスは上の例のような同期するための情報、たとえば
どのcharacterオブジェクトがどのsocketオブジェクトに結びついているかを管理します。
初めの役者はキャラクターとソケットだけでした。
小規模なネットワークソフトであれば問題ないですが、何も考えないで作り始めると
同期するための情報が最終的にはソケットクラスに実装されがちです。
キャラクターとソケットしかいないため当然そうなっていきます。
つまりソケットクラスの関数のなかで、このキャラクターの近くにいるキャラクターを検索してみたり・・
同期するための情報は通信の窓口であるソケットとは次元の違う情報なのに、そうなっていきます。
カオスが生まれる原因はここにあるわけです。
ここまでくると『同期のための通信はソケット同士がする』ことがなぜいけないか分かると思います。
同期するための情報は同期クラスという別の新しい概念を導入して
情報自体、同期クラス、通信の窓口
とすべきなのです。
この同期するための情報を管理する同期クラスですが、これを便利につくってあげると
かなり通信自体が楽になるとおもいます。
このクラスをどう作るべきかってのもまた難しい話なのですが、今日はここまでにしときましょう。