背景:
在游戏开发中不免需要加一些我们自己的功能宏定义比如DebugMod开发模式宏 方便进行gm开发,或者一些debugtool的开发,开发者一定要重视debugTool的开发
不然会面临很多测试上的难题,比如某个流程很长的功能一轮测试下来可能就要几分钟。
主类很简单其他忽略 但是我这边定义了一个逻辑位 DefineBit 这里主要可以学习到逻辑位操作的技巧。点击开启宏之后等待工程编译(使用接口CompilationPipeline.RequestScriptCompilation())
等菊花转完之后就好了,同时之前显示的开启宏会变为关闭宏 ,再次点击按钮取消该宏定义,点击关闭所有宏定义会取消所有defineArray数组定义的所有宏
1.main.cs
public class Main : MonoBehaviour
{#if UNITY_EDITORpublic int DefineBit;
#endif
}
2.编辑器类MainEditor.cs
using System;
using System.IO;
using Launcher;
using Runtime.Core.Constants;
using UnityEditor;
using UnityEditor.Compilation;
using UnityEngine;
using Application = UnityEngine.Application;
[CustomEditor(typeof(Main))]
public class MainEditor : Editor
{
bool SymbleDefine = true;
string[] defineArray = new string[]
{"", "DebugMod","FRUIT_DEBUG","DEV_DEBUG_NET", // 网络调试 "VIP_DEBUG", // 测试vip "UNITASK_DOTWEEN_SUPPORT", // DoTween UniTask"HOT_UPDATE_TEST", // 测试热更新 "DELIVERY_DEV_1_1_3",// 分包开发 "DEBUG_REDPACK", "REMOTE_DEBUG", // 远程测试 "TEST_INPUT" , // 测试输入系统 "TEST_WELCOMEUI" , // 测试欢迎界面 "TEST_RANKMATCHEX" , // 测试排位赛"DEV_MODE",
};public BuildTarget buildTarget
{get{#if UNITY_ANDROIDreturn BuildTarget.Android;#elif UNITY_WEBGLreturn BuildTarget.WebGL;#elif UNITY_STANDALONEreturn BuildTarget.StandaloneWindows;#endif}
}
private void OnEnable()
{int nBit = 0;if(defineArray.Length >= 32){Debug.LogError("警告位已经不够用了");}for(int i = 0; i < defineArray.Length; i++){if (string.IsNullOrEmpty(defineArray[i])) continue;if(EasyUseEditorFuns.HasDebugSymble(buildTarget,defineArray[i])){nBit |= GetBit(nBit, i);} }(target as Main).DefineBit = nBit;//c# read json }static int GetBit(int number, int bitPosition)
{// 检查位是否有效if (bitPosition < 0 || bitPosition >= sizeof(int) * 8){throw new ArgumentOutOfRangeException(nameof(bitPosition), "位位置无效");}// 生成掩码:将 1 左移 bitPosition 位,然后取反int mask = (1 << bitPosition);// 使用按位与操作干掉指定位return number | mask;
}
static int ClearBit(int number, int bitPosition)
{// 检查位是否有效if (bitPosition < 0 || bitPosition >= sizeof(int) * 8){throw new ArgumentOutOfRangeException(nameof(bitPosition), "位位置无效");}// 生成掩码:将 1 左移 bitPosition 位,然后取反int mask = ~(1 << bitPosition);// 使用按位与操作干掉指定位return number & mask;
}static bool HasBit(int number, int bitPosition)
{// 检查位是否有效if (bitPosition < 0 || bitPosition >= sizeof(int) * 8){throw new ArgumentOutOfRangeException(nameof(bitPosition), "位位置无效");}// 判断指定位是否为 1return (number & (1 << bitPosition)) != 0;
}
public override void OnInspectorGUI()
{base.OnInspectorGUI();GUILayout.BeginHorizontal();if(!Application.isPlaying && GUILayout.Button("启动", GUILayout.Height(50)) || Application.isPlaying && GUILayout.Button("退出", GUILayout.Height(50))){EditorBuildSettingsScene[] tempScenes = new UnityEditor.EditorBuildSettingsScene[1];tempScenes[0] = new EditorBuildSettingsScene("Assets/scenes/GameStart.unity", true);EditorBuildSettings.scenes = tempScenes;if (!Application.isPlaying){EditorApplication.isPlaying = true;}else{EditorApplication.ExecuteMenuItem("Edit/Play");}}if(GUILayout.Button("暂停", GUILayout.Height(50))){EditorApplication.ExecuteMenuItem("Edit/Pause");}if(GUILayout.Button("编译c#", GUILayout.Height(50))){EditorUtility.RequestScriptReload();}GUILayout.EndHorizontal();GUILayout.BeginHorizontal();if (GUILayout.Button("打开c#",GUILayout.Height(50))){UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(System.Environment.CurrentDirectory + "/Assets/Launcher/Main.cs",1);//Application.OpenURL(System.Environment.CurrentDirectory + "/Assets/Launcher/Main.cs"); }if (GUILayout.Button("移除monohook插件", GUILayout.Height(50))){if(Directory.Exists(Application.dataPath + "/MonoHook")){EasyUseEditorFuns.DelFolderAllContens(Application.dataPath + "/MonoHook", true);if(File.Exists(Application.dataPath + "/MonoHook.meta")){File.Delete(Application.dataPath + "/MonoHook.meta");}}AssetDatabase.Refresh();}GUILayout.EndHorizontal();Main global = target as Main;SymbleDefine = EditorGUILayout.Foldout(SymbleDefine, new GUIContent("宏定义"));if (SymbleDefine){if(GUILayout.Button("关闭所有宏定义")){for (int i = 1; i < defineArray.Length; i++){if (global && HasBit(global.DefineBit, i)){global.DefineBit = ClearBit(global.DefineBit, i);EasyUseEditorFuns.SetUnitySymbleDefine(buildTarget, false, defineArray[i]);}}AssetDatabase.Refresh();//重新编译整个c#代码 CompilationPipeline.RequestScriptCompilation();}for(int i = 1; i < defineArray.Length; i++){if (global && HasBit(global.DefineBit, i) && GUILayout.Button($"关闭宏{defineArray[i]}")){global.DefineBit = ClearBit(global.DefineBit, i);EasyUseEditorFuns.SetUnitySymbleDefine(buildTarget, false, defineArray[i]);CompilationPipeline.RequestScriptCompilation();}if (global && !HasBit(global.DefineBit, i) && GUILayout.Button($"开启宏{defineArray[i]}")){global.DefineBit = GetBit(global.DefineBit, i);EasyUseEditorFuns.SetUnitySymbleDefine(buildTarget,true, defineArray[i]);CompilationPipeline.RequestScriptCompilation();}}}
}
}
EasyUseEditorFuns.cs
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System;
using System.Reflection;
using UnityEditor.Build;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor.SceneManagement;
using System.Linq;
using JetBrains.Annotations;
using GuideReplace;public static class EasyUseEditorFuns
{public static void SetUnitySymbleDefine(BuildTarget target, bool isAddOrRemove, string symble){NamedBuildTarget nameBt;var symbles = GetScriptSymble(target,out nameBt);if (isAddOrRemove){if (!string.IsNullOrEmpty(symbles)){var symble_arr = symbles.Split(';');if (Array.IndexOf(symble_arr, symble) < 0){symbles += $";{symble}";}}else{symbles = symble;}}else{if (!string.IsNullOrEmpty(symbles)){var symble_arr = symbles.Split(';');var index = Array.IndexOf(symble_arr, symble);if (index >= 0){if (index == symble_arr.Length - 1){symbles = index > 0 ? symbles.Replace($";{symble}", "") : symbles.Replace(symble, "");}else{symbles = symbles.Replace($"{symble};", "");}}}}PlayerSettings.SetScriptingDefineSymbols(nameBt, symbles);AssetDatabase.Refresh();}public static string GetScriptSymble(BuildTarget target,out NamedBuildTarget nameBt){string symbles = "";NamedBuildTarget nameBuildTarget;if (target == BuildTarget.iOS){nameBuildTarget = NamedBuildTarget.iOS;}else if (target == BuildTarget.Android){nameBuildTarget = NamedBuildTarget.Android;}else if (target == BuildTarget.WebGL){nameBuildTarget = NamedBuildTarget.WebGL;}else{nameBuildTarget = NamedBuildTarget.Standalone;}symbles = PlayerSettings.GetScriptingDefineSymbols(nameBuildTarget);nameBt = nameBuildTarget;return symbles;}
}