[Unity 강의] 뱀서라이크 강의 - Addressable

업데이트:

카테고리:

태그: , , ,




리소스 관리

1. 드래그 드롭으로 연결 - 번거롭고 에러가 일어날 수 있다.
2. Resources 폴더를 사용해서 경로로 관리 ex) var a = Resources.Load<GameObject>("Prefabs/Snake_01");
  빌드 시 폴더에 사용 안 하는 Resource가 있을 수 있어서 용량이 커질 수 있다.
  추가 삭제가 어렵다.
3. Addressable 사용
✔ (프로젝트에선 2,3 번을 섞어서 사용)





Addressable

1. Package Manager에서 Addressable 검색 후 설치
2. Window - Asset Management - Addressable - Group - Create Addressable Setting
3. 등록할 Resource를 Addressable 체크 OR 드래그로 그룹에 등록
Image
Image
4. Path 경로, Addressable Name - 키값(원하는 이름으로 바꿔주기)
  - 파일의 위치가 바뀌면 Path 값이 바뀌고 키값을 이용해 찾으면
  - 위치가 바뀌어도 키값으로 경로를 찾을 수 있다. -> 관리가 편해진다.
Image





ResourceManager

✔ 필요한 using 추가
Dictionary<String(Addressable Name),Object>로 리소스 관리.
✔ (Load Instantiate Destroy) 필요한 리소스를 사용할 경우
✔ (LoadAsync LoadAllAsync) 게임에 리소스를 비동기 로드
✔ Label을 이용한 여러 리소스 로드

ResourceManager 코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using System;
using Object = UnityEngine.Object;
using System.Runtime.InteropServices;

public class ResourceManager 
{
    Dictionary<string, UnityEngine.Object> _resources = new Dictionary<string, Object>();

    public T Load<T>(string key) where T : Object
    {
        if (_resources.TryGetValue(key, out Object resource))
            return resource as T;

        return null;
    }

    public GameObject Instantiate(string key, Transform parent = null, bool pooling = false) 
    {
        GameObject prefabs = Load<GameObject>($"{key}");
        if (prefabs==null)
        {
            Debug.Log($"Failed to load Prefabs : {key}");
            return null;
        }

        GameObject go = Object.Instantiate(prefabs, parent);
        go.name = prefabs.name;
        return go;
    }

    public void Destroy(GameObject go) 
    {
        if (go == null)
            return;

        Object.Destroy(go);
    }

    #region 어드레서블
    public void LoadAsync<T>(string key,Action<T> callback = null) where T : UnityEngine.Object 
    {
        // 캐시 확인.
        if (_resources.TryGetValue(key, out Object resource)) 
        {
            callback?.Invoke(resource as T);
            return;
        }

        // 리소스 비동기 로딩 
        var asyncOperation = Addressables.LoadAssetAsync<T>(key);
        asyncOperation.Completed += (op) =>
        {
            _resources.Add(key, op.Result);
            callback?.Invoke(op.Result);
        };
    }

    public void LoadAllAsync<T>(string label, Action<string, int, int> callback) where T : UnityEngine.Object
    {
        // Action<string, int, int> => <Key, loadCount, totalCount>   loadCount, totalCount는 유동적 필요x면 없어도된다.
        var opHandle = Addressables.LoadResourceLocationsAsync(label, typeof(T));
        opHandle.Completed += (op) =>
        {
            int loadCount = 0;
            int totalCount = op.Result.Count;

            foreach (var result in op.Result)
            {
                LoadAsync<T>(result.PrimaryKey, (obj) =>
                {
                    loadCount++;
                    callback?.Invoke(result.PrimaryKey, loadCount, totalCount);
                });
            }
        };
    }
    #endregion
}


GameScene 코드에서 Resource활용
public class GameScene : MonoBehaviour
{
    void Start()
    {
        Managers.Resource.LoadAllAsync<GameObject>("Prefabs", (key,count,totalCount) =>
        {
            Debug.Log($"{key} {count}/{totalCount}");

            if (count==totalCount)
            {
                StartLoaded();
            }
        });
    }

    void StartLoaded() 
    {
        // Resources폴더에서 찾는 방식
        // var a = Resources.Load<GameObject>("Prefabs/Snake_01");

        var player = Managers.Resource.Instantiate("Slime_01.prefab");
        player.AddComponent<PlayerController>();

        GameObject monsterObjects = new GameObject() { name = "@Monsters" };
        var snake = Managers.Resource.Instantiate("Snake_01.prefab", monsterObjects.transform);
        var goblin = Managers.Resource.Instantiate("Goblin_01.prefab", monsterObjects.transform);
        var joystick = Managers.Resource.Instantiate("UI_Joystick.prefab");
        joystick.name = "@UI_Joystick";

        var map = Managers.Resource.Instantiate("Map.prefab");

        map.name = "@Map";
        Camera.main.GetComponent<CameraController>().Target = player;
    }
}



Label을 이용한 리소스 로드

✔ 필요할 때 리소스를 불러오지 않고 게임 시작 시 로딩 화면에서 필요한 Resource를 다 불러온다.
✔ Labels를 이용하는 방식 - Labels - (+) Prefabs
✔ 해당 라벨에 포함된 모든 리소스 로드
✔ -> 키값 추출해서 foreach 비동기 로딩
LoadAllAsync 코드





이것저것 메모

폴더를 Addressable

✔ 폴더 자체를 Addressable로 만들 수도 있다.
Image

프리팹 로드 시 포함된 리소스

✔ 프리팹 로드 시 프리팹에 포함된 Sprite도 같이 로드된다.
✔ 하지만 Sprite가 따로 로드가 필요하면 등록해주면 된다.

람다 복습

✔ GameScene - LoadAllAsync 사용하는 부분
✔ 람다 -> 메서드로?

void Start()
{
    Managers.Resource.LoadAllAsync<GameObject>("Prefabs", (key,count,totalCount) =>
    {
        Debug.Log($"{key} {count}/{totalCount}");
        if (count==totalCount)
        {
            StartLoaded();
        }
    });
}
-----------------------------------------------------------------

private void LambdaTest(string key, int count, int totalCount)
{
    Debug.Log($"{key} {count}/{totalCount}");
    if (count == totalCount)
    {
        StartLoaded();
    }
}

void Start()
{
    Managers.Resource.LoadAllAsync<GameObject>("Prefabs",LambdaTest);
}





잡담, 일기?

데이터로 만들어서 관리가 핵심적이다.
어드레서블 기능이 더 많아서 알아보자.




📔

댓글남기기