유니티 UniTask 정리
- 목차
728x90
먼저 UniTask란?
기존에 있던 Coroutine의 단점을 극복하고자 나온 라이브러리이다.
Coroutine하고 UniTask는 다음과 같이 정리해볼수 있다.
- 실행 방식
- 코루틴: Unity 가 주기적으로 실행
- UniTask: 실행 주기 독립적이며, 즉시 실행
- 성능
- 코루틴: 매 프레임마다 실행되어 오버헤드 발생
- UniTask: 실행 주기 제한 없어 효율적
- 동시성
- 코루틴: 단일 스레드에서 실행되어서 경쟁 상태 발생 가능
- UniTask: 병렬 실행을 위한 도구들을 제공
- 에러 처리
- 코루틴: try-catch로 처리, 복잡할 수 있음
- UniTask: ContinueWith 및 예외 처리 함수로 간편
- 사용 용이성
- 코루틴: 익숙하고 접근성 좋음
- UniTask: 함수형 스타일로 약간의 학습 비용 필요
코루틴은 먼저 매 프레임마다 호출되므로 오버헤드가 발생하는게 제일 크다.
특히 모바일 같은 환경이면 더욱 더 단일코어인 코루틴이면 버벅이는 현상이 심해질 수 있다.
다만 코루틴에 비해 UniTask는 자료도 생각보다 없고 정리가 잘 안되어 있어서 아무래도 배우기 어렵다.
그래서 해당 글은 UniTask관련 함수들과 사용법들을 자세히 알아볼 예정이다.
//먼저 using문을 선언해주어야 한다.
using Cysharp.Threading.Tasks;
//코루틴도 예시로 들거니까 유니티 엔진하고 시스템도 선언해준다.
using UnityEngine;
using System.Collections;
void Start()
{
//UniTask 호출 방법
TestUni().Forget();
//코루틴 호출 방법
TestCoroutine();
}
async UniTaskVoid TestUni()
{
//첫 프레임 스킵
await UniTask.Yield();
//1초 대기
await UniTask.Delay(1000);
//1초 대기
await UniTask.Delay(TimeSpan.FromSeconds(1f));
//Func1Async(), Func2Async()가 모두 완료될때까지 대기
await UniTask.WhenAll(Func1Async(), Func2Async());
// Func1과 Func2 중 하나 완료 시에 실행
await UniTask.WhenAny(Func1Async(), Func2Async());
// FuncAsync 완료 후 실행
await FuncAsync().ContinueWith(_ => {
//쓰고 싶은 메서드나 함수등...
});
// 오류 발생 시 최대 3번 재시도
await UniTaskAsyncEnumerable.Repeat(FuncAsync, 3)
.AsyncRetry();
}
IEnumerator TestCoroutine()
{
//첫 프레임 스킵
yield return new WaitForEndOfFrame();
//1초 대기
yield new WaitForSeconds(1.0f);
//코루틴 끝내기
yield break;
}
코루틴은 예제도 많고 간단해서.. 간단하게 써보았다.
그 외에도 웹에서 호스팅도 가능하고 또한 Dotween과 같이 사용도 가능하다.
다만 Dotween이랑 같이 사용할려면
Edit -> Project Settings->Player->Other Settings->Scripting Define Symbols 에서
UNITASK_DOTWEEN_SUPPORT를 선언해 주어야 한다.
추가로 UniTask를 기준으로 간단한 로딩씬을 구현한 스크립트를 제작해보았다.
이미지의 FillAmount를 기준으로 로딩정도를 차오르게 만들것이다.
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using TMPro;
using Cysharp.Threading.Tasks;
public class LoadingSceneManager : MonoBehaviour
{
public static string nextScene;
[SerializeField] Image ProgressBar;
[SerializeField] Image OtherImage;
[SerializeField] float fillSpeed = 0.1f;
[SerializeField] float otherImageFillSpeed = 0.2f;
private bool fillingOtherImage = true;
void Start()
{
LoadSceneAsync().Forget();
}
public static void LoadScene(string sceneName)
{
nextScene = sceneName;
SceneManager.LoadScene("Loading Scene");
}
async UniTaskVoid LoadSceneAsync()
{
await UniTask.Yield(); // 첫 프레임 스킵
AsyncOperation operation = SceneManager.LoadSceneAsync(nextScene);
operation.allowSceneActivation = false;
float timer = 0.0f;
float targetFillAmount = 0.9f; // 목표로 하는 fillAmount 값 (90%)
float timeToFill = 5.0f; // ProgressBar를 채우는 데 걸리는 시간
while (!operation.isDone)
{
await UniTask.Yield();
timer += Time.deltaTime;
// ProgressBar를 천천히 차게 보이도록 보간 처리
float progress = Mathf.Lerp(ProgressBar.fillAmount, operation.progress, timer / timeToFill);
ProgressBar.fillAmount = progress;
OtherImage.fillAmount = Mathf.Clamp01(OtherImage.fillAmount + (fillSpeed * Time.deltaTime));
if (!(ProgressBar.fillAmount >= targetFillAmount)) continue;
// ProgressBar가 목표치에 도달하면 나머지 시간을 기다린 후 씬 전환
if (timer >= timeToFill)
{
operation.allowSceneActivation = true;
break;
}
if (fillingOtherImage)
{
OtherImage.fillAmount += otherImageFillSpeed * Time.deltaTime;
// OtherImage가 1에 도달하면 빠르게 비우도록 상태 변경
if (!(OtherImage.fillAmount >= 1.0f)) continue;
fillingOtherImage = false;
OtherImage.fillAmount = 1.0f; // 최대로 채운 후 빠르게 비우도록
}
else
{
OtherImage.fillAmount -= otherImageFillSpeed * Time.deltaTime;
// OtherImage가 0에 도달하면 다시 채우도록 상태 변경
if (!(OtherImage.fillAmount <= 0.0f)) continue;
fillingOtherImage = true;
OtherImage.fillAmount = 0.0f; // 최저로 비운 후 빠르게 채우도록
}
}
}
}
728x90
'유니티,Unity,C#' 카테고리의 다른 글
C++, C# 면접 질문 모음집 (0) | 2024.06.12 |
---|---|
유니티 빌드본(PC) 강제 종료 막기(Application.wantsToQuit) (1) | 2023.12.05 |
유로 Assets DamageNumbersPro 리뷰 (1) | 2023.10.29 |
오브젝트 풀링(원하는 스폰지역을 직접 만들어서 넣어주고 랜덤으로 소환) (0) | 2023.06.04 |
유니티 json데이터 암호화하는법(AES암호화방식) (1) | 2023.05.20 |