[Unity] missing script 어떻게 해결할까?

ChangJin·2024년 5월 14일
0

Unity

목록 보기
15/17
post-thumbnail

Player의 하위 GameObject에 부착된 missing script를 모두 해결해야 프리팹으로 만들 수 있는데 이를 위한 Editor 툴을 만들어서 해결했다는 내용입니다.


Player나 Enemy 같은 GameObject은 Spawn에도 쓰이고 다양하게 쓰이기 때문에 프리팹으로 만들어 두어야합니다. 그래서 Player를 프리팹으로 만들고자 hierarchy창에서 Project Prefabs 파일에 끌어다 놓았는데 다음과 같은 에러가 발생했습니다. 에러가 발생한 GameObject가 서너개 정도라면 많아도 10개 이하라면 직접 찾아서 Remove component를 해주면 되겠지만 30개라면? 100개라면? 500개라면? 5000개라면? 생각만해도 끔찍합니다.

그래서 툴로 missing script 삭제를 자동화하는 툴을 만들어보았습니다.


Error!
You are trying to replace or create a Prefab from the instance '파일이름' that references a missing script. This is not allowed.Please change the script or remove it from the GameObject.

1. 모든 missing script들 삭제하기

첫번째 방법은 현재 씬에 존재하는 모든 GameObject를 조회하면서 missing script가 존재한다면 그냥 Remove compoenet를 해버리는 방법입니다.

클릭 한번으로 모든 missing script를 삭제해줍니다.
그러나 원하는 게임 오브젝트의 하위 오브젝트들만 삭제하고 싶을때는 이 방법을 사용하면 안됩니다. 씬에 존재하는 모든 오브젝트의 missing script를 삭제해버릴테니까요.


using UnityEngine;
using UnityEditor;

public class RemoveMissingScripts : Editor
{
    [MenuItem("Tools/Remove Missing Scripts Recursively")]
    public static void RemoveMissingScriptsa()
    {
        // 현재 씬의 모든 GameObject를 대상으로 합니다.
        foreach (GameObject go in GetAllObjectsInScene(true))
        {
            RemoveMissingScriptsFromGameObject(go);
        }
    }

    static void RemoveMissingScriptsFromGameObject(GameObject go)
    {
        // 누락된 스크립트 제거
        int removedCount = GameObjectUtility.RemoveMonoBehavioursWithMissingScript(go);
        if (removedCount > 0)
        {
            Debug.Log($"{removedCount} missing scripts removed from {go.name}", go);
        }

        // 자식 GameObject들에 대해서도 재귀적으로 처리
        foreach (Transform child in go.transform)
        {
            RemoveMissingScriptsFromGameObject(child.gameObject);
        }
    }

    static GameObject[] GetAllObjectsInScene(bool includeInactive)
    {
        return GameObject.FindObjectsOfType<GameObject>(includeInactive);
    }
}


2. hierarchy창에서 선택된 GameObject의 하위 GameObject를 삭제하기


두번째 방법은 hierarchy창에서 선택한 GameObject만 재귀적으로 모든 자식의 missing script를 모두 삭제하는 방법입니다.

이렇게하면 제거하고자하는 GameObject를 선택한 상태로 Tools > Remove Missing Scripts Recursively 이렇게 클릭해주면 해당하는 GameObject의 모든 하위 자식에 있는 missing script를 삭제합니다.



using UnityEngine;
using UnityEditor;

public class RemoveMissingScriptsRecursively : EditorWindow
{
    [MenuItem("Tools/Remove Missing Scripts Recursively")]
    public static void ShowWindow()
    {
        var window = GetWindow<RemoveMissingScriptsRecursively>();
        window.titleContent = new GUIContent("Remove Missing Scripts Recursively");
        window.Show();
    }

    void OnGUI()
    {
        if (GUILayout.Button("Remove Missing Scripts from Selected GameObjects and Their Children"))
        {
            foreach (GameObject go in Selection.gameObjects)
            {
                RemoveScriptsRecursively(go);
            }
            Debug.Log("Missing scripts removed from selected GameObjects and their children.");
        }
    }

    private static void RemoveScriptsRecursively(GameObject go)
    {
        RemoveMissingScript(go); // GameObject에 있는 missing script를 삭제하기

        // 재귀적으로 모든 자식을 조회하기
        foreach (Transform child in go.transform)
        {
            RemoveScriptsRecursively(child.gameObject);
        }
    }

    private static void RemoveMissingScript(GameObject go)
    {
        var components = go.GetComponents<Component>();
        var serializedObject = new SerializedObject(go);
        var prop = serializedObject.FindProperty("m_Component");

		// 반복 루프를 위한 Counter
        int r = 0; 

        for (int j = 0; j < components.Length; j++)
        {
            if (components[j] == null)
            {
                prop.DeleteArrayElementAtIndex(j - r);
                r++;
            }
        }
        serializedObject.ApplyModifiedProperties();
    }
}

코드를 적용하고 이랬던 Console 창이

이렇게 변했습니다.

profile
게임 프로그래머

0개의 댓글

관련 채용 정보