unity3d编辑器系列——独立的编辑器界面

Posted singledigit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了unity3d编辑器系列——独立的编辑器界面相关的知识,希望对你有一定的参考价值。

好多东西直接记在云笔记上,好久没有写博客了,新年分享一下。

写在前面:
前段时间看了E神的框架,各种膜拜,学到了很多东西。&最近工作中要写很多的工具,用到的编辑器的地方比较多,也正好学习了一下编辑器的知识。当然,这次学习的只是编辑器中的很小的一部分,先进行一下记录,以后有事件再进行补充。
 
直观感受:编辑器的部分并没有什么太难的地方,和写ongui的ui比较像
 
下面贴出代码和对应的界面:
例子一:
技术分享图片
 
界面代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
 
namespace MyEditor.Build
{
    public partial class BuildTool : EditorWindow
    {
        private void OnGUI()
        {
            GUILayout.Label("Build Setting", EditorStyles.boldLabel);
            GUILayout.Space(5);
 
            index = EditorGUILayout.Popup("Platform", index, platformNames);
 
            switch (index)
            {
                case 0:
                    platform = "pc";
                    break;
                case 1:
                    platform = "android";
                    break;
            }
 
            companyName = EditorGUILayout.TextField("Company", companyName);
            productName = EditorGUILayout.TextField("Product", productName);
            packageName = EditorGUILayout.TextField("Packet", packageName);
 
            EditorGUILayout.BeginHorizontal();
            outPath = EditorGUILayout.TextField("Out Path", outPath);
            bool pathSelectButtonClick = GUILayout.Button("Select", EditorStyles.miniButton);
            EditorGUILayout.EndHorizontal();
            if (pathSelectButtonClick)
            {
                outPath = EditorUtility.OpenFolderPanel("Build Setting", Application.dataPath, outPath);
            }
            bool saveButtonClick = GUILayout.Button("Save");
            if (saveButtonClick)
            {
                Save();
            }
        }
    }
}
 
//功能代码
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Xml;
 
namespace MyEditor.Build
{
    public partial class BuildTool
    {
        private static string platform;
        private static string companyName;
        private static string productName;
        private static string packageName;
        private static string outPath;
 
        private static int index = 0;
        private static string[] platformNames = { "pc", "android" };
 
        [MenuItem("Tool/Build/Build")]
        private static void Build()
        {
            Init();
            string platformStr = platform.ToLower();
            if (platformStr == "pc")
            {
                Build_Pc();
            }
            else if (platformStr == "android")
            {
                Build_Android();
            }
        }
 
        [MenuItem("Tool/Build/Setting")]
        private static void SetConfig()
        {
            Read();
            GetWindow(typeof(BuildTool));
        }
 
        private static void Build_Pc()
        {
            string path = string.Format(@"{0}/{1}/{2}.exe", outPath, productName, packageName);
            BuildPipeline.BuildPlayer(EditorBuildSettings.scenes, path, BuildTarget.StandaloneWindows64,
                BuildOptions.None);
        }
 
        private static void Build_Android()
        {
            string path = string.Format(@"{0}/{1}_{2}_{3}.apk", outPath, companyName, productName, packageName);
            BuildPipeline.BuildPlayer(EditorBuildSettings.scenes, path, BuildTarget.Android,
                BuildOptions.None);
        }
 
        private static void Init()
        {
            Read();
PlayerSettings.companyName = companyName;
            PlayerSettings.productName = productName;
            PlayerSettings.applicationIdentifier = string.Format("com.{0}.{1}", companyName, productName);
            PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, PlayerSettings.applicationIdentifier);
            PlayerSettings.runInBackground = true;
            PlayerSettings.displayResolutionDialog = ResolutionDialogSetting.Disabled;
        }
 
        private static void Save()
        {
            XmlDocument doc = new XmlDocument();
            XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
            doc.AppendChild(dec);
            XmlElement root = doc.CreateElement("buildSetting");
            doc.AppendChild(root);
 
            XmlElement xmlPlatform = doc.CreateElement("platform");
            XmlElement xmlCompany = doc.CreateElement("company");
            XmlElement xmlProduct = doc.CreateElement("product");
            XmlElement xmlPackage = doc.CreateElement("package");
            XmlElement xmlOutPath = doc.CreateElement("outPath");
 
            xmlPlatform.InnerText = platform;
            xmlCompany.InnerText = companyName;
            xmlProduct.InnerText = productName;
            xmlPackage.InnerText = packageName;
            xmlOutPath.InnerText = outPath;
 
            root.AppendChild(xmlPlatform);
            root.AppendChild(xmlCompany);
            root.AppendChild(xmlProduct);
            root.AppendChild(xmlPackage);
            root.AppendChild(xmlOutPath);
 
            string path = string.Format("{0}/Editor/Config/BuildSetting.xml", Application.dataPath);
            doc.Save(path);
 
            Debug.LogError("save success !!!");
        }
 
