目录
1.工具制作的起因
2.工具的制作
(1).首先在Assets->Editor 目录下创建脚本
(2).创建一个工具窗口
(3).在OnGUI()中draw出来一些按钮/label 等
(4).查询方法
(5).替换方法
3.效果展示:
4.拓展:
5.完整代码:
1.工具制作的起因
现在大多数公司做游戏为了压缩时间和成本,基本都会直接拿以前或者是直接从网上找一些开源的游戏代码,在此基础上进行二次创作,在这种代码环境下做一些新的逻辑,难免会遇到一些困难,比如:
我在开发过程中需要加一个新的layer层来完成我的新代码逻辑 ,但是发现旧的代码已经把全部的layer用掉了我们都知道layer层是没办法添加的。
不明白为什么不能添加的同学可以看下:
Unity layer的介绍与使用以及只有32层的原因
因此我就只能写一个查找预制体layer的工具 以此来找到使用次数最少的layer层,以此来减轻更改layer层对原逻辑的影响。
2.工具的制作
(1).首先在Assets->Editor 目录下创建脚本
(2).创建一个工具窗口
代码如下:
public class ReadOrWriteLayer : EditorWindow{
static string checkPath;
[MenuItem("SelfTools / 打开layer查找窗口")]
public static void OpenWindow() {
ReadOrWriteLayer readOrWriteLayer = EditorWindow.GetWindow<ReadOrWriteLayer>();
readOrWriteLayer.Show();
checkPath = "Assets";
}
}
其中 :ReadOrWriteLayer 是创建类名
checkPath 是查找的路径
注意:我们的类要继承EditorWindow
(3).在OnGUI()中draw出来一些按钮/label 等
代码如下:
GUILayout.BeginHorizontal();
checkPath = EditorGUILayout.TextField("输入当前查找/替换的路径:", checkPath);
GUILayout.EndHorizontal();
GUILayout.Space(10);
动态修改checkPath 即 修改查找或者替换的路径
GUILayout.BeginHorizontal();
chechLayer = EditorGUILayout.TextField("输入当前查找的layer层:", chechLayer);
GUILayout.EndHorizontal();
GUILayout.Space(10); GUILayout.BeginHorizontal();
replaceLayer = EditorGUILayout.TextField("输入替换的layer层:", replaceLayer);
GUILayout.EndHorizontal();
GUILayout.Space(10);
分别输入要查找的layer层和要替换的layer层其中 chechLayer是要查找的layer层 replaceLayer是要替换成的layer层
GUILayout.BeginHorizontal();
if(GUILayout.Button("开始查找", "buttonleft", GUILayout.Width(250), GUILayout.Height(50))) {
if(!int.TryParse(chechLayer, out layer)) {
chechLayer = "";
} else
CheckAllGameObjectByLayer();
}GUILayout.EndHorizontal();
GUILayout.Space(10);
添加按钮
点击后执行查找方法 CheckAllGameObjectByLayer(); 检查输出所有查询的layer预制体路径和子节点路径
GUILayout.BeginHorizontal();
if(GUILayout.Button("开始替换", "buttonleft", GUILayout.Width(250), GUILayout.Height(50))) {
if(!int.TryParse(chechLayer, out layer) || !int.TryParse(replaceLayer, out replacelayer)) {
chechLayer = "";
} else
ReplaceAllGameObjectLayer();
}
GUILayout.EndHorizontal();
GUILayout.Space(10);
添加按钮
点击后执行查找方法 ReplaceAllGameObjectLayer(); 替换所有查询的layer层为替换layer层
(4).查询方法
private void CheckAllGameObjectByLayer() {
//写入进度条的当前值
startVal = 0f;
//输出文件保存路径
savePath = Application.dataPath + "/Editor/LayerSetting.text";
if(File.Exists(savePath))
File.Delete(savePath);
string allStr = "";
//查找checkPath路径下的所有文件路径
string[] allPath = Directory.GetFiles(checkPath, "*.prefab", SearchOption.AllDirectories);
maxValue = allPath.Length;
if(allPath.Length > 0) CreateFile();
//把预制体和预制体里面的子物体写入到文件LayerSetting.text中
using(FileStream fs = new FileStream(savePath, FileMode.Open)) {
StreamWriter sw = new StreamWriter(new BufferedStream(fs), Encoding.UTF8);
for(int i = 0; i < allPath.Length; i++) {
if(File.Exists(allPath[i])) {
//通过路径获取游戏obj
GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(allPath[i]);
if (obj == null) continue;
if(obj.layer == layer) {
allStr += string.Format("{0}\r\n", allPath[i]);
IterationAllGameObject(obj.transform, obj.name, ref allStr);
allStr += "\r\n";
} else {
IterationAllGameObject(obj.transform, obj.name, ref allStr);
}
}
startVal = i + 1;
//刷新当前读取进度
float slider = (float)startVal / maxValue;
//参数1 为标题,参数2为提示,参数3为 进度百分比 0~1 之间
EditorUtility.DisplayProgressBar("Loading", "写入中......", slider);
//写入文件
sw.Write(allStr);
allStr = "";
}
sw.Close();
fs.Close();
fs.Dispose();
}
//全部结束关闭进度条
EditorUtility.ClearProgressBar();
}
//如果保存文件不存在 创建一个
private static void CreateFile() {
if(!File.Exists(savePath)) {
FileStream file = new FileStream(savePath, FileMode.Create);
file.Dispose();
}
}
//迭代obj的所有子物体
private static void IterationAllGameObject(Transform obj, string path, ref string allStr, bool writeLayer = false) {
for(int i = 0; i < obj.childCount; i++) {
GameObject child = obj.GetChild(i).gameObject;
string realPath = path;
if(!writeLayer) {
if(child.layer == layer) {
realPath += string.Format("->{0}\r\n", child.name);
allStr += realPath;
}
} else {
realPath += string.Format("->{0} ::Layer -> {1}\r\n", child.name, child.layer);
allStr += realPath;
}
string namePath = string.Format("{0} ->{1}", path, child.name);
IterationAllGameObject(obj.GetChild(i), namePath, ref allStr, writeLayer);
}
}
(5).替换方法
private void ReplaceAllGameObjectLayer(bool checkLayer = true) {
startVal = 0f;
string[] allPath = Directory.GetFiles(checkPath, "*.prefab", SearchOption.AllDirectories);
maxValue = allPath.Length;
for(int i = 0; i < allPath.Length; i++) {
if(File.Exists(allPath[i])) {
GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(allPath[i]);
if (obj == null) continue;
if(obj.layer == layer) {
obj.layer = replacelayer;
} else if(!checkLayer) {
obj.layer = replacelayer;
}
IterationReplace(obj.transform, checkLayer);
}
startVal = i + 1;
float slider = (float)startVal / maxValue;
//参数1 为标题,参数2为提示,参数3为 进度百分比 0~1 之间
EditorUtility.DisplayProgressBar("Loading", "写入中......", slider);
}
EditorUtility.ClearProgressBar();
//保存全部修改
AssetDatabase.SaveAssets();
}
private static void IterationReplace(Transform obj, bool checkLayer = true) {
for(int i = 0; i < obj.childCount; i++) {
GameObject child = obj.GetChild(i).gameObject;
if(child.layer == layer) {
child.layer = replacelayer;
} else if(!checkLayer)
child.layer = replacelayer;
IterationReplace(obj.GetChild(i), checkLayer);
}
}
至此一个完整的layer层查询/替换工具诞生了
3.效果展示:
这个文件里就是查询的layer层的所有预制体的路径信息
点击替换 输入替换layer层就可以把文件中的所有预制体都替换掉
4.拓展:
由于每次都要手动填写查询目录 我觉得十分烦 想到unity有一个选中逻辑 于是添加了一条鼠标选中后路径更新
代码如下:
static bool isRun = false;
bool toggle; GUILayout.BeginHorizontal();
toggle = EditorGUILayout.BeginToggleGroup("选择路径", toggle);
if(Selection.assetGUIDs.Length > 0 && !isRun && toggle) {
string selectPath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
checkPath = selectPath;
}
EditorGUILayout.EndToggleGroup();
GUILayout.EndHorizontal();
GUILayout.Space(10);
另外在替换或者查询中关闭isRun
效果如下:
勾选选择路径之后 查找/替换路径会自动更换成鼠标选择的路径
注:鼠标选择之后需要移到此面板 此面板才会动态更新路径
5.完整代码:
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
public class ReadOrWriteLayer : EditorWindow {
static string checkPath;
static string savePath;
string chechLayer;
string replaceLayer;
static int layer;
static int replacelayer;
float startVal;
float maxValue;
bool toggle;
static bool isRun = false;
[MenuItem("SelfTools / 打开layer查找窗口")]
public static void OpenWindow() {
ReadOrWriteLayer readOrWriteLayer = EditorWindow.GetWindow<ReadOrWriteLayer>();
readOrWriteLayer.Show();
checkPath = "Assets";
}
void OnGUI() {
GUILayout.BeginHorizontal();
toggle = EditorGUILayout.BeginToggleGroup("选择路径", toggle);
if (Selection.assetGUIDs.Length > 0 && !isRun && toggle)
{
string selectPath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
checkPath = selectPath;
}
EditorGUILayout.EndToggleGroup();
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
checkPath = EditorGUILayout.TextField("输入当前查找/替换的路径:", checkPath);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
chechLayer = EditorGUILayout.TextField("输入当前查找的layer层:", chechLayer);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
replaceLayer = EditorGUILayout.TextField("输入替换的layer层:", replaceLayer);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
if(GUILayout.Button("开始查找", "buttonleft", GUILayout.Width(250), GUILayout.Height(50))) {
if(!int.TryParse(chechLayer, out layer)) {
chechLayer = "";
} else
CheckAllGameObjectByLayer();
}
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
if(GUILayout.Button("开始替换", "buttonleft", GUILayout.Width(250), GUILayout.Height(50))) {
if(!int.TryParse(chechLayer, out layer) || !int.TryParse(replaceLayer, out replacelayer)) {
chechLayer = "";
} else
ReplaceAllGameObjectLayer();
}
GUILayout.EndHorizontal();
GUILayout.Space(10);
}
private void CheckAllGameObjectByLayer() {
isRun = true;
//写入进度条的当前值
startVal = 0f;
//输出文件保存路径
savePath = Application.dataPath + "/Editor/LayerSetting.text";
if(File.Exists(savePath))
File.Delete(savePath);
string allStr = "";
//查找checkPath路径下的所有文件路径
string[] allPath = Directory.GetFiles(checkPath, "*.prefab", SearchOption.AllDirectories);
maxValue = allPath.Length;
if(allPath.Length > 0) CreateFile();
//把预制体和预制体里面的子物体写入到文件LayerSetting.text中
using(FileStream fs = new FileStream(savePath, FileMode.Open)) {
StreamWriter sw = new StreamWriter(new BufferedStream(fs), Encoding.UTF8);
for(int i = 0; i < allPath.Length; i++) {
if(File.Exists(allPath[i])) {
//通过路径获取游戏obj
GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(allPath[i]);
if (obj == null) continue;
if(obj.layer == layer) {
allStr += string.Format("{0}\r\n", allPath[i]);
IterationAllGameObject(obj.transform, obj.name, ref allStr);
allStr += "\r\n";
} else {
IterationAllGameObject(obj.transform, obj.name, ref allStr);
}
}
startVal = i + 1;
//刷新当前读取进度
float slider = (float)startVal / maxValue;
//参数1 为标题,参数2为提示,参数3为 进度百分比 0~1 之间
EditorUtility.DisplayProgressBar("Loading", "写入中......", slider);
//写入文件
sw.Write(allStr);
allStr = "";
}
sw.Close();
fs.Close();
fs.Dispose();
}
//全部结束关闭进度条
EditorUtility.ClearProgressBar();
isRun = false;
}
//如果保存文件不存在 创建一个
private static void CreateFile() {
if(!File.Exists(savePath)) {
FileStream file = new FileStream(savePath, FileMode.Create);
file.Dispose();
}
}
//迭代obj的所有子物体
private static void IterationAllGameObject(Transform obj, string path, ref string allStr, bool writeLayer = false) {
for(int i = 0; i < obj.childCount; i++) {
GameObject child = obj.GetChild(i).gameObject;
string realPath = path;
if(!writeLayer) {
if(child.layer == layer) {
realPath += string.Format("->{0}\r\n", child.name);
allStr += realPath;
}
} else {
realPath += string.Format("->{0} ::Layer -> {1}\r\n", child.name, child.layer);
allStr += realPath;
}
string namePath = string.Format("{0} ->{1}", path, child.name);
IterationAllGameObject(obj.GetChild(i), namePath, ref allStr, writeLayer);
}
}
private void ReplaceAllGameObjectLayer(bool checkLayer = true) {
isRun = true;
startVal = 0f;
string[] allPath = Directory.GetFiles(checkPath, "*.prefab", SearchOption.AllDirectories);
maxValue = allPath.Length;
for(int i = 0; i < allPath.Length; i++) {
if(File.Exists(allPath[i])) {
GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(allPath[i]);
if (obj == null) continue;
if (obj.layer == layer) {
obj.layer = replacelayer;
} else if(!checkLayer) {
obj.layer = replacelayer;
}
IterationReplace(obj.transform, checkLayer);
}
startVal = i + 1;
float slider = (float)startVal / maxValue;
//参数1 为标题,参数2为提示,参数3为 进度百分比 0~1 之间
EditorUtility.DisplayProgressBar("Loading", "写入中......", slider);
}
EditorUtility.ClearProgressBar();
//保存全部修改
AssetDatabase.SaveAssets();
isRun = false;
}
private static void IterationReplace(Transform obj, bool checkLayer = true) {
for(int i = 0; i < obj.childCount; i++) {
GameObject child = obj.GetChild(i).gameObject;
if(child.layer == layer) {
child.layer = replacelayer;
} else if(!checkLayer)
child.layer = replacelayer;
IterationReplace(obj.GetChild(i), checkLayer);
}
}
}