2024-10-24
스크립트에서 public 또는 [SerializeField] 로 변수를 선언하고,
Unity 의 인스펙터 창에서 해당 변수에 필요한 게임 오브젝트, 프리팹, 리소스 등을 수동으로 연결해주는 작업.
이러한 이유로, Addressable Asset System 이나 Scriptable Object 같은 시스템을 이용하거나,
코드에서 동적으로 참조를 설정하는 방식 으로 전환하는 것이 좋다고 한다.
Unity 에서 게임 실행 중에 리소스를 동적으로 로드할 수 있게 해주는 메서드
주로 프리팹, 오디오 클립 등을 동적으로 로드하거나 메모리 관리를 최적화할 때 사용된다.
보통 게임의 리소스 (Ex : 텍스쳐, 오디오, 프리팹 등) 는 프로젝트 빌드 시에 메모리에 로드되지만,
Resources.Load 를 사용하면 런타임에 특정 리소스를 메모리에 로드하여 필요한 시점에 사용할 수 있다.Resources 폴더에 있는 파일만 Resource.Load 를 통해 로드할 수 있다.
Assets/Resources/ 뒤의 경로를 입력 받는다.
Instantiate
를 통해 씬에 인스턴스화하여 새로운 오브젝트를 생성한다.public class PrefabTest : MonoBehaviour
{
GameObject prefab;
GameObject tank;
void Start()
{
prefab = Resources.Load<GameObject>("Prefabs/Tank"); // 1
if(prefab != null)
{
tank = Instantiate(prefab); // 2
Destroy(tank, 3.0f); // 3
}
}
}
Resources.Load
는 동기 방식으로 동작한다.Resources
에서 로드된 오브젝트는 수동으로 메모리에서 해제해야 한다.Resources.UnloadUnUsedAssets()
또는 Destroy()
와 같은 메서드를 통해 메모리를 해제해준다.Instantiate
나 Destroy
를 직접 호출하여 오브젝트들을 생성, 소멸시킬 수 있지만, 해당 코드들이 여기저기서 호출된다면 누가 무엇을 언제 만드는지 추적하기 어려워진다.Resource
를 관리하는 매니저를 만들어서 관리를 하도록 하자.리소스를 효율적으로 관리하고 메모리 사용을 최적화 하기 위해서 구현.
리소스 Load
/ UnLoad
를 한 곳에 모아두어 추적이 용이해진다.
Resource.Load
로 리소스를 동적으로 로드한다.Instantiate
나 Destroy
를 중앙 집중화 한다.제네릭(T) 타입으로 구현되어 있어서 다양한 에셋을 불러올 수 있다.
public class ResourceManager
{
public T Load<T>(string path) where T : Object
{
return Resources.Load<T>(path);
}
public GameObject Instantiate(string path, Transform parent = null)
{
GameObject prefab = Load<GameObject>($"Prefabs/{path}"); // 상황에 따라 경로 맞춰주기
if(prefab == null)
{
Debug.Log($"Failed to load prefab : {path}");
return null;
}
return Object.Instantiate(prefab, parent);
}
public void Destroy(GameObject go)
{
if(go == null)
return;
Object.Destroy(go);
}
}
public class Managers : MonoBehaviour
{
static Managers s_instance; // 유일성 보장
static Managers Instance { get { Init(); return s_instance; } } // 유일한 매니저를 가져온다.
InputManager _input = new InputManager();
ResourceManager _resource = new ResourceManager();
public static InputManager Input { get { return Instance._input; } }
public static ResourceManager Resource { get { return Instance._resource; } }
void Start()
{
Init();
}
void Update()
{
_input.OnUpdate();
}
static void Init()
{
if(s_instance == null)
{
GameObject go = GameObject.Find("@Managers");
if(go == null)
{
go = new GameObject { name = "@Managers" };
go.AddComponent<Managers>();
}
DontDestoryOnLoad(go); // 씬이 변경되어도 삭제되지 않고 유지하도록 설정
s_instance = go.GetComponent<Managers>();
}
}
}
public class PrefabTest : MonoBehaviour
{
GameObject prefab;
GameObject tank;
void Start()
{
tank = Managers.Resources.Instantiate("Tank"); // ResourceManager 를 통한 1 + 2
Managers.Resources.Destory(tank); // ResourceManager 를 통한 3
// 기존의 PrefabTest 코드
// 1. prefab = Resources.Load<GameObject>("Prefabs/Tank");
// 2. tank = Instantiate(prefab);
// 3. Destroy(tank, 3.0f);
}
}