0からマルチプレイヤープロジェクトをセットアップする
オブジェクトの Spawn(生成)

NetworkManager を使用する

Network Manager は、マルチプレイヤーゲームのネットワーク状態を管理するためのコンポーネントです。完全に高レベル API (HLAPI) によって実装されているため、NetworkManager によって行われるすべての作業はスクリプトを通して行うことが可能です。ただし NetworkManager コンポーネントは、多くの便利な機能を 1ヶ所にまとめ、マルチプレイヤーゲームの制作、実行、デバッグをできる限り簡単に行えるように設計されています。

NetworkManager はスクリプトの記述を一切せずに使用することが可能です。エディターのインスペクターによって制御され、それにより全機能の設定ができます。また、NetworkManagerHUD によるランタイムでのシンプルなデフォルトユーザーインターフェースで、ユーザーがネットワークゲームを制御できるようになっています。上級レベルのユーザーに対しては、開発者が NetworkManager からクラスを派生させ、その提供するすべての仮想関数フックをオーバーライドすることで挙動をカスタマイズすることも可能です。

NetworkManager の機能には下記の内容が含まれます。

  • ゲームの状態の管理
  • オブジェクト生成(Spawning)の管理
  • シーンの管理
  • デバッグ情報
  • マッチメイキング
  • カスタマイズ

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 が接続ポートになります。

オブジェクト生成(Spawning)の管理

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 インスペクターには二つのスロットがあります。offlineSceneonlineScene です。これらのスロットにシーンオブジェクトをドラッグすれば、ネットワーク上でのシーン管理がアクティベートされます。

サーバーまたはホストがスタートされるとオンラインシーンがロードされます。これが「現在の」ネットワークシーンになります。このサーバーに接続されたすべてのクライアントもまたシーンのロードを命令されます。このシーンの名前は networkSceneName プロパティーに保存されます。

サーバーまたはホストを停止するか、クライアントの接続が断たれることによってネットワークが停止されると、オフラインシーンがロードされます。これによって、マルチプレイヤーゲームへの接続が断たれたときにゲームが自動的にメニューシーンに戻ることが可能になります。

また、NetworkManager.ServerChangeScene() の呼び出しによって、ゲームがアクティブな時にシーンを変更することも可能です。これにより、その時点で接続されているすべてのクライアントのシーンも変更され、新しいクライアントも新しいシーンをロードできるように networkSceneName が更新されます。

ネットワーク上のシーン管理がアクティブになっているときは、NetworkManager.StartHost()NetworkManager.StopClient() を始めとする、ゲーム状態管理の呼び出しはすべて、シーン変更を生じさせることができます。これはランタイム制御 UI にも当てはまります。したがって、シーンを設定してこれらの関数を呼び出すことで、マルチプレイヤーゲームの流れを簡単に制御することができます。

シーン変更をすると前のシーンのオブジェクトがすべて削除されることに注意してください。NetworkManager は通常はシーン間で存続する必要があるので (そうでないと、シーンが変わるたびにネットワーク接続が断絶されます)、インスペクターの Don’t Destroy On Load ボックスに必ずチェックします。また、繰り返しのプレハブの読み込みや異なるシーン遷移を制御したい場合は、各シーンに設定の異なる NetworkManager を置くことも可能です。

デバッグ情報

NetworkManagerHUD インスペクターウィンドウは、ネットワークの状態に関する情報をランタイムで表示するものです。これには下記の内容が含まれます。

  • ネットワーク接続
  • アクティブな NetworkIdentity サーバー オブジェクト
  • アクティブな NetworkIdentity クライアント オブジェクト
  • クライアント ピア

また、登録されたクライアント メッセージ ハンドラーもプレビューウィンドウに表示されます。

マッチメイキング

NetworkManager ランタイム UI と NetworkManager インスペクター UI は、マッチメーカーサービスとの通信を可能にするものです。関数 NetworkManager.StartMatchmaker() がマッチメイキングを有効にし、NetworkManager.matchmaker プロパティーに NetworkMatch オブジェクトを 1つ追加します。これがアクティブになるとデフォルト 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)
0からマルチプレイヤープロジェクトをセットアップする
オブジェクトの Spawn(生成)