web-dev-qa-db-ja.com

Unity用のシンプルなオンラインゲームサーバーの構築

タンクゲーム2D(Unity)用のオンラインゲームサーバーを構築しようとしています。私のゲームでは、2〜4人のプレイヤーが戦車を操作し、お互いに戦います。

  • Unityネットワーキングを使用しようとしましたが、部屋のプレーヤーの1人を選択して「サーバー」にする必要があるため、ゲームにはあまり適していませんでした。これは、将来の開発にあまり柔軟ではありません(たとえば、「サーバー」が終了しました。他のプレイヤー間の接続を維持するには、多くの作業を行う必要があります)。

  • 次に、サーバーとクライアントの通信用にNodejslàsocket.ioを使用して独自のサーバーを構築しようとしました。非常に簡単です。あるデータからデータを受信し、他のデータにブロードキャストします。物理的な部分が入るまでは正常に機能しているようです。サーバーは、何かがヒットまたは爆発したとクライアントが言ったときにクライアントを信頼し、それを他のクライアントにブロードキャストする必要があります。不正なクライアントは言うまでもなく、ネットワークの遅延により、クライアントの物理シミュレーションは異なります。たとえば、このクライアントで戦車が攻撃されたとしても、もう一方のクライアントの壁の後ろで覆われて生き続ける必要がありますが、遅延のため、背後の戦車が弾丸を捕まえて爆発します。このような場合、サーバーはどちらをリッスンするかを認識していません。

更新

  • @Catwoodが後述するように、PhotonPUNは私にとってもう1つのオプションです。私は以前に彼らのチュートリアルの1つに従ったことがあります。 Photonは、Unityネットワーキングのような「サーバー」であるプレーヤーを必要としません。しかし、サーバーにゲームロジックを実装するにはどうすればよいですか? (信頼できるサーバーの目的で)
  • どうやらSmartfoxserverは別の良い(そして高価な)オプションです。私は彼らのAPIドキュメントを詳しく調べていません。これにゲームロジックとルールを実装できるかどうかはわかりません(簡単にするために、チュートリアルではこの部分をスキップします)。

結論として、ゲームサーバーに関する提案が必要です。

  • 信頼できるサーバーです
  • ゲームルールを処理し、何が起こるかを決定できます(おそらく独自の物理エンジンが必要です)
  • Unity2Dでうまく機能します
  • Javascript、C#、Javaが推奨されます!

一部のゲームサーバーサービス(Photon、Unityネットワーキングなど)はサーバーにゲームロジックを実装する方法を気にしないように見えるので、私は正しい方向に進んでいますか?そしてそれは彼らを権威あるサーバーではないのでしょうか?

私はこの分野に非常に新しいです、何でもありがたいです!

6
FlySoFast

NodeJSで行ったように、ゲーム用に独自のサーバーを作成することをお勧めします。私が知っているソリューションのほとんどは、使用するのが非常に難しく、あなたが望むすべてを行うことができません。

たとえば、ブリザードゲームのハースストーンはクライアント用のUnityに基づいており、カスタムメイドのサーバー側があります。

ゲームサーバーの作成方法に関するアドバイスをいくつか紹介します。

物理的な部分が入るまでは正常に機能しているようです。サーバーは、何かがヒットまたは爆発したとクライアントが言ったときにクライアントを信頼し、それを他のクライアントにブロードキャストする必要があります。

サーバーを作成するときは、クライアント側ではなくサーバー側ですべての重要な決定を行う必要があります。パーティーを開始するのはサーバーであるため、サーバーには次の情報が必要です。

  • 地図のサイズ
  • プレイヤーの数
  • 各プレイヤーに関するデータ(ヘルスポイント、位置、サイズ、攻撃速度...)
  • 意思決定に必要なその他の情報

これで、クライアントは常に次のように非常に小さな信号をサーバーに送信する必要があります

  • 左に移動
  • パーティーに参加する
  • シュート
  • 右に回る
  • 等...

