인프런 커뮤니티 질문&답변

술홍님의 프로필 이미지
술홍

작성한 질문수

유니티 Addressable 을 이용한 패치 시스템 구현

Addressable 핵심 파일 및 플로우 정리

animator안의 animatorcontroller를 불러올수없어요

작성

·

164

0

상황은 이렇습니다.

어떤 캐릭터 프립펩이 있고

그 프리펩안에 animator 컴포넌트를 넣어두었습니다.

그리고 그 animator컴포넌트안에 animatorcontroller를 만들어서 넣어놓은 상황입니다. animatorcontroller안에는 여러가지 애니메이션을 넣어둔상태입니다.

 

이상태에서 캐릭터 프리펩을 addressable에 할당했습니다.

animatorcontroller파일도 addressable에 할당했습니다.

두개를 같은 어드레서블 그룹에 넣은후에

어드레서블을 빌드한후에 서버에 올렸고

using System.Collections;

using System.Collections.Generic;

using System.Linq;

using UnityEngine;

using UnityEngine.AddressableAssets;

using UnityEngine.UI;

public class DownManager : MonoBehaviour

{

[Header("UI")]

public GameObject waitMessage;

public GameObject downMessage;

public Slider downSlider;

public Text sizeInfoText;

public Text downValText;

[Header("Label")]

public AssetLabelReference prefabLabel;

public AssetLabelReference materialLabel;

public AssetLabelReference animationLabel;

public AssetLabelReference textureLabel;

private long patchSize;

private Dictionary<string, long> patchMap = new Dictionary<string, long>();

void Start()

{

waitMessage.SetActive(true);

downMessage.SetActive(false);

StartCoroutine(InitAddressable());

StartCoroutine(CheckUpdateFiles());

}

IEnumerator InitAddressable()

{

var init = Addressables.InitializeAsync();

yield return init;

}

#region Chek Down

IEnumerator CheckUpdateFiles()

{

var labels = new List<string>() { prefabLabel.labelString, materialLabel.labelString, animationLabel.labelString, textureLabel.labelString};

patchSize = default;

foreach (var label in labels)

{

var handle = Addressables.GetDownloadSizeAsync(label);

yield return handle;

patchSize += handle.Result;

}

if (patchSize > decimal.Zero)

{

//Down

waitMessage.SetActive(false);

downMessage.SetActive(true);

sizeInfoText.text = GetFileSize(patchSize);

}

else

{

downValText.text = " 100 % ";

downSlider.value = 1f;

yield return new WaitForSeconds(2f);

LoadingManager.LoadScene("MainLobby");

}

}

private string GetFileSize(long byteCnt)

{

string size = "0 Bytes";

if (byteCnt >= 1073741824.0)

{

size = string.Format("{0:##.##}", byteCnt / 1073741824.0) + " GB";

}

else if (byteCnt >= 1048576.0)

{

size = string.Format("{0:##.##}", byteCnt / 1048576.0) + " MB";

}

else if (byteCnt >= 1024.0)

{

size = string.Format("{0:##.##}", byteCnt / 1024.0) + " KB";

}

else if (byteCnt > 0 && byteCnt < 1024.0)

{

size = byteCnt.ToString() + " Bytes";

}

return size;

}

#endregion

#region DownLoad

public void Button_DownLoad()

{

StartCoroutine(PatchFiles());

}

IEnumerator PatchFiles()

{

var labels = new List<string>() { prefabLabel.labelString, materialLabel.labelString, animationLabel.labelString, textureLabel.labelString};

foreach (var label in labels)

{

var handle = Addressables.GetDownloadSizeAsync(label);

yield return handle;

if (handle.Result != decimal.Zero)

{

StartCoroutine(DownLoadLabel(label));

}

}

yield return CheckDownLoad();

}

IEnumerator DownLoadLabel(string label)

{

patchMap.Add(label, 0);

var handle = Addressables.DownloadDependenciesAsync(label, false);

while (!handle.IsDone)

{

patchMap[label] = handle.GetDownloadStatus().DownloadedBytes;

yield return new WaitForEndOfFrame();

}

patchMap[label] = handle.GetDownloadStatus().TotalBytes;

Addressables.Release(handle);

}

IEnumerator CheckDownLoad()

{

var total = 0f;

downValText.text = "0 %";

while (true)

{

total += patchMap.Sum(tmp => tmp.Value);

downSlider.value = total / patchSize;

downValText.text = (int)(downSlider.value * 100) + " %";

if (total == patchSize)

{

yield return new WaitForSeconds(1f); // 지연 시간 추가

LoadingManager.LoadScene("MainLobby");

break;

}

total = 0f;

yield return new WaitForEndOfFrame();

}

}

#endregion

}

