Network Manager は、マルチプレイヤーゲームのネットワーク状態を管理するためのコンポーネントです。完全に高レベル API (HLAPI) によって実装されているため、NetworkManager によって行われるすべての作業はスクリプトを通して行うことが可能です。ただし NetworkManager コンポーネントは、多くの便利な機能を 1ヶ所にまとめ、マルチプレイヤーゲームの制作、実行、デバッグをできる限り簡単に行えるように設計されています。
NetworkManager はスクリプトの記述を一切せずに使用することが可能です。エディターのインスペクターによって制御され、それにより全機能の設定ができます。また、NetworkManagerHUD によるランタイムでのシンプルなデフォルトユーザーインターフェースで、ユーザーがネットワークゲームを制御できるようになっています。上級レベルのユーザーに対しては、開発者が NetworkManager
からクラスを派生させ、その提供するすべての仮想関数フックをオーバーライドすることで挙動をカスタマイズすることも可能です。
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 コンポーネントがアタッチされたオブジェクトを探し、見付かったオブジェクトのうちのどれか 1つの位置と向きにプレイヤーをオブジェクト生成(Spawn)します。カスタムコードを使用して NetworkManager.startPositions
のリストによって、使用可能な NetworkStartPosition コンポーネントや Network Manager のヘルパー関数 GetStartPosition()
にアクセスすることも可能です。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 は通常はシーン間で存続する必要があるので (そうでないと、シーンが変わるたびにネットワーク接続が断絶されます)、インスペクターの Don’t Destroy On Load ボックスに必ずチェックします。また、繰り返しのプレハブの読み込みや異なるシーン遷移を制御したい場合は、各シーンに設定の異なる NetworkManager を置くことも可能です。
NetworkManagerHUD インスペクターウィンドウは、ネットワークの状態に関する情報をランタイムで表示するものです。これには下記の内容が含まれます。
また、登録されたクライアント メッセージ ハンドラーもプレビューウィンドウに表示されます。
NetworkManager ランタイム UI と NetworkManager インスペクター UI は、マッチメーカーサービスとの通信を可能にするものです。関数 NetworkManager.StartMatchmaker()
がマッチメイキングを有効にし、NetworkManager.matchmaker
プロパティーに NetworkMatch
オブジェクトを 1つ追加します。これがアクティブになるとデフォルト UI で使用され、コールバックが NetworkManager
上で機能するようになり、マッチメイキングが簡単に行えるようになります。
NetworkManager
には派生クラスが使用できる仮想関数があり、これを使用してマッチメーカーのコールバックに対する反応の挙動をカスタマイズできます。
NetworkManager
には、挙動をカスタマイズするために派生クラスが使用することのできる仮想関数があります。これらの関数を実装する場合には、デフォルトの実装によって提供されている機能を確認するようにしてください。例えば、OnServerAddPlayer()
では、接続のためにプレイヤーオブジェクトをアクティベートするために関数 NetworkServer.AddPlayer
を呼び出す必要があります。
Server または Host 上で呼び出される関数
//クライアントが接続したときに呼び出される
public virtual void OnServerConnect(NetworkConnection conn);
// クライアントが接続を切ったときに呼び出される
public virtual void OnServerDisconnect(NetworkConnection conn)
{
NetworkServer.DestroyPlayersForConnection(conn);
}
// クライアントの準備ができたときに呼び出される
public virtual void OnServerReady(NetworkConnection conn)
{
NetworkServer.SetClientReady(conn);
}
// 新しいプレイヤーがクライアントに追加されたときに呼び出される
public virtual void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
var player = (GameObject)GameObject.Instantiate(playerPrefab, playerSpawnPos, Quaternion.identity);
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}
//プレイヤーがクライアントから削除されたときに呼び出される
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);
}
}
// ネットワークエラー発生時に呼び出される
public virtual void OnServerError(NetworkConnection conn, int errorCode);
Client 上で呼び出される関数
// サーバーに接続したときに呼び出される
public virtual void OnClientConnect(NetworkConnection conn)
{
ClientScene.Ready(conn);
ClientScene.AddPlayer(0);
}
// サーバーから接続が切られたときに呼び出される
public virtual void OnClientDisconnect(NetworkConnection conn)
{
StopClient();
}
// ネットワークエラーの発生時に呼び出される
public virtual void OnClientError(NetworkConnection conn, int errorCode);
// サーバーから準備ができていないと伝えられたときに呼び出される
public virtual void OnClientNotReady(NetworkConnection conn);
マッチメーカーのために呼び出される関数
// マッチが作られたときに呼び出される
public virtual void OnMatchCreate(CreateMatchResponse matchInfo)
// マッチのリストが受領されたときに呼び出される
public virtual void OnMatchList(ListMatchResponse matchList)
//マッチが加わったときに呼び出される
public void OnMatchJoined(JoinMatchResponse matchInfo)