984 lines
28 KiB
C#
984 lines
28 KiB
C#
using UnityEngine;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
|
||
public class LineShowModel : 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 Color snapHighlightColor = Color.cyan; // 吸附高亮颜色
|
||
|
||
[Header("圆柱体连线设置")]
|
||
public bool useCylinderWire = true; // 启用圆柱体连线
|
||
public Material cylinderWireMaterial;
|
||
public float cylinderWireDiameter = 0.02f;
|
||
public int cylinderSegments = 8; // 圆柱体面数,影响性能
|
||
|
||
[Header("预览设置")]
|
||
public Material previewMaterial; // 预览线材质
|
||
public Color previewColor = new Color(1, 1, 1, 0.5f); // 预览线颜色(半透明)
|
||
public float previewWireDiameter = 0.015f; // 预览线直径
|
||
|
||
[Header("删除设置")]
|
||
public KeyCode deleteKey = KeyCode.Mouse2; // 默认为鼠标右键
|
||
public float deleteDetectionRadius = 0.5f; // 删除检测半径
|
||
|
||
[Header("状态显示")]
|
||
public DrawingState currentState = DrawingState.Idle;
|
||
|
||
// 连线数据
|
||
private Vector3 startPoint;
|
||
private Vector3 endPoint;
|
||
private GameObject currentWireObject;
|
||
private GameObject previewWireObject; // 预览连线对象
|
||
|
||
// 吸附相关
|
||
private GameObject snapTarget; // 当前吸附目标
|
||
private Renderer snapTargetRenderer; // 吸附目标的渲染器
|
||
private Color snapTargetOriginalColor; // 吸附目标原始颜色
|
||
private bool isSnapTargetHighlighted = false;
|
||
|
||
// 存储所有已创建的连线
|
||
private List<GameObject> allWires = new List<GameObject>();
|
||
|
||
// 起点和终点的碰撞体
|
||
private GameObject startColliderObject;
|
||
private GameObject endColliderObject;
|
||
|
||
// 单例模式,便于外部调用
|
||
public static LineShowModel Instance { get; private set; }
|
||
|
||
[Header("动态粗细设置")]
|
||
public bool enableDynamicThickness = true; // 启用动态粗细
|
||
public float minThickness = 0.005f; // 最小粗细
|
||
public float maxThickness = 0.02f; // 最大粗细
|
||
public float closeDistance = 1.0f; // 视为"近"的距离阈值
|
||
public float farDistance = 10.0f;
|
||
|
||
// 添加相机引用,用于计算距离
|
||
private Camera mainCamera;
|
||
|
||
void Awake()
|
||
{
|
||
// 设置单例
|
||
if (Instance == null)
|
||
{
|
||
Instance = this;
|
||
}
|
||
else
|
||
{
|
||
Destroy(gameObject);
|
||
}
|
||
|
||
mainCamera = Camera.main;
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
HandleInput();
|
||
|
||
if (currentState == DrawingState.SelectingEnd)
|
||
{
|
||
UpdateWirePreview();
|
||
}
|
||
|
||
// 在选择终点状态时检查吸附
|
||
if (currentState == DrawingState.SelectingEnd && enableSnapping)
|
||
{
|
||
CheckForSnapTargets();
|
||
}
|
||
else
|
||
{
|
||
ClearSnapHighlight();
|
||
}
|
||
|
||
// 更新所有连线的动态粗细
|
||
if (enableDynamicThickness && useCylinderWire)
|
||
{
|
||
UpdateAllWiresThickness();
|
||
}
|
||
}
|
||
// 新增方法:更新所有连线的动态粗细
|
||
void UpdateAllWiresThickness()
|
||
{
|
||
if (mainCamera == null) return;
|
||
|
||
foreach (GameObject wire in allWires)
|
||
{
|
||
if (wire == null) continue;
|
||
|
||
LineShowModelCylinderWireData wireData = wire.GetComponent<LineShowModelCylinderWireData>();
|
||
if (wireData == null) continue;
|
||
|
||
// 计算连线中点与相机的距离
|
||
Vector3 wireMidPoint = (wireData.startPoint + wireData.endPoint) / 2f;
|
||
float distanceToCamera = Vector3.Distance(wireMidPoint, mainCamera.transform.position);
|
||
|
||
// 根据距离计算粗细
|
||
float targetThickness = CalculateDynamicThickness(distanceToCamera);
|
||
|
||
// 更新圆柱体粗细
|
||
Transform cylinderTransform = wire.transform.Find("WireCylinder");
|
||
if (cylinderTransform != null)
|
||
{
|
||
Vector3 currentScale = cylinderTransform.localScale;
|
||
cylinderTransform.localScale = new Vector3(
|
||
targetThickness,
|
||
currentScale.y, // 保持高度不变
|
||
targetThickness
|
||
);
|
||
|
||
// 更新数据
|
||
wireData.wireDiameter = targetThickness;
|
||
}
|
||
}
|
||
}
|
||
// 新增方法:根据距离计算动态粗细
|
||
float CalculateDynamicThickness(float distance)
|
||
{
|
||
// 使用线性插值计算粗细
|
||
float t = Mathf.InverseLerp(closeDistance, farDistance, distance);
|
||
t = Mathf.Clamp01(t); // 确保在0-1范围内
|
||
|
||
// 距离越近,线条越细(使用1-t来反转关系)
|
||
float thickness = Mathf.Lerp(minThickness, maxThickness, 1 - t);
|
||
|
||
return thickness;
|
||
}
|
||
// 新增方法:基于相对距离的粗细计算(可选)
|
||
float CalculateDynamicThicknessRelative(Vector3 start, Vector3 end, Vector3 cameraPos)
|
||
{
|
||
// 计算连线中点到相机的距离
|
||
Vector3 midPoint = (start + end) / 2f;
|
||
float distanceToCamera = Vector3.Distance(midPoint, cameraPos);
|
||
|
||
// 计算连线长度
|
||
float lineLength = Vector3.Distance(start, end);
|
||
|
||
// 基于连线长度和相机距离的综合计算
|
||
float lengthFactor = Mathf.Clamp01(lineLength / farDistance);
|
||
float cameraFactor = Mathf.Clamp01(distanceToCamera / farDistance);
|
||
|
||
// 综合因素:连线越长或距离相机越近,线条越细
|
||
float combinedFactor = (lengthFactor + (1 - cameraFactor)) / 2f;
|
||
|
||
return Mathf.Lerp(minThickness, maxThickness, 1 - combinedFactor);
|
||
}
|
||
|
||
// 新增方法:批量更新连线的动态粗细
|
||
public void RefreshAllWiresThickness()
|
||
{
|
||
if (!enableDynamicThickness || !useCylinderWire) return;
|
||
|
||
UpdateAllWiresThickness();
|
||
}
|
||
|
||
// 新增方法:设置动态粗细参数
|
||
public void SetDynamicThicknessParams(float newMinThickness, float newMaxThickness,
|
||
float newCloseDistance, float newFarDistance)
|
||
{
|
||
minThickness = Mathf.Max(0.001f, newMinThickness);
|
||
maxThickness = Mathf.Max(minThickness, newMaxThickness);
|
||
closeDistance = Mathf.Max(0.1f, newCloseDistance);
|
||
farDistance = Mathf.Max(closeDistance + 0.1f, newFarDistance);
|
||
|
||
RefreshAllWiresThickness();
|
||
}
|
||
void HandleInput()
|
||
{
|
||
if (Input.GetMouseButtonDown(0)) // 左键点击
|
||
{
|
||
HandleMouseClick();
|
||
}
|
||
|
||
if (Input.GetKeyDown(KeyCode.Escape)) // 取消当前操作
|
||
{
|
||
CancelDrawing();
|
||
}
|
||
|
||
if (Input.GetKeyDown(deleteKey)) // 删除操作
|
||
{
|
||
HandleDelete();
|
||
}
|
||
}
|
||
|
||
void HandleMouseClick()
|
||
{
|
||
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
||
RaycastHit hit;
|
||
|
||
// 首先检查是否有吸附目标
|
||
if (snapTarget != null)
|
||
{
|
||
HandleSnapTargetClick();
|
||
}
|
||
else if (Physics.Raycast(ray, out hit, Mathf.Infinity, snapLayers))
|
||
{
|
||
HandleColliderClick(hit.collider.gameObject, hit.point);
|
||
}
|
||
else
|
||
{
|
||
// 如果没有击中任何物体,且不在选择起点状态,则忽略
|
||
if (currentState == DrawingState.Idle)
|
||
{
|
||
Debug.Log("请点击一个碰撞体作为连线起点");
|
||
}
|
||
}
|
||
}
|
||
|
||
void HandleSnapTargetClick()
|
||
{
|
||
if (snapTarget == null) return;
|
||
|
||
switch (currentState)
|
||
{
|
||
case DrawingState.Idle:
|
||
// 选择起点
|
||
StartNewWire(snapTarget);
|
||
break;
|
||
|
||
case DrawingState.SelectingEnd:
|
||
// 选择终点
|
||
CompleteWire(snapTarget);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void HandleColliderClick(GameObject colliderObject, Vector3 hitPoint)
|
||
{
|
||
switch (currentState)
|
||
{
|
||
case DrawingState.Idle:
|
||
// 选择起点
|
||
StartNewWire(colliderObject);
|
||
break;
|
||
|
||
case DrawingState.SelectingEnd:
|
||
// 选择终点
|
||
CompleteWire(colliderObject);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void StartNewWire(GameObject startCollider)
|
||
{
|
||
if (startCollider == null) return;
|
||
|
||
startColliderObject = startCollider;
|
||
startPoint = GetObjectCenter(startCollider);
|
||
currentState = DrawingState.SelectingEnd;
|
||
|
||
// 创建预览连线
|
||
CreatePreviewWire();
|
||
|
||
// 高亮起点碰撞体
|
||
HighlightObject(startCollider);
|
||
|
||
Debug.Log($"选择起点: {startCollider.name}");
|
||
}
|
||
|
||
void CompleteWire(GameObject endCollider)
|
||
{
|
||
if (endCollider == null || startColliderObject == null) return;
|
||
|
||
// 检查是否连接到自身
|
||
if (endCollider == startColliderObject)
|
||
{
|
||
Debug.LogWarning("不能连接到自身!");
|
||
CancelDrawing();
|
||
return;
|
||
}
|
||
|
||
endColliderObject = endCollider;
|
||
endPoint = GetObjectCenter(endCollider);
|
||
|
||
// 创建最终的连线
|
||
GameObject newWire = CreateFinalWire();
|
||
|
||
currentState = DrawingState.Idle;
|
||
|
||
// 清除预览和高亮
|
||
ClearPreviewWire();
|
||
ClearSnapHighlight();
|
||
|
||
Debug.Log($"选择终点: {endCollider.name}, 连线完成");
|
||
|
||
// 返回新创建的连线对象,供外部使用
|
||
OnWireCreated?.Invoke(newWire, startColliderObject, endColliderObject);
|
||
}
|
||
|
||
void CreatePreviewWire()
|
||
{
|
||
// 清除之前的预览
|
||
ClearPreviewWire();
|
||
|
||
previewWireObject = new GameObject("PreviewWire");
|
||
|
||
if (useCylinderWire)
|
||
{
|
||
CreateCylinderPreviewWire();
|
||
}
|
||
else
|
||
{
|
||
CreateLineRendererPreviewWire();
|
||
}
|
||
}
|
||
|
||
void CreateCylinderPreviewWire()
|
||
{
|
||
// 创建预览圆柱体
|
||
GameObject cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
||
cylinder.name = "PreviewCylinder";
|
||
cylinder.transform.SetParent(previewWireObject.transform);
|
||
|
||
// 设置预览材质
|
||
Renderer renderer = cylinder.GetComponent<Renderer>();
|
||
if (previewMaterial != null)
|
||
{
|
||
renderer.material = previewMaterial;
|
||
}
|
||
else
|
||
{
|
||
// 创建默认预览材质
|
||
Material defaultPreviewMaterial = new Material(Shader.Find("Standard"));
|
||
defaultPreviewMaterial.color = previewColor;
|
||
renderer.material = defaultPreviewMaterial;
|
||
}
|
||
|
||
// 初始位置和缩放
|
||
cylinder.transform.position = startPoint;
|
||
cylinder.transform.localScale = new Vector3(
|
||
previewWireDiameter,
|
||
0.001f, // 初始高度很小
|
||
previewWireDiameter
|
||
);
|
||
|
||
// 移除碰撞器,避免干扰
|
||
Destroy(cylinder.GetComponent<Collider>());
|
||
}
|
||
|
||
void CreateLineRendererPreviewWire()
|
||
{
|
||
// 使用LineRenderer作为备选预览
|
||
LineRenderer lr = previewWireObject.AddComponent<LineRenderer>();
|
||
lr.positionCount = 2;
|
||
lr.SetPosition(0, startPoint);
|
||
lr.SetPosition(1, startPoint);
|
||
|
||
// 配置LineRenderer
|
||
if (previewMaterial != null)
|
||
{
|
||
lr.material = previewMaterial;
|
||
}
|
||
else
|
||
{
|
||
lr.material = new Material(Shader.Find("Sprites/Default"));
|
||
}
|
||
|
||
lr.startColor = previewColor;
|
||
lr.endColor = previewColor;
|
||
lr.startWidth = previewWireDiameter;
|
||
lr.endWidth = previewWireDiameter;
|
||
lr.useWorldSpace = true;
|
||
}
|
||
|
||
void UpdateWirePreview()
|
||
{
|
||
if (currentState == DrawingState.SelectingEnd && previewWireObject != null)
|
||
{
|
||
Vector3 targetPoint;
|
||
|
||
if (snapTarget != null)
|
||
{
|
||
targetPoint = GetObjectCenter(snapTarget);
|
||
}
|
||
else
|
||
{
|
||
targetPoint = GetMouseWorldPosition();
|
||
}
|
||
|
||
if (useCylinderWire)
|
||
{
|
||
UpdateCylinderPreviewWire(startPoint, targetPoint);
|
||
}
|
||
else
|
||
{
|
||
UpdateLineRendererPreviewWire(startPoint, targetPoint);
|
||
}
|
||
}
|
||
}
|
||
// 修改预览连线的更新方法,也加入动态粗细
|
||
void UpdateCylinderPreviewWire(Vector3 start, Vector3 end)
|
||
{
|
||
Transform cylinderTransform = previewWireObject.transform.Find("PreviewCylinder");
|
||
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(previewWireDiameter, 0.001f, previewWireDiameter);
|
||
return;
|
||
}
|
||
|
||
Vector3 midPoint = (start + end) / 2f;
|
||
|
||
// 计算预览连线的动态粗细
|
||
float previewThickness = previewWireDiameter;
|
||
if (enableDynamicThickness && mainCamera != null)
|
||
{
|
||
float distanceToCamera = Vector3.Distance(midPoint, mainCamera.transform.position);
|
||
previewThickness = CalculateDynamicThickness(distanceToCamera);
|
||
}
|
||
|
||
// 设置圆柱体的位置和旋转
|
||
cylinder.transform.position = midPoint;
|
||
cylinder.transform.up = direction.normalized;
|
||
|
||
// 设置圆柱体的缩放(使用动态粗细)
|
||
cylinder.transform.localScale = new Vector3(
|
||
previewThickness,
|
||
distance / 2f,
|
||
previewThickness
|
||
);
|
||
}
|
||
|
||
void UpdateLineRendererPreviewWire(Vector3 start, Vector3 end)
|
||
{
|
||
LineRenderer lr = previewWireObject.GetComponent<LineRenderer>();
|
||
if (lr != null)
|
||
{
|
||
lr.SetPosition(0, start);
|
||
lr.SetPosition(1, end);
|
||
}
|
||
}
|
||
|
||
GameObject CreateFinalWire()
|
||
{
|
||
if (startColliderObject == null || endColliderObject == null) return null;
|
||
|
||
GameObject wireObject = new GameObject($"Wire_{System.DateTime.Now:yyyyMMddHHmmss}");
|
||
|
||
if (useCylinderWire)
|
||
{
|
||
CreateCylinderWire(wireObject, startPoint, endPoint);
|
||
}
|
||
else
|
||
{
|
||
CreateLineRendererWire(wireObject, startPoint, endPoint);
|
||
}
|
||
|
||
// 添加连线数据组件
|
||
LineShowModelCylinderWireData wireData = wireObject.AddComponent<LineShowModelCylinderWireData>();
|
||
wireData.startPoint = startPoint;
|
||
wireData.endPoint = endPoint;
|
||
wireData.startCollider = startColliderObject;
|
||
wireData.endCollider = endColliderObject;
|
||
wireData.wireDiameter = cylinderWireDiameter;
|
||
wireData.creationTime = System.DateTime.Now;
|
||
|
||
// 添加到连线列表
|
||
allWires.Add(wireObject);
|
||
StartCoroutine(LineManager.instance.Checkconnection(startColliderObject.transform, endColliderObject.transform));
|
||
// 重置起点和终点
|
||
startColliderObject = null;
|
||
endColliderObject = null;
|
||
|
||
return wireObject;
|
||
}
|
||
|
||
|
||
// 修改最终连线的创建方法,初始使用动态粗细
|
||
void CreateCylinderWire(GameObject wireObject, Vector3 start, Vector3 end)
|
||
{
|
||
GameObject cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
||
cylinder.name = "WireCylinder";
|
||
cylinder.transform.SetParent(wireObject.transform);
|
||
|
||
// 计算初始动态粗细
|
||
Vector3 midPoint = (start + end) / 2f;
|
||
float initialThickness = cylinderWireDiameter;
|
||
if (enableDynamicThickness && mainCamera != null)
|
||
{
|
||
float distanceToCamera = Vector3.Distance(midPoint, mainCamera.transform.position);
|
||
initialThickness = CalculateDynamicThickness(distanceToCamera);
|
||
}
|
||
|
||
// 设置材质
|
||
if (cylinderWireMaterial != null)
|
||
{
|
||
Renderer renderer = cylinder.GetComponent<Renderer>();
|
||
renderer.material = cylinderWireMaterial;
|
||
}
|
||
else if (wireMaterial != null)
|
||
{
|
||
Renderer renderer = cylinder.GetComponent<Renderer>();
|
||
renderer.material = wireMaterial;
|
||
}
|
||
|
||
// 计算连线的方向、长度和中点
|
||
Vector3 direction = end - start;
|
||
float distance = direction.magnitude;
|
||
|
||
// 设置圆柱体的位置和旋转
|
||
cylinder.transform.position = midPoint;
|
||
cylinder.transform.up = direction.normalized;
|
||
|
||
// 设置圆柱体的缩放(使用动态粗细)
|
||
cylinder.transform.localScale = new Vector3(
|
||
initialThickness,
|
||
distance / 2f,
|
||
initialThickness
|
||
);
|
||
|
||
// 可选:添加碰撞器
|
||
if (cylinder.GetComponent<Collider>() != null)
|
||
{
|
||
Destroy(cylinder.GetComponent<Collider>());
|
||
}
|
||
}
|
||
|
||
void CreateLineRendererWire(GameObject wireObject, Vector3 start, Vector3 end)
|
||
{
|
||
LineRenderer lr = wireObject.AddComponent<LineRenderer>();
|
||
lr.positionCount = 2;
|
||
lr.SetPosition(0, start);
|
||
lr.SetPosition(1, end);
|
||
|
||
// 配置LineRenderer
|
||
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 ClearPreviewWire()
|
||
{
|
||
if (previewWireObject != null)
|
||
{
|
||
Destroy(previewWireObject);
|
||
previewWireObject = null;
|
||
}
|
||
}
|
||
|
||
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 (hitObject == startColliderObject)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 计算鼠标位置与物体中心的距离
|
||
Vector3 objectCenter = GetObjectCenter(hitObject);
|
||
float distance = Vector3.Distance(GetMouseWorldPosition(), objectCenter);
|
||
|
||
if (distance <= snapDistance)
|
||
{
|
||
// 设置吸附目标
|
||
snapTarget = hitObject;
|
||
|
||
// 高亮显示可吸附的物体
|
||
HighlightSnapTarget(snapTarget);
|
||
}
|
||
}
|
||
}
|
||
|
||
Vector3 GetObjectCenter(GameObject obj)
|
||
{
|
||
if (obj == null) return Vector3.zero;
|
||
|
||
if (snapToColliderCenter)
|
||
{
|
||
Collider collider = obj.GetComponent<Collider>();
|
||
if (collider != null)
|
||
{
|
||
return collider.bounds.center;
|
||
}
|
||
}
|
||
|
||
// 默认使用变换位置
|
||
return obj.transform.position;
|
||
}
|
||
|
||
void HighlightSnapTarget(GameObject target)
|
||
{
|
||
if (target == null) return;
|
||
|
||
snapTargetRenderer = target.GetComponent<Renderer>();
|
||
if (snapTargetRenderer != null)
|
||
{
|
||
// 记录原始颜色
|
||
snapTargetOriginalColor = snapTargetRenderer.material.color;
|
||
|
||
// 设置高亮颜色
|
||
snapTargetRenderer.material.color = snapHighlightColor;
|
||
isSnapTargetHighlighted = true;
|
||
}
|
||
}
|
||
|
||
void HighlightObject(GameObject obj)
|
||
{
|
||
if (obj == null) return;
|
||
|
||
Renderer renderer = obj.GetComponent<Renderer>();
|
||
if (renderer != null)
|
||
{
|
||
// 临时高亮物体
|
||
Color originalColor = renderer.material.color;
|
||
renderer.material.color = Color.green;
|
||
|
||
// 可以在这里添加一个协程来在一段时间后恢复颜色
|
||
StartCoroutine(RestoreColorAfterDelay(renderer, originalColor, 1.0f));
|
||
}
|
||
}
|
||
|
||
IEnumerator RestoreColorAfterDelay(Renderer renderer, Color originalColor, float delay)
|
||
{
|
||
yield return new WaitForSeconds(delay);
|
||
|
||
if (renderer != null)
|
||
{
|
||
renderer.material.color = originalColor;
|
||
}
|
||
}
|
||
|
||
void ClearSnapHighlight()
|
||
{
|
||
if (snapTargetRenderer != null && isSnapTargetHighlighted)
|
||
{
|
||
snapTargetRenderer.material.color = snapTargetOriginalColor;
|
||
snapTargetRenderer = null;
|
||
isSnapTargetHighlighted = false;
|
||
}
|
||
snapTarget = null;
|
||
}
|
||
|
||
public void CancelDrawing()
|
||
{
|
||
ClearPreviewWire();
|
||
ClearSnapHighlight();
|
||
currentState = DrawingState.Idle;
|
||
|
||
// 重置起点和终点
|
||
startColliderObject = null;
|
||
endColliderObject = null;
|
||
|
||
Debug.Log("取消连线操作");
|
||
}
|
||
|
||
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))
|
||
{
|
||
return hit.point;
|
||
}
|
||
|
||
// 如果没有击中任何物体,使用默认平面
|
||
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 ClearAllWires()
|
||
{
|
||
foreach (GameObject wire in allWires)
|
||
{
|
||
if (wire != null)
|
||
Destroy(wire);
|
||
}
|
||
allWires.Clear();
|
||
Debug.Log("已清除所有连线");
|
||
|
||
// 触发事件
|
||
OnAllWiresDeleted?.Invoke();
|
||
}
|
||
|
||
// 公共方法:删除最后一个连线
|
||
public void DeleteLastWire()
|
||
{
|
||
if (allWires.Count > 0)
|
||
{
|
||
GameObject lastWire = allWires[allWires.Count - 1];
|
||
DeleteWire(lastWire);
|
||
}
|
||
else
|
||
{
|
||
Debug.Log("没有可删除的连线");
|
||
}
|
||
}
|
||
|
||
// 公共方法:删除指定连线
|
||
public void DeleteWire(GameObject wireObject)
|
||
{
|
||
if (wireObject == null) return;
|
||
|
||
// 获取连线数据
|
||
LineShowModelCylinderWireData wireData = wireObject.GetComponent<LineShowModelCylinderWireData>();
|
||
GameObject startCollider = wireData?.startCollider;
|
||
GameObject endCollider = wireData?.endCollider;
|
||
|
||
// 从列表中移除
|
||
allWires.Remove(wireObject);
|
||
|
||
// 销毁连线对象
|
||
Destroy(wireObject);
|
||
|
||
Debug.Log($"删除连线: {wireObject.name}");
|
||
|
||
// 触发事件
|
||
OnWireDeleted?.Invoke(wireObject, startCollider, endCollider);
|
||
}
|
||
|
||
// 公共方法:根据碰撞体删除连线
|
||
public void DeleteWiresByCollider(GameObject colliderObject)
|
||
{
|
||
List<GameObject> wiresToDelete = new List<GameObject>();
|
||
|
||
// 查找所有连接到该碰撞体的连线
|
||
foreach (GameObject wire in allWires)
|
||
{
|
||
LineShowModelCylinderWireData wireData = wire?.GetComponent<LineShowModelCylinderWireData>();
|
||
if (wireData != null && (wireData.startCollider == colliderObject || wireData.endCollider == colliderObject))
|
||
{
|
||
wiresToDelete.Add(wire);
|
||
}
|
||
}
|
||
|
||
// 删除找到的连线
|
||
foreach (GameObject wire in wiresToDelete)
|
||
{
|
||
DeleteWire(wire);
|
||
}
|
||
|
||
if (wiresToDelete.Count > 0)
|
||
{
|
||
Debug.Log($"删除了 {wiresToDelete.Count} 条连接到 {colliderObject.name} 的连线");
|
||
}
|
||
}
|
||
|
||
// 公共方法:根据两个碰撞体删除特定连线
|
||
public void DeleteWireByColliders(GameObject startCollider, GameObject endCollider)
|
||
{
|
||
foreach (GameObject wire in allWires)
|
||
{
|
||
LineShowModelCylinderWireData wireData = wire?.GetComponent<LineShowModelCylinderWireData>();
|
||
if (wireData != null &&
|
||
((wireData.startCollider == startCollider && wireData.endCollider == endCollider) ||
|
||
(wireData.startCollider == endCollider && wireData.endCollider == startCollider)))
|
||
{
|
||
DeleteWire(wire);
|
||
Debug.Log($"删除了 {startCollider.name} 和 {endCollider.name} 之间的连线");
|
||
return;
|
||
}
|
||
}
|
||
|
||
Debug.Log($"未找到 {startCollider.name} 和 {endCollider.name} 之间的连线");
|
||
}
|
||
|
||
// 公共方法:设置吸附目标(用于编程控制)
|
||
public void SetSnapTarget(GameObject target)
|
||
{
|
||
if (enableSnapping && target != null)
|
||
{
|
||
snapTarget = target;
|
||
HighlightSnapTarget(target);
|
||
}
|
||
}
|
||
|
||
// 公共方法:清除吸附目标
|
||
public void ClearSnapTarget()
|
||
{
|
||
ClearSnapHighlight();
|
||
}
|
||
|
||
// 公共方法:检查物体是否可以吸附
|
||
public bool CanSnapToObject(GameObject obj)
|
||
{
|
||
if (obj == null) return false;
|
||
|
||
// 检查物体是否在可吸附层
|
||
if (((1 << obj.layer) & snapLayers) == 0) return false;
|
||
|
||
// 检查物体是否有碰撞体
|
||
Collider collider = obj.GetComponent<Collider>();
|
||
if (collider == null) return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
// 公共方法:获取所有连线
|
||
public List<GameObject> GetAllWires()
|
||
{
|
||
return new List<GameObject>(allWires);
|
||
}
|
||
|
||
// 公共方法:获取连接到特定碰撞体的所有连线
|
||
public List<GameObject> GetWiresByCollider(GameObject colliderObject)
|
||
{
|
||
List<GameObject> connectedWires = new List<GameObject>();
|
||
|
||
foreach (GameObject wire in allWires)
|
||
{
|
||
LineShowModelCylinderWireData wireData = wire?.GetComponent<LineShowModelCylinderWireData>();
|
||
if (wireData != null && (wireData.startCollider == colliderObject || wireData.endCollider == colliderObject))
|
||
{
|
||
connectedWires.Add(wire);
|
||
}
|
||
}
|
||
|
||
return connectedWires;
|
||
}
|
||
|
||
// 公共方法:检查两个碰撞体之间是否有连线
|
||
public bool AreCollidersConnected(GameObject collider1, GameObject collider2)
|
||
{
|
||
foreach (GameObject wire in allWires)
|
||
{
|
||
LineShowModelCylinderWireData wireData = wire?.GetComponent<LineShowModelCylinderWireData>();
|
||
if (wireData != null &&
|
||
((wireData.startCollider == collider1 && wireData.endCollider == collider2) ||
|
||
(wireData.startCollider == collider2 && wireData.endCollider == collider1)))
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// 处理删除操作
|
||
void HandleDelete()
|
||
{
|
||
// 如果正在绘制连线,先取消绘制
|
||
if (currentState != DrawingState.Idle)
|
||
{
|
||
CancelDrawing();
|
||
return;
|
||
}
|
||
|
||
// 查找鼠标位置附近的连线
|
||
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
||
RaycastHit hit;
|
||
|
||
if (Physics.Raycast(ray, out hit, Mathf.Infinity))
|
||
{
|
||
GameObject hitObject = hit.collider.gameObject;
|
||
|
||
// 检查是否点击到了连线
|
||
if (IsWire(hitObject))
|
||
{
|
||
DeleteWire(hitObject);
|
||
return;
|
||
}
|
||
|
||
// 检查是否是连线的子物体
|
||
if (hitObject.transform.parent != null)
|
||
{
|
||
GameObject parent = hitObject.transform.parent.gameObject;
|
||
if (IsWire(parent))
|
||
{
|
||
DeleteWire(parent);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果没有找到可删除的对象,尝试删除最后一个连线
|
||
DeleteLastWire();
|
||
}
|
||
|
||
// 检查对象是否是连线
|
||
bool IsWire(GameObject obj)
|
||
{
|
||
if (obj == null) return false;
|
||
|
||
// 检查是否是连线
|
||
if (obj.name.StartsWith("Wire_") || obj.GetComponent<LineShowModelCylinderWireData>() != null)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// 事件定义
|
||
public delegate void WireCreatedHandler(GameObject wire, GameObject startCollider, GameObject endCollider);
|
||
public delegate void WireDeletedHandler(GameObject wire, GameObject startCollider, GameObject endCollider);
|
||
public delegate void AllWiresDeletedHandler();
|
||
|
||
// 事件
|
||
public static event WireCreatedHandler OnWireCreated;
|
||
public static event WireDeletedHandler OnWireDeleted;
|
||
public static event AllWiresDeletedHandler OnAllWiresDeleted;
|
||
}
|
||
|