Scene Loading Sample
- 개요
- 하이라이트
- 프로젝트
- NetworkSceneManager
- 클라이언트 씬 관리
- CustomNetworkSceneManagerBase
- CustomNetworkSceneManagerDefault
개요
Fusion Scene Loading 샘플은 개발자가 필요한 대로 조작할 수 있는 Fusion을 사용한 씬 로딩 방법을 보다 사용자 지정 가능한 방식으로 탐색하고 보여줍니다. 간단한 한 씬 로드 대신, 가산 로드를 사용하여 동시에 로드할 수 있는 최대 4개의 씬을 사용하며, 각 플레이어가 서버에 로드된 씬 중 어떤 장면을 자신 쪽에 로드하고 싶은지 지시할 수 있습니다.
하이라이트
- 씬 로딩 사용자 지정 가능
- 동시에 씬 최대 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
을 반환합니다.