私は今最大参加人数8人の対戦ゲームを共同制作中で、データ同期の方法について悩んでいます。
現状では各パラメータ(8変数で文字列にすると130文字くらい)を文字列にして"_"で区分けして毎フレーム送信しています。現在は"_"で区切られた文字列を分けてそれらを数値に変換して処理しています。
パラメータの内容は
プレイヤーID
位置
向き
マウスが指している座標
アイテム数
体力
攻撃できる回数
残り対戦時間
です。
これでは位置の同期がうまくいっていないためか、他方ではアイテムが取得できて、もう一方側で取得できていない状況が生まれてしまいます。
そのため解決策の一つとして通信の処理の高速化をしようとしており、文字列の処理を、シリアル化してバイナリ形式で全て行おうとしています。また、この方法でなんとかやろうとしているのですが、バイナリを一度文字列に変換したものを送受信する方法でしかまだできません。
文字列で処理する場合とシリアル化する方法では処理速度に大きな差は出るのでしょうか。
ゲームのネットワークでの同期について
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ゲームのネットワークでの同期について
8人同時のオンラインゲームを作成したことはありませんが、毎フレーム完全に同期をとることはタイミング的に不可能だと思います。
ほぼ間違いなく、どれかのPCが1フレーム遅延します。遅延したり、遅延しなかったり不定期に成るのは致し方ありません。
マージンを考慮して2や3フレームぐらい遅延しても問題が起きない同期システムを考案すべきかなと思います。それらもあって、同期は2や3フレーム毎ぐらいにすべきです。
8人同時と言う大変面倒なのは経験がないので勘で言っていますが、同期を取るのはプロでも苦労する代物です。
それと同期の整合性を考えて一台のPCを親にして、親に整合性を合わせたほうが簡単かもしれません。
あとLAN限定なら良いですが、インターネット経由ならもっと遅延を考えたほうが良いと思います。
バイナリの通信の件ですが、同じアーキテクチャのPC間でならバイナリのまま通信は容易です。文字列化は必要ありません。
ほぼ間違いなく、どれかのPCが1フレーム遅延します。遅延したり、遅延しなかったり不定期に成るのは致し方ありません。
マージンを考慮して2や3フレームぐらい遅延しても問題が起きない同期システムを考案すべきかなと思います。それらもあって、同期は2や3フレーム毎ぐらいにすべきです。
8人同時と言う大変面倒なのは経験がないので勘で言っていますが、同期を取るのはプロでも苦労する代物です。
それと同期の整合性を考えて一台のPCを親にして、親に整合性を合わせたほうが簡単かもしれません。
あとLAN限定なら良いですが、インターネット経由ならもっと遅延を考えたほうが良いと思います。
バイナリの通信の件ですが、同じアーキテクチャのPC間でならバイナリのまま通信は容易です。文字列化は必要ありません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ゲームのネットワークでの同期について
返信ありがとうこざいます。
バイナリのまま通信するのは容易であるとおっしゃいましたが調べていてもなかなか見つかりません。
現在clxというライブラリを使っており、char* またはstring型を送受信しているようです。
以前知人に相談したところクラスオブジェクトをそのまま送信したい場合はそのポインタをchar*にキャストして送信すれば良いと言っていたのですが、ポインタはアドレスなだけであってそれ以外の情報を持たない気がします。この方法でバイナリのまま通信できるのでしょうか。
でないとすれば、どうすれば良いでしょうか。見当がつきません。
バイナリのまま通信するのは容易であるとおっしゃいましたが調べていてもなかなか見つかりません。
現在clxというライブラリを使っており、char* またはstring型を送受信しているようです。
以前知人に相談したところクラスオブジェクトをそのまま送信したい場合はそのポインタをchar*にキャストして送信すれば良いと言っていたのですが、ポインタはアドレスなだけであってそれ以外の情報を持たない気がします。この方法でバイナリのまま通信できるのでしょうか。
でないとすれば、どうすれば良いでしょうか。見当がつきません。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ゲームのネットワークでの同期について
clxは使ったことがないので制限は分かりませんが、clxがラップしているであろうWinsock2ではバイナリデータは送受信できます。
そこは、調べてみてくださいとしか言えないですね。
設計次第では、文字列のままでも支障なく通信出来るかも知れませんので後回しにしてもよいでしょう。
バイナリにした所で解決する問題とも思えません。
ちなみにポインタ問題は、セーブファイルやバイナリデータファイルでも同様の問題がありますよね。
普通にセーブファイルやバイナリデータファイルで解決できている事なので通信でも解決できることだと思います。
【補足】ファイル上ではポインタは無くなって別の形で情報保持されます。
そこは、調べてみてくださいとしか言えないですね。
設計次第では、文字列のままでも支障なく通信出来るかも知れませんので後回しにしてもよいでしょう。
バイナリにした所で解決する問題とも思えません。
ちなみにポインタ問題は、セーブファイルやバイナリデータファイルでも同様の問題がありますよね。
普通にセーブファイルやバイナリデータファイルで解決できている事なので通信でも解決できることだと思います。
【補足】ファイル上ではポインタは無くなって別の形で情報保持されます。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ゲームのネットワークでの同期について
お陰様で何をすべきかざっくりとですが分かりました。
あとは自分で調べてみようと思います。
ご返事ありがとうございました。
あとは自分で調べてみようと思います。
ご返事ありがとうございました。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ゲームのネットワークでの同期について
あれ、そういえば。
structにまとめられそうですよ。
これらは文字列データじゃないですよね?プレイヤーID
位置
向き
マウスが指している座標
アイテム数
体力
攻撃できる回数
残り対戦時間
structにまとめられそうですよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ゲームのネットワークでの同期について
現在は文字列データにして送っています。
今後はstruct(or class)にまとめて送るつもりですが、現在送る方法はまだ分かっておりません。
構造体のオブジェクトポインタをchar*にキャストして送ることでパラメータを同期できますか?
教えていただけると幸いです。
今後はstruct(or class)にまとめて送るつもりですが、現在送る方法はまだ分かっておりません。
構造体のオブジェクトポインタをchar*にキャストして送ることでパラメータを同期できますか?
教えていただけると幸いです。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ゲームのネットワークでの同期について
clxの実装を調べてないので何ともいえませんが、送信データ長が引数にあるなら出来る可能性は高いです。
それとstructにまとめでバイナリ送信する場合は、メンバとしてポインタやクラスを含んではいけません。
それとstructにまとめでバイナリ送信する場合は、メンバとしてポインタやクラスを含んではいけません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ゲームのネットワークでの同期について
char*またはstd::stringを送信しているとのことですが、char*で送信する際にその文字列長等を設定しておりますか?
していない場合、多分null characterを終端として認識して送信を行っていると思われますので、構造体をキャストしたところでその内容に0x00が含まれた時点で送信が止まってしまいそうですね。
と、少し調べましたがなるほどC++のstream風な送信を行う機構があるのですね。これをそのまま使用しているのだとしたら、バイナリデータをそのまま送信というのは厳しそうです。
一旦、現在送信を行っている部分等の短いコードを貼ってみてはいかがでしょうか?
追記
iostreamにもそうですが、clx::tcp::sockstream等にもwrite()メンバというのが存在するのですね(読む方はread()メンバ)。構造体を書き込み送信するというのであれば、こちらを利用しつつそのサイズも含んでみればよろしいのではないでしょうか?
していない場合、多分null characterを終端として認識して送信を行っていると思われますので、構造体をキャストしたところでその内容に0x00が含まれた時点で送信が止まってしまいそうですね。
と、少し調べましたがなるほどC++のstream風な送信を行う機構があるのですね。これをそのまま使用しているのだとしたら、バイナリデータをそのまま送信というのは厳しそうです。
一旦、現在送信を行っている部分等の短いコードを貼ってみてはいかがでしょうか?
追記
iostreamにもそうですが、clx::tcp::sockstream等にもwrite()メンバというのが存在するのですね(読む方はread()メンバ)。構造体を書き込み送信するというのであれば、こちらを利用しつつそのサイズも含んでみればよろしいのではないでしょうか?
#include "clx/tcp.h"
struct foo {
float x, y; // 適当なデータメンバ.
int score;
};
int main()
{
foo f;
// fに色々値を入れる処理とか.
// 実際の使用時は正しいIP等を.
clx::tcp::sockstream sock("127.0.0.1", 80);
// バイナリデータ送信.
sock.write( reinterpret_cast<char const*>(&f), sizeof(f) );
// 受信.
sock.read( reinterpret_cast<char*>(&f), sizeof(f) );
}