
오전에는 레시피 정보와 인벤토리 정보를 제작 UI에 연동시키는 작업과 제작 메서드 기능을 마무리했고, 오후에는 프로젝트를 URP로 변환하는 작업과 에디터 툴 생성 관련하여 R&D를 진행했다. 내일까지 프로토타입을 만들고 싶은데 아직 플레이어가 통합이 안돼서 걱정이 된다.
이번에 공유할 코드는 로직보다는 Unity Editor를 활용하는 기능을 소개하려한다. 4일차에 구현한 S.O 자동생성 툴을 사용하여 CSV 파일을 기반으로 아이템, 레시피 S.O를 생성하였다면, 이를 저장하기 위한 자료구조로 Dictionary를 가지는 클래스를 선언할 수 있다.
ItemDictionary단순히 데이터 저장으로 사용할 것이기 때문에 이 또한 S.O로 구현하였고 여기에 Unity Editor를 활용하는 예시 코드를 작성했다.
[CreateAssetMenu(menuName = "ItemDictionary")]
public class ItemDictionary : ScriptableObject
{
// 인스펙터 상에서 아이템을 드래그하여 넣기 위한 List 선언
[SerializeField] public List<ItemBase> Items;
// 인스펙터 상에서 레시피를 드래그하여 넣기 위한 List 선언
[SerializeField] public List<Recipe> Recipes;
// 모든 아이템을 저장하는 자료구조
public Dictionary<int, ItemBase> ItemDic { get; private set; }
// 모든 레시피를 저장하는 자료구조
public Dictionary<int, Recipe> RecipeDic { get; private set; }
// Editor 상에서 사용할 수 있도록 하는 메서드 선언 방식
#if UNITY_EDITOR
public void GenerateDic()
{
Init();
}
#endif
// 런타임 중 Awake에서 한 번 실행하여 Editor에서 실행하지 않은 예외 처리
private void Awake()
{
Init();
}
// 모든 아이템, 레시피 각 Dictionary에 저장 메서드
private void Init()
{
ItemDic = new Dictionary<int, ItemBase>();
RecipeDic = new Dictionary<int, Recipe>();
for (int i = 0; i < Items.Count; i++)
{
int key = Items[i].ItemID;
ItemDic.Add(key,Items[i]);
}
for (int i = 0; i < Recipes.Count; i++)
{
int key = Recipes[i].ItemID;
RecipeDic.Add(key,Recipes[i]);
}
}
}
ItemDicSettingEditor여기서는 명시한 클래스에 접근하여 Editor상에서 메서드를 호출할 수 있는 UI를 구현한다. 이렇게 런타임 중에 동적으로 호출하는 것이 아닌, 에디터 상에서 미리 작업하여 리소스를 아끼는 것이 가능하다.
// 클래스를 명시하고 해당 클래스에 접근할 것임을 미리 선언
[CustomEditor(typeof(ItemDictionary))]
// Editor 상에서 작업할 수 있도록 Editor 상속 => Editor 확장 코드
// Editor 커스텀 UI를 정의할 수 있도록 한다.
public class ItemDicSettingEditor : Editor
{
// Unity Editor에서 인스펙터를 그리는 메서드
public override void OnInspectorGUI()
{
// Unity가 기본적으로 렌더링하는 인스펙터 그리는 메서드
base.OnInspectorGUI();
// target : 인스펙터가 그려지고 있는 오브젝트를 가리키는 기본 제공 변수
// 타입을 명시적으로 캐스팅하여 해당 오브젝트의 메서드, 필드에 접근 가능
ItemDictionary recipeSetting = (ItemDictionary)target;
// GUILayout.Button : 버튼을 생성하고, 클릭되면 true를 반환하는 메서드
if (GUILayout.Button("Generate Dictionary"))
{
// Dictionary 초기화 메서드 호출
recipeSetting.GenerateDic();
// S.O의 내부 상태가 바뀌어도 저장 요청이 없으면 저장x
// SetDirty : 해당 오브젝트를 변경됨 상태로 표시하고 저장할 때 변경 내용 반영
// 해당 코드가 없으면 위에서 초기화해도 에디터 저장시 반영x
EditorUtility.SetDirty(recipeSetting); // 씬 저장 가능하게 표시
}
}
}