DXライブラリで通信対戦

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ASTRON
記事: 10
登録日時: 12年前

DXライブラリで通信対戦

#1

投稿記事 by ASTRON » 12年前

はじめまして。ASTRONといいます。
初質問です。

今現在、DXライブラリをフル活用して通信対戦のできる2Dアクションゲームを製作しています。
プレイヤーの動き等はクライアント側で処理し、座標の同期と当たり判定処理のみサーバーで行うつもりです。
OSはwindowsXP、使用しているコンパイラはVisual C++2010です。
また、通信する方法としてはDXライブラリの通信関係の関数(http://homepage2.nifty.com/natupaji/DxL ... html#R13N1 より下18個)を利用するつもりです。
で、今回質問したいのは、通信対戦において情報を”どのように”通信すれば良いのか、ということです。

少しわかりにくいかもしれませんが、具体的に言いますと、
例えば通信しなければならない内容が、自分の座標x、座標yの2つあるとします。
それを送信するまではいいのですが、このDXライブラリの中の、「バッファから『送信されてきたデータ』を読み込む関数(TCP,UDPに限らず)」は、あくまでバッファから指定した容量を読み込む機能しかありません。x、yの2つのデータを別に読み込むのは難しいのではないでしょうか。
TCP/IPならば、送信される順番や確実性が保証されるのでまだわかりますが、UDPなんかでは送信中にデータの順番が変わったり、ロストする危険性もあるので、この方法では途中から読み込むべきデータを間違えることが大いに有り得ると思います。
複数の別のデータをやり取りしなければならないとき、この場合はどうすれば良いですか?
それとも、この問題に関してはDXライブラリをやめてWinSock等に挑戦した方が良いでしょうか?
よろしくお願いしますm(_ _)m

YuO
記事: 947
登録日時: 14年前
住所: 東京都世田谷区

Re: DXライブラリで通信対戦

#2

投稿記事 by YuO » 12年前

ASTRON さんが書きました:TCP/IPならば、送信される順番や確実性が保証されるのでまだわかりますが、UDPなんかでは送信中にデータの順番が変わったり、ロストする危険性もあるので、この方法では途中から読み込むべきデータを間違えることが大いに有り得ると思います。
ロストしても問題ないように作ります。
パケットに連番を振って,必要なデータを1パケットにしておけば,抜けても問題なくなります。
# 前回受信したパケットより小さい番号を持つパケットは単純に無視すれば良い

さらに,ネットワークには物理的・論理的な遅延がつきまといます。
電磁波の速度は真空中で高々30万km/s (=5000km/フレーム) しかなく,データの速度はそれより遅く (光ファイバーで20万km/s程度),さらにルーターによって遅延が重なります。
TCPの信頼性はさらに遅延をもたらします。
# 近場でやるなら電磁波の速度による遅延などたかがしれていますが。

基本的には,パケットロスト前提,遅延前提でプログラムを組むことになります。

過去の回答で書いたリンクを再掲しておきます。

ASTRON
記事: 10
登録日時: 12年前

Re: DXライブラリで通信対戦

#3

投稿記事 by ASTRON » 12年前

返答ありがとうございます。リンク先のサイト見ました。送信しなくていいデータなどの項目はとくに役に立ちそうです。
また、通信は数メートルと離れていないLAN内で行うのでそこまでレイテンシが酷いことはないはずです。

ですがまだイマイチわかりません。
YuOさんの言う >必要なデータを1パケットにしておく 方法がわからないのですが、どうしたらいいでしょうか?
リンク先のパケットの圧縮はC#だったためよくわかりませんでした(スミマセン…)。
また、結局のところDXライブラリの関数だけでできると言う事でしょうか?
ご迷惑おかけしますがお願いします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: DXライブラリで通信対戦

#4

投稿記事 by softya(ソフト屋) » 12年前

送信データはバイナリデータで構いません。
つまり、バイナリファイルで2つのプログラム間でデータを受け渡しするのと同じです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: DXライブラリで通信対戦

#5

投稿記事 by h2so5 » 12年前

ASTRON さんが書きました:返答ありがとうございます。リンク先のサイト見ました。送信しなくていいデータなどの項目はとくに役に立ちそうです。
また、通信は数メートルと離れていないLAN内で行うのでそこまでレイテンシが酷いことはないはずです。

ですがまだイマイチわかりません。
YuOさんの言う >必要なデータを1パケットにしておく 方法がわからないのですが、どうしたらいいでしょうか?
リンク先のパケットの圧縮はC#だったためよくわかりませんでした(スミマセン…)。
また、結局のところDXライブラリの関数だけでできると言う事でしょうか?
ご迷惑おかけしますがお願いします。
DXライブラリのリファレンスにも書いてありますが、一度に送信するデータ長(=パケットサイズ)を500byte程度に収まるようにします。
データサイズがそれほど大きくないのであれば圧縮する必要はありません。

http://homepage2.nifty.com/natupaji/DxL ... tml#R13N16
 MakeUDPSocket関数 の解説にもありますが、 一度に送信できるデータのサイズは最大で 65507byte ですが、 一度に送信するデータのサイズが大きくなればなるほど相手に届く確率が下がりますので、 なるべくなら500byte以内にしてください。( 尚、LANなど信頼性の高い通信環境の場合はもっと大きくても大丈夫だと思います )

ASTRON
記事: 10
登録日時: 12年前

Re: DXライブラリで通信対戦

#6

投稿記事 by ASTRON » 12年前

皆さん返答ありがとうございます。
softyaさんの言うバイナリデータにするというのは、例えば最初に言った座標x、yの二つを送るとき、ここではx=100、y=300とすると、100300というふうに送って3バイトずつ2回に分けて読み込むということでいいのですか?
それともバイナリということは2進数に直して送るということですかね?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: DXライブラリで通信対戦

#7

投稿記事 by softya(ソフト屋) » 12年前

もしかしてバイナリファイルを扱ったことがないでしょうか?
バイナリデータとは、2進数のデータを取り扱うことです。
安直なバイナリデータの扱い方だと構造体とか変数のメモリ・イメージをそのままファイルに書き出して使います。

「Programming Place Plus C言語編 第42章 バイナリファイルの読み書き」
http://www.geocities.jp/ky_webid/Progra ... c/042.html

通信でやる前に、かならずファイルで理解することをオススメします。
そうしないと通信版を作るときにデバッグできませんので。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ASTRON
記事: 10
登録日時: 12年前

Re: DXライブラリで通信対戦

#8

投稿記事 by ASTRON » 12年前

バイナリファイルを扱ったことは無いですが、読み書きについては武器のデータ読み込みなどに使用するつもりで一度記事を読んだことがあります。
えーと、この場合はデータ全部をバイナリに変換して1行で送信し、向こうで読み込んで順番に変換していくといった感じでしょうか?
それとも…まさかバイナリファイルを送信するとか…

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: DXライブラリで通信対戦

#9

投稿記事 by softya(ソフト屋) » 12年前

バイナリに変換する必要はありません。構造体に集める必要はあるかもしれませんけどね。
バイナリデータはメモリ・イメージなのでメモリイメージをそのまま書きだすのです。
つまり、メモリ・イメージをちゃんと理解していないと扱えないってことですね。

なので、扱いが容易なファイルでまず勉強してくださいと言うことです。
バイナリファイルの中身はバイナリエディタで確認することが出来ますので確認が容易です。
通信だとWireSharkなどで通信内容をキャプチャして確認する必要が出てきます。 ※ デバッグのためには必要な行為なので、ぜひ覚える必要はあるんですけどね。
ちなみにバイナリファイルをわざわざ作って通信する必要はありません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ASTRON
記事: 10
登録日時: 12年前

Re: DXライブラリで通信対戦

#10

投稿記事 by ASTRON » 12年前

バイナリファイルの読み書きをいろいろと試して一応どんなものかはわかりました。
ですが結局のところこの手法をどうやって通信に使えばいいのかわかりません。
本当無知ですみません・・・。

で、今手元に2台のPCが無いので予想だけでいろいろと考えてみました。
以下、DXライブラリのソースコード受け売りに近いものですが、通信部分のみでUDPで考えています。

送信側

コード:

#include "DxLib.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
			 LPSTR lpCmdLine, int nCmdShow )
{
	IPDATA Ip ;	
	int NetUDPHandle ;
	/*自機座標データ(あくまで例です)*/
	int x=100,y=300;

	if( DxLib_Init() == -1 )	// DXライブラリ初期化処理
	{
		 return -1;	// エラーが起きたら直ちに終了
	}

	NetUDPHandle = MakeUDPSocket( -1 ) ;

	/*IPアドレスは具体的に入力していません*/
	Ip.d1 = *** ;
	Ip.d2 = *** ;
	Ip.d3 = *** ;
	Ip.d4 = *** ;


	/*送信部分(わからない場所[1])*/
	NetWorkSendUDP( NetUDPHandle, Ip, 9850, x, 4 ) ;
	NetWorkSendUDP( NetUDPHandle, Ip, 9850, y, 4 ) ;


	DrawString( 0, 0, "文字列を送信しました、何かキーを押すと終了します", GetColor( 255,255,255 ) ) ;

	WaitKey() ;

	DeleteUDPSocket( NetUDPHandle ) ; 

	DxLib_End() ;	// DXライブラリ使用の終了処理

	return 0 ;
}
受信側

