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

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

body,td { font-family: 微软雅黑; font-size: 14pt }

写在前面:

前段时间看了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;

}

}

}

}

原文地址:https://www.cnblogs.com/singledigit/p/8168240.html

时间: 2024-10-20 15:15:41

unity3d编辑器系列——独立的编辑器界面的相关文章

Unity3D引擎扩展中的编辑器定制方法

http://gamerboom.com/archives/36432 作者:Richard Fine Unity3D的方便之处在于,它很容易地扩展编辑器套件.每款游戏都对加工有着不同的需求,可以快速地以完全集成的方法来构建这些内容并极大地提升开发速度. 目前有大量复杂的软件包提供以基本Unity功能套件为基础的复杂工具,从视觉脚本编辑器到编辑器内导航网格生成.但是,有关如何自行构建此类事物的程序说明却很少.我将在下文列举某些在自己的工作中总结的编辑器定制相关信息. Unity-Window(f

Unity3D实践系列04, 脚本的生命周期

Unity3D脚本生命周期是指从脚本的最初唤醒到脚本最终销毁的整个过程.生命周期的各个方法被封装到了MonoBehaviour类中.具体来说如下: 1.In Editor Mode 编辑模式 当在编辑器中把脚本绑定到某个GameObject的时候,调用了MonoBehaviour类的Reset方法. 2.Startup 开始运行阶段 如果脚本所绑定的GameObject是存在的,MonoBehaviour类的的Awake方法首先被调用. 随之执行MonoBehaviour类的OnEnable方法

Android学习系列(23)--App主界面实现

在上篇文章<Android学习系列(22)--App主界面比较>中我们浅略的分析了几个主界面布局,选了一个最大众化的经典布局.今天我们就这个经典布局,用代码具体的实现它. 1.预览图先看下最终的界面设计图:    上面顶部是一个9patch背景图片+标题文字:下面底部是5个tab标签,表示应用的5大模块.中间内容部分则是各个模块的具体内容,可以再分类,或者直接显示内容. 2.准备素材按照上篇文章的界面,我们需要事先提供两大方面的素材:顶部+底部.顶部的素材非常简单,最重要的是背景(9patch

UNITY3D拓展编辑器 - InspectorEditor(属性编辑器)1

前文: 本章节会对InspectorEditor(属性编辑器)的创建方式进行叙述. 正文: 1.代码最终效果 2. 架构阐述 一个InspectorEditor(属性编辑器)产生直接对应着一个继承MonoBehaviour的脚本文件,脚本文件中定义着不同的属性以供InspectorEditor(属性编辑器)去实现.我们可以通过EditorGUILayout/GUILayout来实现InspectorEditor(属性编辑器)界面. 3. EditorGUILayout脚本分析 EditorGUI

Unity3d 开发(五)编辑器的undo操作

div#cpmenu {height:200px;float:left;} div#cpcontent {height:200px;width:150px;float:left;} 文章作者:松阳 原文链接:replaceMe Undo 在Unity3d编辑器扩展中,常常需要兼容Undo的操作即:Cmd/Ctrl + z.在Unity3d对应的接口Undo.RecordObjects可以完成这项工作. 封装 由于它的参数需要我们操作对象的组件,我为他封装了一个操作类.通过托管的方式调用. 实现

Unity3d开发(十一)编辑器DrawCall参数解析

对于Unity运行场景中,有许多可以标记场景状况的参数.这篇文章主要探讨这些参数的意义,其中如果有错误欢迎指正. Game Stats 点击游戏Tab下的Stats可以展开如下界面,可以方便我们查看游戏运行状态. FPS & Time per frame FPS是通常说的帧率.每帧用时指的是渲染一帧需要消耗的用时,这个值只包含每帧更新游戏视图的时间,不受其他在编辑器中功能的影响,例如Profiler.FPS是这个数字的倒数.值得注意的是,这个值会比我们通常说的帧率要高,因为我们是直接计算两帧之间

ZT:Unity3D研究院之使用Animation编辑器编辑动画(五十四)

原文地址:http://www.xuanyusong.com/archives/2246#comments 原文作者: 雨松MOMO 2013年04月16日 于 雨松MOMO程序研究院 发表 Unity提供了Animation编辑器,它可以为我们编辑物理动画.举个例子比如场景中有一个来回摇动的秋千,这个秋千在项目中完全只起到衬托作用,它不会与别的游戏对象有任何交互.如果这个秋千也用代码来写控制它来回摇动,会感觉小题大做.此时完全可以使用Animation编辑器来完成.但是它目前还不能编辑 FK

Linux Shell命令系列(5) VI编辑器

vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Linux系统的任何版本,vi编辑器是完全相同的,因此您可以在其他任何介绍vi的地方进一步了解它.Vi也是Linux中最基本的文本编辑器,学会它后,您将在Linux的世界里畅行无阻. 1.vi的基本概念  基本上vi可以分为三种状态,分别是命令模式(command mode).插入模式(Insert mode)和底行模式(last line

一个关于unity3d的系列文章

写在前面 想来从事unity3d开发已有三年多一些,寻思着该为这个奋斗了这么久的行业做些少许贡献,无赖自身水平局限加上各种拖延症,一直未能实施. 该写什么? 该怎么写? 不知道自己的能力是否能够撑起梦想,最后是否会太监? 也不会做需求分析,自己的文章会否有人问津? 更加不知道文章是否书写正确,不要传递了错误的信息,误人技术,徒留一地鸡毛. 想的多了,做得就少了,越想越无法下笔,但近日开始接手一个陈旧的项目,看着自己无法下手的代码,看着各种解不开的变量关系,才知道,虽然unity3d大大降低了做游