Unity编辑器扩展

Unity编辑器扩展



前言

总结一下unity的扩展,持续更新


一、对Scene面板进行扩展

对scene面板我们可以扩展鼠标右键菜单

在这里插入图片描述

using UnityEngine;
using UnityEngine.UI;
using System;
using UnityEditor;
/*
* Editor:zhaoq4
*/
/// <summary>
/// Scene窗口扩展
/// </summary>
public class TestSceneMenu : MonoBehaviour
{
    [InitializeOnLoadMethod]
    static void InitializeOnLoad()
    {
        SceneView.duringSceneGui += (sceneView) =>
        {
            if (Event.current.button == 1 && Event.current.type == EventType.MouseUp)
            {
                //创建一个菜单
                Rect rect = new Rect(Event.current.mousePosition.x, Event.current.mousePosition.y - 100, 100, 100);
                //菜单内容
                GUIContent[] gUIContents = new GUIContent[] { new GUIContent("test1"), new GUIContent("test2") };
                //对菜单内容进行操作
                EditorUtility.DisplayCustomMenu(rect, gUIContents, -1, (data, opt, select) =>
                {
                    Debug.LogFormat("data:{0},opt:{1},select:{2},value:{3}", data, opt, select, opt[select]);
                }, null);
                //立即使用该事件,防止对其他右键功能产生冲突
                Event.current.Use();
            }
        };
    }
}

二、快捷键

%:表示Windows 下的 Ctrl键和macOS下的Command键。 #:表示Shift键。 &:表示Alt键。 LEFT/RIGHT/UP/DOWN:表示左、右、上、下4个方向键。 F1…F12:表示F1至F12菜单键。 HOME、END、PGUP和PGDN键
using UnityEngine;
using UnityEditor;
/*
* Editor:zhaoq4
*/
public class TestHotKey : MonoBehaviour
{
    //%:表示Windows 下的 Ctrl键和macOS下的Command键。
    //#:表示Shift键。
    //&:表示Alt键。
    //LEFT/RIGHT/UP/DOWN:表示左、右、上、下4个方向键。
    //F1…F12:表示F1至F12菜单键。
    //HOME、END、PGUP和PGDN键
    [MenuItem("GameObject/快捷键 %#z")]
    private static void HotKey()
    {
        Debug.Log("快捷键已经触发");
    }
}

三、预览框

在这里插入图片描述


    public override bool HasPreviewGUI()
    {
        bool hasGUI = base.HasPreviewGUI();
        bool showGUI = (target as TestInspector).showTexture != null;
        return hasGUI || showGUI;
    }

    /// <summary>
    /// 预览图
    /// </summary>
    /// <param name="r"></param>
    /// <param name="background"></param>
    public override void OnPreviewGUI(Rect r, GUIStyle background)
    {
        // base.OnPreviewGUI(r, background);
        Texture2D showTexture = (target as TestInspector).showTexture;
        if (showTexture == null) return;

        float size = Mathf.Min(r.width, r.height);
        float rectx = r.x + r.width / 2 - size / 2;
        float recty = r.y + r.height / 2 - size / 2;

        Rect rect = new Rect(rectx, recty, size, size);
        GUI.DrawTexture(rect, showTexture);
    }

四、编辑器弹窗

在这里插入图片描述

            EditorUtility.DisplayDialog("截屏", "截屏已完成","好的");

五、截屏

        static string path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
        static string imgName = "CaptureScreenshot" + ".png";
        static string filePath = path + "/" + imgName;
        [MenuItem("OverSeasMedia / 截屏 &1")]
        public static void CaptureScreenshot()
        {
            ScreenCapture.CaptureScreenshot(filePath, 0);
            EditorUtility.DisplayDialog("截屏", "截屏已完成,路径已保存在剪切板中", "好的");
            CopyImageToClipboard();
        }

本来是想截屏后保存到系统剪切板中,但是貌似system库中少了东西

        private static void CopyImageToClipboard()
        {
            StringCollection paths = new StringCollection();
            paths.Add(path);
            //会报错: 'Clipboard' is inaccessible due to its protection level
            Clipboard.SetFileDropList(paths);
        }