コード:

#include "DxLib.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
			 LPSTR lpCmdLine, int nCmdShow )
{
	/*受信用変数*/
	int x,y;
	/*自機のグラフィック*/
	int Handle = LoadGraph( "player.png" , TRUE );

	int NetUDPHandle ;

	if( DxLib_Init() == -1 )	// DXライブラリ初期化処理
	{
		 return -1;	// エラーが起きたら直ちに終了
	}

	NetUDPHandle = MakeUDPSocket( 9850 ) ;

	DrawString( 0, 0, "受信待ち", GetColor( 255,255,255 ) ) ;

	while( CheckNetWorkRecvUDP( NetUDPHandle ) == FALSE )
	{
		// ウインドウズメッセージ処理
		if( ProcessMessage() < 0 ) break ;
	}

	/*受信部分(わからない場所[2])*/
	NetWorkRecvUDP( NetUDPHandle, NULL, NULL, x, 4, FALSE ) ;
	NetWorkRecvUDP( NetUDPHandle, NULL, NULL, y, 4, FALSE ) ;


	ClearDrawScreen() ;/*自機を送られてきた座標位置に描画*/
	DrawGraph( x , y , Handle , TRUE );

	WaitKey() ;

	DeleteUDPSocket( NetUDPHandle ) ; 

	DxLib_End() ;	// DXライブラリ使用の終了処理

	return 0 ;	// ソフトの終了
}
おそらく間違っているであろうことはわかっています!
具体的にどう直せばいいのか教えてください。おねがいします!(>人<;)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: DXライブラリで通信対戦

