Files
Main/Assets/Plugins/Code/UniScene/PathGrid/PathLandSystem.cs

481 lines
18 KiB
C#
Raw Normal View History

2025-01-25 04:38:09 +08:00
using System.Collections.Generic;
using UnityEngine;
using Thousandto.Core.Base;
using SimpleAI.Planning;
using SceneEditor.Proxy.Plugin;
using Thousandto.Plugins.Common.UniScene;
namespace Thousandto.Plugins.PathGrid
{
//陆地寻路系统
public class PathLandSystem : PathGridSystem
{
#region
private List<Vector2> _pathPoints2d = new List<Vector2>();
//A星寻路
private AStarPlanner wayPointPlanner = null;
//wayPoint数据
private WayPointPlanData wayPointWorld = null;
#endregion
#region
//在没有wayPoint情况下的纯A星寻路
private List<Vector2> GetPathNoWayPoint(Vector2 startPosition, Vector2 endPosition)
{
_pathPoints2d.Clear();
var grid = _pathWorld;
int startNodeIndex = grid.GetPathNodeIndex(startPosition);
if (grid.IsBlocked(startNodeIndex))
{
return null;
}
int endNodeIndex = grid.GetPathNodeIndex(endPosition);
if (grid.IsBlocked(endNodeIndex))
{
return null;
}
float dx = MathLib.FastAbs(startPosition.x - endPosition.x);
float dz = MathLib.FastAbs(startPosition.y - endPosition.y);
float cdx = dx * grid.InvCellSize + 1;
float cdz = dz * grid.InvCellSize + 1;
float fdd = cdx * cdz;
bool result = false;
if (fdd <= PreSearchSize)
{
_pathPlannder.StartANewPlan(startNodeIndex, endNodeIndex, true);
while (!_pathPlannder.HasPlanCompleted())
{
_pathPlannder.Update(50);
}
result = _pathPlannder.HasPlanSucceeded();
if (!result)
{
if (_pathPlannder.GetAvailableSearchNodeCount() != 0)
{
// search node pool size is ok, add node in openTable has been fully tested.
return null;
}
}
}
if (!result)
{
_pathPlannder.StartANewPlan(startNodeIndex, endNodeIndex);
while (!_pathPlannder.HasPlanCompleted())
{
_pathPlannder.Update(50);
}
}
result = _pathPlannder.HasPlanSucceeded();
if (_pathPlannder.Solution.Count > 0)
{
Vector2 last = startPosition;
_pathPoints2d.Add(startPosition);
var solution = _pathPlannder.Solution;
for (int i = solution.Count - 1; i >= 0; --i)
{
var pt = MathLib.ToVector2_XOZ(grid.GetPathNodePos(solution[i].Index));
if ((pt - last).sqrMagnitude > Vector2.kEpsilon)
{
_pathPoints2d.Add(pt);
last = pt;
}
}
if ((endPosition - last).sqrMagnitude > Vector2.kEpsilon)
{
_pathPoints2d.Add(endPosition);
}
var finalPath = SmoothPath(_pathPoints2d, endPosition);
if (finalPath.Count >= 2)
{
return finalPath;
}
}
return null;
}
//获取点到waypoint的寻路路径
private bool GetGridPath(Vector2 startPosition, Vector2 endPosition, List<Vector2> pathPosition)
{
var grid = _pathWorld;
int startNodeIndex = grid.GetPathNodeIndex(startPosition);
int endNodeIndex = grid.GetPathNodeIndex(endPosition);
float dx = MathLib.FastAbs(startPosition.x - endPosition.x);
float dz = MathLib.FastAbs(startPosition.y - endPosition.y);
float cdx = dx * grid.InvCellSize + 1;
float cdz = dz * grid.InvCellSize + 1;
float fdd = cdx * cdz;
bool result = false;
if (fdd <= PreSearchSize)
{
_pathPlannder.StartANewPlan(startNodeIndex, endNodeIndex, true);
while (!_pathPlannder.HasPlanCompleted())
{
_pathPlannder.Update(50);
}
result = _pathPlannder.HasPlanSucceeded();
if (!result)
{
if (_pathPlannder.GetAvailableSearchNodeCount() != 0)
{
return false;
}
}
}
if (!result)
{
_pathPlannder.StartANewPlan(startNodeIndex, endNodeIndex);
while (!_pathPlannder.HasPlanCompleted())
{
_pathPlannder.Update(50);
}
}
result = _pathPlannder.HasPlanSucceeded();
if (_pathPlannder.Solution.Count > 0)
{
Vector2 last = startPosition;
pathPosition.Add(startPosition);
var solution = _pathPlannder.Solution;
for (int i = solution.Count - 1; i >= 0; --i)
{
var pt = MathLib.ToVector2_XOZ(grid.GetPathNodePos(solution[i].Index));
if ((pt - last).sqrMagnitude > Vector2.kEpsilon)
{
pathPosition.Add(pt);
last = pt;
}
}
if ((endPosition - last).sqrMagnitude > Vector2.kEpsilon)
{
pathPosition.Add(endPosition);
}
}
return result;
}
//寻出waypoint的路径
public bool searchWayPointPath(int startIndex, int endIndex, List<Vector2> pathPosition)
{
if (wayPointWorld.IsNodeBlocked(startIndex))
{
WayPointNode node = wayPointWorld.GetNode(startIndex);
//Debug.LogError(string.Format("{0}这个点放到了阻挡里面",node.name));
return false;
}
if (wayPointWorld.IsNodeBlocked(endIndex))
{
WayPointNode node = wayPointWorld.GetNode(endIndex);
//Debug.LogError(string.Format("{0}这个点放到了阻挡里面", node.name));
return false;
}
FProfiler.Begin("PathLandSystem.searchWayPointPath");
wayPointPlanner.StartANewPlan(startIndex, endIndex);
while (!wayPointPlanner.HasPlanCompleted())
wayPointPlanner.Update(100);
FProfiler.End();
if (!wayPointPlanner.HasPlanSucceeded())
{
//Debug.LogError(string.Format("MapId:{0} 路点编辑有问题,起始路点和终点路点不连通!!!", Owner.Cfg.MapId));
return false;
}
Vector2 tempPos = Vector2.zero;
for (int i = wayPointPlanner.Solution.Count - 1; i >= 0; --i)
{
Vector3 pos = wayPointWorld.m_pointInfo[wayPointPlanner.Solution[i].Index].pos;
tempPos.x = pos.x;
tempPos.y = pos.z;
pathPosition.Add(tempPos);
}
return true;
}
private List<Vector2> GetPath(Vector2 startPosition, Vector2 endPosition)
{
if (wayPointWorld == null)
{
//Debug.LogError(string.Format("MapId:{0} 场景中找不到[WayPoint] WayPointWorld为空",Owner.Cfg.MapId));
return GetPathNoWayPoint(startPosition, endPosition);
}
int startWayPoint = wayPointWorld.GetNearestIndexBypos(ref startPosition);
int endWaypoint = wayPointWorld.GetNearestIndexBypos(ref endPosition);
if (startWayPoint == -1 || endWaypoint == -1)
{
//Debug.LogError(string.Format("MapId:{0} 场景中找不到[WayPoint]",Owner.Cfg.MapId));
return GetPathNoWayPoint(startPosition, endPosition);
}
_pathPoints2d.Clear();
int startNodeIndex = _pathWorld.GetPathNodeIndex(startPosition);
int endNodeIndex = _pathWorld.GetPathNodeIndex(endPosition);
Vector3 startWayPointPos = wayPointWorld.m_pointInfo[startWayPoint].pos;
Vector3 endWayPointPos = wayPointWorld.m_pointInfo[endWaypoint].pos;
Vector2 startWayPoint2d = new Vector2(startWayPointPos.x, startWayPointPos.z);
Vector2 endWayPoint2d = new Vector2(endWayPointPos.x, endWayPointPos.z);
_pathPoints2d.Add(startPosition);
if(!GetGridPath(startPosition, startWayPoint2d, _pathPoints2d))
return null;
if(!searchWayPointPath(startWayPoint, endWaypoint, _pathPoints2d))
return null;
if(!GetGridPath(endWayPoint2d, endPosition, _pathPoints2d))
return null;
var finalPath = SmoothPath(_pathPoints2d, endPosition);
if (finalPath.Count >= 2)
return finalPath;
return null;
}
//优化寻路出来的寻路点,把可以去掉的寻路点去掉
private List<Vector2> SmoothPath(List<Vector2> input, Vector2 endPosition)
{
var ret = Path2dPool.sharedInstance.Allocate(input.Count >> 1);
int count = input.Count;
if (count > 1)
{
ret.Add(input[0]); // add start point
Vector2 s, e, hit;
int curEndIndex = -1;
for (int j = 0; j < count - 1;)
{
s = input[j];
int i = j + 1;
int si = j;
int c = 0;
for (; i < count && c < int.MaxValue; ++i)
{
e = input[i];
if ((i - si) > 1 && Raycast2dSafe(s, e, out hit))
{
break;
}
else
{
curEndIndex = i;
j = i;
}
++c;
}
ret.Add(input[curEndIndex]);
}
}
return ret;
}
#endregion
#region
public override void Initialize(BaseScene scene)
{
base.Initialize(scene);
}
public override void Uninitialize()
{
base.Uninitialize();
}
public bool LoadWayPointData(BaseScene owner)
{
Transform trans = owner.SceneObjectsRoot.Find(BaseScene.WayPointRootName);
if (trans != null)
wayPointWorld = trans.GetComponent<WayPointPlanData>();
if (wayPointWorld != null && wayPointWorld.m_pointInfo != null && wayPointWorld.m_maxNeighborNumber > 0)
{
wayPointPlanner = new AStarPlanner(wayPointWorld.m_pointInfo.Length + 1, 0);
wayPointPlanner.Awake();
wayPointPlanner.Start(wayPointWorld);
}
return true;
}
//根据目标的半径范围,从起点到终点寻路获取寻路点
public override List<Vector2> SearchTargetPath(Vector3 startPos, Vector3 endPos, float targetRadius)
{
var startIsBlock = IsBlocked(startPos);
if(startIsBlock)
{
//Debug.Log("起点在阻挡里");
return null;
}
var endIsSafe = IsSafe(endPos);
if (endIsSafe)
{
//Debug.Log("终点在传送点里");
}
List<Vector2> outPath = Path2dPool.sharedInstance.Allocate(1);
//如果玩家处于跟目标位置一样的点
if (startPos == endPos)
{
return outPath;
}
//如果寻路到的目标点有半径
if (targetRadius > 0.0f)
{
if (Vector3.Distance(startPos, endPos) <= targetRadius)
{
return outPath;
}
}
Vector2 start2d = MathLib.ToVector2_XOZ(startPos);
Vector2 end2d = MathLib.ToVector2_XOZ(endPos);
var blocked = IsBlocked(endPos);
if (blocked)
{
//Debug.Log("目标点在阻挡里");
Vector2 dir = (end2d - start2d).normalized;
Vector2 newPos = end2d - dir * Mathf.Min(targetRadius, CellSize * 0.5f);
if(IsBlocked(newPos))
{
//Debug.Log("在半径边缘的目标点还是在阻挡里");
return null;
}
if (GetCellIndex(start2d) != GetCellIndex(newPos))
{
end2d = newPos;
}
else
{
return outPath;
}
}
Math2d.Circle circle;
circle.Center = end2d;
circle.Radius = targetRadius;
bool goDirect = false;
if(endIsSafe)
{
goDirect = CanGoDirect(start2d, end2d);
}
else
{
goDirect = CanGoDirectSafe(start2d, end2d);
}
if (goDirect)
{
if (targetRadius > 0)
{
Math2d.LineSegment line;
line.Start = start2d;
line.End = end2d;
var solves = Math2d.Intersect_LineSegment_Circle(circle, line);
if (solves != null && solves.Length > 0 && solves[0] != end2d)
{
end2d = solves[0];
}
else
{
return outPath;
}
}
if (start2d != end2d)
{
outPath = Path2dPool.sharedInstance.Allocate(2);
outPath.Add(start2d);
outPath.Add(end2d);
}
else
{
return outPath;
}
}
else
{
var ptlist = GetPath(start2d, end2d);
if (ptlist == null || ptlist.Count < 2)
{
//Debug.Log("通过waypoint寻路没有寻到");
return null;
}
Vector2 currPoint = ptlist.Count > 0 ? ptlist[0] : Vector2.zero;
var _ptlist = Path2dPool.sharedInstance.Allocate(ptlist.Count);
bool earlyBreak = false;
_ptlist.Add(currPoint);
for (int i = 1; i < ptlist.Count; ++i)
{
Vector2 nextPoint = ptlist[i];
if (targetRadius > 0)
{
Math2d.LineSegment line;
line.Start = currPoint;
line.End = nextPoint;
var solves = Math2d.Intersect_LineSegment_Circle(circle, line);
if (solves != null && solves.Length > 0)
{
nextPoint = solves[0];
earlyBreak = true;
}
}
_ptlist.Add(nextPoint);
if (earlyBreak)
{
break;
}
currPoint = nextPoint;
}
outPath = _ptlist;
}
return outPath;
}
public override List<Vector2> SearchPlayerPath(Vector3 startPosition, Vector3 endPosition)
{
if (startPosition == endPosition)
{
return null;
}
else
{
Vector2 hit;
if (!Raycast2d(startPosition, endPosition, out hit))
{
return GetPath(startPosition, endPosition);
}
}
return null;
}
public override List<Vector2> SearchOtherPath(Vector3 startPosition, Vector3 endPosition)
{
if (startPosition == endPosition)
{
return null;
}
else
{
List<Vector2> ret = Path2dPool.sharedInstance.Allocate(2);
ret.Add(startPosition);
ret.Add(endPosition);
return ret;
}
}
//评价路径,返回-1表示无法寻路到达返回距离表示到目标点的实际距离
public override float EvaluatePath(Vector3 startPosition, Vector3 endPosition)
{
List<Vector2> outPath = null;
outPath = SearchTargetPath(startPosition, endPosition, 0f);
if (outPath == null || outPath.Count < 2)
{
//寻路失败,无法到达
return -1f;
}
var result = 0f;
for(int i = 0; i < outPath.Count - 1; ++i)
{
if (IsNotBlockRayCast2d(outPath[i], outPath[i + 1]))
{
result += Vector2.Distance(outPath[i], outPath[i + 1]);
}
else
{
//有阻断,无法到达
return -1f;
}
}
//寻路失败无法到达
return result;
}
#endregion
}
}