레트로의 유니티6 : NGO 네트워크 게임 PONG - 2

네트워크 스폰
네트워크 오브젝트 컴포넌트를 가진 게임 오브젝트는 네트워크 스폰할 수 있다. 즉, 어떤 클라이언트가 네트워크 오브젝트를 가진 게임 오브젝트를 생성했을 때, 다른 클라이언트에서도 동일한 게임 오브젝트가 생성되도록 할 수 있다.
// 예시 코드
var instance = Instantiate(prefab);
var networkObject = instance.GetComponent<NetworkObject>();
networkObject.spawn();
단, Spawn() 메서드는 보안을 위해 서버(호스트)에서만 실행된다. 만일 서버가 아닌 클라이언트가 네트워크 스폰을 해야 한다면, RPC를 통해 클라이언트가 서버에게 해당 게임 오브젝트에 대한 네트워크 스폰을 대신 실행하도록 해야함.
네트워크 스폰이 동작하는 방식
→ Spawn() 메서드를 통해 네트워크 스폰을 실행하면 각 클라이언트는 네트워크 매니저에 등록된 네트워크 프리팹들 중에서 같은 글로벌 오브젝트 ID 해시를 가진 프리팹을 찾아 인스턴스화함. 이는 게임 도중에 네트워크 스폰할 모든 프리팹들이 미리 네트워크 매니저에 등록되어야 하는 이유이기도함.
소유권
| IsOwner | 로컬 클라이언트의 소유인가, 또는 로컬 플레이어 오브젝트인가 |
| IsOwnedByServer | 서버가 소유한 오브젝트인가 |
| IsSpawned | 게임 도중 스폰된 것인가 |
| IsSceneObejct | 씬에 처음부터 있던 오브젝트인가 |
| DestroyWithScene | 씬과 함께 파괴할 오브젝트인가 |
| IsPlayerObejct | 플레이어의 아바타인가 |
| IsLocalPlayer | 로컬 플레이어의 아바타인가 |

IsOwner를 통해 어떤 네트워크 오브젝트가 내(로컬 클라이언트)가 소유한 오브젝트인지 알 수 있다.
기본적으로 다음과 같이 먼저 원본 게임 오브젝트를 인스턴스화하고 네트워크 스폰을 실행한 측에서 해당 네트워크 오브젝트를 소유한다.
// 이 코드는 보통 호스트 또는 서버에서 실행, 기본 소유자: 서버(또는 호스트)
var instance = Instantiate(prefab);
var networkObject = instance.GetComponent<NetworkObject>();
networkObject.Spawn();
다만, 다음과 같은 코드들을 통해 서버가 네트워크 오브젝트의 소유권을 다른 클라이언트에게 이전해줄 수 있다.
var instance = Instantiate(prefab);
var networkObject = instance.GetComponent<NetworkObject>();
networkObject.SpawnWithOwnership(clientId);
var instance = Instantiate(prefab);
var networkObject = instance.GetComponent<NetworkObject>();
networkObject.Spawn(); // 먼저 네트워크에 스폰
networkObject.ChangeOwnership(clientId);
또한 네트워크 스폰을 할 때 SpawnAsPlayerObject() 메서드를 통해 네트워크 오브젝트가 어떤 플레이어의 아바타로서 생성되도록 지정할 수도 있다.
/*
즉, 단순히 소유권만 주는 것이 아니라:
해당 클라이언트의 플레이어 오브젝트로 지정
해당 클라이언트가 소유
IsPlayerObject가 true가 됨
*/
var instance = Instantiate(prefab);
var networkObject = playerGameObject.GetComponent<NetworkObject>();
networkObject.SpawnAsPlayerObject(clientId);
※ 소유권과 플레이어 오브젝트 정리
| 구분 | 의미 |
|---|---|
| 소유권 | 누가 이 오브젝트를 소유하고 제어하는가 |
| 플레이어 오브젝트 | 해당 클라이언트의 대표 아바타인가 |
로비 구현

