こんにちは、Habrahabr!
私は、あなたの多くと同様、マルチプレイヤーゲームの大ファンです。 それらの中で、私は主に競争の精神と改善を獲得し、成果を蓄積する能力に魅了されています。 そして、このタイプのゲームをますます公開するというアイデアは、行動を促すことです。
最近、私自身が自分のプロジェクトを開発し始めました。 そして、このテーマに関する記事がHabrahabrで見つからなかったため、
Unity3Dエンジンに基づいたマルチプレイヤーゲームの作成経験を共有することにしました。 また、
Networkおよび
NetworkViewコンポーネント 、
RPC属性、組み込み
イベントメソッドについても説明します。 記事の最後に、ゲームの例と、もちろんUnityのプロジェクトが記載されています。 だから...
ネットワーククラス
このクラスは、クライアント/サーバー接続を整理するために必要です。 主な機能:サーバーの作成、サーバーへの接続、プレハブのネットワークインスタンスの作成。
主な方法:
Network.Connect(string host、int remotePort、string password = "") -remotePortポートとパスワード
passwordを使用して
ホストサーバーに接続し
ます 。 このメソッドは、NetworkConnectionError列挙を返します。
Network.InitializeServer(int connections、int listenPort、bool useNat) -接続
接続の最大許容数でサーバーを作成します。
listenPortインバウンドポートと
useNat :
NATを使用するかどうか。
NetworkConnectionError列挙も返します。
Network.InitializeSecurity() -不正行為から保護するために
Network.InitializeServer()の前に呼び出されます。
公式ドキュメントの詳細。 クライアントを呼び出さないでください!
Network.Instantiate(オブジェクトプレハブ、Vector3位置、クォータニオン回転、intグループ) -回転
回転およびグループ
groupの位置
位置にあるネットワーク上の
プレハブプレハブのインスタンスを作成します。 作成後に追加のアクションを実行できる作成済みオブジェクト全体を返します。 詳細は記事の後半で説明します。
主なプロパティ:
bool Network.isClientおよび
bool Network.isServer-ゲームがサーバーかクライアントかを決定します。 サーバーが作成されなかった場合、またはサーバーへの接続がなかった場合、両方のプロパティは
falseです。
string Network.incomingPassword-このプロパティは、着信接続のパスワードを設定します。
NetworkPlayer Network.player-ローカル
NetworkPlayerプレーヤーのインスタンスを返します。
NetworkPeerType Network.peerType-現在の接続ステータスを返します:
切断 (切断)、
サーバー (サーバーとして実行)、
クライアント (サーバーに
接続 )、
接続 (試行、接続中)。
NetworkPlayer [] Network.connections-接続されているすべてのプレーヤーを返します。 クライアントでは、サーバープレーヤーのみを返します。
主なイベント(MonoBehaviourから継承された場合):
OnConnectedToServer() -サーバーへの接続が成功したときにクライアントで呼び出されます。
OnDisconnectedFromServer(NetworkDisconnection info) -サーバーから切断するときにクライアントで呼び出され、
Network.Disconnect ()接続が完了するとサーバーで呼び出されます。
情報には、切断の理由:
LostConnection (接続の喪失)および
Disconnected (正常な切断時)が含まれます。
OnFailedToConnect(NetworkConnectionErrorエラー) -接続
エラーが発生したときにクライアントで呼び出され
ます 。
errorにはタイプ
NetworkConnectionErrorの エラーが含まれます。
OnNetworkInstantiate(NetworkMessageInfo info)-Network.Instantiate( )メソッドを使用して新しいインスタンスが作成された場合、クライアントとサーバーで呼び出されます。
NetworkMessageInfoタイプの
情報が含まれます。
OnPlayerConnected(NetworkPlayerプレーヤー) -クライアントが正常に接続し、タイプ
NetworkPlayerの プレーヤーが含まれている場合にサーバーで呼び出されます。
OnPlayerDisconnected(NetworkPlayerプレーヤー) -クライアントが切断され、タイプ
NetworkPlayerの プレーヤーが含まれている場合にサーバーで呼び出されます。
OnServerInitialized() -サーバーが正常に作成された後にサーバーで呼び出されます。
OnSerializeNetworkView(BitStreamストリーム、NetworkMessageInfo情報) -コンポーネントをネットワークと同期するための重要なイベント。 詳細は記事の後半で説明します。
クラスnetwokview
このクラスはUnityのコンポーネントとしても存在し、ネットワーク上のコンポーネントを同期して
RPCを呼び出すように設計されています。
次の
NetworkStateSynchronization同期プロパティがあります。
- オフ -オブジェクトを同期しませんが、リモートプロシージャを呼び出すことができます。
- ReliableDeltaCompressed-パケットを一度に1つずつ送信し、パケットが配信されたかどうかを確認します( TCPなど )。
- 信頼性の低い -配信を保証せずに高速パケット送信を実行します( UDPなど )。
主な方法:
networkView.RPC(文字列名、RPCModeモード、paramsオブジェクト[] args) -リモートプロシージャ名を呼び出し、モードは受信者を決定し
ます、args-プロシージャに渡す引数。
networkView.RPC(文字列名、NetworkPlayerターゲット、paramsオブジェクト[] args) -前のメソッドと同じですが、特定の
NetworkPlayerプレーヤーに送信します。
主なプロパティ:
bool networkView.isMine-オブジェクトがローカルかどうかを決定するプロパティ。 オブジェクトの所有者を確認するために頻繁に使用されます。
コンポーネントnetworkView.observed-同期されるコンポーネント。 これがスクリプトである場合、上記の
OnSerializeNetworkView(BitStreamストリーム、NetworkMessageInfo情報)メソッドを含める必要があります。
NetworkPlayer networkView.owner-オブジェクトの所有者を返すプロパティ。
NetworkStateSynchronization networkView.stateSynchronization-同期のタイプ:
Off 、
ReliableDeltaCompressed 、
Unreliable 。
NetworkViewID networkView.viewIDは、
NetworkViewのネットワーク上の一意の識別子
です 。
RPC属性
ウィキペディアによると、
RPCは、コンピュータープログラムが別のアドレス空間(通常はリモートコンピューター上)で関数またはプロシージャを呼び出すことを可能にするテクノロジーのクラスです。
この属性は、ネットワークから呼び出されるメソッドを割り当てるために使用されます。 機能するためには、
NetworkViewコンポーネントを追加する必要があります。
OnSerializeNetworkViewメソッド(BitStreamストリーム、NetworkMessageInfo情報)
このメソッドは、ネットワーク上のコンポーネントを同期するために使用されます。 データがネットワークを介して送受信されるたびに呼び出されます。
Serializeメソッドを使用して送受信できるデータの種類は
次のとおりです。bool、char、short、int、float、Quaternion、Vector3、NetworkPlayer、NetworkViewID。受信または送信が
進行中かどうかを確認するには
、isReadingまたは
isWritingプロパティが使用されます。
使用例を示します。
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) { Vector3 syncPosition = Vector3.zero;
この例は理想的ではありません。なぜなら、その動作中にオブジェクトが「ひきつる」ためです。 これを回避するには、補間を使用する必要があります。 詳細については、この記事の後半で説明します。
補間
補間の本質は、ネットワークから位置を読み取る間に、画面の更新中に
Lerp関数を介してオブジェクトをスムーズに移動することです。
現在の位置を開始点として、同期をとります-終了点として、フレームが更新されると、オブジェクトを移動します。
ネットワーク同期を最適化する方法の詳細については、開発
者向け Webサイトを参照してください
。ValveDeveloper Community-Source Multiplayer Networkingマルチプレイヤーゲームの例
そのため、基本を理解してから、小さなマルチプレイヤーゲームの作成を開始できます。 例として、
NetworkViewのさまざまな使用方法を使用し
ます 。 自分に最も便利な方法を選択するだけです。
ServerSide.csスクリプトを作成し、そこに以下を記述します。
using UnityEngine; using System.Collections; [RequireComponent( typeof( NetworkView ) )]
クライアントスクリプト
ClientSide.csを作成
します 。
using UnityEngine; using System.Collections; [RequireComponent( typeof( NetworkView ) )]
したがって、クライアントとサーバーのロジックがあり、
MainMenu.csを管理する必要があり
ます 。
using UnityEngine; using System.Collections; public class MultiplayerMenu : MonoBehaviour { const int NETWORK_PORT = 4585;
ネットワーク管理が作成されました。 次に、プレーヤーコントロール
PlayerControls.csを記述します。 この例では、
NetworkViewコンポーネントを使用する別の方法を使用します。
using UnityEngine; using System.Collections; [RequireComponent( typeof( Rigidbody ) )]
同期と制御は分離する必要があることは知っていますが、例として、それらを組み合わせることにしました。 お気づきのように、ここではスクリプトの初期化中にNetworkViewが作成されます。 私の意見では、これは「追加するのを忘れる」可能性(もちろん、
RequireComponent(typeof(Rigidbody))が記述されていない
場合)から保護するためのより便利な方法であり、インスペクター内のオブジェクトのコンポーネント数も減らします。
たとえば、一見、すべてが正しく行われたが、スクリプトが補間せず、同期中のすべてのアクションを無視した場合がありました。 そのため、エラーは、
Observedが私のスクリプトではなく、オブジェクト変換であることが判明しました。
これで、ミニゲームを作成するために必要なスクリプトがすべて揃いました。
空のオブジェクトを作成し、
MultiplayerMenu 、
ServerSide 、
ClientSideスクリプトを割り当て
ます 。
平面を作成し、少し下げます。
プレーヤーのプレハブを作成します(私の例では、これらはボールになります)。 sphereオブジェクトを作成し、
それにPlayerControlsスクリプトを割り当てて、プレハブに追加します。
Player Prefabフィールドの
ClientSideでのプレハブドラッグ。
以上で、プロジェクトをコンパイルし(プレーヤーの設定
で[バックグラウンドで
実行]を有効にすることを忘れないでください)、数回実行します。 ウィンドウの1つで、残りのサーバー(クライアント)をクリックして、結果を確認します。
プロジェクトへのリンク 。
*プロジェクトには論理的なエラーがあるかもしれませんが、この記事の本質には影響しません。
ご清聴ありがとうございました!
マルチプレイヤーゲームの作成に成功することを願っています。