ネットワーク部分の抽象化2

前回、この同期するための情報を管理する同期クラスですが、これを便利につくってあげると
かなり通信自体が楽になるとおもいます。
ということでしたが、この部分をどう作るべきか。非常に難しいところです。


ここをまじめに丁寧に書くと結構膨大になります。本1冊余裕で書けそうなトピックです。
なので99%飛ばしますw
結論から言うとデザインパターンのProxyパターンを使います。
もう少し煮詰めるとCorbaとかDComとかが近いのかな。要するにリモートオブジェクトとその管理クラスです。
そしてその管理クラスが同期クラスになります。


具体的な流れでいうと、こんな感じです。


まずサーバーにスケルトンクラスを継承したプレーヤーキャラクタークラスのオブジェクトを作成します。
同期クラスはスケルトンクラスへの集約となっていて、同期クラスのオブジェクトは各クライアントごとにサーバー側に存在します。
これをサーバー同期クラスとしましょう。


これと同様にクライアント側にも管理クラスとして、クライアント同期クラスがあります。
あるプレーヤーキャラクタークラスのオブジェクトを、サーバー同期クラスのオブジェクトに追加すると
その情報がクライアント同期クラスに伝わり、クライアント同期クラスは
クライアント側にキャラクタークラスのオブジェクトのコピーを自動的に作成します。


このコピーオブジェクトは、スケルトンクラスではなく
スタブクラスというクライアント側のスケルトンクラスに対応するクラスを継承しているクラスのオブジェクトになります。


まさにCorbaとかのリモートオブジェクトのような仕組みですが
この仕組み全体について、フルスクラッチで自分でコーディングするため
用途は限定されますが、非常に軽量なリモートオブジェクトが作れるというメリットがあります。


そして最終的にはキャラクタークラスの各種Set関数の中に
同期を取るための通信処理を入れ込んでしまいます。


つまり

player_character.set_hitpoint(100);
client_socket.send(SET_HITPOINT);
client_socket.send(100);

ではなく

player_character.set_hitpoint(100);

void Player_character::set_hitpoint(unsigned long value)
{
//PLAYER_CHARACTER_SET_HITPOINTはこの関数を表現するID
client_socket.send(PLAYER_CHARACTER_SET_HITPOINT);
client_socket.send(100);
...


とすることでPlayer_characterの外からは通信を意識させないようにできます。
これは、このような簡単の例の場合には、余りありがたみが分かりませんが
実装が進んでいき、構造が複雑になればなるほど効果がでてくるものです。


このような仕組みを作ったとき、あるキャラクターの視界にあるキャラクターが入ったとしたら
お互いのサーバー同期クラスにお互いのキャラクターを追加登録(push_back)するだけで
あとは自動でデータをやり取りしてくれるようになります。
もちろん中では必死にデータの通信をしているのですが
このクラスを利用する側では通信を意識しないで作りこむ事が可能です。


ただし、この方式には適さないデータがある場合もあります。
この方式では、何かしらアクションがあった場合(例えばキャラクターのHitpointが変更された場合など)
サーバークライアント間のラグを問わず、そのままクライアントに流し込むだけになります。
これはHitpointであればあまり問題は起こりません。


ただし位置情報になると話が変わります。
サーバーが保持している位置情報も、各クライアントが保持している位置情報も
ネットワークにはラグがありますから、同時刻で別の位置情報です。
単にクライアントに流し込まれた位置情報で描画し
そのクライアントでその位置情報にめがけて攻撃しても
サーバーで判定される頃にはその位置には誰もいないといった矛盾が起こります。


もちろんこれはゲーム次第です。
カードゲームであればまったく問題になりませんし
ターン制の戦闘を採用しているゲームでも問題ありません。
ターゲット固定できるようなゲームでも問題はあまり?おきません。
(後ろから攻撃したら倍のダメージになるという仕様があれば問題がおきますが・・・)


この辺はゲーム次第、データ次第でこのリモートオブジェクトの仕組みを使うかどうかを検討してください。
また、また改めて断っておきますが、ここまで説明してきて
この問題についての正解は残念ながらないと思います。
この方式が幅広く比較的ベターという(風に私が思っている)だけです。


で、肝心の位置情報はどうやってやり取りすればいいのってのは
また次回にでも。
相変わらず分かりにくい文章ですがw