Scene Loading Sample

개요

Fusion Scene Loading 샘플은 개발자가 필요한 대로 조작할 수 있는 Fusion을 사용한 씬 로딩 방법을 보다 사용자 지정 가능한 방식으로 탐색하고 보여줍니다. 간단한 한 씬 로드 대신, 가산 로드를 사용하여 동시에 로드할 수 있는 최대 4개의 씬을 사용하며, 각 플레이어가 서버에 로드된 씬 중 어떤 장면을 자신 쪽에 로드하고 싶은지 지시할 수 있습니다.

메인 화면으로

하이라이트

  • 씬 로딩 사용자 지정 가능
  • 동시에 씬 최대 4개 로드
  • 클라이언트 측 씬 관심 관리

메인 화면으로

다운로드

버전 릴리즈 일자 다운로드
1.1.1 Jun 14, 2022 Fusion Scene Loading 1.1.1 Build 4

메인 화면으로

프로젝트

데모를 실행하기 전에 Photon Cloud 용 Fusion AppId를 생성하고 PhotonAppSettings 에셋에 복사 붙여 넣어야 합니다. 앱 ID는 Photon 관리 화면에서 생성할 수 있습니다. Realtime Id가 아닌 Fusion App Id를 생성해야 합니다.

Fusion 메뉴 Fusion > Realtime Settings에서 photon 앱 설정 에셋을 선택할 수 있습니다.

생성한 App Id를 App Id Fusion 필드에 붙여 넣으시면 됩니다.

메인 화면으로

폴더 구조

샘플 코드는 Scripts 폴더에 있습니다. 이 폴더는 다음과 같이 세분됩니다. * Helpers - 편의를 위한 중요하지 않은 클래스입니다. * Sample - 샘플이 제공하는 두 씬에서 사용되는 로직입니다. * CustomSceneObjectProviders - 씬 로딩을 처리하는 샘플 코어 클래스입니다.

메인 화면으로

샘플 루프

MainScene에는 세션 이름을 입력하는 필드와 클라이언트 씬 관리를 활성화하기 위한 확인란이 두 개의 버튼과 함께 표시되며, 사용 가능한 두 가지 모드로 들어갑니다.

클라이언트 씬 관리는 세션의 호스트에 대해서만 사용되며 클라이언트는 세션의 호스트에서 속성을 가져옵니다. 제공된 이름의 세션이 없으면 호스트 모드에서 세션이 생성됩니다.

사용 가능한 4개의 씬을 참조하는 "Button sample" 4개의 버튼이 표시됩니다. 호스트는 로드하려는 씬을 전환할 수 있으며 클라이언트 씬 관리가 활성화된 경우 로드하려는 씬도 전환해야 합니다.

"Character sample"에서 각 플레이어는 제어할 캐릭터를 가지고 있으며, 맵의 모서리에 가까이 가면 해당 영역을 참조하는 씬이 로드되고, 영역을 벗어나면 언로드 됩니다. 클라이언트 씬 관리가 활성화된 경우 클라이언트는 현재 씬만 로드합니다.

메인 화면으로

NetworkSceneManager

사용자 지정 씬 배열을 로드하려면 해당 네트워크 속성을 가진 NetworkBehaviour가 있어야 합니다. 또한 현재 씬을 로드하고 원하는 씬을 로드하도록 유지하는 역할을 합니다. 이 작업은 ClientSceneManagement가 활성화된 경우 사용됩니다. 이 클래스는 Initialized 시작 게임 args 액션 내에서 생성됩니다.

public class NetworkSceneManager : NetworkBehaviour 
{

  private const int MAXSCENES = 4;
  [Networked] public NetworkBool ClientSceneManagement { get; set; }
  [Networked, Capacity(MAXSCENES)] public NetworkLinkedList<SceneRef> Scenes => default;
  public List<SceneRef> MyScenes = new List<SceneRef>(MAXSCENES);
  public List<SceneRef> LoadedScenes = new List<SceneRef>(MAXSCENES);

  private SceneRef _sceneToUnload;

  //...
}

메인 화면으로

확장 메소드

NetworkSceneManager 이 스폰 되면, Runner.SceneManager에서 쉽게 접근할 수 있는 사용자 지정 확장 메서드의 레퍼런스로 등록됩니다.

//NetworkSceneManager

public override void Spawned()
{
    if (Runner.SceneManager())
    {
      Runner.Despawn(Object);
      return;
    }

    DontDestroyOnLoad(this);
    Runner.SetSceneManager(this);
}

메인 화면으로

씬 추가 및 제거

NetworkSceneManager에는 씬을 추가하고 제거하는 메소드가 있습니다. public void AddScene(int sceneIndex). public void RemoveScene(int sceneIndex). 호스트의 [Networked] Scenes 링크 목록과 클라이언트 측의 MyScenes 목록에서 씬 인덱스를 처리합니다.

