[유니티] 게임 진입 구조잡기 - as연산자, 비동기식 데이터 로드
==새로 알게된 부분==
- App
public void ChangeScene(eSceneType sceneType)
{
Debug.LogFormat("ChangeScene: {0}", sceneType);
var oper = SceneManager.LoadSceneAsync(sceneType.ToString());
switch (sceneType)
{
case eSceneType.Title:
//비동기 로드
oper.completed += (obj) => {
//씬로드가 완료됨 (메모리에 다 올라감)
//인스턴스에 접근 가능
this.titleMain = GameObject.FindObjectOfType<TitleMain>();
this.titleMain.uiDirector.onClick = () => {
this.ChangeScene(eSceneType.Loading);
};
this.titleMain.Init();
};
break;
case eSceneType.Loading:
oper.completed += (obj) => {
var loadingMain = GameObject.FindObjectOfType<LoadingMain>();
loadingMain.Init();
};
break;
case eSceneType.Lobby:
oper.completed += (obj) => {
};
break;
}
}
- SceneManager.LoadSceneAsync() - 반환타입 : AsyncOperation
- 유니티는 SceneManager 클래스를 사용해 씬 전환을 제어할 수 있다. 씬 전환을 제어하는 방식은 동기화 방식과 비동기화 방식으로 나눌 수 있다. 동기화 방식은 씬을 호출하는 행동 이외에, 다른 작업을 수행하지 않는다. 비동기화 방식은 씬을 호출하는 동시에 현재 진행 중인 작업을 계속 실행하고, 씬의 호출이 완료되면, 씬을 불러온다.
- 일반적으로 사용하는 LoadScene() 메서드를 사용하면 게임이 멈추고 해당 로딩이 끝날때 까지 멈춤이 지속되기 때문에 유저에게 불편한 경험을 줄수 있다. 그렇기에 SceneManager.LoadSceneAsync() 코루틴를 사용하면 비동기적으로 씬을 로드할수 있고 게임이 끊기지 않고 매끄럽게 진행하게 만드는게 가능하다.
- 아래는 AsyncOperation 클래스의 프로퍼티 목록이다.
- allowSceneActivation : 씬을 활성화 시킨다.
- isDone : 씬의 호출이 완료 되었는지를 확인한다. 완료되면 isDone은 true 값을 가진다.
- progress : 씬의 호출이 얼마나 이루어 졌는지 알려주는 값이다. 0~1.0사이의 값을 가진다. 1.0이 되면, isDone은 True로 값을 가진다.
- priority : 멀티씬을 로드할 때 씬을 호출하는 순서를 나타낸다
- .completed 이벤트 : 작업완료시 호출되는 이벤트함수 (쉽게 말해 로딩이 다 되었을때 사용할수 있는 이벤트 함수)
- AsyncOperation - Uunity Api: Link
- AsyncOperation - Uunity Api: Link
Unity - Scripting API: SceneManagement.SceneManager.LoadSceneAsync
You can provide the full Scene path, the path shown in the Build Settings window, or just the Scene name. If you only provide the Scene name, Unity loads the first Scene in the list that matches. If you have multiple Scenes with the same name but different
docs.unity3d.com
Unity - Scripting API: AsyncOperation
AsyncOperation class in UnityEngine / Inherits from:YieldInstruction / Implemented in:UnityEngine.CoreModule Description Asynchronous operation coroutine. Properties allowSceneActivationAllow Scenes to be activated as soon as it is ready. isDoneHas the ope
docs.unity3d.com
- AssetManager
public IEnumerator LoadAsync(string fullPath)
{
var req = Resources.LoadAsync<GameObject>(fullPath);
yield return req;
//어셋로드 완료
var arr = fullPath.Split('/');
var key = arr[arr.Length - 1];
this.dicPrefabs.Add(key, (GameObject)req.asset);
++this.loadedAssetCount;
Debug.LogFormat("{0}/{1}\t{2}", this.loadedAssetCount, DataManager.instance.GetAssetDatas().Count, fullPath);
var per = (float)this.loadedAssetCount / DataManager.instance.GetAssetDatas().Count;
this.onProgress(per);
}
- Resources.LoadAsync<T>(path) - 반환타입 ResourceRequest
- 지정된 경로에서 특정 오브젝트를 비동기로 로드한다.
- ResourceRequest 타입 데이터는 AsyncOperation타입의 데이터와 마찬가지로 Event액션을 포함한 프로퍼티들을 사용 가능하다.
- https://docs.unity3d.com/kr/530/ScriptReference/Resources.LoadAsync.html
Resources-LoadAsync - Unity 스크립팅 API
Asynchronously loads an asset stored at path in a Resources folder.
docs.unity3d.com
==오랜만에 내용==
- App
private void Awake()
{
DontDestroyOnLoad(this.gameObject);
}
- 씬이 전환될때 DontDestroyOnLoad(GameObject)메서드를 이용하여 오브젝트가 삭제되는것을 막을수 있다.
public void ChangeScene(eSceneType sceneType, SceneArgs args = null)
{
Debug.LogFormat("ChangeScene: {0}", sceneType);
var oper = SceneManager.LoadSceneAsync(sceneType.ToString());
switch (sceneType)
{
case eSceneType.Title:
//비동기 로드
oper.completed += (obj) => {
//씬로드가 완료됨 (메모리에 다 올라감)
//인스턴스에 접근 가능
this.titleMain = GameObject.FindObjectOfType<TitleMain>();
this.titleMain.uiDirector.onClick = () => {
this.ChangeScene(eSceneType.Loading);
};
this.titleMain.Init();
};
break;
case eSceneType.Loading:
oper.completed += (obj) =>
{
var loadingMain = GameObject.FindObjectOfType<LoadingMain>();
loadingMain.onComplete = () =>
{
Debug.Log("onComplete 정의 완료");
this.ChangeScene(eSceneType.Lobby);
};
loadingMain.Init();
};
break;
case eSceneType.Lobby:
oper.completed += (obj) =>
{
var lobbyMain = GameObject.FindObjectOfType<UILobbyMain>();
lobbyMain.onClickStartGame = (selectedId) =>
{
var args = new GameSceneArgs() { selectedCharacterId = selectedId };
this.ChangeScene(eSceneType.Game, args);
};
lobbyMain.Init();
};
break;
case eSceneType.Game:
oper.completed += (obj) => {
var gameSceneArgs = args as GameSceneArgs;
var gameMain = GameObject.FindObjectOfType<GameMain>();
gameMain.Init(gameSceneArgs.selectedCharacterId);
};
break;
}
}
- as 연산자
- 클래스간의 캐스팅 작업시 사용하는 연산자
- 생성자로 생성된 부모클래스 변수를 자식 클래스 변수에 할당하려고 하면 컴파일 에러가 난다 (이는 형식 변환을 해주어도 마찬가지)
- 이럴때 as 연산자는 업캐스팅이 가능하다면 변수에 할당하고 불가능하다면 null 값을 반환한다.
- 또 다른 is 연산자는 업캐스팅이 가능한지 아닌지에대해 부울 값을 반환한다
- SceneArgs 클래스를 상속받은 GameSceneArgs 클래스 변수(UILobbyMain에서 액션 대리자로 전달받은 매개변수를 필드로 가지고 있는 GameSceneArgs 클래스) 를 ChangeScene 메서드의 매개변수로 전달해주고 (씬을 전환하는 기능을 하는 메서드를 만들었다) 해당 변수가 GameSceneArgs 타입으로 다운 캐스팅 되어변수에 담길수 있게 도와준 기능을 한게 as 연산자 였다. 이후 해당 변수의 필드를 GameMain script의 Init함수로 전달 받을수 있게 하였다. (제대로 이해한게 맞는지 좀더 살펴보아야겠다.)
- UITitleDirector
this.txtVersion.text = string.Format("v{0}", Application.version);
- Application.version 프로퍼티
- 앱의 버전설정 (Build Setttings 에서 설정 가능)