效果演示
注意:外挂式脚本需要放在Editor目录。
NodeManagerEditor脚本
using System;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(NodeManager1))]
public class NodeManagerEditor1:Editor
{
public NodeManager1 _nodeManger;
/// <summary>
/// 是否进入编辑模式
/// </summary>
public bool _isEditor;
private void OnEnable()
{
_nodeManger = (NodeManager1)target;
}
private void OnDisable()
{
_nodeManger = null;
}
public override void OnInspectorGUI()
{
SerializedProperty sp = serializedObject.FindProperty("nodes");
// 第一个参数:要为其创建字段的 SerializedProperty
// 第二个参数: 要使用的可选标签, 如果未指定,则使用属性本身的标签
// 第三个参数:如果为 true,将绘制包含子项的属性;否则仅绘制控件本身
EditorGUILayout.PropertyField(sp, new GUIContent("路点"), true);
serializedObject.ApplyModifiedProperties();
// 绘制对象
_nodeManger.go = EditorGUILayout.ObjectField("节点对象样式", _nodeManger.go, typeof(GameObject), true) as GameObject;
// 绘制开始编辑按钮
if (!_isEditor && GUILayout.Button("开始编辑"))
{
// 点击开始编辑,打开windows窗口。思考为什么需要打开windows窗口
NodeWindows1.openWindow(_nodeManger.gameObject);
_isEditor = true;
}
else if(_isEditor && GUILayout.Button("关闭编辑")){
NodeWindows1.closeWindow();
_isEditor = false;
}
if (GUILayout.Button("删除最后一个节点"))
{
RemoveLastNode();
}
if (GUILayout.Button("删除所有节点"))
{
RemoveAll();
}
}
private void RemoveAll()
{
for (int i = 0; i < _nodeManger.nodes.Count; i++)
{
if(_nodeManger.nodes[i] != null)
{
DestroyImmediate(_nodeManger.nodes[i]);
}
}
_nodeManger.nodes.Clear();
}
private void RemoveLastNode()
{
// 只要保证存在节点,才能删除节点
if(_nodeManger.nodes.Count > 0)
{
// 从场景中删除游戏物体
DestroyImmediate(_nodeManger.nodes[_nodeManger.nodes.Count - 1]);
// 从列表中删除游戏物体
_nodeManger.nodes.RemoveAt(_nodeManger.nodes.Count - 1);
}
}
// 进入编辑模式后,需要创建结点,需要获取鼠标点击事件,通过射线
RaycastHit hitInfo;
// 在编辑场景中,只要鼠标移动、点击等,都会触发该函数
private void OnSceneGUI()
{
// 如果没有进入编辑模式,直接返回
if (!_isEditor)
{
return;
}
// 如果进入编辑模式,需要获取射线、鼠标事件
if(Event.current.button == 0 && Event.current.type == EventType.MouseDown)
{
// 鼠标按下
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
if(Physics.Raycast(ray,out hitInfo,100, 1 << 31))
{
// 生成一个节点
// 为什么要加一个 Vector3.up * 0.1f?
// 使得物体生成的位置,在水平面上
GengerateNode(hitInfo.point + Vector3.up * 0.1f);
}
}
}
private void GengerateNode(Vector3 position)
{
// GameObject go = Resources.Load<GameObject>("PathNode");
GameObject go = Instantiate(_nodeManger.go, position, Quaternion.identity, _nodeManger.transform);
_nodeManger.nodes.Add(go);
}
}
public class NodeWindows1 : EditorWindow
{
static NodeWindows1 window;
static GameObject go;
private void Update()
{
// 始终保持面板不会跳转
Selection.activeGameObject = go;
}
public static void openWindow(GameObject node)
{
go = node;
window = EditorWindow.GetWindow<NodeWindows1>();
}
public static void closeWindow()
{
window.Close();
}
}
NodeManager脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode] // 在编辑模式下可以执行一些生命周期函数
public class NodeManager1 : MonoBehaviour
{
/// <summary>
/// 存储路径的所有节点
/// </summary>
public List<GameObject> nodes;
public GameObject go;
private 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);
}
}
}
评论区