변경점
- UGS 인증을 별도의 클래스로 만들어주었습니다. 또한 UGS에 로그인을 한 뒤 Vivox에 로그인 하도록 변경하였습니다.
public class NetworkAuthenticate : MonoSingleton<NetworkAuthenticate>
{
public TMP_InputField nameInput;
//로그인 성공시 호출
public event Action OnAuthenticateSuccessEvent;
private readonly string loginText = "Connecting";
protected async override void Awake()
{
Create();
if (Instance != this)
{
Destroy(gameObject);
}
await UnityServices.InitializeAsync();
}
//인증 메서드 - UGS에 연결
public async void Authenticate()
{
LoadingSceneController.Instance.ActiveNetworkLoadingUI(loginText);
string playerName;
//플레이어 프로필 설정
playerName = nameInput.text;
try
{
AuthenticationService.Instance.SwitchProfile(playerName);
//인증 시도
await AuthenticationService.Instance.SignInAnonymouslyAsync();
await AuthenticationService.Instance.UpdatePlayerNameAsync(playerName);
}
catch (Exception ex)
{
Debug.Log(ex);
Debug.Log("UGS 연결 실패");
}
try
{
await VivoxAuthenticate();
}
catch (Exception ex)
{
Debug.Log(ex);
Debug.Log("Vivox 로그인 실패");
}
OnAuthenticateSuccessEvent?.Invoke();
}
public async Task VivoxAuthenticate()
{
await VivoxService.Instance.InitializeAsync();
LoginOptions options = new LoginOptions();
options.DisplayName = AuthenticationService.Instance.PlayerName;
await VivoxService.Instance.LoginAsync(options);
}
}
Vivox 를 여기서 로그인하고 게임에 참여할 때는 채팅 채널에 참여하기만 하도록 수정해주었습니다.
- NetworkObject들의 스폰을 클라이언트의 씬 로드후 시점으로 변경하였습니다.
public class NetworkSpawnController : MonoSingleton<NetworkSpawnController>
{
//...생략
protected override void Awake()
{
Create();
if (Instance != this)
{
Destroy(gameObject);
}
NetworkManager.Singleton.SceneManager.OnSynchronizeComplete += SpawnManager;
}
public void SpawnManager(ulong clientId)
{
if (NetworkManager.Singleton.IsHost && NetworkManager.ServerClientId != clientId)
{
NetworkObject netGameManager = Instantiate(networkGameManager);
netGameManager.Spawn(true);
}
}
//... 생략
}
현재 NetworkGameManager 오브젝트가 스폰되는것을 기점으로 추가적으로 캐릭터등의 NetworkObject들이 스폰되도록 되어있습니다.
NetworkGameManager 의 스폰을 NetworkSpawnController 로 옮겨주었으며, 스폰 메서드를 NetworkSceneManager 의 OnSynchronizeComplete 이벤트에 구독시킴으로써, 클라이언트가 씬 로드를 끝내고 동기화를 끝내면 스폰을 시작하도록 변경해주었습니다.
추가된 내용
- LoadingScene 추가
네트워크 연결, 씬 로드등의 상황에서 버튼등과의 상호작용을 막고, 현재 씬을 로드하거나 인터넷 연결중임을 보여줄 수 있는 UI를 추가해주었습니다
이는 로비에서 로그인할때, 로비에서 게임씬으로 넘어갈때, 게임씬에서 로비씬으로 넘어갈때 모두 사용되어야하기 때문에 별도의 씬을 만든 뒤, Addictive 로 씬을 중첩하여 사용하도록 만들어주었습니다.
Addictive 형태로 씬 로딩을 변경하면서, 다른 씬으로 넘어가는 스크립트에 변경이 생겼습니다.
public class NetworkSceneChanger : MonoSingleton<NetworkSceneChanger>
{
private Scene currentScene;
public string VoiceChannelName { get; set; }
private void Start()
{
currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene("LoadingScene", LoadSceneMode.Additive);
//씬 로드후, ActiveScene 내용을 바꿔주기 위해 사용
SceneManager.sceneLoaded += OnSceneLoad;
}
public void ChangeScene(string sceneName)
{
//이전의 Active씬 언로드
SceneManager.UnloadSceneAsync(currentScene);
if (NetworkManager.Singleton.IsHost)
{
//호스트가 씬 변경후, 클라이언트와 씬을 동기화
NetworkManager.Singleton.SceneManager.ActiveSceneSynchronizationEnabled = true;
NetworkManager.Singleton.SceneManager.SetClientSynchronizationMode(LoadSceneMode.Additive);
NetworkManager.Singleton.SceneManager.LoadScene(sceneName, LoadSceneMode.Additive);
}
}
private void OnSceneLoad(Scene scene, LoadSceneMode mode)
{
//로딩씬이 로드될때는 작동하지 않음
if (scene.name == "LoadingScene") return;
//ActiveScene 변경
SceneManager.SetActiveScene(scene);
currentScene = scene;
}
public void ClientChangeScene(string sceneName)
{
//연결 해제등의 이유로 서버를 통해서가 아닌 클라이언트가 씬을 변경할때 사용
SceneManager.UnloadSceneAsync(currentScene);
SceneManager.LoadScene(sceneName, LoadSceneMode.Additive);
Scene changedScene = SceneManager.GetSceneByName(sceneName);
SceneManager.SetActiveScene(changedScene);
currentScene = changedScene;
}
}
게임을 시작할때는 NetworkSceneManager를 통해 호스트가 씬 변경을 시도하게됩니다. 이때, 호스트와 클라이언트는 모두 이전의 ActiveScene 인 로비씬을 언로드 합니다.
또한, 클라이언트는 호스트와 동기화된 씬을 로드할 수 있도록 설정해주었습니다.
씬이 로드되면 클라이언트와 호스트는 개별적으로 SceneManager 의 sceneLoaded 이벤트를 통해 OnSceneLoad 메서드를 작동시켜서 Addictive 로 로드된 씬을 ActiveScene으로 변경하고 현재 씬 정보를 저장합니다.
저장된 씬 정보는 이후 씬을 변경할 때, 해당씬의 언로드를 위해 사용됩니다.
Addictive 형태로 씬을 로드할경우, ActiveScene이 이전 씬으로 되어있으며, Instantiate 같은 생성 메서드의 경우 ActiveScene 에서 오브젝트를 생성해주기 때문에 ActiveScene 을 변경해주는 작업이 별도로 필요했습니다.
※ 아직 씬이 로드된 뒤 로딩 이미지를 끄는 기능을 만들지 않았습니다.
이 로딩 이미지를 끄는 기능을 만들면서, 로딩이 완료되면 플레이어가 움직일 수 있도록 하는 기능을 추가로 만들게될것 같습니다.
트러블슈팅
- 클라이언트 플레이어의 씬이 로드되지 않는 현상
- Vivox 로그인 시점을 옮기면서 로딩이 빨라지게되었고, 클라이언트가 연결되고 씬 로드를 하기 전에 호스트의 씬이 로드되고 NetworkObject들을 생성하면서 이러한 문제가 발생한것으로 보입니다.
- 현재 NetworkManager를 통해서가 아닌, 씬 로드후 플레이어 캐릭터를 스폰하는 방식을 사용하는데 이때 클라이언트에게 소유권이 넘어가지 않는듯한 모습을 보였습니다.
- 이후, 클라이언트의 씬이 로드된 후 오브젝트들을 생성하면서 문제가 해결되었습니다.
- 로비씬이 Unload 되지 않는 현상
- NetworkSceneManager를 통해 Load 와 Unload를 이어서 사용할경우, 아래에 위치한 코드가 작동되지 않는것을 확인하였습니다.
- 이전씬을 각자 삭제한 뒤, 씬 로드를 NetworkSceneManager를 사용하여 호출하고, 클라이언트의 씬 내용을 호스트에게 동기화 하는것으로 문제를 해결하였습니다.
'내일배움캠프 > 프로젝트' 카테고리의 다른 글
팀 프로젝트 - 맵 에디터 기반 제작 (0) | 2024.12.11 |
---|---|
팀 프로젝트 - 클라이언트 캐릭터 위치문제 (0) | 2024.12.10 |
팀 프로젝트 - 리팩토링 대상 정리 (0) | 2024.12.05 |
팀 프로젝트 진행 - 멀티플레이 구현 (0) | 2024.12.04 |
팀프로젝트 진행 - 재시작 문제 해결 (0) | 2024.12.03 |