Network Manager는 단순한 빌트인 플레이어 스포닝 기능을 제공합니다. 하지만 스폰된 새 플레이어 각각에 컬러를 할당하는 경우에는 플레이어 스포닝 시스템을 커스터마이즈하는 것이 좋습니다.
이를 위해서는 고유 스크립트를 사용하여 네트워크 관리자의 기본 동작을 오버라이드해야 합니다.
네트워크 관리자는 플레이어를 추가할 때 플레이어 프리팹의 게임 오브젝트도 인스턴스화한 후 해당 연결과 연관시킵니다. 이 작업을 수행하기 위해 네트워크 관리자는 NetworkServer.AddPlayerForConnection을 호출합니다. 이 동작은 NetworkManager.OnServerAddPlayer를 오버라이드하여 수정할 수 있습니다. OnServerAddPlayer
의 기본 구현은 플레이어 프리팹의 새 플레이어 인스턴스를 인스턴스화하고, NetworkServer.AddPlayerForConnection을 호출하여 새 플레이어 인스턴스를 스폰합니다. OnServerAddPlayer
의 커스텀 구현 역시 NetworkServer.AddPlayerForConnection
을 호출해야 하지만, 해당 메서드에 필요한 다른 인스턴스화 작업을 수행할 수도 있습니다.
아래 예제에서는 플레이어의 컬러를 커스터마이즈합니다. 먼저, 컬러 스크립트를 플레이어 프리팹에 추가하십시오.
using UnityEngine;
using UnityEngine.Networking;
class Player : NetworkBehaviour
{
[SyncVar]
public Color color;
}
그런 다음 NetworkManager를 생성하여 스포닝을 처리하십시오.
using UnityEngine;
using UnityEngine.Networking;
public class MyNetworkManager : NetworkManager
{
public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
GameObject player = (GameObject)Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
player.GetComponent<Player>().color = Color.red;
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}
}
OnServerAddPlayer
에서 NetworkServer.AddPlayerForConnection
함수를 호출할 필요는 없습니다. 올바른 연결 오브젝트와 playerControllerId
가 전달된 경우 OnSe
rverAddPlayer`가 반환된 이후에 호출될 수도 있습니다. 이 경우 원격 데이터 소스에서 플레이어 데이터를 로드하는 것과 같은 비동기적 과정을 중간에 실행하도록 할 수 있습니다.
대부분의 멀티플레이어 게임에서는 일반적으로 클라이언트당 하나의 플레이어를 요구하지만, HLAPI는 플레이어와 클라이언트를 별도의 개념으로 취급합니다. 이는 일부 상황(예: 여러 컨트롤러가 하나의 콘솔 시스템에 연결된 경우)에서 단일 연결에 여러 개의 플레이어 게임 오브젝트가 필요할 수 있기 때문입니다. 하나의 연결에 여러 명의 플레이어가 있는 경우 playerControllerId
프로퍼티를 사용하여 구분해야 합니다. 이 식별자의 범위는 연결로만 한정되므로, 해당 클라이언트의 플레이어와 연결된 컨트롤러 ID에 매핑됩니다.
시스템이 서버에서 NetworkServer.AddPlayerForConnection
으로 전달된 플레이어 게임 오브젝트를 자동으로 스폰하기 때문에 플레이어에 대해 NetworkServer.Spawn을 호출할 필요가 없습니다. 플레이어가 준비되면 씬에서 네트워크로 연결된 액티브 게임 오브젝트(연결된 NetworkIdentity가 있는 게임 오브젝트)가 플레이어의 클라이언트에 스폰됩니다. 게임 내에서 네트워크로 연결된 게임 오브젝트는 모두 해당 클라이언트에서 최신 상태로 생성되기 때문에 게임의 다른 참가자들과 동기화됩니다.
플레이어 게임 오브젝트를 생성하기 위해 NetworkManager
에서 playerPrefab을 사용하지 않아도 괜찮습니다. 다른 방법으로도 플레이어를 생성할 수 있습니다.
플레이어와 더불어 클라이언트 연결 역시 “준비” 상태가 있습니다. 호스트는 준비된 클라이언트에 스폰된 오브젝트와 상태 동기화 업데이트 정보를 보냅니다. 준비되지 않은 클라이언트는 이들 업데이트를 보내지 않은 경우입니다. 클라이언트가 최초로 서버에 연결하면 준비된 상태가 아닙니다. 이런 준비되지 않은 상태에서 클라이언트는 서버 게임 상태와의 실시간 인터랙션이 필요하지 않은 작업(예: 씬 로딩, 플레이어가 아바타를 선택하도록 허용, 로그인 상자 채우기)을 수행할 수 있습니다. 클라이언트가 게임 전 작업을 모두 마치고 해당 에셋이 전부 로드되면 ClientScene.Ready를 호출하여 “준비” 상태로 전환할 수 있습니다. 위의 단순한 예제는 준비 상태의 구현을 보여줍니다. 이는 NetworkServer.AddPlayerForConnection
를 통해 플레이어를 추가하면 클라이언트가 준비 상태가 아닌 경우 준비 상태로 전환하기 때문입니다.
클라이언트는 준비 상태가 아니더라도 네트워크 메시지를 송수신할 수 있으며, 액티브 플레이어 게임 오브젝트가 없어도 가능합니다. 따라서 메뉴나 선택 화면에 있는 클라이언트 역시 플레이어 게임 오브젝트가 없더라도 게임에 연결하여 상호작용이 가능합니다. 커맨드와 RPC 호출을 사용하지 않고 메시지를 보내는 방법은 네트워크 메시지에 대한 문서를 참조하십시오.
연결용 플레이어 오브젝트를 교체하려면 NetworkServer.ReplacePlayerForConnection을 사용하십시오. 이는 게임 이전 로비 화면과 같은 특정 상황에서 플레이어가 내릴 수 있는 커맨드를 제한하는 데 유용합니다. 이 함수는 AddPlayerForConnection
와 동일한 인수를 가지지만, 해당 연결에 플레이어가 있더라도 가능하다는 점이 다릅니다. 이전 플레이어 게임 오브젝트를 삭제할 필요는 없습니다. NetworkLobbyManager는 이 방법을 통해 로비의 모든 플레이어가 준비되면 NetworkLobbyPlayer 오브젝트를 게임플레이 플레이어 게임 오브젝트로 전환합니다.
게임 오브젝트를 삭제한 후 ReplacePlayerForConnection
을 사용하여 플레이어를 다시 스폰할 수도 있습니다. 일부 경우에는 게임 오브젝트를 비활성화한 후 다시 스폰할 때 해당 게임 속성을 초기화하는 것이 더 좋습니다. 다음 코드 예제는 삭제된 게임 오브젝트를 새 게임 오브젝트로 실제로 교체하는 방법을 보여줍니다.
class GameManager
{
public void PlayerWasKilled(Player player)
{
var conn = player.connectionToClient;
var newPlayer = Instantiate<GameObject>(playerPrefab);
Destroy(player.gameObject);
NetworkServer.ReplacePlayerForConnection(conn, newPlayer, 0);
}
}
연결용 플레이어 게임 오브젝트가 제거된 경우 해당 클라이언트는 커맨드를 실행할 수 없습니다. 하지만 네트워크 메시지를 보낼 수는 있습니다.
ReplacePlayerForConnection
을 사용하려면 게임 오브젝트와 클라이언트 간 관계를 생성하기 위해 해당 플레이어의 클라이언트에 대한 NetworkConnection 게임 오브젝트가 필요합니다. 이는 보통 NetworkBehaviour 클래스의 connectionToClient 프로퍼티이지만, 만일 기존 플레이어가 이미 제거된 경우 사용하지 못할 수도 있습니다.
연결을 찾기 위해 몇몇 리스트를 사용할 수도 있습니다. NetworkLobbyManager`를 사용하는 경우 로비 플레이어는 lobbySlots에서 찾을 수 있습니다. 또한, NetworkServer는 connections와 localConnections 리스트를 가지고 있습니다.