        private static void Read()
        {
            string path = string.Format("{0}/Editor/Config/BuildSetting.xml", Application.dataPath);
            if (!File.Exists(path))
            {
                Debug.LogError("dont find this file");
                return;
            }
 
            XmlDocument xml = new XmlDocument();
            xml.Load(path);
            XmlNode root = xml.SelectSingleNode("buildSetting");
 
            XmlNodeList xmlContents = root.ChildNodes;
            XmlElement xmlPlatform = xmlContents.Item(0) as XmlElement;
            XmlElement xmlCompany = xmlContents.Item(1) as XmlElement;
            XmlElement xmlProduct = xmlContents.Item(2) as XmlElement;
            XmlElement xmlPackage = xmlContents.Item(3) as XmlElement;
            XmlElement xmlOutPath = xmlContents.Item(4) as XmlElement;
 
            platform = xmlPlatform.InnerText;
            companyName = xmlCompany.InnerText;
            productName = xmlProduct.InnerText;
            packageName = xmlPackage.InnerText;
            outPath = xmlOutPath.InnerText;
 
            if (platform == "pc") index = 0;
            else if (platform == "android") index = 1;
        }
    }
}
 
例子二:
本来是想写一个打ab包的工具来着,结果界面写差不多的时候,一整理流程逻辑发现打包的方式有问题。所以只好拿半成品来凑数了,不过界面的部分还算是能看的。界面的部分如下:
技术分享图片
 
总体界面
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
 
namespace MyEditor.AB
{
    public partial class ABTool : EditorWindow
    {
        private string rootPath;
        private FolderWindow folderWindow;
        private static Vector2 scrollVec_Selected = Vector2.zero;
        private static Vector2 scrollVec_Total = Vector2.zero;
        private void Awake()
        {
            rootPath = Application.dataPath;
            folderWindow = new FolderWindow(rootPath, null);
        }
 
        private void OnGUI()
        {
            GUILayout.Label("AssetBundle Setting");
            GUILayout.Space(10);
 
            SetPlatformArea();
            SetInBundleArea();
            SetAllArea();
            SetViewArea();
            SetButtonArea();
        }
 
        private void SetPlatformArea()
        {
            GUILayout.BeginArea(new Rect(5, 30, 180, 80), EditorStyles.helpBox);
            GUILayout.Label("Platform");
 
            if (EditorGUILayout.Toggle("PC", pc))
            {
                pc = true;
                android = false;
                ios = false;
            }
            if (EditorGUILayout.Toggle("Android", android))
            {
                android = true;
                pc = false;
                ios = false;
            }
            if (EditorGUILayout.Toggle("IOS", ios))
            {
                pc = false;
                android = false;
                ios = true;
            }
 
            GUILayout.EndArea();
        }
 
        private void SetInBundleArea()
        {
            GUILayout.BeginArea(new Rect(5, 120, 180, 400), EditorStyles.helpBox);
            GUILayout.Label("In Bundle");
            scrollVec_Selected = EditorGUILayout.BeginScrollView(scrollVec_Selected);
            folderWindow.DrawSelected();
            paths = folderWindow.GetSelectedPaths();
            GUILayout.EndScrollView();
            GUILayout.EndArea();
        }
 
        private void SetAllArea()
        {
            GUILayout.BeginArea(new Rect(190, 30, 180, 490), EditorStyles.helpBox);
            GUILayout.Label("All");
            scrollVec_Total = GUILayout.BeginScrollView(scrollVec_Total);
            folderWindow.Draw();
            GUILayout.EndScrollView();
            GUILayout.EndArea();
        }
 
        private void SetViewArea()
        {
            GUILayout.BeginArea(new Rect(375, 30, 180, 490), EditorStyles.helpBox);
            GUILayout.Label("View Files");
            GUILayout.BeginScrollView(new Vector2(375, 60), EditorStyles.helpBox);
 
 
            GUILayout.EndScrollView();
            GUILayout.EndArea();
 
        }
 
        private void SetButtonArea()
        {
            GUILayout.BeginArea(new Rect(5, 530, 365, 30));
            EditorGUILayout.BeginHorizontal();
            bool isSaveClick = GUILayout.Button("Save", EditorStyles.miniButtonLeft);
            GUILayout.Space(5);
            bool isRefreshClick = GUILayout.Button("Refresh", EditorStyles.miniButtonRight);
            EditorGUILayout.EndHorizontal();
            GUILayout.EndArea();
            if (isSaveClick)
            {
                SaveConfig();
            }
            if (isRefreshClick)
            {
                SetConfig();
            }
        }
 
    }
}
 
