当前位置: 首页 > news >正文

编辑器场景视窗扩展

接上文编辑器菜单栏扩展测试

具体代码如下:

     //开窗口调用
    private void OnEnable()
    {
        Debug.Log("enable");
    }
    //关窗口调用
    private void OnDisable()
    {
        Debug.Log("disable");
    }
    //开窗口时每帧调用
    private void Update()
    {
        Debug.Log("update");
    }
    private void OnGUI()
    {
        if (GUILayout.Button("测试点击"))
        {
            Debug.Log("测试点击");
        }
    }
    //场景结构发生变化,执行回调函数
    private void OnHierarchyChange()
    {
        Debug.Log("hierarchy");
    }
    //项目结构发生变化,执行回调函数
    private void OnProjectChange()
    {
        Debug.Log("Project");
    }
    //被选中物体发生变化,执行回调函数
    private void OnSelectionChange()
    {
        //获取当前选中的物体的名称
        Debug.Log(Selection.activeGameObject.name);
    }
编辑器场景视窗扩展

实现在Plane上开始编辑后通过点击生成Cube并连线的功能:

相应的代码如下:

NodeManager脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]//在编辑模式下可以执行一些生命周期函数
public class NodeManager : MonoBehaviour
{
    public List<GameObject> nodes;//存储了所有编辑器下点击生成的点,并使用预制体显示
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        for(int i = 0; i < nodes.Count - 1; i++)
        {
            Debug.DrawLine(nodes[i].transform.position,
                nodes[i+1].transform.position,
                Color.red,
                Time.deltaTime);
        }
    }
}

 NodeManagerEditor脚本

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

public class NodeWindow : EditorWindow
{
    static NodeWindow window;
    static GameObject nodeManager;
    public static void OpenWindow(GameObject manager)
    {
        nodeManager= manager;
        //真正开启了一个窗口
        window = EditorWindow.GetWindow<NodeWindow>();
    }
    void Update()
    {
        //通过窗口的Update,每帧执行一次,当前选中的对象为Plane
        Selection.activeGameObject= nodeManager;
    }
    public static void CloseWindow()
    {
        window.Close();
    }
}
//外挂式关联NodeManager
[CustomEditor(typeof(NodeManager))]
public class NodeManagerEditor : Editor
{
    NodeManager manager;
    bool isEditor = false;//是否是编辑的状态
    //当选中带有NodeManager组件的对象时,获得组件
    void OnEnable()
    {
        manager = (NodeManager)target;
    }
    //绘制组件的生命周期函数
    public override void OnInspectorGUI()
    {
        //通过终极的数据获取方法,显示列表中的数据
        serializedObject.Update();
        SerializedProperty nodes = serializedObject.FindProperty("nodes");
        EditorGUILayout.PropertyField(nodes, new GUIContent("路径"), true);
        serializedObject.ApplyModifiedProperties();
        //开始编辑的开关
        if (!isEditor && GUILayout.Button("开始编辑"))
        {
            NodeWindow.OpenWindow(manager.gameObject);
            //调用打开界面的方法
            isEditor = true;//改变状态变成编辑模式
        }//结束编辑的开关
        else if (isEditor && GUILayout.Button("结束编辑"))
        {
            NodeWindow.CloseWindow();//调用关闭界面的方法
            isEditor = false;//改变状态变成非编辑模式
        }
        //删除按钮
        if (GUILayout.Button("删除最后一个节点"))
        {
            RemoveAtLast();
        }
        //删除所有按钮
        else if (GUILayout.Button("删除所有节点"))
        {
            RemoveAll();
        }

    }
    RaycastHit hit;
    //当选中关联的脚本挂载的物体
    //当鼠标在Scene视图下发生变化时,执行该方法,比如鼠标移动,比如鼠标的点击
    void OnSceneGUI()
    {
        if (!isEditor)
        {
            return;
        }
        //鼠标按下左键时发射一条射线
        //非运行时,使用Event类
        //Event.current.button 判断鼠标是哪个按键的(0:鼠标左键)
        //Event.current.type 判断鼠标的事件方式的
        if (Event.current.button == 0 && Event.current.type == EventType.MouseDown)
        {
            //Debug.Log("鼠标按下");
            //从鼠标的位置需要发射射线了
            //因为是从Scene视图下发射射线,跟场景中的摄像机并没有关系,所以不能使用相机发射射线的方法
            //从编辑器GUI中的一个点向世界定义一条射线,参数一般都是鼠标的坐标
            Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
            if(Physics.Raycast(ray, out hit,100))
            {
                //需要在检测的点实例化,路点
                InstancePathNode(hit.point + Vector3.up * 0.1f);
            }
        }
    }
    

