일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- spritelibrary
- LookAt
- 붕괴 스타레일
- 게임용어
- 게임
- 내일배움캠프
- 블렌더
- 일상
- 스파르타내일배움캠프
- 원신
- 게임 회사
- spritemask2d
- 취업
- 프로그래밍
- ag 내일배움캠프
- 뭐드라
- 붕괴스타레일
- 컴포넌트
- 후기
- 까먹기전에메모
- materialpropertyblock
- 연습
- 공부
- 유니티
- 스파르타내일배움캠프TIL
- 점프
- 게임분석
- 취미
- 코딩
- 나만의 견해
- Today
- Total
덴바의 노트
유니티 MissingScript 제거하는 자동화 툴 만들기 본문
오늘의 키워드
Import한 에셋 내에 존재하는 MissingSciprt를 가진 오브젝트 정리 툴 만들기
발생 상황
유니티를 사용하다보면 무조건 에셋을 다운 받아서 Import하는 경험을 하게 됩니다.
이 때 해당 에셋과 자신의 프로젝트의 버전이 호환되지 않거나, 에셋 내부에 있는 스크립트를 제외한 파일이 필요해서 Scripts를 제외하고 Import 받게되면 Prefab에 MissingScript
가 부착되어 있는 상태가 됩니다.
이와 같은 경험은 주로 `Character` 같은 파일을 임포트하게 되면 자주 일어납니다.
저의 경우는 바로 이 `UnityChan` 캐릭터를 프로젝트에 Import하면서 발생했습니다.
UnityChan 캐릭터 에셋에는 위와 같이 캐릭터의 퀄리티를 높이기 위한 다양한 Scripts들이 존재합니다.
하지만 저는 해당 Scripts를 사용하고 싶지 않았기에 해당 Check를 해제한 결과 많은 MissingScripts가 발생했습니다.
코드
유니티에는 항상 우리가 모르는 라이브러리, 클래스, 함수 등이 존재합니다. 단지, 우리가 그 존재를 모르고 있을 뿐입니다.
GameObjectUtility
`UnityEditor`에 존재하는 하나의 클래스로 정확히는 `Editor/Mono/GameObjectUtility.h`에 해당 기능에 자세히 저장되어있습니다.
UnityEditor를 이용하면 MissingScript를 코드를 통해서 자동으로 지울 수 있습니다.
먼저 위 문제와 관련된 GameObjectUtility의 주요 메서드 입니다.
int GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(GameObject obj);
- 파라미터로 넘긴 GameObject에 MissingScript가 존재하는지 파악하고, 존재한다면 해당 MissingScript의 개수를 반환합니다. 존재하지 않을 경우 0을 반환합니다.
int RemoveMonoBehavioursWithMissingScript(GameObject go);
- 파라미터로 넘긴 GameObject에 존재하는 모든 MissingScript를 제거합니다. 그리고 제거한 MissingScript의 개수를 반환합니다. 존재하지 않을 경우 0을 반환합니다.
코드 구현
클릭한 오브젝트에 존재하는 모든 MissingScript 제거하기
#if UNITY\_EDITOR
public class AutomaticTool
{
}
#endif
STEP 01
먼저 EDITOR Tool 제작용으로 사용할 클래스를 하나 생성합니다.
만약 해당 파일에 Assets/Editor
폴더에 있으면 상관 없지만,
그렇지 않다면 반드시 위와 같이 `#if UNITY_EDITOR ... #endif`로 전처리를 해야 합니다.
그렇지 않을 경우 Build 시 에러가 발생하여 **Build 실패**를 하게 됩니다.
[MenuItem("Denba/AutoTool/RemoveMissingScriptSelectedObject")]
public static void RemoveMissingScriptSelectedObject(){}
STEP 02
함수를 만들고 Editor 내에서 Runtime 외에도 해당 스크립트를 실행할 수 있게 합니다.
저의 경우는 유니티의 메뉴창에서 사용할 수 있게 하기 위해서 MenuItem()을 이용했습니다.
STEP03
MissingScript를 부착하고 있는 오브젝트를 넘겨줘야 합니다.
다양한 방법이 있지만 저는 최대한의 편리성을 위해 Selection을 사용했습니다.
var objs = Selection.objects;
Selection은 말대로 \`선택\`으로 마우스로 클릭하여 Inspector에 정보가 뜬 상태의 오브젝트를 Selection은 가지고 있습니다. objects, 즉 복수형인 이유는 Ctrl + LClick, 또는 드래그로 오브젝트를 선택할 수 있기 때문입니다.
STEP04
GameObjectUtility를 이용하여 MissingScript를 제거하는 코드를 구현합니다.
private static void RemoveMissingScripts(GameObject obj)
{
int scriptCount = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(obj);
if (scriptCount > 0)
{
Util.Log($"{obj.name}오브젝트에서 MissingScripts를 제거했습니다");
GameObjectUtility.RemoveMonoBehavioursWithMissingScript(obj);
}
var objs = obj.GetComponentsInChildren();
foreach (var child in objs)
{
if (GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(child.gameObject) > 0)
{
Util.Log($"{child.name}오브젝트에서 MissingScripts를 제거했습니다");
GameObjectUtility.RemoveMonoBehavioursWithMissingScript(child.gameObject);
}
}
Util.Log($"{obj.name}의 모든 MissingScript를 제거했습니다");
}
먼저 파라미터로 GameObject를 두고, GetMonoBehavioursWithMissingScriptCount를 이용하여 MissingScripts가 존재하는지 확인합니다.
존재할 경우 RemoveMonoBehavioursWithMissingScript로 해당 오브젝트를 전달합니다.
그 후 GetComponentsInChildren()을 이용하여 자식 오브젝트에 존재하는 모든 MissingScript를 제거합니다.
STEP05
Selection을 이용하여 Objects들을 가져왔으니 방금 구현한 RemoveMissingScripts의 파라미터 값으로 보내줍니다.
** Scene에 있는 오브젝트를 클릭한 후 Tool을 사용할 경우에는 문제가 없지만, Project에 있는 파일을 클릭하고 사용할 경우, 문제가 발생할 수 있으니 GameObject인지 파악 후 사용합니다.
[MenuItem("Denba/AutoTool/RemoveMissingScriptSelectedObject")\]
public static void RemoveMissingScriptSelectedObject()
{
var objs = Selection.objects;
foreach (var obj in objs)
{
if (obj is GameObject)
{
RemoveMissingScripts(obj as GameObject);
}
}
}
Project에 존재하는 모든 GameObject의 MissingScript 제거하기
위에 있는 방법은 매우 좋은 방법이지만, 일일이 모든 파일을 클릭해가면서 MissingScript를 제거하는 것은 생각 외로 번거롭습니다.
역시 한 번의 클릭만으로 모든 MissingScript를 제거할 수 있으면 좋을 것 입니다.
프로젝트 창의 검색 오른쪽을 보면 네모, 삼각형, 원이 그려져 있는 아이콘이 보입니다. 이는 필터 기능입니다. (생각 외로 모르는 분이 많더라고요...)
파일의 타입 별로 프로젝트 폴더 내에 있는 파일을 필터링할 수 있습니다.
그 중에서 Prefab이 있습니다. 이를 눌러보면, 현재 소지하고 있는 Prefab 파일이 나옵니다. 이 때 검색창을 자세히 보면 `t:Prefab`이라고 적혀있습니다. 여기서 t는 Type이며 Prefab은 그 타입 중 하나 입니다.
이 필터링을 이용해서 프로젝트 내에 있는 모든 Prefab의 MissingScript를 제거하겠습니다.
[MenuItem("Denba/AutoTool/RemoveAllOfMissingScriptInProject")\]
public static void RemoveAllOfMissingScriptInProject()
{
}
먼저 이전과 같이 Tool 형식으로 함수를 만들어줍니다.
var objs = AssetDatabase.FindAssets("t:Prefab");
그 후 `AssetDatabase`의 FindAssets 함수를 이용하여 아까 본 필터값을 문자열로 넣습니다.
이 때 반환되는 것은 찾으려는 Asset의 GUID 값을 string의 배열로 반환하게 됩니다.
var path = AssetDatabase.GUIDToAssetPath(obj);
var gm = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject));
RemoveMissingScripts(gm as GameObject);
AssetDatabase.GUIDToAssetPath(guid)를 이용하여 `Assets/Data/` 이 와 같은 형식으로 Path를 반환합니다.
그리고 해당 Path를 가지고 AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) 를 실행하게 되면 해당 위치에 있는 GameObject 타입의 에셋을 반환하게 됩니다.
나머지는 MissingScript를 제거하기 위해 구현했던 RemoveMissingScript(GameOjbect) 함수에 방금 로드한 에셋을 GameObject로 넣어줍니다.
구현한 함수를 실행하면 프로젝트에 존재하는 모든 Missing Object를 제거해줍니다.
오늘은 간단한 Tool 제작을 해봤습니다. 솔직히 처음에는 자동화 툴 같은 것이 없어도, 꾸준히 다운 받은 에셋을 관리하면 될 것이라고 생각했지만, 인간은 역시 그렇게까지는 꾸준하고 성실한 동물은 아닌 것 같습니다.
툴이 있으면 작업 효율이 엄청나게 올라가기에 작업하다가 불편한 것이 있다면 반드시 해당 부분에 대한 자동화를 구현해두는 것을 개인적으로 추천합니다.
'프로그래밍 노트 > TIL' 카테고리의 다른 글
내일배움캠프 25일차 TIL : 오브젝트 풀링 #1 개념 (0) | 2024.05.23 |
---|---|
내일배움캠프 24일차 TIL : SpriteLibrary #2 (0) | 2024.05.22 |
내일배움캠프 23일차 TIL : SpriteLibrary (0) | 2024.05.21 |
내일배움캠프 21일차 TIL : 기존 시야각 구하기 문제점 해결 (0) | 2024.05.17 |
내일배움캠프 20일차 TIL : 수학을 이용한 시야각 구하기 (0) | 2024.05.16 |