LobbyManager 클래스가 네트워크 이벤트를 감지하고 동기화 기능을 활용할 수 있도록 NetworkBehaviour 클래스를 상속시킨다.
NetworkBehaviour 타입은 유니티 네트워크 이벤트들을 감지할 수 있다. 또한 RPC와 NetworkVariable 타입 등 넷코드 관련 네트워크 기능을 사용할 수 있다.
// OnNetworkSpawn은 NetworkBehaviour를 상속한 스크립트에서 자동 실행되는 네트워크 이벤트 메서드
// OnNetworkSpawn은 NetworkBehaviour가 스폰(생성)될 때 호출됨
// 네트워크 오브젝트가 씬에 미리 배치되어 있다면, 해당 씬이 로드되고 NGO가 오브젝트를 네트워크 오브젝트로 초기화한 직후 OnNetworkSpawn()이 실행된다. -> 씬에 같은 오브젝트가 있어도, 각 컴퓨터에서 별도의 로컬 오브젝트로 초기화한 뒤 NGO가 서로 연결해 관리한다는 뜻
// 효과는 호스트와 클라이언트가 각자 가진 오브젝트를 NGO가 같은 네트워크 오브젝트로 연결해 위치·상태 등을 동기화하고, 그 연결이 끝난 뒤 초기화 코드를 실행할 수 있게 하는 것
public override void OnNetworkSpawn()
{
// 먼저 자기 자신의 준비 상태를 등록
_clientReadyStates.Add(NetworkManager.LocalClientId, false);
// 서버인 경우에만 네트워크 매니저에 클라이언트가 호스트에 연결되었거나(OnClientConnectedCallback), 연결이 끊어졌을 때(OnClientisconnectedCallback) 실행할 콜백을 등록한다.
if (IsServer)
{
// 클라이언트가 접속하거나 떠났을 때 호출할 콜백 등록
NetworkManager.OnClientConnectedCallback += OnClientConnected;
NetworkManager.OnClientDisconnectCallback += OnClientDisconnected;
// 클라이언트가 씬 로드를 완료했을 때 호출할 콜백 등록
// 각 클라이언트가 네트워크 매니저를 통해 씬을 로드할 때마다 자동 실행되는 OnLoadComplete 이벤트에 OnClientSceneLoadComplete 콜백을 등록함.
// OnLoadComplete 이벤트는 자신뿐만 아니라 다른 모든 클라이언트들이 씬을 로드할 때마다 호스트 측에서 실행됨.
NetworkManager.SceneManager.OnLoadComplete += OnClientSceneLoadComplete;
/*
클라이언트가 새로 연결될 때 해당 클라이언트가 연결은 되었지만 로딩 등의 이유로 아직 로비 씬에 진입하지 않았을 수도 있다.
OnClientConnectedCallback 이벤트만 감지하면 클라이언트가 연결된 것만 알 수 있고 로비 씬까지 진입했는지는 알 수 없다.
네트워크 매니저의 OnClientConnectedCallback와 SceneManager.OnLoadComplete 이벤트를 모두 구독함으로써 각 클라이언트가 접속은 했으나 아직 로비 씬으로 진입하지 못한 상태와 연결도 되었고 로비 씬에 진입한 상태를 나누어 감지할 수 있다.
*/
}
UpdateLobbyText(); // 로비 텍스트를 갱신
}
RPC 속성
| 속성 | 호출하는 쪽 | 실제 실행되는 쪽 | 주된 용도 |
|---|---|---|---|
[ServerRpc] | 클라이언트 | 서버 또는 호스트 | 클라이언트의 요청을 서버에 전달 |
[ClientRpc] | 서버 또는 호스트 | 모든 클라이언트 | 서버의 결과나 명령을 클라이언트에 전달 |
메서드 명은 각 속성을 메서드명 끝에 달아준다.
예시: ClientRpc 속성 선언과 메서드 작성

새 글이 올라오면 Develog 알림으로 알려드려요
댓글을 작성하려면 로그인이 필요합니다.
아직 댓글이 없습니다. 첫 번째 댓글을 작성해보세요.
Develog는 단순히 글을 쓰는 공간이 아닙니다. 성장의 과정을 기록하고, 그 기록으로 나를 증명하며 원하는 기회를 얻는 곳이길 바랐습니다. 누군가의 꿈으로 향하는 중간다리가 되는 것, 그것이 Develog를 만든 이유입니다.

게임업계 취업을 준비하다 보면 조금 불편한 현실을 마주하게 됩니다. 게임회사에 들어가고 싶은 사람은 많습니다. 특히 신입 채용은 더 그렇습니다. 공고 하나에 많은 지원자가 몰리고, 회사 입장에서는 비슷한 조건의 지원자 가운데 사람을 선택할 수 있습니다. 그래서 다른 산업에서 흔히 이야기하는 “처음부터 연봉을 낮춰 부르지 마세요.” “적극적으로 협상하세요.”

우리들의 게임 발매 이야기
Develog는 단순히 글을 쓰는 공간이 아닙니다. 성장의 과정을 기록하고, 그 기록으로 나를 증명하며 원하는 기회를 얻는 곳이길 바랐습니다. 누군가의 꿈으로 향하는 중간다리가 되는 것, 그것이 Develog를 만든 이유입니다.


게임업계 취업을 준비하다 보면 조금 불편한 현실을 마주하게 됩니다. 게임회사에 들어가고 싶은 사람은 많습니다. 특히 신입 채용은 더 그렇습니다. 공고 하나에 많은 지원자가 몰리고, 회사 입장에서는 비슷한 조건의 지원자 가운데 사람을 선택할 수 있습니다. 그래서 다른 산업에서 흔히 이야기하는 “처음부터 연봉을 낮춰 부르지 마세요.” “적극적으로 협상하세요.”
