unity 编辑器二次开发,在非运行状态下,在scene场景连续点击层级为“lIneCube”的两个物体后出现一条线连接两个物体,如果两次点击为同一个物体则无逻辑,删除物体时与之相连的线全部删除
时间: 2023-12-17 15:05:55 浏览: 171
这个需求可以通过编写一个自定义的Editor脚本来实现。首先,我们需要为Unity的Editor创建一个新的脚本。在Unity的Project视图中,右键点击Assets文件夹,选择Create->C# Script并将其命名为“LineCubeEditor”。然后进入脚本文件,并添加以下代码:
```csharp
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(LineCube))]
public class LineCubeEditor : Editor
{
private Vector3 startPos;
private Vector3 endPos;
private bool isConnecting = false;
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
}
public void OnSceneGUI()
{
LineCube lineCube = target as LineCube;
if (lineCube == null)
return;
Event e = Event.current;
switch (e.type)
{
case EventType.MouseDown:
if (e.button == 0)
{
startPos = HandleUtility.GUIPointToWorldRay(e.mousePosition).origin;
isConnecting = true;
GUIUtility.hotControl = GUIUtility.GetControlID(FocusType.Passive);
e.Use();
}
break;
case EventType.MouseMove:
if (isConnecting)
{
endPos = HandleUtility.GUIPointToWorldRay(e.mousePosition).origin;
HandleUtility.Repaint();
}
break;
case EventType.MouseUp:
if (e.button == 0 && isConnecting)
{
endPos = HandleUtility.GUIPointToWorldRay(e.mousePosition).origin;
if (startPos != endPos)
{
GameObject startObj = lineCube.GetClickedObject(startPos);
GameObject endObj = lineCube.GetClickedObject(endPos);
if (startObj != null && endObj != null && startObj != endObj)
{
lineCube.CreateLine(startObj, endObj);
}
}
isConnecting = false;
GUIUtility.hotControl = 0;
e.Use();
}
break;
}
}
}
```
在这个脚本中,我们为LineCube对象添加了一个自定义的Inspector,并override了OnSceneGUI()函数来处理鼠标事件。具体地,当鼠标按下时,我们记录下起点位置,将连接状态设置为true,并且将当前控制设置为“热控件”,以便接管所有鼠标输入。当鼠标移动时,如果当前处于连接状态,我们记录下终点位置并强制重绘场景。当鼠标释放时,如果当前处于连接状态,我们记录下终点位置,并找到最近的两个LineCube对象。如果两个对象都存在且不相同,则创建一条线连接它们。最后,我们将连接状态重置为false,并将当前控制设置为0,以便返回Unity的默认行为。
接下来,我们需要在LineCube脚本中添加一些功能来支持上述编辑器脚本。具体地,我们需要添加以下函数:
```csharp
public GameObject GetClickedObject(Vector3 position)
{
Ray ray = new Ray(position, Vector3.forward);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
GameObject obj = hit.collider.gameObject;
if (obj != null && obj.GetComponent<LineCube>() != null)
{
return obj;
}
}
return null;
}
public void CreateLine(GameObject startObj, GameObject endObj)
{
GameObject lineObj = new GameObject("Line");
LineRenderer line = lineObj.AddComponent<LineRenderer>();
line.SetPositions(new Vector3[] { startObj.transform.position, endObj.transform.position });
line.startWidth = 0.1f;
line.endWidth = 0.1f;
startObj.GetComponent<LineCube>().AddLine(lineObj);
endObj.GetComponent<LineCube>().AddLine(lineObj);
}
public void AddLine(GameObject lineObj)
{
if (!connectedLines.Contains(lineObj))
{
connectedLines.Add(lineObj);
}
}
public void RemoveLine(GameObject lineObj)
{
if (connectedLines.Contains(lineObj))
{
connectedLines.Remove(lineObj);
DestroyImmediate(lineObj);
}
}
private void OnDrawGizmos()
{
Gizmos.color = Color.green;
Gizmos.DrawWireCube(transform.position, Vector3.one);
}
```
在这个脚本中,我们添加了一个GetClickedObject函数来返回当前鼠标位置最接近的LineCube对象。我们还添加了一个CreateLine函数来创建LineRenderer对象来连接两个LineCube对象,并将其添加到它们的connectedLines列表中。我们还添加了一个AddLine函数来将连接到该对象的LineRenderer对象添加到connectedLines列表中。最后,我们添加了一个OnDrawGizmos函数,以便在Unity编辑器中正确绘制LineCube对象。
最后,我们需要在LineCube脚本中添加一个connectedLines列表,以跟踪所有连接到该对象的LineRenderer对象,并且在删除该对象时,我们需要遍历所有连接到它的LineRenderer对象,并将它们全部删除。具体代码如下:
```csharp
using System.Collections.Generic;
using UnityEngine;
public class LineCube : MonoBehaviour
{
public List<GameObject> connectedLines = new List<GameObject>();
private void OnDestroy()
{
foreach (GameObject lineObj in connectedLines)
{
if (lineObj != null)
{
LineCube otherCube = lineObj.GetComponent<LineRenderer>().GetOtherCube(gameObject).GetComponent<LineCube>();
otherCube.RemoveLine(lineObj);
}
}
}
}
```
在这个脚本中,我们添加了一个connectedLines列表来存储所有连接到该对象的LineRenderer对象。我们还添加了一个OnDestroy函数,在该对象被销毁时,我们遍历connectedLines列表,并将每个LineRenderer对象从连接到它的另一个LineCube对象的connectedLines列表中删除,并销毁该LineRenderer对象。
现在,我们已经完成了所有的编码。在Unity编辑器中,我们可以将LineCube脚本添加到一个GameObject中,并将该对象复制多次以创建多个LineCube对象。然后,我们可以选择Scene视图中的两个对象,并在它们之间创建一条连接线。如果我们删除任何一个连接的对象,与之相连的所有线都将被正确地删除。
阅读全文