编辑器场景视窗扩展

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

具体代码如下:

cs 复制代码
     //开窗口调用
    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脚本

cs 复制代码
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脚本

cs 复制代码
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视图点击三次的效果)如图:

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

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

相关推荐
繁依Fanyi2 小时前
ColorAid —— 一个面向设计师的色盲模拟工具开发记
开发语言·前端·vue.js·编辑器·codebuddy首席试玩官
第一片心意4 小时前
彻底解决sublime text4无法打开install package界面安装插件问题
编辑器·sublime text·package control·sublime text4·install package
bloglin9999911 小时前
cursor/vscode启动项目connect ETIMEDOUT 127.0.0.1:xx
ide·vscode·编辑器·nodejs·cursor
谢尔登1 天前
【VSCode】修改侧边文件资源管理器中的文件夹折叠模式
ide·vscode·编辑器
bloglin999991 天前
关闭VSCode 自动更新
ide·vscode·编辑器
向宇it1 天前
【unity游戏开发——编辑器扩展】使用MenuItem自定义菜单栏拓展
开发语言·ui·unity·c#·编辑器·游戏引擎
谢尔登1 天前
【VSCode】快捷键合集(持续更新~)
ide·vscode·编辑器
繁依Fanyi2 天前
Animaster:一次由 CodeBuddy 主导的 CSS 动画编辑器诞生记
android·前端·css·编辑器·codebuddy首席试玩官
2301_803554522 天前
vim,gcc/g++,makefile,cmake
linux·编辑器·vim
ykjhr_3d2 天前
解锁课程编辑器之独特风姿
编辑器