이번에는 animation clip을 반복적으로 만들어야하는 상황에서 조금 더 편의를 제공해주는 preset save/load 기능을 만들어보겠습니다.
해당 정보는 json 파일을 통해 저장할수도 있지만, 에디터 상에서 편하게 조작할 수 있도록 ScriptableObject 와 Editor를 통해 Inspector 창을 커스텀해보도록 하겠습니다.
namespace AutoAnimaker.Core
{
public static class PresetLoader
{
public static List<AnimOptionSO> LoadScriptableObjects()
{
List<AnimOptionSO> scriptableObjects = new List<AnimOptionSO>();
// type : AnimOptionSO
string[] guids = AssetDatabase.FindAssets("t:AnimOptionSO", new[] { Constants.PATH_PRESET });
scriptableObjects.Clear();
foreach (string guid in guids)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
AnimOptionSO asset = AssetDatabase.LoadAssetAtPath<AnimOptionSO>(assetPath);
if (asset != null)
{
scriptableObjects.Add(asset);
}
}
return scriptableObjects;
}
}
}
우선 ScriptableObject에 필요한 정보들을 선언해주고 위와 같이 AssetDatabase.FindAssets 함수를 통해 받아옵니다. ( "t:~" 는 type을 의미합니다.)
Editor 스크립트에서 해당 함수를 통해 Preset 리스트를 받고 선택할 수 있게 만들어줍니다.
private void DrawHeader()
{
// ...
// ScriptableObject Selection Dropdown
if (scriptableObjects.Count > 0)
{
var names = scriptableObjects.Select(obj => obj.name).ToArray();
int selectedIndex = scriptableObjects.IndexOf(selectedObject);
int newSelectedIndex = EditorGUILayout.Popup("Select ScriptableObject", selectedIndex, names);
if (newSelectedIndex != selectedIndex)
{
selectedObject = scriptableObjects[newSelectedIndex];
Debug.Log("Selected ScriptableObject: " + selectedObject.name);
}
}
// ...
}
LINQ와 Popup을 사용하여 이름들을 드롭다운으로 출력합니다.

이제 Save/Load 기능을 만들어야 합니다.
Save 와 Load 를 구현할 때 주의해야할 점은, List나 배열같은 경우 대입연산자를 사용하면 Deep Copy가 되지 않는다는 점입니다.
DeepCopy를 사용하지 않고 그냥 대입연산자를 사용하게 되면 아래 사진과 같이 ScriptableObject와 Editor간에 동기화가 생깁니다.

public SpriteAnimatorStruct GetDeepCopy()
{
SpriteAnimatorStruct tmpStruct = new SpriteAnimatorStruct();
tmpStruct.animationNames = new List<string>(this.animationNames);
tmpStruct.sprite = this.sprite;
return tmpStruct;
}
우선, 해당 자료형에 GetDeepCopy 함수를 만들어줍니다.
(이름과 다르게 class 자료형이기 때문에 필요합니다.)
public void SavePreset()
{
// other settings...
// NOT REF. Deep Copy
Array.Clear(selectedObject.animatorStructs, 0, selectedObject.animatorStructs.Count());
selectedObject.animatorStructs = new SpriteAnimatorStruct[animatorStructs.Length];
for (int i = 0; i < animatorStructs.Length; i++)
{
selectedObject.animatorStructs[i] = animatorStructs[i].GetDeepCopy();
}
}
그 후에 위와같이 배열을 선언하고 GetDeepCopy로 받은 데이터를 대입합니다.

Load 기능은 정확히 반대로만하면 되기 때문에 생략하겠습니다.
여기까지 Preset의 Save/Load를 구현해봤습니다.
아직 Inspector 창을 커스텀하는 일이 남아있지만 CustomEditor와 비슷하게 할 수 있으리라 생각합니다.
지금은 이미 만들어진 Preset에만 저장이 가능하기 때문에, 도중에 Preset 폴더에 SO를 추가한다고 해도 Editor에서 접근하지 못하는 문제점이 있습니다. ( Preset Load를 OnEnable 때 한 번만 합니다.)
따라서, Editor 내부에서 SO를 만드는 기능을 추가해주어야 합니다.
Sprite Preview 기능 또한 Unfocus 되면 바로 닫히도록 되어있는데, 이는 widthPx나 colCount 등을 조정하는데 있어서 불편함이 생길 수 있었습니다. 해당 부분도 바로 고쳐보도록 하겠습니다.
https://docs.unity3d.com/6000.0/Documentation/ScriptReference/AssetDatabase.FindAssets.html