ND_SimulationAutomaticControl/Assets/Scripts/Line/WireDrawingSystem.cs

2170 lines
66 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
// 连线连接数据结构
[System.Serializable]
public class WireConnectionData
{
public GameObject startInterface;
public GameObject endInterface;
public GameObject startConnectionPoint;
public GameObject endConnectionPoint;
}
public class WireDrawingSystem : MonoBehaviour
{
public enum DrawingState
{
Idle, // 空闲状态
SelectingStart, // 选择起点
SelectingEnd // 选择终点
}
[Header("连线设置")]
public Material wireMaterial;
public Color wireColor = Color.red;
public float wireWidth = 0.02f;
[Header("吸附设置")]
public bool enableSnapping = true; // 启用吸附功能
public float snapDistance = 1.0f; // 吸附距离
public LayerMask snapLayers = -1; // 可吸附的层
public bool snapToColliderCenter = true; // 吸附到碰撞体中心
public bool snapToTransformCenter = false; // 吸附到变换组件中心
public Color snapHighlightColor = Color.cyan; // 吸附高亮颜色
[Header("高亮设置")]
public bool enableHighlight = true; // 启用点击物体高亮效果
public Color clickHighlightColor = Color.green; // 点击高亮颜色
public float highlightDuration = 1.0f; // 高亮持续时间
[Header("碰撞设置")]
public bool requireColliderForConnection = true; // 要求物体必须有碰撞体才能连线
public bool addColliderToWires = false; // 是否为连线添加碰撞器
[Header("状态显示")]
public DrawingState currentState = DrawingState.Idle;
// 连线数据
private Vector3 startPoint;
private Vector3 endPoint;
private LineRenderer currentWire;
private GameObject currentWireObject;
// 吸附相关
private GameObject snapTarget; // 当前吸附目标
private Renderer snapTargetRenderer; // 吸附目标的渲染器
public Color snapTargetOriginalColor = Color.blue; // 吸附目标原始颜色
private bool isSnapTargetHighlighted = false; // 新增:标记是否正在高亮
// 修复问题:记录鼠标点击的实际位置
private Vector3 actualMousePosition;
public List<GameObject> model = new List<GameObject>();
public List<Material> Colors = new List<Material>();
/// <summary>
/// 接线头样式
/// </summary>
[Header("接线头样式")]
public GameObject LineModel;
[Header("连接点模型设置")]
public GameObject connectionPointPrefab; // 连接点模型预制体
public float connectionPointScale = 0.1f; // 连接点模型缩放
public Material connectionPointMaterial; // 连接点材质
[Header("吸附点预览")]
public GameObject snapPreviewPrefab; // 吸附点预览预制体
private GameObject currentSnapPreview; // 当前吸附点预览
private List<GameObject> connectionPoints = new List<GameObject>(); // 存储所有连接点
[Header("删除设置")]
public KeyCode deleteKey = KeyCode.Mouse1; // 默认为鼠标右键
public float deleteDetectionRadius = 0.5f; // 删除检测半径
// 存储所有已创建的连线和连接点
private List<GameObject> allWires = new List<GameObject>();
private List<GameObject> allConnectionPoints = new List<GameObject>();
[Header("模型堆叠设置")]
public float verticalOffset = 0.2f; // 模型垂直偏移量
public bool enableStacking = true; // 启用模型堆叠
public int maxStackCount = 5; // 最大堆叠数量 (0表示无限制)
public Color maxStackWarningColor = Color.yellow; // 达到最大堆叠数量时的警告颜色
public Color selfConnectionWarningColor = Color.magenta; // 自连接警告颜色
// 存储每个接口上的模型堆叠信息
private Dictionary<string, List<GameObject>> interfaceStacks = new Dictionary<string, List<GameObject>>();
// 用于临时存储当前操作的目标接口
private GameObject currentStartInterface;
private GameObject currentEndInterface;
// 防止自连接
private GameObject startInterfaceObject;
private GameObject endInterfaceObject;
private bool isSnapTargetHighlighteds = false; // 新增:标记是否正在高亮
// 存储所有被高亮的接口,确保都能恢复颜色
private Dictionary<GameObject, Color> highlightedInterfaces = new Dictionary<GameObject, Color>();
// 连线数据存储
private Dictionary<GameObject, WireConnectionData> wireConnectionData = new Dictionary<GameObject, WireConnectionData>();
//存储接口的原始材质,防止材质实例化问题
private Dictionary<GameObject, Material> originalMaterials = new Dictionary<GameObject, Material>();
//存储当前高亮的接口,确保不会重复高亮
private GameObject currentlyHighlightedInterface = null;
// 高亮相关
private Coroutine currentHighlightCoroutine; // 当前高亮协程
private GameObject lastClickedObject; // 最后点击的物体
[Header("圆柱体连线设置")]
public bool useCylinderWire = true; // 启用圆柱体连线
public Material cylinderWireMaterial;
public float cylinderWireDiameter = 0.02f;
public int cylinderSegments = 8; // 圆柱体面数,影响性能
// 移除原来的LineRenderer相关设置或者保留作为备选
[Header("传统连线设置(备选)")]
public bool useLineRenderer = false;
void Update()
{
HandleInput();
if (useCylinderWire)
{
UpdateCylinderWirePreview();
}
else
{
UpdateWirePreview(); // 原有的LineRenderer更新
}
// 在选择终点状态时检查吸附
if (currentState == DrawingState.SelectingEnd && enableSnapping)
{
CheckForSnapTargets();
UpdateSnapPreview();
}
else
{
ClearSnapPreview();
if (currentState != DrawingState.SelectingEnd)
{
ClearAllHighlights();
}
}
Debug.Log("字典内总数:" + interfaceStacks.Count);
}
/// <summary>
/// 处理点击物体高亮效果
/// </summary>
void HandleClickHighlight(GameObject clickedObject)
{
if (!enableHighlight || clickedObject == null) return;
// 停止之前的高亮协程
if (currentHighlightCoroutine != null)
{
StopCoroutine(currentHighlightCoroutine);
}
// 开始新的高亮协程
currentHighlightCoroutine = StartCoroutine(HighlightObject(clickedObject));
}
/// <summary>
/// 高亮物体协程
/// </summary>
IEnumerator HighlightObject(GameObject targetObject)
{
if (targetObject == null) yield break;
Renderer renderer = targetObject.GetComponent<Renderer>();
if (renderer == null) yield break;
// 确保使用材质实例
EnsureMaterialInstance(targetObject);
// 记录原始颜色
Color originalColor = renderer.material.color;
if (!highlightedInterfaces.ContainsKey(targetObject))
{
highlightedInterfaces[targetObject] = originalColor;
}
// 设置高亮颜色
renderer.material.color = clickHighlightColor;
// 等待指定时间
yield return new WaitForSeconds(highlightDuration);
// 恢复原始颜色
if (renderer != null && targetObject != null)
{
if (highlightedInterfaces.ContainsKey(targetObject))
{
renderer.material.color = highlightedInterfaces[targetObject];
highlightedInterfaces.Remove(targetObject);
}
else
{
renderer.material.color = originalColor;
}
}
currentHighlightCoroutine = null;
}
/// <summary>
/// 在指定位置创建连接点模型,支持在已有模型上方堆叠
/// </summary>
/// <param name="position">基础位置</param>
/// <param name="isStartPoint">是否为起点</param>
/// <param name="targetInterface">目标接口物体</param>
bool CreateConnectionPoint(Vector3 position, bool isStartPoint, GameObject targetInterface = null)
{
if (connectionPointPrefab == null)
{
Debug.LogWarning("连接点预制体未设置,无法创建连接点模型");
return false;
}
// 检查堆叠数量限制
if (targetInterface != null && enableStacking && IsStackLimitReached(targetInterface))
{
Debug.LogWarning($"接口 {targetInterface.name} 已达到最大堆叠数量限制 ({maxStackCount}),无法创建更多连接点");
ShowStackLimitWarning(targetInterface);
return false;
}
// 计算最终位置
Vector3 finalPosition = CalculateStackedPosition(position, targetInterface);
GameObject connectionPoint = Instantiate(connectionPointPrefab);
connectionPoint.name = $"ConnectionPoint_{(isStartPoint ? "Start" : "End")}_{System.DateTime.Now:HHmmss}";
connectionPoint.transform.position = finalPosition;
connectionPoint.transform.localScale = Vector3.one * connectionPointScale;
// 设置材质
if (connectionPointMaterial != null)
{
Renderer renderer = connectionPoint.GetComponent<Renderer>();
if (renderer != null)
{
renderer.material = connectionPointMaterial;
}
}
// 记录堆叠信息
if (targetInterface != null && enableStacking)
{
RegisterConnectionPointWithInterface(connectionPoint, targetInterface);
}
// 添加到连接点列表
allConnectionPoints.Add(connectionPoint);
Debug.Log($"创建连接点: {finalPosition}, 类型: {(isStartPoint ? "" : "")}, 目标接口: {targetInterface?.name ?? ""}, 堆叠高度: {GetStackCountForInterface(targetInterface)}");
return true;
}
/// <summary>
/// 检查接口是否达到堆叠数量限制 - 增强版
/// </summary>
bool IsStackLimitReached(GameObject targetInterface)
{
if (targetInterface == null || maxStackCount <= 0)
return false;
int currentCount = GetStackCountForInterface(targetInterface);
bool isLimitReached = currentCount >= maxStackCount;
if (isLimitReached)
{
Debug.Log($"堆叠限制检查: 接口 {targetInterface.name} 已达到限制 ({currentCount}/{maxStackCount})");
}
return isLimitReached;
}
/// <summary>
/// 检查是否尝试自连接
/// </summary>
bool IsSelfConnection(GameObject targetInterface)
{
if (targetInterface == null || startInterfaceObject == null)
return false;
return targetInterface == startInterfaceObject;
}
/// <summary>
/// 显示堆叠数量限制警告
/// </summary>
void ShowStackLimitWarning(GameObject targetInterface)
{
// 临时高亮显示达到限制的接口
Renderer renderer = targetInterface.GetComponent<Renderer>();
if (renderer != null)
{
// 确保使用材质实例
EnsureMaterialInstance(targetInterface);
// 记录原始颜色
if (!highlightedInterfaces.ContainsKey(targetInterface))
{
highlightedInterfaces[targetInterface] = renderer.material.color;
Debug.Log($"记录接口 {targetInterface.name} 的原始颜色(堆叠警告): {renderer.material.color}");
}
// StartCoroutine(FlashWarningColor(renderer, maxStackWarningColor, targetInterface));
}
}
/// <summary>
/// 显示自连接警告
/// </summary>
void ShowSelfConnectionWarning(GameObject targetInterface)
{
// 临时高亮显示自连接警告
Renderer renderer = targetInterface.GetComponent<Renderer>();
if (renderer != null)
{
// 确保使用材质实例
EnsureMaterialInstance(targetInterface);
// 记录原始颜色
if (!highlightedInterfaces.ContainsKey(targetInterface))
{
highlightedInterfaces[targetInterface] = renderer.material.color;
Debug.Log($"记录接口 {targetInterface.name} 的原始颜色(自连接警告): {renderer.material.color}");
}
//StartCoroutine(FlashWarningColor(renderer, selfConnectionWarningColor, targetInterface));
}
}
/// <summary>
/// 闪烁警告颜色
/// </summary>
IEnumerator FlashWarningColor(Renderer targetRenderer, Color warningColor, GameObject targetInterface = null)
{
if (targetRenderer == null) yield break;
// 确保使用材质实例
if (targetInterface != null)
{
EnsureMaterialInstance(targetInterface);
}
// 保存当前颜色
Color currentColor = targetRenderer.material.color;
// 设置警告颜色
targetRenderer.material.color = warningColor;
Debug.Log($"设置接口 {targetInterface?.name} 为闪烁警告颜色: {warningColor}");
yield return new WaitForSeconds(0.5f);
if (targetRenderer != null && targetInterface != null)
{
// 恢复原始颜色
if (highlightedInterfaces.ContainsKey(targetInterface))
{
targetRenderer.material.color = highlightedInterfaces[targetInterface];
Debug.Log($"恢复接口 {targetInterface.name} 的原始颜色: {highlightedInterfaces[targetInterface]}");
}
else
{
targetRenderer.material.color = currentColor;
Debug.Log($"恢复接口 {targetInterface.name} 的当前颜色: {currentColor}");
}
}
}
/// <summary>
/// 注册连接点到接口堆叠系统
/// </summary>
void RegisterConnectionPointWithInterface(GameObject connectionPoint, GameObject targetInterface)
{
if (targetInterface == null) return;
if (!interfaceStacks.ContainsKey(targetInterface.name))
{
interfaceStacks[targetInterface.name] = new List<GameObject>();
Debug.Log($"为接口 {targetInterface.name} 创建新堆叠列表");
}
if (interfaceStacks[targetInterface.name].Count < 2)
{
interfaceStacks[targetInterface.name].Add(connectionPoint);
}
Debug.Log($"连接点 {connectionPoint.name} 已注册到接口 {targetInterface.name},当前总数: {interfaceStacks[targetInterface.name].Count}");
// 添加接口引用组件
ConnectionPointInterfaceReference refComponent = connectionPoint.GetComponent<ConnectionPointInterfaceReference>();
if (refComponent == null)
{
refComponent = connectionPoint.AddComponent<ConnectionPointInterfaceReference>();
}
refComponent.targetInterface = targetInterface;
}
/// <summary>
/// 从接口堆叠系统中移除连接点
/// </summary>
void UnregisterConnectionPointFromInterface(GameObject connectionPoint)
{
ConnectionPointInterfaceReference refComponent = connectionPoint.GetComponent<ConnectionPointInterfaceReference>();
if (refComponent != null && refComponent.targetInterface != null)
{
GameObject targetInterface = refComponent.targetInterface;
if (interfaceStacks.ContainsKey(targetInterface.name))
{
interfaceStacks[targetInterface.name].Remove(connectionPoint);
// 如果接口没有更多连接点,移除接口条目
if (interfaceStacks[targetInterface.name].Count == 0)
{
interfaceStacks.Remove(targetInterface.name);
}
// Debug.Log($"连接点 {connectionPoint.name} 已从接口 {targetInterface.name} 移除,剩余数量: {interfaceStacks.ContainsKey(targetInterface) ? interfaceStacks[targetInterface].Count : 0}");
}
}
}
/// <summary>
/// 计算堆叠位置
/// </summary>
Vector3 CalculateStackedPosition(Vector3 basePosition, GameObject targetInterface)
{
if (targetInterface == null || !enableStacking)
{
Debug.Log("没有目标接口或堆叠功能已禁用,使用基础位置");
return basePosition;
}
int stackCount = GetStackCountForInterface(targetInterface);
Vector3 offset = Vector3.forward * (stackCount * verticalOffset);
Vector3 finalPosition = GetObjectCenter(targetInterface) + offset;
Debug.Log($"接口: {targetInterface.name}, 堆叠数量: {stackCount}, 基础位置: {basePosition}, 最终位置: {finalPosition}");
return finalPosition;
}
/// <summary>
/// 获取接口上的模型堆叠数量 - 增强版
/// </summary>
int GetStackCountForInterface(GameObject targetInterface)
{
if (targetInterface == null || !interfaceStacks.ContainsKey(targetInterface.name))
{
return 0;
}
// 清理已销毁的模型引用
interfaceStacks[targetInterface.name].RemoveAll(item => item == null);
int count = interfaceStacks[targetInterface.name].Count;
// 调试日志
if (count > 0)
{
Debug.Log($"接口 {targetInterface.name} 当前堆叠数量: {count}");
foreach (var point in interfaceStacks[targetInterface.name])
{
if (point != null)
{
Debug.Log($" - {point.name}");
}
}
}
return count;
}
/// <summary>
/// 删除未完成的连接点(用于取消操作时)
/// </summary>
void RemoveUnfinishedConnectionPoints()
{
// 删除最近创建但未完成的连接点
if (allConnectionPoints.Count > 0)
{
// 查找未附加到连线的连接点
List<GameObject> toRemove = new List<GameObject>();
foreach (GameObject point in allConnectionPoints)
{
if (point != null && point.transform.parent == null)
{
toRemove.Add(point);
}
}
// 删除这些连接点
foreach (GameObject point in toRemove)
{
// 从接口堆叠系统中移除
UnregisterConnectionPointFromInterface(point);
allConnectionPoints.Remove(point);
Destroy(point);
}
}
}
/// <summary>
/// 清除所有连接点
/// </summary>
public void ClearAllConnectionPoints()
{
foreach (GameObject point in connectionPoints)
{
if (point != null)
Destroy(point);
}
connectionPoints.Clear();
}
/// <summary>
/// 删除所有连线和连接点
/// </summary>
public void ClearAll()
{
// 创建连线列表的副本,避免在遍历时修改集合
List<GameObject> wiresToDelete = new List<GameObject>(allWires);
foreach (GameObject wire in wiresToDelete)
{
if (wire != null)
DeleteWire(wire);
}
allWires.Clear();
// 创建连接点列表的副本
List<GameObject> pointsToDelete = new List<GameObject>(allConnectionPoints);
foreach (GameObject point in pointsToDelete)
{
if (point != null)
DeleteConnectionPoint(point);
}
allConnectionPoints.Clear();
// 清除堆叠信息
interfaceStacks.Clear();
// 清除连线数据
wireConnectionData.Clear();
// 清除吸附点预览
ClearSnapPreview();
// 清除所有高亮
ClearAllHighlights();
// 恢复所有接口的原始材质
List<GameObject> interfacesToRestore = new List<GameObject>(originalMaterials.Keys);
foreach (GameObject interfaceObj in interfacesToRestore)
{
if (interfaceObj != null)
{
RestoreOriginalMaterial(interfaceObj);
}
}
originalMaterials.Clear();
Debug.Log("已清除所有连线和连接点");
}
/// <summary>
/// 将连接点附加到连线对象上
/// </summary>
/// <param name="wireObject">连线对象</param>
void AttachConnectionPointsToWire(GameObject wireObject)
{
// 查找最近创建的两个未附加的连接点
List<GameObject> unattachedPoints = new List<GameObject>();
foreach (GameObject point in allConnectionPoints)
{
if (point != null && point.transform.parent == null)
{
unattachedPoints.Add(point);
}
}
// 将最近的两个连接点附加到连线
if (unattachedPoints.Count >= 2)
{
for (int i = unattachedPoints.Count - 1; i >= Mathf.Max(0, unattachedPoints.Count - 2); i--)
{
unattachedPoints[i].transform.SetParent(wireObject.transform);
}
}
}
void HandleInput()
{
if (Input.GetMouseButtonDown(0)) // 左键点击
{
HandleMouseClick();
}
if (Input.GetKeyDown(KeyCode.Escape))// 取消当前操作
{
CancelDrawing();
}
if (Input.GetMouseButtonDown(2))
{
HandleDelete();
}
}
/// <summary>
/// 处理删除操作
/// </summary>
void HandleDelete()
{
// 首先清除所有高亮,确保颜色恢复
ClearAllHighlights();
// 如果正在绘制连线,先取消绘制
if (currentState != DrawingState.Idle)
{
CancelDrawing();
return;
}
// 清除吸附点预览
ClearSnapPreview();
// 查找鼠标位置附近的连线和连接点
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
bool foundObjectToDelete = false;
if (Physics.Raycast(ray, out hit, Mathf.Infinity))
{
// 检查是否点击到了连线或连接点
GameObject hitObject = hit.collider.gameObject;
if (IsWireOrConnection(hitObject))
{
DeleteObjectIfWireOrConnection(hitObject);
foundObjectToDelete = true;
}
}
// 如果没有找到可删除的对象,尝试删除最后一个连线
if (!foundObjectToDelete)
{
DeleteLastWire();
}
// 删除后再次确保清除所有高亮
ClearAllHighlights();
}
/// <summary>
/// 检查对象是否是连线或连接点
/// </summary>
bool IsWireOrConnection(GameObject obj)
{
if (obj == null) return false;
// 检查是否是连线
if (obj.name.StartsWith("Wire_") || obj.GetComponent<LineRenderer>() != null)
{
return true;
}
// 检查是否是连接点
if (obj.name.StartsWith("ConnectionPoint_"))
{
return true;
}
// 检查是否是连线的一部分(子物体)
if (obj.transform.parent != null)
{
GameObject parent = obj.transform.parent.gameObject;
if (parent.name.StartsWith("Wire_") || parent.GetComponent<LineRenderer>() != null)
{
return true;
}
}
return false;
}
/// <summary>
/// 清除所有高亮接口的颜色
/// </summary>
void ClearAllHighlights()
{
// 恢复所有被高亮接口的原始颜色
List<GameObject> interfacesToRestore = new List<GameObject>(highlightedInterfaces.Keys);
foreach (GameObject interfaceObj in interfacesToRestore)
{
if (interfaceObj != null)
{
RestoreInterfaceColor(interfaceObj);
}
}
highlightedInterfaces.Clear();
// 清除当前吸附目标的高亮
if (snapTargetRenderer != null && isSnapTargetHighlighted)
{
// 如果当前吸附目标不在字典中,使用保存的原始颜色
if (!highlightedInterfaces.ContainsKey(snapTarget))
{
// snapTargetRenderer.material.color = snapTargetOriginalColor;
Debug.Log($"恢复吸附目标 {snapTarget?.name} 的原始颜色: {snapTargetOriginalColor}");
}
snapTargetRenderer = null;
isSnapTargetHighlighted = false;
}
// 停止点击高亮协程
if (currentHighlightCoroutine != null)
{
StopCoroutine(currentHighlightCoroutine);
currentHighlightCoroutine = null;
}
// 重置当前高亮接口
currentlyHighlightedInterface = null;
snapTarget = null;
}
/// <summary>
/// 恢复单个接口的颜色
/// </summary>
void RestoreInterfaceColor(GameObject interfaceObject)
{
if (interfaceObject == null) return;
Renderer renderer = interfaceObject.GetComponent<Renderer>();
if (renderer != null)
{
// 如果这个接口在记录中,使用记录的颜色
if (highlightedInterfaces.ContainsKey(interfaceObject))
{
Color originalColor = highlightedInterfaces[interfaceObject];
renderer.material.color = originalColor;
Debug.Log($"恢复接口 {interfaceObject.name} 的原始颜色: {originalColor}");
// 从字典中移除,避免重复恢复
highlightedInterfaces.Remove(interfaceObject);
}
//else
//{
// // 如果不在字典中,尝试使用默认颜色
// renderer.material.color = new Color(0.85f, 0.71f, 0.4f);
// Debug.Log($"设置接口 {interfaceObject.name} 为默认白色");
//}
// 恢复原始材质
RestoreOriginalMaterial(interfaceObject);
}
}
/// <summary>
/// 删除指定的连线或连接点
/// </summary>
void DeleteObjectIfWireOrConnection(GameObject obj)
{
if (obj == null) return;
// 检查是否是吸附预览
if (obj.name == "SnapPreview")
{
ClearSnapPreview();
return;
}
// 检查是否是连线
if (obj.name.StartsWith("Wire_") || obj.GetComponent<LineRenderer>() != null)
{
DeleteWire(obj);
return;
}
// 检查是否是连接点
if (obj.name.StartsWith("ConnectionPoint_"))
{
// 如果是连接点,找到其父连线并删除
if (obj.transform.parent != null)
{
GameObject parent = obj.transform.parent.gameObject;
if (parent.name.StartsWith("Wire_") || parent.GetComponent<LineRenderer>() != null)
{
DeleteWire(parent);
return;
}
}
// 如果没有父连线,单独删除连接点
DeleteConnectionPoint(obj);
return;
}
// 检查是否是连线的一部分(子物体)
if (obj.transform.parent != null)
{
GameObject parent = obj.transform.parent.gameObject;
if (parent.name.StartsWith("Wire_") || parent.GetComponent<LineRenderer>() != null)
{
DeleteWire(parent);
return;
}
}
// 如果没有匹配的类型,尝试删除最后一个连线
Debug.Log("未找到可删除的对象,尝试删除最后一个连线");
DeleteLastWire();
}
/// <summary>
/// 删除指定的连线
/// </summary>
void DeleteWire(GameObject wireObject)
{
if (wireObject == null)
{
Debug.LogWarning("尝试删除空的连线对象");
return;
}
Debug.Log($"开始删除连线: {wireObject.name}");
// 获取连线数据
WireData wireData = wireObject.GetComponent<WireData>();
GameObject startInterface = null;
GameObject endInterface = null;
if (wireData != null)
{
startInterface = wireData.snapStartObject;
endInterface = wireData.snapEndObject;
}
else
{
// 尝试从存储的数据中获取
if (wireConnectionData.ContainsKey(wireObject))
{
startInterface = wireConnectionData[wireObject].startInterface;
endInterface = wireConnectionData[wireObject].endInterface;
}
}
// 删除连线的所有连接点(子物体)
foreach (Transform child in wireObject.transform)
{
if (child.name.StartsWith("ConnectionPoint_"))
{
Debug.Log($"删除连接点: {child.name}");
// 从接口堆叠系统中移除
UnregisterConnectionPointFromInterface(child.gameObject);
allConnectionPoints.Remove(child.gameObject);
Destroy(child.gameObject);
}
}
// 从列表中移除并销毁连线
bool removedFromList = allWires.Remove(wireObject);
if (removedFromList)
{
Debug.Log($"从连线列表中移除: {wireObject.name}");
}
else
{
Debug.LogWarning($"连线 {wireObject.name} 不在连线列表中");
}
// 从连线数据存储中移除
if (wireConnectionData.ContainsKey(wireObject))
{
wireConnectionData.Remove(wireObject);
}
Destroy(wireObject);
Debug.Log($"销毁连线对象: {wireObject.name}");
// 恢复连线两端接口的颜色和材质
if (startInterface != null)
{
RestoreInterfaceColor(startInterface);
RestoreOriginalMaterial(startInterface);
Debug.Log($"恢复起点接口颜色和材质: {startInterface.name}");
}
if (endInterface != null)
{
RestoreInterfaceColor(endInterface);
RestoreOriginalMaterial(endInterface);
Debug.Log($"恢复终点接口颜色和材质: {endInterface.name}");
}
// 清除吸附点预览和高亮
ClearSnapPreview();
ClearAllHighlights();
Debug.Log($"连线删除完成: {wireObject.name}");
}
/// <summary>
/// 删除指定的连接点
/// </summary>
void DeleteConnectionPoint(GameObject connectionPoint)
{
if (connectionPoint == null)
{
Debug.LogWarning("尝试删除空的连接点对象");
return;
}
Debug.Log($"开始删除连接点: {connectionPoint.name}");
// 获取连接点对应的接口
ConnectionPointInterfaceReference refComponent = connectionPoint.GetComponent<ConnectionPointInterfaceReference>();
GameObject targetInterface = refComponent?.targetInterface;
// 从接口堆叠系统中移除
UnregisterConnectionPointFromInterface(connectionPoint);
// 从列表中移除并销毁连接点
bool removedFromList = allConnectionPoints.Remove(connectionPoint);
if (removedFromList)
{
Debug.Log($"从连接点列表中移除: {connectionPoint.name}");
}
else
{
Debug.LogWarning($"连接点 {connectionPoint.name} 不在连接点列表中");
}
Destroy(connectionPoint);
Debug.Log($"销毁连接点对象: {connectionPoint.name}");
// 恢复对应接口的颜色和材质
if (targetInterface != null)
{
RestoreInterfaceColor(targetInterface);
RestoreOriginalMaterial(targetInterface);
Debug.Log($"恢复接口颜色和材质: {targetInterface.name}");
}
// 清除吸附点预览和高亮
ClearSnapPreview();
ClearAllHighlights();
Debug.Log($"连接点删除完成: {connectionPoint.name}");
}
/// <summary>
/// 删除最后一个创建的连线
/// </summary>
void DeleteLastWire()
{
if (allWires.Count > 0)
{
GameObject lastWire = allWires[allWires.Count - 1];
Debug.Log($"删除最后一个连线: {lastWire.name}");
DeleteWire(lastWire);
}
else
{
Debug.Log("没有可删除的连线");
}
}
/// <summary>
/// 删除最后一个连接点
/// </summary>
void DeleteLastConnectionPoint()
{
if (allConnectionPoints.Count > 0)
{
GameObject lastPoint = allConnectionPoints[allConnectionPoints.Count - 1];
DeleteConnectionPoint(lastPoint);
}
else
{
Debug.Log("没有可删除的连接点");
}
}
void HandleMouseClick()
{
// 首先清除所有可能的高亮状态
ClearAllHighlights();
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
// 获取鼠标的实际世界位置
actualMousePosition = GetMouseWorldPosition();
// 重置当前接口
currentStartInterface = null;
currentEndInterface = null;
// 首先检查是否有吸附目标
if (snapTarget != null)
{
// 检查吸附目标是否有碰撞体
if (requireColliderForConnection && !HasCollider(snapTarget))
{
Debug.LogWarning($"目标物体 {snapTarget.name} 没有碰撞体,无法连线");
return;
}
// 检查是否尝试自连接
if (currentState == DrawingState.SelectingEnd && IsSelfConnection(snapTarget))
{
Debug.LogWarning("不能连接到自身接口!");
ShowSelfConnectionWarning(snapTarget);
return;
}
// 新增:检查堆叠限制
if (enableStacking && IsStackLimitReached(snapTarget))
{
Debug.LogWarning($"目标接口 {snapTarget.name} 已达到堆叠限制 ({GetStackCountForInterface(snapTarget)}/{maxStackCount}),无法连接");
ShowStackLimitWarning(snapTarget);
return;
}
// 应用点击高亮效果
HandleClickHighlight(snapTarget);
// 如果有吸附目标,使用吸附点的位置
Vector3 targetPoint = GetObjectCenter(snapTarget);
// 设置当前接口
if (currentState == DrawingState.Idle)
{
currentStartInterface = snapTarget;
startInterfaceObject = snapTarget; // 记录起点接口
// 新增:检查起点接口的堆叠限制
if (enableStacking && IsStackLimitReached(snapTarget))
{
Debug.LogWarning($"起点接口 {snapTarget.name} 已达到堆叠限制 ({GetStackCountForInterface(snapTarget)}/{maxStackCount}),无法创建新连线");
ShowStackLimitWarning(snapTarget);
return;
}
}
else if (currentState == DrawingState.SelectingEnd)
{
currentEndInterface = snapTarget;
// 新增:检查终点接口的堆叠限制
if (enableStacking && IsStackLimitReached(snapTarget))
{
Debug.LogWarning($"终点接口 {snapTarget.name} 已达到堆叠限制 ({GetStackCountForInterface(snapTarget)}/{maxStackCount}),无法连接");
ShowStackLimitWarning(snapTarget);
return;
}
}
switch (currentState)
{
case DrawingState.Idle:
StartNewWire(targetPoint);
break;
case DrawingState.SelectingStart:
break;
case DrawingState.SelectingEnd:
CompleteWire(targetPoint);
break;
}
}
else if (Physics.Raycast(ray, out hit, Mathf.Infinity, snapLayers))
{
GameObject hitObject = hit.collider.gameObject;
// 检查击中的物体是否有碰撞体
if (requireColliderForConnection && !HasCollider(hitObject))
{
Debug.LogWarning($"目标物体 {hitObject.name} 没有碰撞体,无法连线");
return;
}
// 检查是否尝试自连接
if (currentState == DrawingState.SelectingEnd && IsSelfConnection(hitObject))
{
Debug.LogWarning("不能连接到自身接口!");
ShowSelfConnectionWarning(hitObject);
return;
}
// 新增:检查堆叠限制
if (enableStacking && IsStackLimitReached(hitObject))
{
Debug.LogWarning($"目标接口 {hitObject.name} 已达到堆叠限制 ({GetStackCountForInterface(hitObject)}/{maxStackCount}),无法连接");
ShowStackLimitWarning(hitObject);
return;
}
// 应用点击高亮效果
HandleClickHighlight(hitObject);
// 如果有击中物体,使用击中点的位置
Vector3 targetPoint = GetSnapPoint(hit);
// 检查是否在吸附距离内,如果是则设置当前接口
Vector3 objectCenter = GetObjectCenter(hitObject);
float distance = Vector3.Distance(hit.point, objectCenter);
if (distance <= snapDistance)
{
if (currentState == DrawingState.Idle)
{
currentStartInterface = hitObject;
startInterfaceObject = hitObject; // 记录起点接口
// 新增:检查起点接口的堆叠限制
if (enableStacking && IsStackLimitReached(hitObject))
{
Debug.LogWarning($"起点接口 {hitObject.name} 已达到堆叠限制 ({GetStackCountForInterface(hitObject)}/{maxStackCount}),无法创建新连线");
ShowStackLimitWarning(hitObject);
return;
}
}
else if (currentState == DrawingState.SelectingEnd)
{
currentEndInterface = hitObject;
// 新增:检查终点接口的堆叠限制
if (enableStacking && IsStackLimitReached(hitObject))
{
Debug.LogWarning($"终点接口 {hitObject.name} 已达到堆叠限制 ({GetStackCountForInterface(hitObject)}/{maxStackCount}),无法连接");
ShowStackLimitWarning(hitObject);
return;
}
}
}
switch (currentState)
{
case DrawingState.Idle:
StartNewWire(targetPoint);
break;
case DrawingState.SelectingStart:
break;
case DrawingState.SelectingEnd:
CompleteWire(targetPoint);
break;
}
}
else
{
// 如果没有击中任何物体,且要求必须有碰撞体,则不允许连线
if (requireColliderForConnection)
{
Debug.LogWarning("没有找到带有碰撞体的物体,无法连线");
return;
}
// 如果没有击中任何物体,使用实际鼠标位置
switch (currentState)
{
case DrawingState.Idle:
StartNewWire(actualMousePosition);
break;
case DrawingState.SelectingStart:
break;
case DrawingState.SelectingEnd:
CompleteWire(actualMousePosition);
break;
}
}
}
// 检查物体是否有碰撞体
bool HasCollider(GameObject obj)
{
if (obj == null) return false;
// 检查所有类型的碰撞器
Collider collider3D = obj.GetComponent<Collider>();
Collider2D collider2D = obj.GetComponent<Collider2D>();
return (collider3D != null || collider2D != null);
}
// 修改 StartNewWire 方法,传递目标接口
void StartNewWire(Vector3 point)
{
// 新增:最终确认起点接口的堆叠限制
if (startInterfaceObject != null && enableStacking && IsStackLimitReached(startInterfaceObject))
{
Debug.LogWarning($"起点接口 {startInterfaceObject.name} 已达到堆叠限制 ({GetStackCountForInterface(startInterfaceObject)}/{maxStackCount}),无法创建新连线");
ShowStackLimitWarning(startInterfaceObject);
currentState = DrawingState.Idle;
startInterfaceObject = null;
return;
}
startPoint = point;
currentState = DrawingState.SelectingEnd;
// 记录起点接口
startInterfaceObject = currentStartInterface;
// 创建起点连接点模型,传递当前接口
bool created = CreateConnectionPoint(point, true, startInterfaceObject);
if (!created)
{
// 如果创建失败,取消连线操作
currentState = DrawingState.Idle;
startInterfaceObject = null;
return;
}
CreateWirePreview();
Debug.Log($"选择起点: {point}, 接口: {startInterfaceObject?.name ?? ""}");
}
// 修改 CompleteWire 方法,传递目标接口
void CompleteWire(Vector3 point)
{
// 记录终点接口
endInterfaceObject = currentEndInterface;
// 最终检查是否尝试自连接
if (endInterfaceObject != null && IsSelfConnection(endInterfaceObject))
{
Debug.LogWarning("不能连接到自身接口!");
ShowSelfConnectionWarning(endInterfaceObject);
CancelDrawing();
return;
}
// 新增:最终确认终点接口的堆叠限制
if (endInterfaceObject != null && enableStacking && IsStackLimitReached(endInterfaceObject))
{
Debug.LogWarning($"终点接口 {endInterfaceObject.name} 已达到堆叠限制 ({GetStackCountForInterface(endInterfaceObject)}/{maxStackCount}),无法连接");
ShowStackLimitWarning(endInterfaceObject);
CancelDrawing();
return;
}
endPoint = point;
currentState = DrawingState.Idle;
// 创建终点连接点模型,传递当前接口
bool created = CreateConnectionPoint(point, false, endInterfaceObject);
if (!created)
{
// 如果创建失败,删除起点连接点并取消连线
RemoveUnfinishedConnectionPoints();
startInterfaceObject = null;
endInterfaceObject = null;
return;
}
FinalizeWire();
Debug.Log($"选择终点: {point}, 接口: {endInterfaceObject?.name ?? ""}");
// 清除所有高亮,确保颜色恢复
ClearAllHighlights();
// 重置当前接口
currentStartInterface = null;
currentEndInterface = null;
startInterfaceObject = null;
endInterfaceObject = null;
}
void CreateWirePreview()
{
currentWireObject = new GameObject("WirePreview");
if (useCylinderWire)
{
CreateCylinderWirePreview();
}
else
{
// 原有的LineRenderer代码
currentWire = currentWireObject.AddComponent<LineRenderer>();
ConfigureLineRenderer(currentWire);
currentWire.positionCount = 2;
currentWire.SetPosition(0, startPoint);
currentWire.SetPosition(1, startPoint);
}
}
/// <summary>
/// 创建圆柱体连线预览
/// </summary>
void CreateCylinderWirePreview()
{
// 创建初始圆柱体(长度很短)
GameObject cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
cylinder.name = "WireCylinder";
cylinder.transform.SetParent(currentWireObject.transform);
// 设置材质
if (cylinderWireMaterial != null)
{
Renderer renderer = cylinder.GetComponent<Renderer>();
renderer.material = cylinderWireMaterial;
}
// 初始位置和缩放
cylinder.transform.position = startPoint;
cylinder.transform.localScale = new Vector3(
cylinderWireDiameter,
0.001f, // 初始高度很小
cylinderWireDiameter
);
// 移除碰撞器,避免干扰
Destroy(cylinder.GetComponent<Collider>());
}
/// <summary>
/// 更新圆柱体连线预览
/// </summary>
void UpdateCylinderWirePreview()
{
if (currentState == DrawingState.SelectingEnd && currentWireObject != null)
{
Vector3 targetPoint;
if (snapTarget != null)
{
targetPoint = GetObjectCenter(snapTarget);
}
else
{
targetPoint = GetMouseWorldPosition();
}
if (useCylinderWire)
{
UpdateCylinderWire(startPoint, targetPoint);
}
else
{
// 原有的LineRenderer更新代码
if (currentWire != null)
{
currentWire.SetPosition(1, targetPoint);
}
}
}
}
/// <summary>
/// 更新圆柱体连线的位置和形状
/// </summary>
void UpdateCylinderWire(Vector3 start, Vector3 end)
{
Transform cylinderTransform = currentWireObject.transform.Find("WireCylinder");
if (cylinderTransform == null) return;
GameObject cylinder = cylinderTransform.gameObject;
// 计算连线的方向、长度和中点
Vector3 direction = end - start;
float distance = direction.magnitude;
if (distance < 0.001f)
{
// 距离太短,隐藏圆柱体
cylinder.transform.localScale = new Vector3(cylinderWireDiameter, 0.001f, cylinderWireDiameter);
return;
}
Vector3 midPoint = (start + end) / 2f;
// 设置圆柱体的位置和旋转
cylinder.transform.position = midPoint;
cylinder.transform.up = direction.normalized; // 圆柱体默认朝向Y轴
// 设置圆柱体的缩放
// 圆柱体原始高度为2所以实际高度 = scaleY * 2
cylinder.transform.localScale = new Vector3(
cylinderWireDiameter,
distance / 2f, // 因为原始高度为2所以要除以2
cylinderWireDiameter
);
}
/// <summary>
/// 最终确定圆柱体连线
/// </summary>
void FinalizeCylinderWire()
{
if (currentWireObject == null) return;
Transform cylinderTransform = currentWireObject.transform.Find("WireCylinder");
if (cylinderTransform == null) return;
GameObject cylinder = cylinderTransform.gameObject;
// 更新最终位置
UpdateCylinderWire(startPoint, endPoint);
// 添加圆柱体连线数据
CylinderWireData wireData = currentWireObject.AddComponent<CylinderWireData>();
wireData.startPoint = GetConnectionPointObject(true);
wireData.endPoint = GetConnectionPointObject(false);
wireData.startInterface = startInterfaceObject;
wireData.endInterface = endInterfaceObject;
wireData.wireDiameter = cylinderWireDiameter;
// 可选:添加碰撞器
if (addColliderToWires)
{
AddCylinderWireCollider(cylinder);
}
// 添加到连线列表
allWires.Add(currentWireObject);
Debug.Log($"圆柱体连线完成: {currentWireObject.name}");
}
/// <summary>
/// 获取连接点对象(用于连线数据)
/// </summary>
GameObject GetConnectionPointObject(bool isStartPoint)
{
// 查找最近创建的连接点
for (int i = allConnectionPoints.Count - 1; i >= 0; i--)
{
GameObject point = allConnectionPoints[i];
if (point != null && point.transform.parent == null)
{
if (isStartPoint && point.name.Contains("Start"))
return point;
else if (!isStartPoint && point.name.Contains("End"))
return point;
}
}
return null;
}
/// <summary>
/// 为圆柱体连线添加碰撞器
/// </summary>
void AddCylinderWireCollider(GameObject cylinder)
{
CapsuleCollider collider = cylinder.AddComponent<CapsuleCollider>();
collider.isTrigger = true;
// 胶囊碰撞器会自动匹配圆柱体的形状
// 方向设置为Y轴圆柱体的默认方向
collider.direction = 1; // 1 = Y轴
}
void UpdateWirePreview()
{
if (currentState == DrawingState.SelectingEnd && currentWire != null)
{
Vector3 targetPoint;
// 如果有吸附目标,使用吸附点
if (snapTarget != null)
{
targetPoint = GetObjectCenter(snapTarget);
}
else
{
// 否则使用实际鼠标位置
targetPoint = GetMouseWorldPosition();
}
currentWire.SetPosition(1, targetPoint);
}
}
void CheckForSnapTargets()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
// 清除之前的吸附高亮
ClearSnapHighlight();
// 检查鼠标位置附近是否有可吸附的物体
if (Physics.Raycast(ray, out hit, Mathf.Infinity, snapLayers))
{
GameObject hitObject = hit.collider.gameObject;
// 如果要求碰撞体但物体没有碰撞体,跳过
if (requireColliderForConnection && !HasCollider(hitObject))
{
return;
}
// 检查是否尝试自连接
if (currentState == DrawingState.SelectingEnd && IsSelfConnection(hitObject))
{
// 自连接目标仍然可以吸附,但会显示警告
ShowSelfConnectionWarning(hitObject);
}
// 检查堆叠数量限制
if (enableStacking && maxStackCount > 0 && IsStackLimitReached(hitObject))
{
// 达到堆叠限制的接口仍然可以吸附,但会显示警告
ShowStackLimitWarning(hitObject);
}
// 计算鼠标位置与物体中心的距离
Vector3 objectCenter = GetObjectCenter(hitObject);
float distance = Vector3.Distance(GetMouseWorldPosition(), objectCenter);
if (distance <= snapDistance)
{
// 设置吸附目标
snapTarget = hitObject;
// 高亮显示可吸附的物体
HighlightSnapTarget(snapTarget);
}
}
}
Vector3 GetSnapPoint(RaycastHit hit)
{
if (!enableSnapping)
return hit.point;
GameObject hitObject = hit.collider.gameObject;
Vector3 objectCenter = GetObjectCenter(hitObject);
// 检查是否在吸附距离内
float distance = Vector3.Distance(hit.point, objectCenter);
if (distance <= snapDistance)
{
return objectCenter;
}
return hit.point;
}
Vector3 GetObjectCenter(GameObject obj)
{
if (obj == null) return Vector3.zero;
if (snapToColliderCenter)
{
Collider collider = obj.GetComponent<Collider>();
if (collider != null)
{
return collider.bounds.center;
}
}
if (snapToTransformCenter)
{
return obj.transform.position;
}
// 默认使用碰撞体中心
Collider defaultCollider = obj.GetComponent<Collider>();
if (defaultCollider != null)
{
return defaultCollider.bounds.center;
}
// 如果都没有,使用变换位置
return obj.transform.position;
}
void HighlightSnapTarget(GameObject target)
{
if (target == null) return;
// 如果已经高亮了其他接口,先恢复它的颜色
if (currentlyHighlightedInterface != null && currentlyHighlightedInterface != target)
{
RestoreInterfaceColor(currentlyHighlightedInterface);
}
snapTargetRenderer = target.GetComponent<Renderer>();
if (snapTargetRenderer != null)
{
// 确保使用材质实例,避免影响其他对象
EnsureMaterialInstance(target);
// 记录原始颜色到字典中
if (!highlightedInterfaces.ContainsKey(target))
{
highlightedInterfaces[target] = snapTargetRenderer.material.color;
Debug.Log($"记录接口 {target.name} 的原始颜色: {snapTargetRenderer.material.color}");
}
// 设置高亮颜色
// snapTargetRenderer.material.color = snapHighlightColor;
Debug.Log($"设置接口 {target.name} 为吸附高亮颜色: {snapHighlightColor}");
// 更新当前高亮接口
currentlyHighlightedInterface = target;
isSnapTargetHighlighted = true;
}
}
/// <summary>
/// 确保使用材质实例,避免影响其他使用相同材质的对象
/// </summary>
void EnsureMaterialInstance(GameObject target)
{
if (target == null) return;
Renderer renderer = target.GetComponent<Renderer>();
if (renderer != null)
{
// 如果还没有记录原始材质,记录下来
if (!originalMaterials.ContainsKey(target))
{
originalMaterials[target] = renderer.sharedMaterial;
}
// 确保使用材质实例
if (renderer.sharedMaterial == renderer.material)
{
// 如果共享材质和实例材质相同,说明还没有创建实例
renderer.material = new Material(renderer.sharedMaterial);
Debug.Log($"为接口 {target.name} 创建材质实例");
}
}
}
/// <summary>
/// 恢复接口的原始材质
/// </summary>
void RestoreOriginalMaterial(GameObject target)
{
if (target == null) return;
if (originalMaterials.ContainsKey(target))
{
Renderer renderer = target.GetComponent<Renderer>();
if (renderer != null)
{
// 恢复原始材质
renderer.sharedMaterial = originalMaterials[target];
Debug.Log($"恢复接口 {target.name} 的原始材质");
}
// 从字典中移除
originalMaterials.Remove(target);
}
}
void ClearSnapHighlight()
{
if (snapTargetRenderer != null && isSnapTargetHighlighted)
{
// snapTargetRenderer.material.color = snapTargetOriginalColor;
snapTargetRenderer = null;
isSnapTargetHighlighted = false;
}
snapTarget = null;
}
// 修改 FinalizeWire 方法,添加记录功能
void FinalizeWire()
{
if (currentWireObject != null)
{
currentWireObject.name = $"Wire_{System.DateTime.Now:yyyyMMddHHmmss}";
// 将连接点附加到连线对象
AttachConnectionPointsToWire(currentWireObject);
if (useCylinderWire)
{
FinalizeCylinderWire();
}
else
{
// 原有的LineRenderer最终化代码
FinalizeLineRendererWire();
}
}
currentWire = null;
currentWireObject = null;
}
/// <summary>
/// 最终化LineRenderer连线原有的FinalizeWire内容
/// </summary>
void FinalizeLineRendererWire()
{
// 这里放置原有的FinalizeWire方法中的LineRenderer相关代码
FinalizeWire();
// 包括添加到连线列表、添加WireData组件等
allWires.Add(currentWireObject);
if (addColliderToWires)
{
AddWireCollider(currentWire);
}
WireData data = currentWireObject.AddComponent<WireData>();
data.startPoint = startPoint;
data.endPoint = endPoint;
data.creationTime = System.DateTime.Now;
if (startInterfaceObject != null)
{
data.snapStartObject = startInterfaceObject;
}
if (endInterfaceObject != null)
{
data.snapEndObject = endInterfaceObject;
}
WireConnectionData connectionData = new WireConnectionData
{
startInterface = startInterfaceObject,
endInterface = endInterfaceObject
};
wireConnectionData[currentWireObject] = connectionData;
Debug.Log($"连线完成: {currentWireObject.name}");
}
// 修改 CancelDrawing 方法,确保正确清理
void CancelDrawing()
{
if (currentWireObject != null)
{
Destroy(currentWireObject);
}
RemoveUnfinishedConnectionPoints();
ClearSnapPreview();
ClearAllHighlights();
// 恢复所有接口的原始材质
List<GameObject> interfacesToRestore = new List<GameObject>(originalMaterials.Keys);
foreach (GameObject interfaceObj in interfacesToRestore)
{
if (interfaceObj != null)
{
RestoreOriginalMaterial(interfaceObj);
}
}
originalMaterials.Clear();
currentState = DrawingState.Idle;
currentWire = null;
currentWireObject = null;
currentStartInterface = null;
currentEndInterface = null;
startInterfaceObject = null;
endInterfaceObject = null;
Debug.Log("取消连线操作");
}
/// <summary>
/// 更新吸附点预览模型
/// </summary>
void UpdateSnapPreview()
{
if (snapPreviewPrefab == null) return;
// 如果有吸附目标,显示预览
if (snapTarget != null)
{
if (currentSnapPreview == null)
{
currentSnapPreview = Instantiate(snapPreviewPrefab);
currentSnapPreview.name = "SnapPreview";
currentSnapPreview.transform.localScale = Vector3.one * connectionPointScale * 0.8f;
// 设置为半透明
Renderer renderer = currentSnapPreview.GetComponent<Renderer>();
if (renderer != null)
{
Color color = renderer.material.color;
color.a = 0.5f;
renderer.material.color = color;
}
}
Vector3 snapPosition = GetObjectCenter(snapTarget);
currentSnapPreview.transform.position = snapPosition;
// 根据状态改变预览颜色
Renderer previewRenderer = currentSnapPreview.GetComponent<Renderer>();
if (previewRenderer != null)
{
// 如果尝试自连接,使用自连接警告颜色
if (currentState == DrawingState.SelectingEnd && IsSelfConnection(snapTarget))
{
previewRenderer.material.color = selfConnectionWarningColor;
}
// 如果达到堆叠限制,改变预览颜色
else if (enableStacking && maxStackCount > 0 && IsStackLimitReached(snapTarget))
{
previewRenderer.material.color = maxStackWarningColor;
}
else
{
// 恢复半透明颜色
Color color = previewRenderer.material.color;
color.a = 0.5f;
previewRenderer.material.color = color;
}
}
}
else if (currentSnapPreview != null)
{
// 没有吸附目标时隐藏预览
ClearSnapPreview();
}
}
/// <summary>
/// 清除吸附点预览
/// </summary>
void ClearSnapPreview()
{
if (currentSnapPreview != null)
{
Destroy(currentSnapPreview);
currentSnapPreview = null;
}
}
void ConfigureLineRenderer(LineRenderer lr)
{
if (wireMaterial != null)
{
lr.material = wireMaterial;
}
else
{
// 使用默认材质
lr.material = new Material(Shader.Find("Sprites/Default"));
}
lr.startColor = wireColor;
lr.endColor = wireColor;
lr.startWidth = wireWidth;
lr.endWidth = wireWidth;
lr.useWorldSpace = true;
}
// 修复:改进的碰撞器添加方法
void AddWireCollider(LineRenderer lr)
{
if (lr.positionCount < 2)
{
Debug.LogWarning("连线点数不足,无法添加碰撞器");
return;
}
// 创建胶囊碰撞器而不是网格碰撞器避免Convex Mesh错误
CreateCapsuleCollidersAlongLine(lr);
}
// 修复:使用胶囊碰撞器替代网格碰撞器
void CreateCapsuleCollidersAlongLine(LineRenderer lr)
{
// 获取连线上的所有点
Vector3[] positions = new Vector3[lr.positionCount];
lr.GetPositions(positions);
// 为连线的每个线段创建胶囊碰撞器
for (int i = 0; i < positions.Length - 1; i++)
{
Vector3 start = positions[i];
Vector3 end = positions[i + 1];
// 计算线段长度和方向
float distance = Vector3.Distance(start, end);
if (distance < 0.01f) continue; // 跳过太短的线段
Vector3 direction = (end - start).normalized;
// 创建胶囊碰撞器
CapsuleCollider capsule = currentWireObject.AddComponent<CapsuleCollider>();
// 设置胶囊碰撞器的方向和位置
capsule.direction = 2; // Z轴方向
capsule.height = distance;
capsule.radius = wireWidth / 2;
// 计算胶囊的位置和旋转
capsule.center = start + direction * distance / 2;
// 设置胶囊的方向
if (direction != Vector3.zero)
{
capsule.transform.rotation = Quaternion.LookRotation(direction);
}
capsule.isTrigger = true;
}
}
// 修复:改进的鼠标位置获取方法
Vector3 GetMouseWorldPosition()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
// 优先使用吸附目标的位置
if (snapTarget != null)
{
return GetObjectCenter(snapTarget);
}
// 其次使用射线击中的位置
if (Physics.Raycast(ray, out hit, Mathf.Infinity, snapLayers))
{
// 检查击中的物体是否有碰撞体
if (requireColliderForConnection && !HasCollider(hit.collider.gameObject))
{
// 如果没有碰撞体,继续寻找其他点
return FindAlternativePosition(ray);
}
return GetSnapPoint(hit);
}
// 如果没有击中任何物体,使用默认平面
return FindAlternativePosition(ray);
}
// 寻找替代位置(当没有碰撞体时)
Vector3 FindAlternativePosition(Ray ray)
{
// 尝试在默认平面上寻找位置
Plane defaultPlane = new Plane(Vector3.up, Vector3.zero);
float enter;
if (defaultPlane.Raycast(ray, out enter))
{
return ray.GetPoint(enter);
}
// 最后使用射线上的一个点
return ray.origin + ray.direction * 10f;
}
// 公共方法:开始新连线
public void StartNewWire()
{
if (currentState != DrawingState.Idle)
{
CancelDrawing();
}
currentState = DrawingState.SelectingStart;
}
// 公共方法:设置吸附目标(用于编程控制)
public void SetSnapTarget(GameObject target)
{
if (enableSnapping && target != null)
{
// 检查目标是否有碰撞体
if (requireColliderForConnection && !HasCollider(target))
{
Debug.LogWarning($"目标物体 {target.name} 没有碰撞体,无法设置为吸附目标");
return;
}
snapTarget = target;
HighlightSnapTarget(target);
}
}
// 公共方法:清除吸附目标
public void ClearSnapTarget()
{
ClearSnapHighlight();
}
// 公共方法:检查物体是否可以连线
public bool CanConnectToObject(GameObject obj)
{
if (obj == null) return false;
// 如果不需要碰撞体,任何物体都可以连线
if (!requireColliderForConnection) return true;
// 检查物体是否有碰撞体
return HasCollider(obj);
}
/// <summary>
/// 检查接口是否可以接受新连接点(考虑堆叠限制和自连接)
/// </summary>
public bool CanInterfaceAcceptConnection(GameObject targetInterface)
{
if (targetInterface == null) return true;
// 检查自连接
if (IsSelfConnection(targetInterface))
{
return false;
}
// 检查堆叠限制
if (!enableStacking || maxStackCount <= 0) return true;
return !IsStackLimitReached(targetInterface);
}
/// <summary>
/// 获取接口上所有连接点的位置信息
/// </summary>
public List<Vector3> GetConnectionPointsOnInterface(GameObject targetInterface)
{
List<Vector3> positions = new List<Vector3>();
if (interfaceStacks.ContainsKey(targetInterface.name))
{
foreach (GameObject connectionPoint in interfaceStacks[targetInterface.name])
{
if (connectionPoint != null)
{
positions.Add(connectionPoint.transform.position);
}
}
}
return positions;
}
/// <summary>
/// 获取接口上的连接点数量
/// </summary>
public int GetConnectionPointCountOnInterface(GameObject targetInterface)
{
return GetStackCountForInterface(targetInterface);
}
/// <summary>
/// 获取接口的剩余可用连接点数量
/// </summary>
public int GetRemainingConnectionSlots(GameObject targetInterface)
{
if (!enableStacking || maxStackCount <= 0) return int.MaxValue;
int currentCount = GetStackCountForInterface(targetInterface);
return Mathf.Max(0, maxStackCount - currentCount);
}
/// <summary>
/// 设置特定接口的最大堆叠数量(覆盖全局设置)
/// </summary>
public void SetInterfaceMaxStackCount(GameObject targetInterface, int maxCount)
{
// 这里可以扩展为每个接口有不同的最大堆叠数量
// 目前使用全局设置,但保留接口用于未来扩展
Debug.Log($"接口 {targetInterface?.name} 最大堆叠数量请求设置为 {maxCount},当前使用全局设置: {maxStackCount}");
}
/// <summary>
/// 清除特定接口上的所有连接点
/// </summary>
public void ClearConnectionPointsOnInterface(GameObject targetInterface)
{
if (interfaceStacks.ContainsKey(targetInterface.name))
{
// 创建副本,避免在遍历时修改集合
List<GameObject> pointsToRemove = new List<GameObject>(interfaceStacks[targetInterface.name]);
foreach (GameObject connectionPoint in pointsToRemove)
{
if (connectionPoint != null)
{
DeleteConnectionPoint(connectionPoint);
}
}
interfaceStacks.Remove(targetInterface.name);
}
}
/// <summary>
/// 设置高亮功能开启/关闭
/// </summary>
public void SetHighlightEnabled(bool enabled)
{
enableHighlight = enabled;
if (!enabled)
{
// 如果禁用高亮,立即停止所有高亮效果
if (currentHighlightCoroutine != null)
{
StopCoroutine(currentHighlightCoroutine);
currentHighlightCoroutine = null;
}
// 恢复所有高亮物体的颜色
ClearAllHighlights();
}
}
/// <summary>
/// 切换高亮功能状态
/// </summary>
public void ToggleHighlight()
{
SetHighlightEnabled(!enableHighlight);
Debug.Log($"点击高亮效果: {(enableHighlight ? "" : "")}");
}
/// <summary>
/// 设置高亮颜色
/// </summary>
public void SetHighlightColor(Color color)
{
clickHighlightColor = color;
}
/// <summary>
/// 设置高亮持续时间
/// </summary>
public void SetHighlightDuration(float duration)
{
highlightDuration = Mathf.Max(0.1f, duration);
}
public void SetColor_Model(string color)
{
if (currentState != DrawingState.Idle)
{
return;
}
switch (color)
{
case "红":
connectionPointPrefab = model[0];
snapPreviewPrefab = model[0];
cylinderWireMaterial = Colors[0];
break;
case "绿":
connectionPointPrefab = model[1];
snapPreviewPrefab = model[1];
cylinderWireMaterial = Colors[1];
break;
case "黑":
connectionPointPrefab = model[2];
snapPreviewPrefab = model[2];
cylinderWireMaterial = Colors[2];
break;
case "黄":
connectionPointPrefab = model[3];
snapPreviewPrefab = model[3];
cylinderWireMaterial = Colors[3];
break;
}
}
}