유니티
[Unity] 씬을 통한 씬 로딩
- -
현재 문제점
- 씬을 이동하면서 발생하는 문제로
하나의 씬에서 다른 씬을 불러오면서 메모리 로드 용량이 너무 비대해지니까
씬을 로딩하면서 게임이 멈춰버리는 현상을 발견
해결 방법
- 중간에 빈 LoadingScene를 불러들여 다음씬으로 이동
조건 1. 씬 로딩 시 로딩 시 로딩씬을 불러들려야함.
조건 2. 로딩씬을 불러들일 때 로딩의 상태를 가지고 있어야 됨[게임 동작을 위함]
조건 3. 로딩된 씬에서 다음 씬에 전달할 내용을 가지고 있어야 함[튜토리얼 시작 또는 스킵]
첫번째. 로딩에 사용할 전역 변수 생성
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
/// <summary>
/// 씬을 로딩할 때 사용하는 중간 대리자
/// </summary>
public class SceneLoader :MonoBehaviour
{
//씬이 로드가 되었는가?
public static bool Loaded = true;
public static string name_Title = "TitleScene";
public static string name_Main = "Main";
public void LoadScene(string name, Action action = null)
{
DontDestroyOnLoad(gameObject);
//게임 진행을 막기 위함
Time.timeScale = 0.0f;
if (!Loaded)
{
Debug.Log("이미 씬 로딩 중");
return;
}
Loaded = false;
//1. 로딩 씬 로드
StartCoroutine(LoadCroutine(name, action));
}
IEnumerator LoadCroutine(string name, Action action)
{
Debug.Log("로딩 씬 로드 시작");
AsyncOperation _operation = SceneManager.LoadSceneAsync("LoadScene");
_operation.allowSceneActivation = false;
//로드가 끝날때까지 기다린다.
while (_operation.progress <0.9f)
{
yield return null;
}
_operation.allowSceneActivation = true;
while (!_operation.isDone)
{
yield return null;
}
Debug.Log("로딩 씬 로딩이 완료 되었습니다.");
LoadSceneLoader loader = FindObjectOfType<LoadSceneLoader>();
//씬 종료 후 실행할 옵션
if (action != (null))
{
loader.SetLoadEndAction(action);
}
//씬 로딩 진행
loader.Load(name);
Debug.Log("로딩 글로벌 로더 오브젝트 삭제");
Destroy(gameObject);
}
public static void Load(string name, Action action = null)
{
if (Loaded)
{
GameObject go = new GameObject("SceneLoaderGlobal");
go.AddComponent<SceneLoader>().LoadScene(name, action);
}
}
}
-씬이 로드를 위한 로딩씬 로드를 하여 메모리 사용량을 감소시킨다.
- 해당 스크립트에서 로딩씬에서 사용하는 로드스크립트를 찾아 다음 씬을 로드합니다.
- action을 통해 모든 씬이 로딩이 되고나서 행해야될 동작을 수행합니다.
두번째. 로딩씬에 있는 씬 로더
using System;
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Random = UnityEngine.Random;
public class LoadSceneLoader : MonoBehaviour
{
[SerializeField] CanvasGroup c_group;
[SerializeField] Image image_progress;
[SerializeField] TMP_Text loadingTip;
string CurrentSceneName ="TitleScene";
//로딩이 끝나고 나서의 실행 함수를 지정합니다.
public Action action_endLoad;
private void Start()
{
DontDestroyOnLoad(gameObject);
}
//씬을 로딩합니다.
public void Load(string _name)
{
//종료 후 씬 정상 동작을 위함
Time.timeScale = 0.0f;
CurrentSceneName = _name;
StartCoroutine(LoadCroutine());
}
IEnumerator LoadCroutine()
{
//텍스트 표시
loadingTip.text = LocalLanguageSetting.Instance.GetLocalText("Tip", $"Loading{Random.Range(1, 3)}");
//step 1 fadeinScreen
yield return FadeInCroutine();
Debug.Log("씬을 로드 합니다 : " + CurrentSceneName);
AsyncOperation _operation = SceneManager.LoadSceneAsync(CurrentSceneName);
_operation.allowSceneActivation = false;
//step 2 view progressBar
float _progress = 0.0f;
while (_progress < 0.89f)
{
if(_progress > _operation.progress) { continue; }
_progress += Time.unscaledDeltaTime * 0.333f;
image_progress.fillAmount = _progress;
yield return null;
}
_operation.allowSceneActivation = true;
Debug.Log("씬 로드에 성공했습니다. : " + CurrentSceneName);
//작업이 끝날때까지 대기 시킨다.
while (!_operation.isDone)
{
Debug.Log("맵을 불러오고 있습니다.");
image_progress.fillAmount = _operation.progress;
yield return null;
}
//화면을 보여준다.
yield return FadeOutCroutine();
//씬 로드가 되면서 지정된 동작을 수행합니다.
if (action_endLoad != null) { action_endLoad(); action_endLoad = null; }
//로드의 종료를 알림
SceneLoader.Loaded = true;
//다시 정상 동작
Time.timeScale = 1.0f;
Debug.Log("씬 로더 오브젝트 삭제 : " + name);
Destroy(gameObject);
}
~LoadSceneLoader()
{
Debug.LogWarning($"{name} 오브젝트 삭제");
}
//화면을 가린다.
IEnumerator FadeInCroutine()
{
float t = 0.0f;
while (t < 1.0f)
{
c_group.alpha = t;
t += Time.unscaledDeltaTime * 0.5f;
yield return null;
}
yield return null;
c_group.alpha = 1;
Debug.Log("화면 Fadein 되었습니다.");
}
//화면을 보여준다.
IEnumerator FadeOutCroutine()
{
float t = 1.0f;
while (t > 0.0f)
{
c_group.alpha = t;
t -= Time.unscaledDeltaTime * 0.5f;
yield return null;
}
c_group.alpha = 0;
Debug.Log("화면 Fadeout 되었습니다.");
}
//씬 종료 후 실행할 동작 지정
public void SetLoadEndAction(Action _action)
{
action_endLoad = _action;
}
}
- 다음으로 호출할 씬 이름을 통해 다음 씬을 호출
- 호출된 씬은 Action에 정의된 내용을 통해 다음 동작을 수행하고 씬이 변경됨
동작
정리
씬 용량이 크다보니 씬을 통한 로딩이 필요함을 느꼈고, 이를 적용하였다.
씬을 로딩할 때,
AsyncOperation _operation = SceneManager.LoadSceneAsync(CurrentSceneName);
의 기능을 통해 씬 로드 상태를 판단할 수 있어 좋았다.
씬이 로드되면 오브젝트가 모두 삭제되기 때문에 오브젝트를 임시로 DontDestroyOnLoad()로 지정했다가
모든 씬이 로드되고 난 후에 삭제한다.
이럴 줄 알았으면...한 스크립트에서 모두 해결할 것을 그랬다..
'유니티' 카테고리의 다른 글
[Unity] 오브젝트 깜빡거리는 문제 (0) | 2024.01.29 |
---|---|
[Unity] 최적화 과정 [코드 포함] (1) | 2024.01.21 |
[Unity]유니티 UI 최적화 (0) | 2023.11.25 |
[Unity] 유니티 카메라 안에 오브젝트 판단 GetDistanceToPoint (1) | 2023.11.25 |
유니티 단축키 (2) | 2023.11.25 |
Contents
공감은 먹으면 김빠져(푸핫)