나는 아기자기하고 귀여운 게임을 좋아한다.
그리고 타이쿤류도 좋아한다.
고양이 스낵바는 내게는 딱 맞는 게임이였다.
어느 순간 광고 때문에 안하게 된건 있지만..
아무튼.. 고양이 스낵바를 제작한 트리플라의 팀 블로그를 어쩌다가 보게되었는데, 꽤나 누르고 싶은 제목이 보였다.
<트리플라 팀 블로그>
<한 달 안에 게임 제작이 가능했던 이유> 라는 제목에 어그로가 끌려 들어갔는데, 내용도 좋았다.
UI 작업을 위해 프리펩을 입맛대로 만들어놓고 꺼내쓰는 작업방식이 꽤나 따라해보고 싶어졌다.
그래서 나도 하나 만들어 두면 좋지 않을까 생각해서 따라 해봤다.
마우스 오른쪽 클릭으로 메뉴 뜨게 하기
[MenuItem("GameObject/커스텀UI/커스텀텍스트", false, 1)]
public static void Test() => Debug.Log("테스트");
이런식으로 MenuItem 애트리부트를 사용해주면 마우스 오른쪽을 클릭했을때 해당 메뉴를 볼 수있다.
static으로 해두어야 한다.
프리펩 생성 코드 작성
특정 폴더에 만들어둔 프리펩을 만드는 기능을 만들어야 한다.
특정 폴더 위치는 Assets - Prefabs - CustomUI 로 결정했다.
Editor 폴더에 CustomUIPrefabSystem이라는 클래스를 만들어 주었다.
using UnityEditor;
using UnityEngine;
public class CustomUIPrefabSystem
{
/// <summary>
/// 커스텀UI 프리펩 생성
/// </summary>
public static void CreateCustomUIPrefab(string fileName)
{
string prefabPath = $"Assets/Prefabs/CustomUI/{fileName}.prefab";//프리펩 경로
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);//프리펩 로드
if (prefab != null)
{
GameObject instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;//프리펩 생성
// 선택된 오브젝트가 있을 경우 해당 오브젝트의 자식으로 설정
if (Selection.activeTransform != null)
{
instance.transform.SetParent(Selection.activeTransform, false);
}
EditorGUIUtility.PingObject(instance);// 새로 생성된 오브젝트를 화면에 표시
Undo.RegisterCreatedObjectUndo(instance, "Create " + instance.name); //Undo 기능 등록
}
else
{
Debug.LogError("프리펩이 없습니다! " + prefabPath);
}
}
}
프리펩을 생성하고, 선택한 UI가 있으면 자식으로 넣어주었다.
생성되고 하이라이트 되는 기능과 Undo가 가능하도록 추가해주었다.
에디터 작업을 많이 안해봐서 에디터 클래스들이 생소했다.
- AssetDatabase => 경로로 프리펩 로드
- PrefabUtility => 로드된 프리펩 생성
- Selection => 현재 활성화된 트랜스폼이나, 여러개를 선택해도 Objects로 가져 올 수 있다.
- EditorGUIUtility => 생성했을때 생성한 프리펩을 알려주기위해 PingObject 함수를 사용했다.
- Undo => 말그대로 Undo(실행취소) 기능을 위해 넣어주었다.
프리펩 생성 해보기
3개의 프리펩을 만들고 코드를 추가 했다.
[MenuItem("GameObject/커스텀UI/HelloText",false,1)]
public static void Create_HelloText() => CreateCustomUIPrefab("HelloText");
[MenuItem("GameObject/커스텀UI/Panel",false,1)]
public static void Create_Panel() => CreateCustomUIPrefab("Panel");
[MenuItem("GameObject/커스텀UI/Square",false,1)]
public static void Create_Square() => CreateCustomUIPrefab("Square");
의도한대로 잘 작동한다.
하지만 여기서 한가지 의문이 든다.
사실 UI는 개발자가 아닌 다른 직군이 만지기도 하는데, 만약 커스텀UI 프리펩이 수정 된다면?
그때마다 코드를 다시 수정하는것도 서로 상당히 번거로운 일이다.
수정을 하면 클릭 한번으로 수정되게 만들어 보자.
자동 코드 생성기능 만들기
기능을 정리해보자면
1. 현재 CustomUI 폴더에 있는 프리펩들을 싹 다 가져온다.
2. 자동으로 MenuItem 애트리부트가 붙은 코드를 생성해준다.
3. 컴파일
이렇게만 작동되게 하면 끝이다.
이번에는 AutoCodeGenerator라는 클래스를 만들어주었다.
물론 Editor 폴더에 넣어주었다.
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Text;
public partial class AutoCodeGenerator
{
[MenuItem("Assets/Refresh_CustomUIPrefab")]
public static void Refresh_CustomUIPrefab()
{
if(!File.Exists("Assets/Editor/CustomUIPrefabSystem.cs"))
{
Debug.LogError("File does not exist: ");
return;
}
string scriptCode = $@"
using UnityEditor;
using UnityEngine;
public class CustomUIPrefabSystem
{{
/// <summary>
/// 커스텀UI 프리펩 생성
/// </summary>
public static void CreateCustomUIPrefab(string fileName)
{{
string prefabPath = $""Assets/Prefabs/CustomUI/{{fileName}}.prefab"";//프리펩 경로
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);//프리펩 로드
if (prefab != null)
{{
GameObject instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;//프리펩 생성
// 선택된 오브젝트가 있을 경우 해당 오브젝트의 자식으로 설정
if (Selection.activeTransform != null)
{{
instance.transform.SetParent(Selection.activeTransform, false);
}}
EditorGUIUtility.PingObject(instance);// 새로 생성된 오브젝트를 화면에 표시
Undo.RegisterCreatedObjectUndo(instance, ""Create "" + instance.name); //Undo 기능 등록
}}
else
{{
Debug.LogError(""UIPrefab not found at "" + prefabPath);
}}
}}
//AutoGenerated Code
{GetAutoGeneratedCode()}
}}
";
File.WriteAllText("Assets/Editor/CustomUIPrefabSystem.cs", scriptCode.Trim());
AssetDatabase.Refresh(); //갱신
}
길긴 하지만 사실 별 기능은 없다.
한가지 알고가야 하는건 문자열 앞에 @ 를 붙이는건 \ , \n, + 등등.. 문자열에서 신경써야 하는 부분을 전부 신경쓰지 않고 문자 그대로를 넣을 수 있다.
그리고 그 상태에서도 문자열 보간을 하고 싶다면 $를 붙이고 똑같이 써주면 된다.
즉 문자열 앞에 $@를 붙이면 된다. (순서 바뀌면 안됨)
코드를 보면 중괄호가 2개씩 있는데, 이게 다 $를 붙여서 문자열 보간을 추가 했기 때문이다.
중괄호를 2개를 안하면 함수의 중괄호들이 난리가 난다.
한마디로 {GetAutoGenerateCode()} 코드 한줄을 넣기 위해 ..
1. 파일 탐색 창에서 갱신 할 수 있게 MenuItem 애트리부트를 달아주었다.
2. CustomUIPrefabSystem 파일이 있나 확인하고 , 클래스를 복붙해서 넣어주었다.
3. 자동 생성 코드를 중간에 추가해주고, CustomUIPrefabSystem 스크립트를 수정해주었다.
4. 갱신은 필수
그럼 이제 GetAutoGenerateCode 함수를 보자.
/// <summary>
/// 자동 생성 코드
/// </summary>
public static string GetAutoGeneratedCode()
{
StringBuilder sb = new StringBuilder();
DirectoryInfo dir = new DirectoryInfo(Application.dataPath+ "/Prefabs/CustomUI");
FileInfo[] info = dir.GetFiles("*.prefab");
for (int i = 0; i < info.Length; i++)
{
string filename = Path.GetFileNameWithoutExtension(info[i].Name);
sb.AppendLine($@" [MenuItem(""GameObject/커스텀UI/{filename}"",false,1)]");
sb.AppendLine($@" public static void Generate_{filename.Replace(" ", "_")}() => CreateCustomUIPrefab(""{filename}"");
");
}
return sb.ToString();
}
CustomUI 폴더의 모든 prefab 확장자 파일을 가져와서 그 수만큼 반복문을 돈다.
파일 이름에 맞춰 메뉴생성, 함수 코드 생성을 해주었다.
여기서 중요한것은 유니티는 복붙을 하면 공백+숫자가 생긴다.
다른 곳에는 몰라도 코드에는 공백이 있으면 안되기 때문에 Replace 함수를 써서 공백 대신 언더바를 넣는 코드를 삽입해주었다.
코드 자동생성까지 잘 실행이 된다.
마치며
에디터나 툴만드는거를 좋아한다. 그래서 재밌는 작업이였다.
이런 시스템을 많이 갖추면 작업속도가 많이 올라가지 않을까? 라는 희망을 가져본다.
'게임 엔진 > Unity' 카테고리의 다른 글
Github Action으로 Unity 자동 빌드 제작해보기 (CI/CD) - 2편 (0) | 2024.03.23 |
---|---|
Github Action으로 Unity 자동 빌드 제작해보기 (CI/CD) - 1편 (0) | 2024.03.23 |
[Unity] Canvas - RenderMode & Scaler (0) | 2023.08.04 |
[Unity 잡학사전] Unity UI 시스템 성능 최적화 (1) | 2023.08.04 |
[Unity]코루틴으로 값을 리턴 받고 싶을 때 (0) | 2023.07.21 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!