界面细节部分
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEditor;
 
namespace MyEditor.AB
{
    public partial class ABTool
    {
        private class FolderWindow
        {
            private string path;
            private string name;
            private int level;
            private FolderWindow parent;
            private List<FolderWindow> childWins = new List<FolderWindow>();
 
            private bool isSelected = false;
 
            public FolderWindow(string _path, FolderWindow _parent)
            {
                path = _path;
                name = Path.GetFileNameWithoutExtension(_path);
                parent = _parent;
 
                FolderWindow temp = parent;
                while (temp != null)
                {
                    temp = temp.parent;
                    level++;
                }
 
                if (ABTool.paths.Contains(path))
                {
                    SetSelected();
                }
                string[] paths = Directory.GetDirectories(_path);
                for (int i = 0; i < paths.Length; i++)
                {
                    FolderWindow childWin = new FolderWindow(paths[i], this);
                    childWins.Add(childWin);
                }
            }
 
            public void Draw()
            {
                EditorGUILayout.BeginHorizontal();
                GUILayout.Space(level * 15);
                isSelected = EditorGUILayout.Toggle(isSelected);
                GUILayout.Label(name);
                EditorGUILayout.EndHorizontal();
 
                if (isSelected)
                {
                    for (int i = 0; i < childWins.Count; i++)
                    {
                        childWins[i].Draw();
                    }
                }
            }
 
            public void DrawSelected()
            {
                if (!isSelected) return;
                EditorGUILayout.BeginHorizontal();
                GUILayout.Space(level * 15);
                isSelected = EditorGUILayout.Toggle(isSelected);
                GUILayout.Label(name);
                EditorGUILayout.EndHorizontal();
                for (int i = 0; i < childWins.Count; i++)
                {
                    childWins[i].DrawSelected();
                }
            }
 
            public List<string> GetSelectedPaths()
            {
                List<string> list = new List<string>();
                if (isSelected)
                {
                    int num = 0;
                    for (int i = 0; i < childWins.Count; i++)
                    {
                        var childList = childWins[i].GetSelectedPaths();
                        if (childList.Count == 0)
                        {
                            continue;
                        }
                        list.AddRange(childWins[i].GetSelectedPaths());
                        num++;
                    }
                    if (num == 0)
                    {
                        list.Add(path);
                    }
                }
                return list;
            }
 
            private void SetSelected()
            {
                isSelected = true;
                var temp = parent;
                while (temp != null)
                {
                    temp.SetSelected();
                    temp = temp.parent;
                }
            }
        }
    }
}
 
界面功能部分
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Xml;
using System.IO;
using Singledigit.Runtime;
 
namespace MyEditor.AB
{
    public partial class ABTool
    {
        private static List<string> paths = new List<string>();
 
        private static bool pc = true;
        private static bool android = true;
        private static bool ios = true;
 
 
        [MenuItem("Tool/AssetBundle/Setting")]
        private static void SetConfig()
        {
            ReadConfig();
            GetWindow<ABTool>();
        }
 
        [MenuItem("Tool/AssetBundle/Build")]
        private static void Build()
        {
            AssetDatabase.RemoveUnusedAssetBundleNames();
 
            ReadConfig();
            string outPath = Application.streamingAssetsPath;
            string abOutPath = string.Format("Assets/{0}", Util.Path.GetUnityPath(outPath));
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }
            BuildTarget buildTarget = pc ? BuildTarget.StandaloneWindows :
                (android ? BuildTarget.Android :
                (ios ? BuildTarget.iOS : BuildTarget.NoTarget));
 
            AssetBundleBuild[] abs = new AssetBundleBuild[paths.Count];
 
            for (int i = 0; i < abs.Length; i++)
            {
                string unityPath = Util.Path.GetUnityPath(paths[i]);
                string abName = Util.Path.GetPathName(unityPath);
                abs[i] = new AssetBundleBuild();
                abs[i].assetBundleName = abName;
                Debug.LogError(abName);
                string[] fileNames = Directory.GetFiles(paths[i]);
                List<string> fileNamesWithoutMeta = new List<string>();
                for (int j = 0; j < fileNames.Length; j++)
                {
                    if (fileNames[j].Contains(".meta"))
                    {
                        continue;
                    }
                    string abFileName = string.Format("Assets/{0}", Util.Path.GetUnityPath(fileNames[j]));
                    fileNamesWithoutMeta.Add(abFileName);
                    Debug.LogError(abFileName);
                }
                abs[0].assetNames = fileNamesWithoutMeta.ToArray();
            }
 
            BuildPipeline.BuildAssetBundles(abOutPath,
                abs,
                BuildAssetBundleOptions.None,
                BuildTarget.StandaloneWindows);
        }
 
