-小狗饼干- / 洛12
1051 字
5 分钟
Unity 编辑器扩展工具集
曲线工具
这个工具用于生成和编辑 Unity 的 AnimationCurve 曲线,可以方便地将曲线数据转换为代码,也可以从代码中还原曲线。
using System.Collections;using System.Collections.Generic;using System.Text.RegularExpressions;using UnityEditor;using UnityEngine;
public class CurveTool : EditorWindow{ private AnimationCurve curve;
private string target_Str = "";
[MenuItem("工具/曲线工具")] public static void OpenWindow() { GetWindow<CurveTool>("曲线工具"); }
private void OnGUI() { GUILayout.Space(20f); EditorGUILayout.CurveField(curve);
GUILayout.Space(20f); if (GUILayout.Button("生成")) { target_Str = ""; target_Str += $"AnimationCurve curve;\n"; target_Str += $"Keyframe[] keyframes = new Keyframe[{curve.length}];\n"; for (int i = 0; i < curve.length; i++) target_Str += $"keyframes[{i}] = new Keyframe({curve.keys[i].time}f, {curve.keys[i].value}f, {curve.keys[i].inTangent}f, {curve.keys[i].outTangent}f, {curve.keys[i].inWeight}f, {curve.keys[i].outWeight}f);\n"; target_Str += $"curve = new AnimationCurve(keyframes);"; }
GUILayout.Space(20f); target_Str = GUILayout.TextArea(target_Str);
if (GUILayout.Button("复原")) { MatchCollection mc = Regex.Matches(target_Str, @"-*?\d+(\.\d+)*(?=f)"); List<Keyframe> keys = new List<Keyframe>(); Keyframe key = new Keyframe(); for (int i = 0; i < mc.Count; i++) { switch (i % 6) { case 0: key = new Keyframe(); key.time = float.Parse(mc[i].Value); break;
case 1: key.value = float.Parse(mc[i].Value); break;
case 2: key.inTangent = float.Parse(mc[i].Value); break;
case 3: key.outTangent = float.Parse(mc[i].Value); break;
case 4: key.inWeight = float.Parse(mc[i].Value); break;
case 5: key.outWeight = float.Parse(mc[i].Value); keys.Add(key); break; } } curve = new AnimationCurve(keys.ToArray()); } }}正则测试工具
这个工具提供了一个可视化的正则表达式测试环境,支持多种文本输入方式,包括自定义文本、脚本文件和 StepScript。
using System.Collections;using System.Collections.Generic;using System.IO;using System.Text.RegularExpressions;using UnityEditor;using UnityEngine;
namespace PersonalTool{ public class RegexTestTool : EditorWindow { public static RegexTestTool Tool;
private string regexStr; private Vector2 scrollPos = Vector2.zero;
private string fileString; private MatchCollection matches = null; private string[] splits = null;
private string coverStr = "";
private int preFileType = 0; private int fileType = 0;
private string filename = ""; private string fileID = "";
private bool isTrans = true;
[MenuItem("工具/正则测试工具")] private static void OpenWindow() { Tool = GetWindow<RegexTestTool>("正则测试工具"); Tool.Show(); }
private void OnEnable() { using (StreamReader sr = new StreamReader(Application.dataPath + "<FILE_PATH>")) { fileString = sr.ReadToEnd(); } }
private void OnGUI() { GUILayout.Label("正则表达式"); regexStr = GUILayout.TextArea(regexStr); EditorGUILayout.BeginHorizontal(); fileType = GUILayout.Toolbar(fileType, new string[] { "自定义文本", "脚本", "StepScript" }); if (preFileType != fileType) { coverStr = ""; fileID = ""; preFileType = fileType; } EditorGUILayout.EndHorizontal(); switch (fileType) { case 0: GUILayout.Label("覆盖测试文本"); coverStr = GUILayout.TextArea(coverStr); break;
case 1: EditorGUILayout.BeginHorizontal(); GUILayout.Label("脚本名称"); filename = GUILayout.TextField(filename); if (GUILayout.Button("确定")) { if (CheckInput(filename, out string id)) { string filePath = Application.dataPath + $"<FILE_PATH>"; if (File.Exists(filePath)) { fileID = id; coverStr = File.ReadAllText(filePath); } } } EditorGUILayout.EndHorizontal(); GUILayout.Label($"当前脚本:{(fileID == "" ? "<FILE_NAME>" : fileID)}"); break;
case 2: if (File.Exists(Application.dataPath + $"/.StepEditorProgram/StepScript.txt")) { coverStr = File.ReadAllText(Application.dataPath + $"/.StepEditorProgram/StepScript.txt"); } GUILayout.Label($"StepScript 加载{(coverStr == "" ? "失败" : "成功")}"); isTrans = GUILayout.Toggle(isTrans, "是否转义回正常符号"); break; } EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Match")) { if (regexStr == null || regexStr == "") return; matches = null; splits = null; matches = Regex.Matches(coverStr != "" ? coverStr : fileString, regexStr, RegexOptions.ExplicitCapture); //var obj = AssetDatabase.LoadAssetAtPath<Object>("<FILE_PATH>"); //Selection.activeObject = obj; //EditorGUIUtility.PingObject(obj); //Regex.Match("12", @"{[^{}]*(((?'Open'{)[^{}]*)+((?'-Open'})[^{}]*)+)*(?(Open)(?!))}"); //Regex.Match("12", @"[\x20\t]+case\s+\d+\s*:[\s\S]*?break;"); //Regex.Match("12", @"public\s+(async\s+)?override\s+(async\s+)?void\s+(command(Start|Update|End))[^{]*?{((?<open>{)|(?<-open>})|[^{}])*(?(open)(?!))}\s*(#HH#)+"); //Regex.Match("12", @"(?<=#HH#)\s*switch\s*\(StepController\.Instance\.currentIndex\)[^{]*?{((?<open>{)|(?<-open>})|[^{}])*(?(open)(?!))}\s*(#HH#)+"); } if (GUILayout.Button("Split")) { if (regexStr == null || regexStr == "") return; matches = null; splits = null; splits = Regex.Split(coverStr != "" ? coverStr : fileString, regexStr, RegexOptions.ExplicitCapture); } EditorGUILayout.EndHorizontal(); if (GUILayout.Button("清除")) { matches = null; splits = null; } if (matches != null && matches.Count != 0) { scrollPos = EditorGUILayout.BeginScrollView(scrollPos); foreach (Match m in matches) { string temp = ""; if (isTrans) { temp = m.Value.Replace("#HH#", "\n"); temp = temp.Replace("#SYH#", "\""); } EditorGUILayout.TextArea(isTrans ? temp : m.Value); } EditorGUILayout.EndScrollView(); } if (splits != null && splits.Length != 0) { scrollPos = EditorGUILayout.BeginScrollView(scrollPos); foreach (string s in splits) { string temp = ""; if (isTrans) { temp = s.Replace("#HH#", "\n"); temp = temp.Replace("#SYH#", "\""); } EditorGUILayout.TextArea(isTrans ? temp : s); } EditorGUILayout.EndScrollView(); } }
private bool CheckInput(string inputStr, out string id) { id = null; if (Regex.IsMatch(inputStr, @"^[Ee]+\d+[Cc]+\d+$")) { id = Regex.Replace(inputStr, @"[Ee]+", "E"); id = Regex.Replace(id, @"[Cc]+", "C"); return true; } return false; } }}文件创建扩展
这个扩展提供了自定义的文件创建功能,包括 MLab 脚本、普通脚本和文本文件的创建,并支持自动替换文件模板中的关键字。
using System;using System.Collections;using System.Collections.Generic;using System.IO;using System.Text;using System.Text.RegularExpressions;using UnityEditor;using UnityEngine;
namespace PersonalTool.FileExtension{ public class FileCreateExtension : EditorWindow { private const string MLAB_SCRIPT_TEMPLATE_PATH = "Assets/Editor/PersonalTool/FileExtension/MLabScriptTemplate.txt"; [MenuItem("Assets/Create/MLab Script (.cs)", false, 31)] public static void CreateFile_MLabScript() { string filePath = AssetDatabase.GenerateUniqueAssetPath(GetSelectedPathOrFallback() + "NewMLabScript.cs"); ProjectWindowUtil.CreateAssetWithContent(filePath, File.ReadAllText(MLAB_SCRIPT_TEMPLATE_PATH), EditorGUIUtility.FindTexture("d_cs Script Icon")); }
private const string NORMAL_SCRIPT_TEMPLATE_PATH = "Assets/Editor/PersonalTool/FileExtension/NormalScriptTemplate.txt"; [MenuItem("Assets/Create/Normal Script (.cs)", false, 31)] public static void CreateFile_NormalScript() { string filePath = AssetDatabase.GenerateUniqueAssetPath(GetSelectedPathOrFallback() + "NewNormalScript.cs"); ProjectWindowUtil.CreateAssetWithContent(filePath, File.ReadAllText(NORMAL_SCRIPT_TEMPLATE_PATH), EditorGUIUtility.FindTexture("d_cs Script Icon")); }
[MenuItem("Assets/Create/Text Asset (.txt)", false, 31)] public static void CreateFile_TextAsset() { string filePath = AssetDatabase.GenerateUniqueAssetPath(GetSelectedPathOrFallback() + "New Text Asset.txt"); ProjectWindowUtil.CreateAssetWithContent(filePath, "", EditorGUIUtility.FindTexture("d_TextAsset Icon")); }
private static string GetSelectedPathOrFallback() { string path = "Assets"; foreach (UnityEngine.Object obj in Selection.GetFiltered<UnityEngine.Object>(SelectionMode.Assets)) { path = AssetDatabase.GetAssetPath(obj); if (!string.IsNullOrEmpty(path) && File.Exists(path)) { path = Path.GetDirectoryName(path); break; } } return path + "/"; } }
public class CustomFileProcessor : UnityEditor.AssetModificationProcessor { public const string CompanyName = "moolsnet"; public const string Author = "请署名"; public const string Version = "1.0";
private static void OnWillCreateAsset(string path) { path = path.Replace(".meta", ""); if (!path.EndsWith(".cs")) return;
string content = File.ReadAllText(path); if (!Regex.IsMatch(content, @"#CutsomClassName#")) return;
content = ReplaceKeywords(content, path); File.WriteAllText(path, content);
AssetDatabase.Refresh(); }
public static string ReplaceKeywords(string input, string filePath) { input = input.Replace("#FileName#", Path.GetFileName(filePath)); input = input.Replace("#CompanyName#", CompanyName); input = input.Replace("#Author#", Author); input = input.Replace("#CreateTime#", DateTime.Now.ToString("F")); input = input.Replace("#Version#", Version); input = input.Replace("#UnityVersion#", Application.unityVersion); input = input.Replace("#CutsomClassName#", Path.GetFileNameWithoutExtension(filePath)); return input; } }}