unity开发之辅助脚本(自动绑定prefab)

2018-08-08  本文已影响196人  gt154

这段时间都没更新,原因很简单,懒癌上身,得治啊...

正好最近写了个工具,可以选中prefab,自动查找相应脚本并绑定prefab中需引用的组件,本想用在项目里,不过可能用不到了,虽然没太大用,也就省点拖拽的力,但都已经写出来了,想着也不要浪费,于是乎,这篇文章诞生了。

使用规则

  1. prefab名字应与c#脚本名一致

  2. 脚本中成员变量的命名与prefab中相应的组件相同,且命名不可重复!!!
    脚本中成员变量的命名与prefab中相应的组件相同,且命名不可重复!!!
    脚本中成员变量的命名与prefab中相应的组件相同,且命名不可重复!!!

重要的事情说三遍,我是以名字为tag的,所以命名为什么重要大家应该明白了。
 


代码

1.UIPathData类

public class UIPathData
{
    private string name;

    public string Name
    {
        get { return name; }
    }


    string folder;

    public string Folder
    {
        get { return folder; }
    }

    public UIPathData(string name, string folder)
    {
        this.name = name;
        this.folder = folder;
    }
}

2.Tools类

public class Tools {

    private static string scriptsPath = Application.dataPath + "/Scripts";
    private static string prefabDirPath = Application.dataPath + "/Prefab";

    [MenuItem("Tools/UI/Remove c# file in prefab")]
    public static void removeCSharpFiles()
    {
        string[] paths = Directory.GetFiles(prefabDirPath, "*.prefab", SearchOption.AllDirectories);
        Debug.Log("-------count :  " + paths.Length);
        for (int i = 0; i < paths.Length; ++i)
        {
            string path = paths[i].Replace(@"\", "/");
            path = path.Substring(path.IndexOf("Assets"));
            GameObject obj = AssetDatabase.LoadAssetAtPath(@path, typeof(GameObject)) as GameObject;
            MonoBehaviour mono = obj.GetComponent<MonoBehaviour>();
            if (mono != null)
            {
                Debug.Log("-------remove mono in  " + obj.name);
                GameObject.DestroyImmediate(mono, true);
            }
        }
    }

    [MenuItem("Assets/Bind C# file to prefabs in Directory")]
    public static void bindScriptToPrefabs()
    {
        string dirname;
        UnityEngine.Object[] objs = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Unfiltered);
        if (objs.Length > 0)
        {
            dirname = string.Format("{0}/{1}", Path.GetDirectoryName(AssetDatabase.GetAssetPath(objs[0])), objs[0].name);
            string[] paths = Directory.GetFiles(dirname, "*.prefab", SearchOption.AllDirectories);
            for (int i = 0; i < paths.Length; ++i)
            {
                string path = paths[i].Replace(@"\", "/");
                bindFileToPrefab(path);
            }
        }
    }
 

    [MenuItem("Assets/Bind C# file to prefab")]
    public static void bindScriptToPrefab()
    {
        bindFileToPrefab(null);
    }
    
    public static void bindFileToPrefab(string path)
    {
        if (path == null && Selection.assetGUIDs.Length > 0)
        {
            path = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
        }

        string[] paths = Directory.GetFiles(scriptsPath, "*.cs", SearchOption.AllDirectories);
        FileInfo[] files = new FileInfo[paths.Length];
        for (int i = 0; i < paths.Length; ++i)
        {
            files[i] = new FileInfo(paths[i]);
        }

        GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
        if (prefab != null)
        {
            MonoBehaviour mono = prefab.GetComponent<MonoBehaviour>();
            if(mono != null)
            {
                GameObject.DestroyImmediate(mono, true);
            }


            string name = prefab.name;
            bool tag = false;
            for (int i = 0; i < files.Length; ++i)
            {
                if (files[i].Name.Split('.')[0].Equals(name))
                {
                    foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
                    {
                        Type t = asm.GetType(name);
                        if (t != null)
                        {
                            prefab.AddComponent(t);
                            tag = true;
                            break;
                        }
                    }

                    if(tag)
                    {
                        break;
                    }
                }
            }

            mono = prefab.GetComponent<MonoBehaviour>();
            if(mono != null)
            {
                Type t = mono.GetType();
                FieldInfo[] fields = t.GetFields();
                string[] uipaths = UIRelativePath(prefab.gameObject.transform, fields);
                for (int i = 0; i < fields.Length; ++i)
                {
                    var component = prefab.gameObject.transform.Find(uipaths[i]).GetComponent(fields[i].FieldType);
                    fields[i].SetValue(mono, component);
                }
                Debug.Log("------- bind " + prefab.name + ".prefab success ! ");
            }
        }
    }

    private static string[] UIRelativePath(Transform root, FieldInfo[] fields)
    {
        string[] result = new string[fields.Length];

        Stack<KeyValuePair<Transform, string>> stack = new Stack<KeyValuePair<Transform, string>>();
        stack.Push(new KeyValuePair<Transform, string>(root, ""));
        while (stack.Count > 0)
        {
            KeyValuePair<Transform, string> node = stack.Pop();
            for (int t = 0; t < fields.Length; ++t)
            {
                if (node.Key.name.Equals(fields[t].Name))
                {
                    result[t] = node.Value;
                    break;
                }
            }

            for (int i = 0; i < node.Key.childCount; ++i)
            {
                Transform child = node.Key.GetChild(i);
                string path = node.Value.Equals("") ? child.name : string.Format("{0}/{1}", node.Value, child.name);
                stack.Push(new KeyValuePair<Transform, string>(child, path));
            }

        }

        return result;
    }
}

这里面其实还应该做个检查,是否有存在命名相同的情况,按规则是不允许出现命名相同的。
最后还是欢迎大家给出各种建议和意见,以及附上源码地址
源码地址:https://github.com/gtgt154/ScriptBindToPrefab

上一篇下一篇

猜你喜欢

热点阅读