플레이어 오브젝트(Player Objects)
네트워크 관리자 콜백(Network Manager callbacks)

오브젝트(Object) 가시성

Unity 네트워킹과 관련한 주요 개념은 서버에 있는 모든 게임 오브젝트가 모든 플레이어에게 전부 보일 필요는 없다는 것입니다. 이 개념에 따르면 관련성이 있거나 관심을 가져야 하는 게임 오브젝트에만 플레이어에게 보여지므로 때때로 “관심 영역”이라고 불립니다. 이 개념을 사용하는 게임 기능으로는 전장의 안개, 은신, 근접 기반 가시성 등이 있습니다. 게임 월드가 서버에서 아주 크거나 다수의 네트워크 게임 오브젝트를 포함하고 있을 때 특히 유용합니다. 플레이어에 보이는 게임 오브젝트의 수를 줄이면 로그인 시간이 줄어들며, 대역폭 사용 역시 줄어듭니다. 플레이어에게 보이는 게임 오브젝트만 업데이트하면 되기 때문입니다.

NetworkProximityChecker

플레이어의 오브젝트 가시성을 제한하는 가장 간단한 방법은 빌트인 컴포넌트인 NetworkProximityChecker를 사용하는 것입니다. 이 컴포넌트는 Unity 3D 물리 또는 2D 물리 시스템과 함께 플레이어가 근접한 게임 오브젝트만 볼 수 있도록 합니다. 이 컴포넌트를 사용하려면 제한된 가시성을 가지도록 할 네트워크 게임 오브젝트의 프리팹에 단순히 추가하면 됩니다. NetworkProximityChecker는 설정 가능한 파라미터가 있습니다. “가시 범위” 외부에 있는 게임 오브젝트는 플레이어에게 보이지 않게 되며, 각 플레이어가 볼 수 있는 게임 오브젝트는 “가시성 업데이트 간격”마다 다시 산출됩니다.

NetworkProximityChecker가 올바르게 작동하려면 오브젝트에 물리 콜라이더가 있어야 합니다.

원격 클라이언트에서의 가시성

원격 클라이언트의 플레이어가 네트워크 게임에 참여하면, 플레이어가 볼 수 있는 게임 오브젝트만 해당 클라이언트에게 스폰됩니다. 따라서 플레이어가 네트워크 게임 오브젝트가 다수 존재하는 거대한 월드에 진입하더라도 그 진입 시간이 적당한 수준에 머물 수 있습니다. 이 과정은 씬의 네트워크 게임 오브젝트에 적용되지만, 에셋 로딩에 영향을 주지는 않습니다. 등록된 프리팹과 씬 게임 오브젝트의 에셋은 정상적으로 로드됩니다

플레이어가 월드에서 이동하면 가시 게임 오브젝트 역시 변합니다. 이 과정에서 클라이언트는 이들 변경점에 대해 전달받습니다. 게임 오브젝트가 더 이상 보이지 않게 되면 ObjectHide 메시지가 클라이언트로 보내집니다. 이 메시지는 기본적으로 게임 오브젝트를 제거하는 동작을 하도록 합니다. 게임 오브젝트가 보이게 되면 클라이언트는 ObjectSpawn 메시지를 처음으로 게임 오브젝트가 생성된 시점과 동일한 방법으로 받게 됩니다. 따라서 게임 오브젝트는 기본적으로 생성되는 다른 게임 오브젝트와 동일하게 인스턴스화됩니다.

호스트에서의 가시성

호스트는 서버와 동일한 씬을 공유하므로, 로컬 플레이어가 볼 수 없는 게임 오브젝트를 제거할 수는 없습니다. 그 대신 NetworkBehaviour의 가상 함수가 아래와 같이 호출됩니다.

public virtual void OnSetLocalVisibility(bool vis)
{
}

함수는 호스트에서 가시성 상태를 변경하는 게임 오브젝트상의 모든 네트워크 스크립트에서 호출됩니다. 또한 HUD 요소나 렌더러 비활성화와 같이 각 스크립트가 어떻게 반응해야 하는지에 대한 커스텀화를 가능하게 합니다. NetworkProximityChecker가 디폴트로 구현된 경우 게임 오브젝트의 모든 Renderer 컴포넌트를 활성화 또는 비활성화시킵니다.

커스텀 가시성

NetworkProximityChecker는 Unity 네트워킹의 공용 가시성 인터페이스를 사용하여 구현됩니다. 인터페이스를 사용하면 원하는 모든 가시성 규칙을 구현할 수 있습니다. 각각의 NetworkIdentity는 플레이어가 볼 수 있는 게임 오브젝트 집합을 계속 추적합니다. 이는 게임 오브젝트의 “관찰자”라고 합니다.

NetworkIdentity에는 아래의 한 개의 함수가 있습니다.

// call this to rebuild the set of players observing this GameObject
public void RebuildObservers(bool initialize);

NetworkProximityChecker는 이 함수를 일정 간격마다 호출하며, 이를 통해 각 플레이어가 이동하더라도 가시 게임 오브젝트 집합이 업데이트됩니다.

NetworkBehaviour에는 가시성 여부를 결정하는 가상 함수가 있습니다. 아래 예제를 참조하십시오.

// called when a new player enters the game
public override bool OnCheckObserver(NetworkConnection newObserver);

// called when RebuildObservers is invoked 
public override bool OnRebuildObservers(HashSet<NetworkConnection> observers, bool initial);

새로운 플레이어가 게임에 참여하면 서버의 모든 네트워크 게임 오브젝트에 대해 OnCheckObservers 함수가 호출됩니다. 만일 true가 반환되는 경우 플레이어가 게임 오브젝트의 관찰자에 추가됩니다. NetworkProximityCheck는 이 함수 구현에 있어서 단순한 거리 검사를 수행합니다.

RebuildObservers가 호출되면 OnRebuildObservers 함수가 서버에서 호출됩니다. 이 함수는 게임 오브젝트를 볼 수 있는 플레이어로 채워질 관찰자 집합을 요구합니다. 그 이후 NetworkServer는 기존 가시성 집합과 새로운 가시성 집합 간 차이점에 기반하여 ObjectHideObjectSpawn 메시지 전송을 처리합니다. NetworkProximityCheckerPhysics.OverlapSphere를 사용하여 해당 게임 오브젝트의 가시성 범위에 있는 플레이어를 검색합니다.

게임 오브젝트가 플레이어인지 확인하려면 NetworkIdentity에 유효한 connectionToClient가 있는지 확인하면 됩니다. 아래는 그 예제입니다.

    var hits = Physics.OverlapSphere(transform.position, visRange);
        foreach (var hit in hits)
        {
            // (if a GameObject has a connectionToClient, it is a player)
            var uv = hit.GetComponent<NetworkIdentity>();
            if (uv != null && uv.connectionToClient != null)
            {
                observers.Add(uv.connectionToClient);
            }
        }
플레이어 오브젝트(Player Objects)
네트워크 관리자 콜백(Network Manager callbacks)