六、条件编译

可以在这里定义宏
一般情况下可以在代码中加入条件编译,在项目设置中加入该宏定义即可

#if AMPLIFY_SHADER_EDITOR
            //TODO
#endif

另一种方式是,直接使用特性类,使其生效

        [Conditional("AMPLIFY_SHADER_EDITOR")]
        private static void OnTest()
        {

        }

七.利用UiToolKit可以开发出更加优雅的调试界面

使用UItoolKit可以快速的建立一个调试面板

入口,可以在播放的时候显示在Game的左上角

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor;

#if UNITY_EDITOR
	//入口
    public class DebugGUIOnEditMode : MonoBehaviour
    {
        private static DebugGUIOnEditMode _current;
        [RuntimeInitializeOnLoadMethod]
        static void Initialize()
        {
            var g = new GameObject("DebugGUI");
            _current = g.AddComponent<DebugGUIOnEditMode>();
            UnityEngine.Object.DontDestroyOnLoad(g);
            XLog.ILog("DebugGUI", "实例化完成");
        }

        private void OnGUI()
        {
            if (GUILayout.Button("Debug面板"))
            {
                DebugGUI.ShowWindow();
            }
        }
    }
#endif
  1. 主脚本,这个脚本是使用Uitoolkit自动生成的,可以根据需要进行重构
    里面包含了根据枚举生成选项,对ui的事件进行注册
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
using DG.Tweening;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine.Rendering.Universal;
using System.Linq;

