저번에 preset을 로드하고 저장하는 기능까지 구현했지만, 새로운 프리셋을 만들거나 삭제하는 기능은 없습니다.
물론 프리셋이 저장된 폴더에 가서 만들거나 삭제해도 되지만, 이는 얘기치 않은 null exception 이나 여러 문제들을 일으킬 수 있기 때문에 Editor 차원에서 지원해야합니다.
public static AnimOptionSO CreateNewPreset(string name)
{
if (HasFilesInFolder(name + ".asset")) {
return null;
}
AnimOptionSO newAsset = ScriptableObject.CreateInstance<AnimOptionSO>();
AssetDatabase.CreateAsset(newAsset, Constants.PATH_PRESET + "/" + name + ".asset");
AssetDatabase.SaveAssets();
EditorUtility.FocusProjectWindow();
Selection.activeObject = newAsset;
return newAsset;
}
private static bool HasFilesInFolder(string name)
{
string[] assetGuids = AssetDatabase.FindAssets("", new[] { Constants.PATH_PRESET });
foreach (string guid in assetGuids)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
if (System.IO.Path.GetFileName(assetPath.ToUpper()) == name.ToUpper())
{
return true; // File exists
}
}
return false; // No file exists
}
위의 CreateNewPreset 을 통해 전달받은 이름의 Preset을 만듭니다.
여기서 생기는 문제는, 이름이 겹칠 경우에 예기치 못한 동작들이 발생할 수 있기 때문에 미리 확인하고 막아야합니다.
여기서는 HasFilesInFolder 함수를 통해서 만들기 전에 같은 이름의 파일이 있는지 확인하도록 했습니다.
그 후에, SaveAssets 로 디스크에 저장하고, FocusProjectWindow 로 생성된 프리셋에 포커스를 줬습니다.
if (GUILayout.Button("Save as new preset..."))
{
AnimOptionSO tmpSo = PresetLoader.CreateNewPreset(presetName);
if (tmpSo == null)
{
EditorUtility.DisplayDialog("Denied",
"The preset with the same name already exists.", "OK");
}
else
{
SavePreset(tmpSo);
scriptableObjects = PresetLoader.LoadScriptableObjects();
}
}
에디터에서는 위와같이 처리해주었습니다.
버튼을 누르면 CreateNewPreset 이 호출되고, 반환값이 null 이라면 Dialogue를, null이 아니라면 새로 만든 프리셋 SO에 현재 설정된 값들을 저장해주었습니다.


같은 이름의 프리셋을 생성하려고 하면 다이얼로그 창이 띄워지는 것을 확인할 수 있습니다.
public static void RemovePreset(string name)
{
AssetDatabase.DeleteAsset(Constants.PATH_PRESET + "/" + name + ".asset");
AssetDatabase.SaveAssets();
}
프리셋을 삭제하는 부분은 생각보다 간단합니다.
파일의 경로를 토대로 삭제하고, SaveAssets 로 바로 디스크에 적용합니다.
private void RemovePreset()
{
if (scriptableObjects.Count <= 1)
{
EditorUtility.DisplayDialog("Denied",
"You cannot delete this asset because it is the only one remaining.",
"OK");
return;
}
PresetLoader.RemovePreset(selectedObject.name);
scriptableObjects = PresetLoader.LoadScriptableObjects();
selectedObject = scriptableObjects[0];
}
에디터에서는 Null Exception 이 발생하지 않도록 주의해야합니다.
삭제했을 때, scriptableObjects 나 selectedObject 에서 삭제한 SO를 참조하고 있다면 에러가 발생합니다.
그러한 상황을 방지하기 위해서, 삭제한 직후에 SO들을 다시 로드하도록 구현했습니다.
에디터보다는 에셋을 다루는 부분이다보니 생각보다 빠르게 끝낼 수 있었습니다.
이제 남은 부분은 다음과 같습니다.