Files
Main/Assets/Plugins/Code/UniScene/PathGrid/PathGridSystem.cs
2025-01-25 04:38:09 +08:00

462 lines
14 KiB
C#
Raw Permalink 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 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;
}
}
}