        private static void ReadConfig()
        {
            string savePath = string.Format("{0}/Editor/Config/ABSetting.xml", Application.dataPath);
            if (!File.Exists(savePath))
            {
                Debug.LogError("dont have abSetting config");
                return;
            }
            XmlDocument doc = new XmlDocument();
            doc.Load(savePath);
 
            XmlNode root = doc.SelectSingleNode("ABSetting");
 
            XmlNodeList childs = root.ChildNodes;
            XmlElement xmlPlatform = childs[0] as XmlElement;
            string platformStr = xmlPlatform.InnerText;
            pc = false;
            android = false;
            ios = false;
            if (platformStr == "pc")
            {
                pc = true;
            }
            else if (platformStr == "android")
            {
                android = true;
            }
            else if (platformStr == "ios")
            {
                ios = true;
            }
 
            XmlNode pathsNode = childs[1];
            XmlNodeList pathChilds = pathsNode.ChildNodes;
            paths.Clear();
 
            for (int i = 0; i < pathChilds.Count; i++)
            {
                paths.Add(pathChilds[i].InnerText);
            }
        }
 
        private static void SaveConfig()
        {
            XmlDocument doc = new XmlDocument();
            XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", null);
            doc.AppendChild(dec);
 
            XmlElement root = doc.CreateElement("ABSetting");
            doc.AppendChild(root);
 
            XmlElement xmlPlatform = doc.CreateElement("platform");
            xmlPlatform.InnerText = pc ? "pc" : (android ? "android" : (ios ? "ios" : ""));
            root.AppendChild(xmlPlatform);
 
            XmlElement xmlPaths = doc.CreateElement("paths");
            root.AppendChild(xmlPaths);
 
            for (int i = 0; i < paths.Count; i++)
            {
                XmlElement path = doc.CreateElement("path");
                path.InnerText = paths[i];
                xmlPaths.AppendChild(path);
            }
 
            string savePath = string.Format("{0}/Editor/Config/ABSetting.xml", Application.dataPath);
            doc.Save(savePath);
 
            Debug.LogError("save success!!!");
        }
 
        private static AssetBundleBuild[] CreateAssetBundleData()
        {
            List<AssetBundleBuild> datas = new List<AssetBundleBuild>();
            for (int i = 0; i < paths.Count; i++)
            {
                var data = new AssetBundleBuild();
                string path = paths[i];
                data.assetBundleName = Util.Path.GetPathName(path) + ".unity3d";
                string[] files = Directory.GetFiles(path);
                List<string> assetNames = new List<string>();
                for (int j = 0; j < files.Length; j++)
                {
                    if (files[j].Contains(".meta")) continue;
                    assetNames.Add(files[j].Replace(Application.dataPath, ""));
                }
 
                data.assetNames = assetNames.ToArray();
 
                datas.Add(data);
            }
 
            return datas.ToArray();
        }
    }
}
 
界面中用到的Path函数
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
namespace Singledigit.Runtime
{
    public static partial class Util
    {
        public static class Path
        {
            public static string GetDataPath()
            {
                return string.Format("{0}/", Application.dataPath);
            }
 
            public static string GetStreamingAssetsPath()
            {
                return string.Format("{0}/", Application.streamingAssetsPath);
            }
 
            public static string Format(string _path)
            {
                return _path.Replace("\\\\", "/");
            }
 
            public static string GetUnityPath(string _fullPath)
            {
                string path = System.IO.Path.GetFullPath(_fullPath);
                string unityDataPath = System.IO.Path.GetFullPath(GetDataPath());
                path = path.Replace(unityDataPath, "");
 
                return Format(path);
            }
 
            public static string GetFullPath(string _unityPath)
            {
                string path = System.IO.Path.Combine(Application.dataPath, _unityPath);
                path = System.IO.Path.GetFullPath(path);
                return Format(path);
            }
 
            public static string GetPathName(string _unityPath)
            {
                string[] names = _unityPath.Split(‘/‘, ‘\\\\‘);
                string name = "";
                for (int i = 0; i < names.Length; i++)
                {
                    if (names[i] == "") continue;
                    name = string.Format("{0}_{1}", name, names[i].ToLower());
                }
                return name;
            }
        }
    }
}
 

 

以上是关于unity3d编辑器系列——独立的编辑器界面的主要内容,如果未能解决你的问题,请参考以下文章

Unity3d开发编辑器DrawCall参数解析

Unity3D的编辑器扩展 右键弹出菜单栏

unity3d打不开曲线编辑器

[干货分享]Unity3D 深入解析Timeline编辑器

unity3D 学习一.工具准备:unity安装以及代码编辑器(vs code)

unity3D 学习一.工具准备:unity安装以及代码编辑器(vs code)