메인 화면으로

씬 업데이트 감지 및 오래된 씬 언로드

bool IsSceneUpdated(out SceneRef sceneRef)은 로드해야 할 씬이 있거나 로드해서는 안 되는 씬이 있으면 반환하고 누락된 씬의 인덱스에 out 변수를 할당해야 합니다. 로드하려는 씬을 클라이언트가 지시할 수 있으므로 씬을 로드해야 하는 경우에만 반환해야 합니다. (!ClientSceneManagement || MyScenes.Contains(Scenes[i])) 조건이 필요합니다.

public bool IsSceneUpdated( out SceneRef sceneRef )
{
    for (int i = 0; i < Scenes.Count; i++)
    {
      if (Scenes[i] != default && !LoadedScenes.Contains(Scenes[i]) && (!ClientSceneManagement || MyScenes.Contains(Scenes[i])))
      {
        sceneRef = Scenes[i];
        LoadedScenes.Add(Scenes[i]);
        return false;
      }
    }
    sceneRef = SceneRef.None;
    return true;
}

UnloadOutdatedScenes() 함수는 로드되지 않은 씬이 있는지 탐지하고 해당 씬을 적절하게 제거합니다.

public void UnloadOutdatedScenes(Action<AsyncOperation> removeOutdatedObjects)
{
    _sceneToUnload = LoadedScenes.Except(ClientSceneManagement ? MyScenes.Intersect(Scenes) : Scenes).FirstOrDefault();
    if (_sceneToUnload)
    {
      SceneManager.UnloadSceneAsync(_sceneToUnload).completed += removeOutdatedObjects;
      LoadedScenes.Remove(_sceneToUnload);
    }
}

메인 화면으로

클라이언트 씬 관리

클라이언트 씬 관리 로직은 클라이언트가 관심 있는 씬만 로드하도록 허용하여 동일한 씬에 속하지 않는 영역에 있는 2개의 클라이언트가 현재 씬만 로드할 수 있도록 하는 것입니다. 호스트/서버는 세션에 대한 상태 권한이 있으므로 여전히 모든 씬을 로드해야 합니다.

이미 인용된 씬 목록을 만들어 MyScenes은 원하는 씬을, LoadedScenes은 로컬로 로드된 씬을, Scenes(네트워크로 연결되어야 하는 유일한 씬)는 호스트/서버가 로드한 모든 씬을 지칭하는 씬을 가리킵니다. 클라이언트 씬 관리를 사용하도록 설정한 경우 로드하려는 씬은 LoadedScenes에 없고 MyScenes Scenes이며, 활성화되지 않은 경우 Scenes만 참조로 사용합니다. 언로드할 씬을 감지하는 경우에도 마찬가지입니다.

메인 화면으로

CustomNetworkSceneManagerBase

이 클래스는 NetworkSceneManagerBase의 복제본에 가깝지만 몇 가지 변경 사항이 있습니다. 가장 중요한 것은 구현을 위한 두 가지 추상 메소드를 지정한다는 것입니다.

  • bool IsScenesUpdated() - 로드해야 하는 씬이 있으면 리턴합니다.
  • SceneRef GetDesiredSceneToLoad() - 로드할 누락된 씬의 SceneRef를 리턴합니다.

그리고 이제 여러 씬을 지원하므로 _sceneObjects 딕셔너리에 씬에 찾은 NetworkObject를 추가합니다.

foreach (var sceneObject in sceneObjects)
{
    _sceneObjects.Add(sceneObject.Key, sceneObject.Value);
}

메인 화면으로

CustomNetworkSceneManagerDefault

이 클래스는 CustomNetworkSceneManagerBase에서 상속받으므로 전달된 추상 메소드를 구현합니다.

SwitchScene

유니티 측의 로드 씬을 적절하게 처리하고 해당 씬에 있는 모든 NetworkObjects를 리턴하기 위해 구현해야 하는 코루틴입니다.

메인 화면으로

IsScenesUpdated()

새 씬을 로드해야 하는 시기를 지시합니다. 이 구현에서는 NetworkSceneManager에서 동일한 이름의 함수를 호출하여 언로드할 씬이 있는지 확인합니다.

protected override bool IsScenesUpdated()
{
    if (Runner.SceneManager() && Runner.SceneManager().Object)
    {

        Runner.SceneManager().UnloadOutdatedScenes((op) => RemoveNotValidSceneObjets());

        return Runner.SceneManager().IsSceneUpdated(out _desiredScene);
    }

    return true;
}

메인 화면으로

GetDesiredSceneToLoad()

전에 보인 바와 같이 IsScenesUpdated()에 할당된 로드할 씬 _desiredScene을 반환합니다.


기술문서 TOP으로 돌아가기