好多东西直接记在云笔记上,好久没有写博客了,新年分享一下。
写在前面:
前段时间看了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;
}
}
}
}