462 lines
14 KiB
C#
462 lines
14 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
using System.IO;
|
|||
|
|
|||
|
using PathEditor.Proxy.Plugin;
|
|||
|
using Thousandto.Core.Base;
|
|||
|
using SimpleAI.Navigation;
|
|||
|
using SimpleAI.Planning;
|
|||
|
using Thousandto.Plugins.Common.UniScene;
|
|||
|
using UnityEngine;
|
|||
|
using FFileReader = UnityEngine.Gonbest.MagicCube.FFileReader;
|
|||
|
|
|||
|
namespace Thousandto.Plugins.PathGrid
|
|||
|
{
|
|||
|
//路径网格寻路系统
|
|||
|
public class PathGridSystem
|
|||
|
{
|
|||
|
#region//常量
|
|||
|
private const int PlannerRowCount = 128;
|
|||
|
private const int PlannerColCount = 128;
|
|||
|
#endregion
|
|||
|
|
|||
|
#region //私有变量
|
|||
|
private GameObject navObj = null;
|
|||
|
//从文件中读取路径的网格数据
|
|||
|
private static PathGirdData _pathGridData = null;
|
|||
|
//陆地寻路系统
|
|||
|
private static PathLandSystem _pathLandSystem = null;
|
|||
|
//动态阻挡
|
|||
|
public Dictionary<int, PathBlocker> dynamicBlockers = null;
|
|||
|
//处于的场景
|
|||
|
private BaseScene _owner = null;
|
|||
|
//上次载入的文件名,用以判断是否重新加载
|
|||
|
private string _frontLoadFile = string.Empty;
|
|||
|
#endregion
|
|||
|
|
|||
|
#region //公共变量
|
|||
|
public PathWorld _pathWorld = null;
|
|||
|
public static PathPlanner _pathPlannder = new PathPlanner(PlannerRowCount * PlannerColCount, PreSearchSize);
|
|||
|
public const int PreSearchSize = 20 * 20;
|
|||
|
public static PathType PathType = PathType.Land;
|
|||
|
#endregion
|
|||
|
|
|||
|
#region //属性
|
|||
|
public PathGirdData PathGridData
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _pathGridData;
|
|||
|
}
|
|||
|
}
|
|||
|
public float CellSize
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _pathGridData.CellSize;
|
|||
|
}
|
|||
|
}
|
|||
|
public BaseScene Owner
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _owner;
|
|||
|
}
|
|||
|
}
|
|||
|
public static PathGridSystem instance
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (PathType == PathType.Land)
|
|||
|
{
|
|||
|
if (_pathLandSystem == null)
|
|||
|
{
|
|||
|
_pathLandSystem = new PathLandSystem();
|
|||
|
}
|
|||
|
return _pathLandSystem;
|
|||
|
}
|
|||
|
return null;
|
|||
|
}
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region//构造函数
|
|||
|
//私有构造函数,防止外部new
|
|||
|
protected PathGridSystem()
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
|
|||
|
//初始化寻路系统
|
|||
|
public virtual void Initialize(BaseScene scene)
|
|||
|
{
|
|||
|
#if UNITY_EDITOR
|
|||
|
FProfiler.Begin("PathGridSystem.Navigator");
|
|||
|
if(navObj == null)
|
|||
|
{
|
|||
|
navObj = new GameObject("[Navigator]");
|
|||
|
}
|
|||
|
navObj.transform.parent = AppRoot.Transform;
|
|||
|
|
|||
|
PathItemMonoBehaviour script = navObj.GetComponent<PathItemMonoBehaviour>();
|
|||
|
if (script == null)
|
|||
|
{
|
|||
|
script = navObj.AddComponent<PathItemMonoBehaviour>();
|
|||
|
}
|
|||
|
script.m_mergedPathGrid = PathGridData.MergedData;
|
|||
|
script.m_mergedWeightPathGrid = PathGridData.MergeWeightData;
|
|||
|
script.m_heightMap = PathGridData.HeightMap;
|
|||
|
script.m_numberOfRows = PathGridData.NumberOfRows;
|
|||
|
script.m_numberOfColumns = PathGridData.NumberOfColumns;
|
|||
|
script.m_cellSize = PathGridData.CellSize;
|
|||
|
FProfiler.End();
|
|||
|
#endif
|
|||
|
FProfiler.Begin("PathGridSystem.Initialize");
|
|||
|
int nodeNum = PathGridData.NumberOfRows * PathGridData.NumberOfColumns;
|
|||
|
_pathWorld = new PathWorld(PathGridData);
|
|||
|
_pathWorld.Awake();
|
|||
|
|
|||
|
_pathPlannder.Awake();
|
|||
|
_pathPlannder.Start(_pathWorld);
|
|||
|
|
|||
|
if(dynamicBlockers == null)
|
|||
|
{
|
|||
|
dynamicBlockers = new Dictionary<int, PathBlocker>();
|
|||
|
}
|
|||
|
_owner = scene;
|
|||
|
FProfiler.End();
|
|||
|
}
|
|||
|
|
|||
|
//卸载寻路系统
|
|||
|
public virtual void Uninitialize()
|
|||
|
{
|
|||
|
_pathGridData = null;
|
|||
|
if (dynamicBlockers != null)
|
|||
|
{
|
|||
|
dynamicBlockers.Clear();
|
|||
|
dynamicBlockers = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//从地图路径网格文件中读出数据
|
|||
|
public void LoadPathGridData(String fileName)
|
|||
|
{
|
|||
|
var filePath = FileUtils.MapInfoDirPath + '/' + fileName;
|
|||
|
if(_pathGridData == null || filePath != _frontLoadFile)
|
|||
|
{
|
|||
|
_frontLoadFile = filePath;
|
|||
|
if (_pathGridData == null)
|
|||
|
{
|
|||
|
_pathGridData = new PathGirdData();
|
|||
|
}
|
|||
|
FFileReader.ReadBytesAsync(filePath,x=> {
|
|||
|
if (x != null)
|
|||
|
{
|
|||
|
_pathGridData.Load(x);
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//获取路径网格的长和宽
|
|||
|
public Vector2 Get2DSize()
|
|||
|
{
|
|||
|
Vector2 size = new Vector2(0.0f, 0.0f);
|
|||
|
if (PathGridData != null)
|
|||
|
{
|
|||
|
size.x = PathGridData.NumberOfColumns * PathGridData.CellSize;
|
|||
|
size.y = PathGridData.NumberOfRows * PathGridData.CellSize;
|
|||
|
}
|
|||
|
return size;
|
|||
|
}
|
|||
|
|
|||
|
//移除动态阻挡
|
|||
|
public bool RemoveBlocker(ref int id)
|
|||
|
{
|
|||
|
PathBlocker blocker = null;
|
|||
|
if (dynamicBlockers.TryGetValue(id, out blocker))
|
|||
|
{
|
|||
|
if (dynamicBlockers.Remove(id))
|
|||
|
{
|
|||
|
blocker.Disable();
|
|||
|
id = 0;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
//开启指定动态阻挡
|
|||
|
public bool EnableBlocker(int id)
|
|||
|
{
|
|||
|
PathBlocker blocker = null;
|
|||
|
if (dynamicBlockers != null && dynamicBlockers.TryGetValue(id, out blocker))
|
|||
|
{
|
|||
|
return blocker.Enable();
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
//关闭指定动态阻挡
|
|||
|
public bool DisableBlocker(int id)
|
|||
|
{
|
|||
|
PathBlocker blocker = null;
|
|||
|
if (dynamicBlockers != null && dynamicBlockers.TryGetValue(id, out blocker))
|
|||
|
{
|
|||
|
return blocker.Disable();
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
//增加动态圆圈阻挡
|
|||
|
public int AddCircleBlocker(ref Vector2 center, float radius, int instId = 0)
|
|||
|
{
|
|||
|
var blocker = PathBlocker.CreateCircle(PathGridData, ref center, radius, instId);
|
|||
|
if (!dynamicBlockers.ContainsKey(blocker.instId))
|
|||
|
{
|
|||
|
dynamicBlockers.Add(blocker.instId, blocker);
|
|||
|
return blocker.instId;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
//增加四个方格的阻挡
|
|||
|
public int AddAABBBlocker(ref Vector2 center, ref Vector2 size, int instId = 0)
|
|||
|
{
|
|||
|
var blocker = PathBlocker.CreateAABB(PathGridData, ref center, ref size, instId);
|
|||
|
if (!dynamicBlockers.ContainsKey(blocker.instId))
|
|||
|
{
|
|||
|
dynamicBlockers.Add(blocker.instId, blocker);
|
|||
|
return blocker.instId;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
//增加指定方向上的阻挡
|
|||
|
public int AddOBBBlocker(ref Vector2 center, ref Vector2 size, ref Vector2 dir, int instId = 0)
|
|||
|
{
|
|||
|
var blocker = PathBlocker.CreateOBB(PathGridData, ref center, ref size, ref dir, instId);
|
|||
|
if (!dynamicBlockers.ContainsKey(blocker.instId))
|
|||
|
{
|
|||
|
dynamicBlockers.Add(blocker.instId, blocker);
|
|||
|
return blocker.instId;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
//判断两点之间是否有阻挡单元,有的话,找到离玩家最近的那个阻挡点
|
|||
|
public bool Raycast2d(Vector2 start, Vector2 end, out Vector2 hit)
|
|||
|
{
|
|||
|
return PathGridData.Raycast2d(start, end, out hit);
|
|||
|
}
|
|||
|
|
|||
|
//判断两点之间是否有安全单元,有的话,找到离玩家最近的那个阻挡点
|
|||
|
public bool Raycast2dSafe(Vector2 start, Vector2 end, out Vector2 hit)
|
|||
|
{
|
|||
|
return PathGridData.Raycast2dSafe(start, end, out hit);
|
|||
|
}
|
|||
|
|
|||
|
public bool RayCastJumpBlock(Vector2 start, Vector2 end, out Vector2 hit)
|
|||
|
{
|
|||
|
return PathGridData.Raycast2dJumpBlock(start, end,out hit);
|
|||
|
}
|
|||
|
|
|||
|
public bool RaycastEx2d(Vector2 start, Vector2 end, out Vector2 hit, Func<int, int, bool, bool> func)
|
|||
|
{
|
|||
|
return PathGridData.RaycastEx2d(start, end, out hit, func);
|
|||
|
}
|
|||
|
|
|||
|
//判断两点之间是否有跳跃单元,有的话,找到离玩家最近的跳跃点
|
|||
|
public bool Raycast2dJump(Vector2 start, Vector2 end, out Vector2 hit)
|
|||
|
{
|
|||
|
return PathGridData.Raycast2dJump(start, end, out hit);
|
|||
|
}
|
|||
|
|
|||
|
//判断一个位置到另一个位置是否可以直走
|
|||
|
public bool CanGoDirect(Vector2 startPos, Vector2 endPos)
|
|||
|
{
|
|||
|
Vector2 hit;
|
|||
|
return !PathGridData.Raycast2d(startPos, endPos, out hit);
|
|||
|
}
|
|||
|
|
|||
|
//判断一个位置到另一个位置是否经过了安全区
|
|||
|
public bool CanGoDirectSafe(Vector2 startPos, Vector2 endPos)
|
|||
|
{
|
|||
|
Vector2 hit;
|
|||
|
return !PathGridData.Raycast2dSafe(startPos, endPos, out hit);
|
|||
|
}
|
|||
|
|
|||
|
//获取指定单元格的类型
|
|||
|
public PathGridType GetCellType(Vector2 position)
|
|||
|
{
|
|||
|
int cellIndex = _pathWorld.GetCellIndex(ref position);
|
|||
|
return _pathWorld.GetCellType(cellIndex);
|
|||
|
}
|
|||
|
|
|||
|
//指定位置是否可以跳跃
|
|||
|
public bool IsJump(Vector2 position)
|
|||
|
{
|
|||
|
int cellIndex = _pathWorld.GetCellIndex(ref position);
|
|||
|
return _pathWorld.IsJump(cellIndex);
|
|||
|
}
|
|||
|
|
|||
|
//指定位置是否可以跳跃
|
|||
|
public bool IsJump(Vector3 position)
|
|||
|
{
|
|||
|
int cellIndex = _pathWorld.GetCellIndex(ref position);
|
|||
|
return _pathWorld.IsJump(cellIndex);
|
|||
|
}
|
|||
|
|
|||
|
//指定位置是否可以跳跃
|
|||
|
public bool IsJump(ref Vector2 position)
|
|||
|
{
|
|||
|
int cellIndex = _pathWorld.GetCellIndex(ref position);
|
|||
|
return _pathWorld.IsJump(cellIndex);
|
|||
|
}
|
|||
|
|
|||
|
//指定位置是否可以跳跃
|
|||
|
public bool IsJump(ref Vector3 position)
|
|||
|
{
|
|||
|
int cellIndex = _pathWorld.GetCellIndex(ref position);
|
|||
|
return _pathWorld.IsJump(cellIndex);
|
|||
|
}
|
|||
|
|
|||
|
//指定位置是否能跳指定高度
|
|||
|
public bool CanJump(ref Vector2 position, float height)
|
|||
|
{
|
|||
|
int cellIndex = _pathWorld.GetCellIndex(ref position);
|
|||
|
return _pathWorld.CanJump(cellIndex, height);
|
|||
|
}
|
|||
|
|
|||
|
//指定位置是否阻挡
|
|||
|
public bool IsBlocked(Vector2 position)
|
|||
|
{
|
|||
|
int cellIndex = _pathWorld.GetCellIndex(ref position);
|
|||
|
return _pathWorld.IsBlocked(cellIndex);
|
|||
|
}
|
|||
|
|
|||
|
//指定位置是否阻挡
|
|||
|
public bool IsBlocked(Vector3 position)
|
|||
|
{
|
|||
|
int cellIndex = _pathWorld.GetCellIndex(ref position);
|
|||
|
return _pathWorld.IsBlocked(cellIndex);
|
|||
|
}
|
|||
|
|
|||
|
//指定位置是否是安全区
|
|||
|
public bool IsSafe(Vector3 position)
|
|||
|
{
|
|||
|
int cellIndex = _pathWorld.GetCellIndex(ref position);
|
|||
|
return _pathWorld.IsSafe(cellIndex);
|
|||
|
}
|
|||
|
|
|||
|
//指定位置是否阻挡
|
|||
|
public bool IsBlocked(ref Vector2 position)
|
|||
|
{
|
|||
|
int cellIndex = _pathWorld.GetCellIndex(ref position);
|
|||
|
return _pathWorld.IsBlocked(cellIndex);
|
|||
|
}
|
|||
|
|
|||
|
//指定位置是否阻挡
|
|||
|
public bool IsBlocked(ref Vector3 position)
|
|||
|
{
|
|||
|
int cellIndex = _pathWorld.GetCellIndex(ref position);
|
|||
|
return _pathWorld.IsBlocked(cellIndex);
|
|||
|
}
|
|||
|
|
|||
|
//获取指定位置的路径网格的单元格索引
|
|||
|
public int GetCellIndex(Vector2 position)
|
|||
|
{
|
|||
|
return _pathWorld.GetCellIndex(ref position);
|
|||
|
}
|
|||
|
|
|||
|
public Vector2 CalculationRayCastPos2d(Vector2 start, Vector2 end)
|
|||
|
{
|
|||
|
if (start == end)
|
|||
|
return start;
|
|||
|
|
|||
|
var dis = Vector2.Distance(end, start);
|
|||
|
var whileCount = (int)(dis / CellSize + 1);
|
|||
|
|
|||
|
var tmpPos = Vector2.zero;
|
|||
|
var result = start;
|
|||
|
var lerpValue = 0f;
|
|||
|
for (int i = 0; i <= whileCount; ++i)
|
|||
|
{
|
|||
|
lerpValue = i / (float)whileCount;
|
|||
|
tmpPos = Vector2.Lerp(start, end, lerpValue);
|
|||
|
if (IsBlocked(tmpPos))
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
result = tmpPos;
|
|||
|
}
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
//开始点到目标点是否通畅
|
|||
|
public bool IsNotBlockRayCast2d(Vector2 start, Vector2 end)
|
|||
|
{
|
|||
|
if (start == end)
|
|||
|
return true;
|
|||
|
|
|||
|
var dis = Vector2.Distance(end, start);
|
|||
|
var whileCount = (int)(dis / CellSize + 1);
|
|||
|
|
|||
|
var tmpPos = Vector2.zero;
|
|||
|
var result = start;
|
|||
|
var lerpValue = 0f;
|
|||
|
for (int i = 0; i <= whileCount; ++i)
|
|||
|
{
|
|||
|
lerpValue = i / (float)whileCount;
|
|||
|
tmpPos = Vector2.Lerp(start, end, lerpValue);
|
|||
|
if (IsBlocked(tmpPos))
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
result = tmpPos;
|
|||
|
}
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
//开始点到目标点是否通畅
|
|||
|
public bool IsNotBlockRayCast(Vector3 start, Vector3 end)
|
|||
|
{
|
|||
|
return IsNotBlockRayCast2d(new Vector2(start.x, start.z), new Vector2(end.x, end.z));
|
|||
|
}
|
|||
|
|
|||
|
//玩家角色寻路
|
|||
|
public virtual List<Vector2> SearchPlayerPath(Vector3 startPosition, Vector3 endPosition)
|
|||
|
{
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
//其他怪物的寻路
|
|||
|
public virtual List<Vector2> SearchOtherPath(Vector3 startPosition, Vector3 endPosition)
|
|||
|
{
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
//寻路到某个物体
|
|||
|
public virtual List<Vector2> SearchTargetPath(Vector3 startPosition, Vector3 endPosition, float targetRadius)
|
|||
|
{
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
//评价路径,返回-1表示无法寻路到达,返回距离表示到目标点的实际距离
|
|||
|
public virtual float EvaluatePath(Vector3 startPosition, Vector3 endPosition)
|
|||
|
{
|
|||
|
return -1f;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|