NetworkViewは、位置情報を指定しただけだとポリゴンの位置がワープしたような動きを見せる。
これは問題なので、もう少しスムーズに見せる方法を模索してみた。


■なにが問題なのか

この問題は、NetworkViewが一定間隔ごとにしか同期してくれない所にある。
この送信間隔は、1秒間に15回くらいらしい。(Unreliableの場合)

またState Synchronizationが圧縮(Reliable Delta Compressed)の場合も同様の問題に加え、
圧縮時間とかもあるんじゃないかなと。
つまりObservedの同期では、ぬるぬるとした同期には限界があるということ。

詳しくは公式HPの文書を見たほうが正確だと思う。


■対策

この問題の対策は、大雑把に3つ。
1.位置を中間補正する
2.モデルの位置を予測する
3.通信帯域なんて関係ない。全力で通信する

MMORPGやシミュレーションゲームは1が良いと思う。
アクションゲームやFPSを作りたければ1と2のハイブリットが良い感じになると思う。
3はネタだったのだが、思ったよりも高品質に動いてしまった。


■対策:位置を中間補正について

簡単に言えば、過去の位置情報から更新した位置情報までの座標を、
スムーズに補完してやる考え方。
そうすれば、位置が多少飛んでもここまで問題にはならない。

簡単な方法では、
モデルの位置と同期する位置を分けておき、モデルが同期する位置を追うといった方法がある。
Vector3.Lerpで位置情報を調整してやれば、簡単に実装できる。

他にも、スクリプト同期で座標を取得し補完する方法もある。
ソースコード


■対策:モデルの位置予測について

これはモデルの位置情報をクライアント側である程度予測しておくことで、
位置更新時の差違を最小に抑える考え方。

この方法は動作の反映が早いので、アクションゲーム等に向いてると思う。
ただし、予測が外れた時に位置ずれを起こすので、
予測位置と同期した位置の中間補正してやる必要がある。

一番かんたんな実装方法は、rigidbodyをNetworkViewで同期させておき、
モデルの移動はrigidbodyに任せること。
こうすれば、モデルの位置情報をrigidbodyが予測してくれる。

rigidbodyが使えない場合は、キー入力を送信してやれば予測が立てやすい。
この場合は移動距離を通信時間で見積もってやると、それなりにうまくいきそう。

通信時間はNetwork.GetAveragePing(networkView.owner)で出せるらしい。
ただ自分の環境では値が0か1にしかならない。

Network.timeの値をソースコード同期で送ってもらい、
自分のNetwork.timeと比較する方法のほうが正しいのかもしれない。


■対策:全力で通信する

そもそもモデルが飛ぶのは通信間隔の設定があるのが問題なので、
そいつを無くしてしまえばいい。
これはローカル環境ならそれなりに上手くいくが、
ネットワーク越しの場合は保証できない。

送信回数の設定はNetwork.sendRate で行なっている。
なので、Network.sendRateの影響を受けないRPCで位置情報をUpdate毎に送信するか、
Network.sendRateの回数を像が飛ばない程に上げてやればいい。

サーバーのOnConnectedToServerやOnServerInitialized時に
Network.sendRate = 60.0f とか。(初期値は15.0f)



いやあ、ネットワークは奥が深い。

フォローボタン
フォローボタン