#11

投稿記事 by softya(ソフト屋) » 12年前

私としてはファイルで実験したほうが分かりやすいと思うんですけどね。
ファイルで上手く行ったら、通信に移植する方法が理解の最短だと思います。

まず、x,yは構造体にしてください。
そしてNetWorkSendUDP()で扱うのは構造体です。
とりあえず、これをやってみてください。

それとNetWorkSendUDP()の第4引数で渡すのはポインタですよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ASTRON
記事: 10
登録日時: 12年前

Re: DXライブラリで通信対戦

#12

投稿記事 by ASTRON » 12年前

わ!
ポインタだったのが私の盲点でした!恥ずかしくて死にそうです。

構造体ポインタについて調べてきました。
つまり、NetWorkSendUDP()の第4引数には構造体ポインタを渡して送信するのですね。

で、また疑問なのですが送られた先では NetWorkRecvUDP()の第4引数にまた同じ構造を持った構造体のポインタを渡せば、きちんと正しい場所に代入されるということでいいんですか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: DXライブラリで通信対戦

#13

投稿記事 by softya(ソフト屋) » 12年前

試したほうが早いでしょう。
同じPC内で送信側と受信側を起動して127.0.0.1のIPアドレスで通信出来ますので試してみてください。
届いたかはデバッガで確認できます。
つまり、受け取り側だけデバッガでブレークポイントを指定してデバッグ開始です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ASTRON
記事: 10
登録日時: 12年前

Re: DXライブラリで通信対戦

#14

投稿記事 by ASTRON » 12年前

すみません!
再度質問したいのですが、DXライブラリのTCP/IP通信で新たな接続を確認するGetNewAcceptNetWork()という関数のことです。
これはリファレンスでは接続側と受信側双方ひとつのPC同士でしか通信していないので載っていないのですが、もし1フレーム以内に2台以上のPCが接続してきた場合どういった反応をするのでしょうか。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: DXライブラリで通信対戦

#15

投稿記事 by softya(ソフト屋) » 12年前

複数回GetNewAcceptNetWork()してみるとか? 試しみてください。
ところで、そんなに激しく通信する必要があるゲームなのでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ASTRON
記事: 10
登録日時: 12年前

Re: DXライブラリで通信対戦

#16

投稿記事 by ASTRON » 12年前

いえ、特にそんな必要は。
でも一応60fpsの5vs5アクションゲームですし、情報の変更があるときのみといってもかなり通信するんじゃないでしょうか。

ASTRON
記事: 10
登録日時: 12年前

Re: DXライブラリで通信対戦

#17

投稿記事 by ASTRON » 12年前

サーバー部分なんとかできました。
皆様本当にありがとうございました!

閉鎖

“C言語何でも質問掲示板” へ戻る