Files
DefendNJ/Assets/_Valheim/Scripts/Player/GuideArrowPath.cs

230 lines
6.7 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 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;
}
}