NetworkManager は、マルチプレイヤーゲームのネットワーク状態を管理するためのコンポーネントです。完全に HLAPI によって実装されているため、NetworkManager によって行われるすべての作業は別の方法でも行うことが可能です。ですが NetworkManager は、多くの便利な機能を1ヶ所にまとめることで、マルチプレイヤーゲームの制作・実行・デバッグをできる限り簡単に行えるように設計されています。
NetworkManager はスクリプトの記述を一切せずに使用することが可能です。エディターでのインスペクターによる制御が可能であり、全機能の設定を行うことができるようになっています。またランタイムでのシンプルなデフォルト・ユーザーインターフェースが NetworkManagerHUD として提供され、ユーザーがネットワークゲームを制御できるようになっています。高度な使用方法としては、開発者が NetworkManager からクラスを派生させ、その提供するすべての仮想関数フックをオーバーライドすることで挙動をカスタマイズすることも可能です。
NetworkManager の機能には下記の内容が含まれます。
NetworkManager は、マルチプレイヤーゲームの制御コンポーネントの核として使用することができます。使用を開始するには、開始シーンに空のゲームオブジェクトを作成するか、適当なマネージャー オブジェクトを選択してください。次に NetworkManager コンポーネントをメニューの Network/NetworkManager から追加します。新規に追加された NetworkManager コンポーネントは、おおむね以下のように表示されます。
エディター内にある NetworkManager のインスペクターによって、ネットワークに関連するさまざまな事項の設定を行えます。
NetworkManagerHUD も、NetworkManager と連携して機能するコンポーネントのひとつです。ゲーム実行中にネットワーク状態を制御できるシンプルなユーザー インターフェースを提供しています。これはネットワーク プロジェクトを始めるにあたり役立ちますが、完成したゲームの UI 用ではありません。NetworkManagerHUD は以下のように表示されます。
実際のゲームでは、ゲームの状態を制御したり、プレイヤーがプレイしたいゲームの種類を選択したりできるようにするための適切なユーザー インターフェースが提供されます。しかしまずは、開発者がゲームを制御するためにこれを使用します。
Unet のマルチプレイヤーゲームは三つのモードで実行できます - クライアント、専用サーバー、あるいは、クライアントであると同時にサーバーでもある「ホスト」の3つです。ネットワークでは、この3つの場合、すべてにおいて機能するコードとアセットを作成できるように設計されています。同一ゲームのシングルプレイヤー版とマルチプレイヤー版の開発を同じように行えます。
NetworkManager では、これらの各モードの入力方法を複数提供しています。NetworkManager.StartClient()、NetworkManager.StartServer()、および NetworkManager.StartHost() はすべてスクリプト コードで使用でき、キーボードの入力ハンドラーやカスタム ユーザー インターフェースから呼び出すことが可能です。オプションで表示できるデフォルトのランタイム制御もこれらの関数を呼び出すことができます。また プレイモードで使用可能な NetworkManagerHUD インスペクターもこれらの関数を呼び出せます。
どんな方法でゲームの状態を変えたとしても、networkAddress プロパティーと networkPort プロパティーが使用されます。サーバーあるいはホストが開始されると networkPort がリッスン ポートになります。クライアントが開始された場合、networkAddress が接続アドレス、networkPort が接続ポートになります。
NetworkManager は、ネットワーク化されたオブジェクトの生成をプレハブから管理するために使用できます。ほとんどのゲームは主要なプレイヤーオブジェクトとしてプレハブを利用しているので、NetworkManager にはプレイヤー プレハブをドラッグするスロットがあります。プレイヤー プレハブがセットされると、そのプレハブからゲームの各ユーザーにプレイヤー オブジェクトが自動的に生成されます。これはホストされるサーバーのローカルプレイヤーと、リモートクライアントのリモートプレイヤーに適用されます。プレイヤー プレハブは必ず NetworkIdentity コンポーネントを持つ必要があることにご注意ください。
プレイヤー プレハブに加え、動的に生成されるその他のオブジェクトのプレハブも ClientScene に登録される必要があります。これは ClientScene.RegisterPrefab() 関数で行えますが、NetworkManager によって自動的に行うことも可能です。オブジェクト生成リストにプレハブを追加すると、それが自動的に登録されます。NetworkManager インスペクターのオブジェクト生成セクションは、以下のように表示されます。
プレイヤー プレハブが設定されれば、ゲームをホストとして開始してプレイヤー オブジェクトが生成されるのを確認することができます。ゲームを停止するとプレイヤーオブジェクトが破壊されます。ゲームの別のコピーを実行してクライアントとして localhost に接続すると、プレイヤーオブジェクトがもう一つ現れ、そのクライアントを停止するとそのクライアントのプレイヤーオブジェクトが破壊されます。
プレイヤーオブジェクトは NetworkManager.OnServerAddPlayer の初期実装により生成(Spawn)されます。プレイヤーオブジェクトの作成される方法をカスタマイズしたい場合は、その仮想関数をオーバーライドすることも可能です。初期実装はおおむね以下のようになっています。
public virtual void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
var player = (GameObject)GameObject.Instantiate(playerPrefab, playerSpawnPos, Quaternion.identity);
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}
関数 NetworkServer.AddPlayerForConnection() は、プレイヤーオブジェクトが新規作成された場合には、それが生成(Spawn)されてクライアントの接続と関連付けられるように、必ず呼び出さなければなりません。それによりオブジェクトが生成(Spawn)されるので、プレイヤーオブジェクトの為に NetworkServer.Spawn を呼び出す必要はありません。
プレイヤーの生成(Spawn)される位置を制御するには NetworkStartPosition コンポーネントを使用できます。NetworkManager はシーン内の NetworkStartPosition オブジェクトを探し、見付かった NetworkStartPosition オブジェクトのうちのどれか一つの位置と向きにプレイヤーをオブジェクト生成(Spawn)します。カスタムコードを使用して NetworkManager.startPositions のリストによって、使用可能な NetworkStartPositionsand にアクセスすることも可能です。また NetworkManager にはヘルパー関数 GetStartPosition() も提供されており、開始ポジションを探すための OnServerAddPlayer の実装に使用することができます。
開始ポジションを使用するには、プレイシーン内のオブジェクトに NetworkStartPosition コンポーネントをアタッチします。ひとつのシーン内に複数の開始ポジションを設定することも可能です。次に NetworkManager がオブジェクトの位置と向きを開始ポジションとして登録します。クライアントがゲームに参加してプレイヤーが追加されると、開始ポジションのうちのひとつに、プレイヤーオブジェクトが同じ位置と向きで作成されます。
NetworkManager には、PlayerSpawnMethod
プロパティーがあります。これを使用して、開始ポジション
がどのように選択されるか設定することができます。
startPosition
のオプションでプレイヤーを生成するには、 Random を選択しますstartPosition
オプションを繰り返すには Round Robin を選択します生成の部分のコードは以下のようになります。
if (m_PlayerSpawnMethod == PlayerSpawnMethod.Random && s_StartPositions.Count > 0)
{
// try to spawn at a random start location
int index = Random.Range(0, s_StartPositions.Count);
return s_StartPositions[index];
}
if (m_PlayerSpawnMethod == PlayerSpawnMethod.RoundRobin && s_StartPositions.Count > 0)
{
if (s_StartPositionIndex >= s_StartPositions.Count)
{
s_StartPositionIndex = 0;
}
Transform startPos = s_StartPositions[s_StartPositionIndex];
s_StartPositionIndex += 1;
return startPos;
}
ほとんどのゲームは、複数のシーンを有しています。通常は少なくとも、ゲームが実際にプレイされるシーンの他にタイトル画面あるいはスタートメニュー シーンがあります。NetworkManager は、シーンの状態とシーンの遷移を、マルチプレイヤーゲームにおいて自動的に管理するように設計されています。NetworkManager インスペクターには二つのスロットがあります。offlineScene と onlineScene です。これらのスロットにシーンオブジェクトをドラッグすれば、ネットワーク上でのシーン管理がアクティベートされます。
サーバーまたはホストがスタートされるとオンラインシーンがロードされます。これが「現在の」ネットワークシーンになります。このサーバーに接続されたすべてのクライアントもまたシーンのロードを命令されます。このシーンの名前は networkSceneName プロパティーに保存されます。
サーバーまたはホストを停止するか、クライアントの接続が断たれることによってネットワークが停止されると、オフラインシーンがロードされます。これによって、マルチプレイヤーゲームへの接続が断たれたときにゲームが自動的にメニューシーンに戻ることが可能になります。
また、NetworkManager.ServerChangeScene() の呼び出しによって、ゲームがアクティブな時にシーンを変更することも可能です。これにより、その時点で接続されているすべてのクライアントのシーンも変更され、新しいクライアントも新しいシーンをロードできるように networkSceneName が更新されます。
ネットワーク上のシーン管理がアクティブになっている時は、NetworkManager.StartHost() や NetworkManager.StopClient() を始めとする、ゲーム状態管理の呼び出しはすべて、シーン変更を生じさせることができます。これはランタイム制御 UI にも当てはまります。したがって、シーンを設定してこれらの関数を呼び出すことで、マルチプレイヤーゲームの流れを簡単に制御することができます。
NetworkManager には派生クラスが使用できる仮想関数があり、これを使用してマッチメーカーのコールバックに対する反応の挙動をカスタマイズできます。
NetworkManagerHUD インスペクターパネルは、ネットワークの状態に関する情報をランタイムで表示するものです。これには下記の内容が含まれます。
また、登録されたクライアント メッセージ ハンドラーもプレビューウィンドウに表示されます。
NetworkManager ランタイム UI と NetworkManager インスペクター UI は、マッチメーカー サービスとの通信を可能にするものです。関数 NetworkManager.StartMatchmaker() がマッチメイキングを有効にし、NetworkManager.matchmaker プロパティーに NetworkMatch オブジェクトを一つ追加します。これがアクティブになるとデフォルト UI で使用され、コールバックが NetworkManager 上で機能するようになり、マッチメイキングが簡単に行えるようになります。
NetworkManager には派生クラスが使用できる仮想関数があり、これを使用してマッチメーカーのコールバックに対する反応の挙動をカスタマイズできます。
NetworkManager には、挙動をカスタマイズするために派生クラスが使用することのできる仮想関数があります。これらの関数を実装する場合には、初期実装によって提供されている機能を確認するようにしてください。例えば、OnServerAddPlayer() では、接続のためにプレイヤーオブジェクトをアクティベートするには関数 NetworkServer.AddPlayer を呼び出す必要があります。
Server または Host 上で呼び出される関数
// called when a client connects
public virtual void OnServerConnect(NetworkConnection conn);
// called when a client disconnects
public virtual void OnServerDisconnect(NetworkConnection conn)
{
NetworkServer.DestroyPlayersForConnection(conn);
}
// called when a client is ready
public virtual void OnServerReady(NetworkConnection conn)
{
NetworkServer.SetClientReady(conn);
}
// called when a new player is added for a client
public virtual void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
var player = (GameObject)GameObject.Instantiate(playerPrefab, playerSpawnPos, Quaternion.identity);
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}
// called when a player is removed for a client
public virtual void OnServerRemovePlayer(NetworkConnection conn, short playerControllerId)
{
PlayerController player;
if (conn.GetPlayer(playerControllerId, out player))
{
if (player.NetworkIdentity != null && player.NetworkIdentity.gameObject != null)
NetworkServer.Destroy(player.NetworkIdentity.gameObject);
}
}
// called when a network error occurs
public virtual void OnServerError(NetworkConnection conn, int errorCode);
Client 上で呼び出される関数
// called when connected to a server
public virtual void OnClientConnect(NetworkConnection conn)
{
ClientScene.Ready(conn);
ClientScene.AddPlayer(0);
}
// called when disconnected from a server
public virtual void OnClientDisconnect(NetworkConnection conn)
{
StopClient();
}
// called when a network error occurs
public virtual void OnClientError(NetworkConnection conn, int errorCode);
// called when told to be not-ready by a server
public virtual void OnClientNotReady(NetworkConnection conn);
マッチメーカーのために呼び出される関数
// called when a match is created
public virtual void OnMatchCreate(CreateMatchResponse matchInfo)
// called when a list of matches is received
public virtual void OnMatchList(ListMatchResponse matchList)
// called when a match is joined
public void OnMatchJoined(JoinMatchResponse matchInfo)