    ///<summary>
    ///生成节点
    /// </summary>
    /// <param name="position"></param>
    void InstancePathNode(Vector3 position)
    {
        //点预制体
        GameObject prefab = Resources.Load<GameObject>("Cube");
        //点对象生成到Plane的子物体下
        GameObject cube = Instantiate<GameObject>(prefab, position, Quaternion.identity, manager.transform);
        manager.nodes.Add(cube); //把生成的路点添加到列表里
    }

    ///<summary>
    ///删除最后一个节点
    /// </summary>
    void RemoveAtLast()
    {

        //保证有节点才能删节点
        if(manager.nodes.Count > 0)
        {
            //从场景中删除游戏物体
            DestroyImmediate(manager.nodes[manager.nodes.Count-1]);
            //把该节点从列表中移除
            manager.nodes.RemoveAt(manager.nodes.Count-1);
        }
    }

    ///<summary>
    ///删除所有的节点
    /// </summary>
    void RemoveAll()
    {
        //遍历删除所有节点物体
        for(int i = 0; i < manager.nodes.Count; i++)
        {
            if (manager.nodes[i] != null)
            {
                DestroyImmediate(manager.nodes[i]);
            }
        }
        manager.nodes.Clear();//请空列表
    }
}

Plane检视器初始如图:

选中Plane游戏物体并点击开始编辑后(鼠标在Scene视图点击三次的效果)如图:

删除最后一个节点及删除所有节点的具体功能即字面意思。

该系列专栏为网课课程笔记,仅用于学习参考。    

http://www.dtcms.com/a/99849.html

相关文章:

  • SpringBean模块(一)定义如何创建生命周期
  • 《C++Linux编程进阶:从0实现muduo 》-第6讲.C++死锁问题如何分析调试-原子操作,互斥量,条件变量的封装
  • 稻壳模板下载器(Windows):免费获取WPS稻壳模板的利器
  • Java中优先级队列的实现
  • 蓝桥杯备考------>双指针(滑动窗口)
  • 华为OD机试2025A卷 - 最大值(Java Python JS C++ C )
  • PyTorch 2.6.0没有对应的torch-sparse版本,不要下载pytorch最新版本,否则用不了图神经网络torch_geometric
  • vmware_unbantu刷新IP
  • EtherNet/IP转ProfiNet协议转换网关驱动西门子PLC与流量计的毫秒级压力同步控制
  • 洛谷题单1-P5706 【深基2.例8】再分肥宅水-python-流程图重构
  • MySQL单表查询、多表查询
  • linux实现rsync+sersync实时数据备份
  • Redis-快速入门
  • GPT Actions
  • 【硬件测试】基于FPGA的16QAM+帧同步系统开发与硬件片内测试,包含高斯信道,误码统计,可设置SNR
  • 【Find My全球市场观察:中国制造如何改写游戏规则?】
  • 游戏引擎学习第191天
  • 【Python】工作笔记:返回当月第一天、昨天;上月第一天、当天;全年节假日
  • 淘宝客户端动态化页面搭建
  • Linux课程学习一
  • 【区块链安全 | 第五篇】DeFi概念详解
  • Kubernetes比同规格虚拟机性能相差多少?
  • 《Express:Node.js 里的 “闪电侠”》
  • Playwright从入门到实战:比Selenium更快的数据爬取案例实战
  • STL-string容器
  • 蓝桥杯嵌入式学习笔记
  • SQL IF(xxx, 1, 0) 窗口函数
  • 【嵌入式学习3】TCP服务器客户端 - UDP发送端接收端
  • Supabase 匿名密钥与服务角色密钥详细对比文档
  • .NET 9 中的新增功能:关键更新和 C# 12 功能简化