ユーザーのアクションとユーザーのデータに基づいて、サーバーはゲームの「シミュレーション」を実行できます。

  • アクションが許可されているかどうかを確認します
  • 許可されている場合は、アクションをシミュレートします。そうでない場合は、キューに入れます
  • 何が起こっているかに関する情報をユーザーに送信します(プレーヤー1がヒット、プレーヤー2が死ぬ、プレーヤー4が左に移動するなど)。

これにより、サーバーは何かがいつ発生するかを認識し、何が発生するかを決定します。クライアント側の情報に依存するのではなく、プレーヤーの希望するアクションを受け取るだけです。

ただし、おっしゃるように、遅延やその他のネットワーク要因のために、クライアントはサーバーに過度に依存することはできません。最近のゲームでは、クライアントはサーバーと同じプレーヤーに関するデータを持っており、何が起こっているかを画面に表示するためにサーバーに常に依存しているわけではありません。

一部のオンラインゲームをプレイした場合、サーバーとの接続が失われると、プレイを継続できる時間が少しありますが(移動、撮影など)、自分以外は何も移動しないことに気付いたかもしれません。これは、サーバーの情報がなくても、クライアントがアクションに基づいてゲームを「実行」し続けるためです。

ただし、クライアントからプレーヤーに表示される内容とサーバーのシミュレーションで行われる内容との大きな違いを回避するために、クライアントとサーバーは一定の間隔で「同期」します。

たとえば、左に移動することにした場合、クライアントは移動速度を知っているため、サーバーに依存せずに移動を表示できます。

同期が発生すると、サーバーはクライアントに重要な情報を送信し、クライアントは現在表示されている情報をサーバーが送信する情報に変更します。

左の移動の例では、サーバーとクライアントで移動速度が異なる場合、クライアントが同期命令を受信すると、プレーヤーが表示された位置から別の位置に「テレポート」されることに気付くでしょう。これは、一部のパケットが失われた場合、または待ち時間が長い場合にも発生する可能性があります。

サーバー側とクライアント側の両方でオンラインゲームを作成する場合、レイテンシーの処理は大きな課題であり、この質問のトピックではありません。

要約すると、サーバーは

  • 自家製であること
  • クライアントからのアクションのみを受け取る
  • ゲームをシミュレートする
  • 何が起こっているかについての情報をクライアントに送信する
  • クライアントと定期的に同期する

この助けを願っています=)


さて、あなたのゲームでは、プレイヤーはアクションMOVEしか使用できないと仮定します。

ユーザーがサーバーに接続すると、ゲームを起動できます。ユーザーは移動できるため、2Dマップがあり、ユーザーにはサイズ、初期位置、速度があります。したがって、サーバーは新しい「GameParty」を開始し、上記のデータを初期化する必要があります。この例では、次のデフォルト値が設定されていると仮定します。

map_width = 512;
map_height = 512;
user_width = 2;
user_height = 2;
user_speed = 1;
user_posx = 20;  
user_posy = 20;

クライアントが移動したいとき、彼は移動したいというパケットをサーバーに送信します。クライアント<->サーバー通信には任意のプロトコルを使用できます。私はバイナリプロトコルを使用しますが、Jsonを使用するとします。

{action: move; value: left};

これにより、サーバーはユーザーが左に移動したいことを認識します。したがって、サーバー側で新しい位置を取得するには、user_posxを値user_speedだけ減らす必要があります。この位置がマップの端にある場合は、2つの選択肢があり、ユーザーをマップのもう一方の端に表示してアクションを禁止します。

一定の時間間隔で、サーバーはクライアントにプレーヤーの現在の位置を送信します。

12
Gary Olsson

アセットストアには、信頼できるサーバーである Photon というアセットがあります。モバイル以外のデバイスでも無料です。これはあなたの質問の最初の部分を確実に処理します。

この素晴らしい チュートリアル が役立ちます。

2
Catwood