230 lines
6.7 KiB
C#
230 lines
6.7 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using Mirror;
|
||
using UnityEngine;
|
||
|
||
[RequireComponent(typeof(LineRenderer))]
|
||
public class GuideArrowPath : NetworkBehaviour
|
||
{
|
||
// 内部变量
|
||
private LineRenderer lineRenderer;
|
||
|
||
// 障碍物检测设置
|
||
public LayerMask obstacleMask = 1; // 障碍物层
|
||
public float pathHeight = 0.5f; // 路径显示高度
|
||
public int maxRaycastPoints = 10; // 最大射线检测点数
|
||
|
||
void Awake()
|
||
{
|
||
// 在Awake中初始化,确保在其他脚本调用前准备好
|
||
InitializeLineRenderer();
|
||
}
|
||
|
||
void Start()
|
||
{
|
||
// 确保在Start中也有初始化,双重保险
|
||
InitializeLineRenderer();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化LineRenderer
|
||
/// </summary>
|
||
private void InitializeLineRenderer()
|
||
{
|
||
if (lineRenderer == null)
|
||
{
|
||
lineRenderer = GetComponent<LineRenderer>();
|
||
if (lineRenderer == null)
|
||
{
|
||
Debug.LogError("LineRenderer component is missing on " + gameObject.name);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据起点与终点计算路径,并更新Line Renderer的显示
|
||
/// </summary>
|
||
public void SetPath(Vector3 start, Vector3 end)
|
||
{
|
||
// 确保lineRenderer已初始化
|
||
if (lineRenderer == null)
|
||
{
|
||
InitializeLineRenderer();
|
||
|
||
// 如果仍然为null,直接返回
|
||
if (lineRenderer == null)
|
||
{
|
||
Debug.LogError("LineRenderer is still null after initialization!");
|
||
return;
|
||
}
|
||
}
|
||
|
||
List<Vector3> path = CalculateSimplePath(start, end);
|
||
|
||
if (path != null && path.Count > 1)
|
||
{
|
||
lineRenderer.positionCount = path.Count;
|
||
|
||
// 调整路径点高度
|
||
List<Vector3> adjustedPath = new List<Vector3>();
|
||
foreach (Vector3 point in path)
|
||
{
|
||
adjustedPath.Add(new Vector3(point.x, pathHeight, point.z));
|
||
}
|
||
|
||
lineRenderer.SetPositions(adjustedPath.ToArray());
|
||
}
|
||
else
|
||
{
|
||
lineRenderer.positionCount = 0;
|
||
Debug.LogWarning("未能计算出有效路径!");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算简单路径(直线 + 障碍物避让)
|
||
/// </summary>
|
||
private List<Vector3> CalculateSimplePath(Vector3 start, Vector3 end)
|
||
{
|
||
List<Vector3> path = new List<Vector3>();
|
||
path.Add(start);
|
||
|
||
// 检查起点到终点是否有直接路径
|
||
if (!Physics.Linecast(start, end, obstacleMask))
|
||
{
|
||
// 没有障碍物,直接使用直线路径
|
||
path.Add(end);
|
||
return path;
|
||
}
|
||
else
|
||
{
|
||
// 有障碍物,尝试找到绕过障碍物的路径
|
||
List<Vector3> obstacleAvoidancePath = FindObstacleAvoidancePath(start, end);
|
||
if (obstacleAvoidancePath != null && obstacleAvoidancePath.Count > 0)
|
||
{
|
||
return obstacleAvoidancePath;
|
||
}
|
||
}
|
||
|
||
// 如果无法找到有效路径,返回空路径
|
||
return new List<Vector3> { start, end };
|
||
}
|
||
|
||
/// <summary>
|
||
/// 寻找绕过障碍物的路径
|
||
/// </summary>
|
||
private List<Vector3> FindObstacleAvoidancePath(Vector3 start, Vector3 end)
|
||
{
|
||
List<Vector3> path = new List<Vector3>();
|
||
path.Add(start);
|
||
|
||
Vector3 direction = (end - start).normalized;
|
||
float totalDistance = Vector3.Distance(start, end);
|
||
|
||
// 沿着方向进行多次射线检测,寻找可通行的路径点
|
||
for (int i = 1; i <= maxRaycastPoints; i++)
|
||
{
|
||
float t = (float)i / maxRaycastPoints;
|
||
Vector3 testPoint = start + direction * totalDistance * t;
|
||
|
||
// 检查从上一个点到当前点是否有障碍物
|
||
Vector3 lastPoint = path[path.Count - 1];
|
||
if (!Physics.Linecast(lastPoint, testPoint, obstacleMask))
|
||
{
|
||
// 没有障碍物,添加路径点
|
||
path.Add(testPoint);
|
||
}
|
||
else
|
||
{
|
||
// 有障碍物,尝试绕过
|
||
Vector3 bypassPoint = FindBypassPoint(lastPoint, testPoint);
|
||
if (bypassPoint != lastPoint) // 确保找到了有效的绕过点
|
||
{
|
||
path.Add(bypassPoint);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 确保终点被添加
|
||
if (path[path.Count - 1] != end)
|
||
{
|
||
path.Add(end);
|
||
}
|
||
|
||
return path.Count > 1 ? path : null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 寻找绕过障碍物的点
|
||
/// </summary>
|
||
private Vector3 FindBypassPoint(Vector3 from, Vector3 to)
|
||
{
|
||
Vector3 direction = (to - from).normalized;
|
||
float distance = Vector3.Distance(from, to);
|
||
|
||
// 尝试从不同方向绕过障碍物
|
||
Vector3[] testDirections = {
|
||
Vector3.Cross(direction, Vector3.up).normalized, // 右侧
|
||
Vector3.Cross(direction, Vector3.down).normalized, // 左侧
|
||
Vector3.up, // 上方
|
||
new Vector3(direction.z, 0, -direction.x).normalized // 另一个侧向
|
||
};
|
||
|
||
float[] testDistances = { 2f, 3f, 5f }; // 测试不同的绕过距离
|
||
|
||
foreach (Vector3 testDir in testDirections)
|
||
{
|
||
foreach (float testDist in testDistances)
|
||
{
|
||
Vector3 bypassStart = from + testDir * testDist;
|
||
Vector3 bypassEnd = to + testDir * testDist;
|
||
|
||
// 检查绕过路径是否可行
|
||
if (!Physics.Linecast(from, bypassStart, obstacleMask) &&
|
||
!Physics.Linecast(bypassStart, bypassEnd, obstacleMask) &&
|
||
!Physics.Linecast(bypassEnd, to, obstacleMask))
|
||
{
|
||
return bypassStart;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果找不到绕过点,返回原始起点
|
||
return from;
|
||
}
|
||
|
||
public float GetToTargetDis(Vector3 start, Vector3 end)
|
||
{
|
||
List<Vector3> path = CalculateSimplePath(start, end);
|
||
|
||
if (path != null && path.Count > 1)
|
||
{
|
||
float dis = 0;
|
||
for (int i = 0; i < path.Count - 1; i++)
|
||
{
|
||
dis += Vector3.Distance(path[i], path[i + 1]);
|
||
}
|
||
return dis;
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
public void ShowPath()
|
||
{
|
||
if (lineRenderer == null)
|
||
InitializeLineRenderer();
|
||
|
||
if (lineRenderer != null)
|
||
lineRenderer.enabled = true;
|
||
}
|
||
|
||
public void ClosePath()
|
||
{
|
||
if (lineRenderer == null)
|
||
InitializeLineRenderer();
|
||
|
||
if (lineRenderer != null)
|
||
lineRenderer.enabled = false;
|
||
}
|
||
} |