Siv3D + Ruby で通信ゲームを作る #3 ゲームの同期
Siv3D + Ruby で通信ゲームを作ろうの第3回です。
前回で入力の同期は出来ましたが、ゲームの開始の同期やボールの再配置が出来ていません。
今回はその入力以外の同期を行っていきます。
ゲーム開始の同期
入力の同期はある程度ごまかせますが、そもそも開始したのがずれていたのでは話になりません。
そこで、「start」を受信した時ではなく、「start」の受信と共に開始時刻を受け取るようにし、その時刻に一斉に開始するようにします。
Main.cppはWaitingクラスを、main.rbはacceptメソッドを読んでから「start」を送信するまでを変更します。
手っ取り早く時刻を扱うのにUNIXタイム(UTC)を使用します。「start」を送信した時刻から3秒後を開始し時刻に設定することによって3秒以内の遅延なら、各クライアントで同時刻で開始できるようになりました。
ボールの再配置
入力のみを同期しているので、サーバはボールが画面外に出たかを知る術がありません。なので、クライアントに判定させるのですが、判定するのは1人だけでいいはずなので、今回は親に任せます。
画面外に出た時にサーバに「goal」という文字列を送信し、サーバはそれを各クライアントに送信し直します。入力の時と同様に画面外に出た瞬間ではなく、一度サーバを通すことを忘れないでください。
また、画面外に出てから実際に再配置するまでタイムラグがあるので、そのままだと「goal」という文字列が何回も送信されてしまいます。遅れてサーバが受信して、再配置されたのに送ってしまったら大変なので、isSendGoal変数を使って1回だけ送るようにしましょう。
サーバをループさせる
ゲームは完成しましたが、1回対戦する度にrubyコマンドを打ってサーバを起動しなければなりません。
1回対戦しただけで、サーバが落ちているのではサービスにならないので、全体をループで囲んで繰り返し対戦できるようにします。
今までは気にしてしませんでしたが、終了する時にソケットをクローズするのを忘れないでください。
相手がいなくなって対戦が終了したのに、通信が終わったことが通知されず、幽霊と対戦する羽目になります。
まとめ
通信対戦ゲームが作れたでしょうか?
オンライン要素となると、難しくて作るのが大変なイメージがありますが、仕組みさえ理解してしまえば簡単なので、これを機にオンライン要素や通信対戦に挑戦してみてください!
おまけ
コピペで動くSiv3DとRubyを置いておきます。