ネットワーク その10 オブジェクト所有権

クライアント/サーバーピア・ツー・ピア型のどちらのネットワーク形態が優れているのかを議論するのが好きな人たちがいます。しかし、個人的にこの議論は間違ったものだと思います。誰が 「どちらか一方のネットワーク形態を選ばなくてはいけない」 と言ったんですが?私は両方の長所を活かしたハイブリット形式の大ファンです。

ネットワークプログラミングは妥協との戦いです。100%の正確さと、ラグがまったく無いという2つの状態を両立することは不可能で、トレードオフをしなければいけません。

時にはラグが多少大きくっなっても正確さをとる場合もあれば、逆に正確さを犠牲にして高いレスポンスを必要とする場合もあります。

100万ドルの問題:  どのマシンがどのデータを管理するか?

ゲーム内のそれぞれのデータについてのコスト/実益の分析を以下の質問に答えることでできます。

  1. そのデータは独立したものですか、もしくはそれ以外のデータと状態を一致させる必要がありますか?
  2. 全プレイヤーがそのデータのラグに対して同等に気にする必要がありますか、それともひとりのプレイヤーが他のプレイヤーよりも気にしなければいけませんか?
  3. そのデータのラグはどれだけ重要なものですか?ゲームデザインを変更することによって、その重要度を低くはできませんか?
  4. データ変化を予測することはできますか?間違った予測をした場合、問題になりますか、それともエラーをスムースに訂正することができますか?

この質問の答えによって、どのようにデータを管理すればいいのかが判ります。

  1. 沢山のデータの整合性が必要な場合、それらは1台のマシンによって管理されるべき
  2. もしひとりのプレイヤーがデータのラグに対して他のプレイヤーより気にしなくてはいけない場合、そのデータはそのプレイヤーのローカルマシンによって管理されるべき
  3. ラグが大きな問題となる場合は、予測アルゴリズムを適用するべき
  4. 予測ミスが大きな問題となる場合は、予測アルゴリズムは適用すべきではない

1と2の質問はどのマシンがデータを管理するかの指標になり、3と4の予測アルゴリズムの適用についての質問は別々のものだということに注意

 

例えば:

スペースシップの移動

  • スペースシップを操作しているプレイヤーにとってレイテンシは重要な問題。
  • それぞれのマシンでスペースシップの位置が多少ずれていても、大体の位置があっているのなら問題はない。最悪ケースとしては2つのスペースシップがぶつかったときに、それぞれのマシンでは多少違った方向に跳ね返るが、ゲーム的には問題はない。
  • 多少の予測ミスは問題にならない。間違った位置から正しい位置へと、誰にも気づかれること無く補正することができる。

結論:それぞれのスペースシップはそれぞれのローカルマシンによって管理されるべき。予測アルゴリズムを適用する。

 

レースの勝敗

  • レイテンシは特に重要ではない。あなたがゴールラインを通過してから0.5秒後に結果が表示されても大丈夫(カッコイイアニメーションやカメラワークで、このレイテンシを隠すことができる)。
  • それぞれのマシンでレース結果が違うのはダメ。勝者は常にひとり。
  • 間違った予測結果は大問題。「優勝おめでとう!!」と表示されて少し経ってから「やっぱり2位でした~」と表示されるのはひどすぎる。

結論:1台のマシンがレース結果を決めるべき。予測アルゴリズムは適用しない

 

死亡判定

  • 殺されたプレイヤーにとってレイテンシは重要だが、他のプレイヤーにとっては特に重要ではない。
  • マシン毎に違った結果になるのは問題。もし私が死んでいるのなら、他のマシンでも死んでいなくてはならない。
  • 予測ミスは許されない。「ぐはぁ、やられたー」と叫びながら派手なアニメーションが再生され、血飛沫を撒き散らしながら地面を転がった挙句に「ぐふぅ」と事切れた数秒後に何事もなかったのように生き返るのは問題。

結論:それぞれのマシンがローカルプレイヤーの死亡判定をするべき。他のマシンは死亡判定の予測をしてはいけない。

追記:ここでは視覚的な予測を適用することができる。例えば、私のマシンがヘッドショットだと判定するが、ヘッドショットされたプレイヤーの位置が100%確実ではないので死亡アニメーションを再生することはできない。その代わりに「ダメージを受けた」というアニメーションを再生することができ、視覚的なフィードバックを即座に得ることができる。もし、ヘッドショットを決めたプレイヤーから死亡か確定したという連絡が届いた場合は死亡アニメーションへスムースに変化させることができる。仮にこの予測が外れた場合でもダメージアニメーションをキャンセルして通常のアニメーションに戻すことができる。

 

ビークル(乗り物)に乗る

私は一度、キャラクターが徒歩で歩き回り、いろんなビークルに乗り降りすることができるゲームのプロトタイプ製作をしたことがありました。ビークルに乗っている間は「スペースシップの移動」の例で説明したのとまったく一緒です。ただビークルに乗ると言うのは違います。一度に複数のプレイヤーが運転することはできませんから!

この問題を解決するために、まずどのマシンがどのオブジェクトに対して所有権を持っているのかを表すデータをつくりました。これで動的にビークルの所有権の変更ができます。次にどのマシンが所有権を持っているのかを決めなければいけません。

ビークルのステート(操作、物理シム、衝突判定等)は、そのビークルを運転しているプレイヤーがいるマシンによって管理されます。それ以外に、この所有権を誰が持つべきを決める管理マシンを決めました。もしビークルに誰も乗っていない場合は、管理しているビークルの数が最も少ないマシンに所有権があります。

ビークルのとなりに立ち「乗る」ボタンを押した時に以下の処理をします。

  • クライアントマシンは「乗せてください」というメッセージをビークル所有権管理マシンに送ります
  • クライアントマシンではキャラクターがビークルに乗り込むアニメーションが再生されますが、まだ所有権がないので運転することはできません。
  • 通常
    • ビークル所有権管理マシンは要求があったクライアントマシンに所有権を渡します
    • ビークル所有権管理マシンからの「乗って良いよ」というメッセージはキャラクターんがビークルに乗り込むアニメーションが終わるまでに届き、ビークルを問題なく運転することができます。この乗り込むアニメーションはラグを隠蔽するわけです。
  • 二人同時に乗り込もうとしたとき
    • ビークル所有権管理マシンは「すまん、君は乗れん」というメッセージを一方に送ります
    • 乗り込み要求を断られたキャラクターは乗り込みアニメーションをキャンセルしてビークルに乗り込む前の位置にもどされます。
    • 先に乗り込み要求を申請したキャラクターはビークルを運転することができます。

 

ビークルを運転しているときはピア・ツー・ピア形式ですが、大事な決定をするのはクライアント/サーバー形式になっています。

アイディアとしては大事な決定を下す単一の管理マシンが全てのデータを管理する必要がないということです。マシンAはビークルの乗り降りを管理して、マシンBはパワーアップアイテムの管理、そしてマシンCはセッション終了時に誰が勝敗を決定するといった感じに管理するものを割り振ることができます。

 

 

これで私がネットワークに関して言わなければならないことの全てです。

THE END

 

原文:
http://blogs.msdn.com/shawnhar/archive/2008/01/03/network-object-ownership.aspx