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;
|
||
}
|
||
}
|
||
}
|