//Toggle_HighConfig
#if UNITY_EDITOR
    public class DebugGUI : EditorWindow
    {
        VisualElement root;

        ToolbarButton tbtn_3DAPI;
        ToolbarButton tbtn_Other;

        VisualElement ve_Panel;
        ObjectField objectField;

        /// <summary>
        /// 颜色组
        /// </summary>
        VisualElement colorGroup;

        /// <summary>
        /// 车轮组
        /// </summary>
        VisualElement wheelGroup;
        /// <summary>
        /// 门
        /// </summary>
        VisualElement doorGroup;

        /// <summary>
        /// 闪灯组
        /// </summary>
        VisualElement lampsSingalGroup;

        private void Awake()
        {
            Application.wantsToQuit += () =>
            {
                CloseWindow();
                return true;
            };
        }

        private void OnDestroy()
        {
            Application.wantsToQuit -= () =>
            {
                CloseWindow();
                return true;
            };
        }

        //[MenuItem("Window/UI Toolkit/DebugGUI")]
        public static bool ShowWindow()
        {
            if (Application.isPlaying)
            {
                DebugGUI wnd = GetWindow<DebugGUI>();
                return true;
            }
            else
            {
                return false;
            }
        }

        public static void CloseWindow()
        {
            DebugGUI wnd = GetWindow<DebugGUI>();
            wnd.Close();
        }

        void CreateGUI()
        {
            Init();
            RegisterEvent();
            CloseAllPanel();
        }

        private void Init()
        {
            root = rootVisualElement;
            if (!File.Exists(Application.dataPath + "/Apps/CarControl/Scripts/UIToolkit/DebugGUI.uxml"))
            {
                return;
            }

            var visualTree =
                AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
                    "Assets/Apps/CarControl/Scripts/UIToolkit/DebugGUI.uxml");
            visualTree.CloneTree(root);

            tbtn_3DAPI = root.Q<ToolbarButton>("tbtn_3DAPI");
            tbtn_Other = root.Q<ToolbarButton>("tbtn_Other");

            ve_Panel = root.Q<VisualElement>("ve_Panel");
            objectField = root.Q<ObjectField>("ObjectField");
            objectField.objectType = typeof(GameObject);
            colorGroup = root.Q<VisualElement>("ColorGroup");
            wheelGroup = root.Q<VisualElement>("WheelGroup");
            doorGroup = root.Q<VisualElement>("DoorGroup");
            lampsSingalGroup = root.Q<VisualElement>("LampsSingalGroup");
            InstantiateDoorElement();
            InstantiateColorElement();
            InstantiateWheelElement();
            InstantiateLampsElement();
        }

        /// <summary>
        /// 车门
        /// </summary>
        private void InstantiateDoorElement()
        {
            CarbodyLocation carbodyLocation = new CarbodyLocation();
            string[] names = Enum.GetNames(carbodyLocation.GetType());

            for (int i = 0; i < names.Count(); i++)
            {
                //构建车门类型
                DoorSwitchingMode mode = DoorSwitchingMode.Normal;
                var buttonGroup = CreateDoorSwitchingModeElement();
                buttonGroup.RegisterValueChangedCallback((value) =>
                {
                    mode = (DoorSwitchingMode)value.newValue;
                });
                //车门开关
                Toggle toggle = new Toggle();
                toggle.name = "tg_" + (CarbodyLocation)i;
                toggle.text = ((CarbodyLocation)i).ToString();
                var pos = (CarbodyLocation)i;
                toggle.RegisterValueChangedCallback(value =>
                {
                    EventCenter.Broadcast<bool, CarbodyLocation, TweenCallback, DoorSwitchingMode>(EEventDefine.CarControl_SetDoor, value.newValue, pos, null, mode);
                });
                doorGroup.Add(toggle);
                doorGroup.Add(buttonGroup);
            }

        }

        /// <summary>
        /// 创建开关方式
        /// </summary>
        private RadioButtonGroup CreateDoorSwitchingModeElement()
        {
            //开关方式
            DoorSwitchingMode doorSwitchingMode = new DoorSwitchingMode();
            //先生成单选按钮组
            string[] names = Enum.GetNames(doorSwitchingMode.GetType());
            RadioButtonGroup radiogroup = new RadioButtonGroup("", names.ToList());
            radiogroup.style.flexDirection = FlexDirection.Row;//横向排列
            radiogroup.style.alignItems = Align.Stretch;//拉伸
            radiogroup.style.justifyContent = Justify.SpaceAround;
            radiogroup.choices = names;
            return radiogroup;
        }

        private void InstantiateWheelElement()
        {
            WheelStyle wheelStyle = new WheelStyle();
            string[] name = Enum.GetNames(wheelStyle.GetType());
            for (int i = 0; i < name.Length; i++)
            {
                int index = i;
                Action action = () =>
                    EventCenter.Broadcast<WheelStyle>(EEventDefine.CarControl_SetWheelChanged, (WheelStyle)index);
                ToolbarButton toolbar = new ToolbarButton(action);
                toolbar.style.borderTopWidth = 1;
                toolbar.style.borderBottomWidth = 1;
                toolbar.style.borderLeftWidth = 1;
                toolbar.style.borderRightWidth = 1;
                toolbar.style.minWidth = 200;
                toolbar.style.maxWidth = 500;
                toolbar.name = "btn" + name[i];
                toolbar.text = name[i];
                wheelGroup.Add(toolbar);
            }
        }

        private void InstantiateLampsElement()
        {
            LampsSingal singals = new LampsSingal();
            string[] name = Enum.GetNames(singals.GetType());
            for (int i = 0; i < name.Length; i++)
            {
                int index = i;
                Action action = () =>
                    EventCenter.Broadcast<LampsSingal>(EEventDefine.CarControl_OnLampsSingal, (LampsSingal)index);
                ToolbarButton toolbar = new ToolbarButton(action);
                toolbar.style.borderTopWidth = 1;
                toolbar.style.borderBottomWidth = 1;
                toolbar.style.borderLeftWidth = 1;
                toolbar.style.borderRightWidth = 1;
                toolbar.style.minWidth = 200;
                toolbar.style.maxWidth = 500;
                toolbar.name = "btn" + name[i];
                toolbar.text = name[i];
                toolbar.style.unityTextAlign = new StyleEnum<TextAnchor>(TextAnchor.MiddleCenter);
                lampsSingalGroup.Add(toolbar);
            }
        }

        private bool isHighConfig;

        /// <summary>
        /// 获取枚举中的颜色,并实例化
        /// </summary>
        private void InstantiateColorElement()
        {
            CarpaintColors cc;
            if (FindObjectWithCompanent(out cc))
            {
                for (int i = 0; i < cc.GetCarpaint.Length; i++)
                {
                    int index = i;


                    root.Q<Toggle>("Toggle_HighConfig").RegisterValueChangedCallback(
                        (isOn) => { isHighConfig = isOn.newValue; }
                        //EventCenter.Broadcast<CarbodyLocation, bool>(EEventDefine.CarControl_SetTirePressureSwitch, CarbodyLocation.FL, isOn.newValue)
                    );

                    Action action = () =>
                        EventCenter.Broadcast<CarPaintColorID, bool>(EEventDefine.CarControl_SetCarpaintColor,
                            cc.GetCarpaint[index].id, isHighConfig);

                    ToolbarButton toolbar = new ToolbarButton(action);
                    toolbar.style.borderTopWidth = 1;
                    toolbar.style.borderBottomWidth = 1;
                    toolbar.style.borderLeftWidth = 1;
                    toolbar.style.borderRightWidth = 1;
                    toolbar.style.minWidth = 200;
                    toolbar.style.maxWidth = 500;
                    toolbar.name = "btn_" + cc.GetCarpaint[i].id.ToString();
                    toolbar.text = cc.GetCarpaint[i].ToString();
                    colorGroup.Add(toolbar);
                }
            }
            else
            {
                Debug.LogError("<ERROR : 场景中未找到车漆相关配置!>");
            }
        }

        /// <summary>
        /// 场景中查找换色对象
        /// </summary>
        /// <param name="comp"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        bool FindObjectWithCompanent<T>(out T comp) where T : Component
        {
            foreach (var go in Resources.FindObjectsOfTypeAll<T>())
            {
                comp = go.GetComponent<T>();
                if (comp != null)
                    return true;
            }

            comp = null;
            return false;
        }

        void RefrashView(int index)
        {
            CloseAllPanel();
            ve_Panel[index].style.display = DisplayStyle.Flex;
        }

        private void CloseAllPanel()
        {
            for (int i = 0; i < ve_Panel.childCount; i++)
            {
                ve_Panel[i].style.display = DisplayStyle.None;
            }
        }

        void OnDisable()
        {
            UnregisterEvent();
        }

        void RegisterEvent()
        {
            tbtn_3DAPI.clicked += () => RefrashView(tbtn_3DAPI.tabIndex);
            tbtn_Other.clicked += () => RefrashView(tbtn_Other.tabIndex);
            root.Q<Button>("btn_Find").clicked += () => { FindMaterialsInGameObject((GameObject)objectField.value); };
        }

        void UnregisterEvent()
        {
            tbtn_3DAPI.clicked -= () => RefrashView(tbtn_3DAPI.tabIndex);
            tbtn_Other.clicked -= () => RefrashView(tbtn_Other.tabIndex);

            root.Q<Button>("btn_LampsSingal").clicked -= () => EventCenter.Broadcast(EEventDefine.CarControl_OnLampsSingal);

        }

        /// <summary>
        /// 查找物体上的shade文件路径
        /// </summary>
        /// <param name="select"></param>
        void FindMaterialsInGameObject(GameObject select)
        {
            Renderer renderer;
            bool ishave = select.TryGetComponent<Renderer>(out renderer);
            if (select == null || !ishave) return;
            //Object fileObject = PrefabUtility.GetCorrespondingObjectFromSource(select);
            for (int i = 0; i < select.GetComponent<Renderer>().materials.Length; i++)
            {
                Shader shader = select.GetComponent<Renderer>().materials[i].shader;
            }
        }
    }
#endif

大致的布局,左边页签其实可以做的更好一点

八.利用ADF扩展GameView窗口

Unity 不用反射方式利用ADF方式设置自定义Game窗口分辨率

总结

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值