이렇게 다운로드를 받았습니다.

 

그리고나서

using System.Collections;

using System.Collections.Generic;

using System.IO;

using UnityEngine;

using UnityEngine.AddressableAssets;

using UnityEngine.ResourceManagement.AsyncOperations;

public class GameManager : MonoBehaviour

{

public GameObject _player;

public Dictionary<string, string> stateNameMap = new Dictionary<string, string>();

private IEnumerator CreateCharacter()

{

var initializeOperation = Addressables.InitializeAsync();

yield return initializeOperation;

if (initializeOperation.Status == AsyncOperationStatus.Succeeded)

{

Debug.Log("Addressables initialized successfully");

LocalPlayerLoad();

}

}

private void Start()

{

StartCoroutine(CreateCharacter());

}

public void LocalPlayerLoad()

{

Addressables.InstantiateAsync("Assets/Project/Asset/Prefab/Human.prefab", new Vector3(0, 0, 0), Quaternion.identity).Completed += callback =>

{

if (callback.Status == AsyncOperationStatus.Succeeded)

{

_player = callback.Result;

}

};

}

}

이렇게 Human이라는 프리펩을 불러왔는데 animator창을 열고 불러와진 Human캐릭터를 하이어라키에서 선택을하면 현재 애니메이션의 상태가 보여야하는데

이런식으로 나오는겁니다.. 이건 animatorcontroller를못불러온건가요? 아니면 addressable로 지정하면 원래 볼수없는건가요? 근데 이렇게 나오면 애니메이션 상태를 볼수없기때문에 디버깅이 너무 어려워지는데.. 제가 뭔가 잘못한게 맞겠죠?

답변 1

0

안녕하세요, 인프런 AI 인턴입니다.

님의 문제는 Addressable 시스템을 이용하여 에셋을 로드할 때, Unity Editor 내에서 에셋의 상세 정보(여기서는 Animator Controller의 상태)를 직접적으로 확인하기 어렵다는 점에서 발생합니다. Unity의 Addressable Asset 시스템은 게임의 빌드 크기를 줄이고, 필요할 때 원격이나 로컬에서 에셋을 동적으로 로드할 수 있도록 설계되었습니다. 그러나, 이 시스템을 사용하면 에셋이 런타임에만 로드되기 때문에, Editor에서는 에셋의 상세 내용을 직접 볼 수 없습니다.

이런 문제에 대한 하나의 해결 방법은 에셋을 로드한 뒤, 코드를 통해 에셋의 세부 사항을 로그로 출력하거나 디버그하는 방법입니다. 예를 들어, Animator 컴포넌트를 로드한 후, 해당 컴포넌트의 상태나 포함된 애니메이션 클립 목록 등을 Debug.Log를 사용해 출력할 수 있습니다. 이 방법은 런타임에만 가능하지만, 문제 진단에 도움이 될 수 있습니다.

또 다른 방법으로, 개발 과정에서 일시적으로 Addressable이 아닌 일반적인 에셋 참조를 사용해 에딧터 내에서 에셋을 확인하고, 문제가 해결된 후 다시 Addressable로 전환하는 방식도 있습니다. 이렇게 하면 개발 단계에서 에셋의 상태를 더 쉽게 확인하고 디버깅할 수 있습니다.

결론적으로, Addressable을 사용할 경우 원래 볼 수 없는 것이 일반적입니다. 디버깅이 어려울 경우, 위에서 제안한 방법을 시도해 보시기 바랍니다. Addressable 시스템은 효율적인 에셋 관리와 성능 최적화를 위해 매우 유용하지만, 개발 과정에서는 몇 가지 추가적인 고려 사항이 필요합니다.

술홍님의 프로필 이미지
술홍

작성한 질문수

질문하기