using RichCreator.Utility.Structs;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using RichCreator.Utility.Skills;
|
using RichCreator.Utility.InputControl;
|
using RichCreator.Utility.PathFinding;
|
using RichCreator.Utility.Utilitys;
|
|
namespace RichCreator.Utility.Maps
|
{
|
/// <summary>
|
/// 房间信息
|
/// </summary>
|
public class HouseInfo
|
{
|
public HouseInfo(HousePathInfo houseInfo)
|
{
|
this.HousePathInfo = houseInfo;
|
InitPathInfo(null);
|
}
|
|
public HouseInfo(Int32 index,MapType mapType,bool isEnd, HIDCode[] skills,Int32[] withoutNumber)
|
{
|
this.Index = index;
|
this.MapType = mapType;
|
this.IsEnd = isEnd;
|
|
Skills = new SkillQueue();
|
for (int i = 0; skills!=null&&i < skills.Length; i++)
|
{
|
Skills.EnQueue(false,skills[i]);
|
}
|
|
if (index < 0)
|
{
|
throw new ArgumentOutOfRangeException("houseIndex");
|
}
|
|
try
|
{
|
this.HousePathInfo = HousePathInfo.From(this.MapType, index);
|
}
|
catch (Exception e)
|
{
|
throw e;
|
}
|
|
InitPathInfo(withoutNumber);
|
}
|
|
|
/// <summary>
|
/// 房间编号
|
/// </summary>
|
public Int32 Index { get; set; }
|
|
private Direction[] doorDirection = null;
|
/// <summary>
|
/// 门的位置
|
/// todo:cacel
|
/// </summary>
|
public Direction[] DoorDirection
|
{
|
get
|
{
|
return doorDirection;
|
}
|
}
|
|
/// <summary>
|
/// 技能队列
|
/// </summary>
|
public SkillQueue Skills { get; set; }
|
|
/// <summary>
|
/// 是否为结束房间
|
/// </summary>
|
public bool IsEnd { get; set; }
|
|
/// <summary>
|
/// 地图类型
|
/// </summary>
|
public MapType MapType { get; set; }
|
|
|
/// <summary>
|
/// 房间信息
|
/// </summary>
|
public HousePathInfo HousePathInfo { get; private set; }
|
|
/// <summary>
|
/// 路径查找器
|
/// </summary>
|
private Dijkstra<ZTPoint> PathFinder { get; set; }
|
|
/// <summary>
|
/// 定位字典
|
/// </summary>
|
private Dictionary<Int32, ZTPoint> LocationDic = new Dictionary<int, ZTPoint>();
|
|
/// <summary>
|
/// 排除数字
|
/// </summary>
|
public Dictionary<Int32, bool> WithoutNumber = new Dictionary<int, bool>();
|
|
/// <summary>
|
/// 屏幕坐标转地图坐标
|
/// </summary>
|
/// <param name="screenCoordinate"></param>
|
/// <param name="locationParameter"></param>
|
/// <param name="locationCoordinate"></param>
|
/// <returns></returns>
|
public ZTPoint ScreenToMapCoordinate(ZTPoint screenCoordinate,ParametersPoint locationCoor)
|
{
|
if (!LocationDic.ContainsKey(locationCoor.Parameter))
|
{
|
throw new ArgumentOutOfRangeException("不存在的定位点,parameter:" + locationCoor.Parameter.ToString());
|
}
|
|
//目标屏幕坐标+(定位点地图坐标-定位点屏幕坐标)
|
return screenCoordinate.Add(LocationDic[locationCoor.Parameter].Sub(locationCoor.Point));
|
}
|
|
/// <summary>
|
/// 地图坐标转屏幕坐标
|
/// </summary>
|
/// <param name="mapCoordinate"></param>
|
/// <param name="locationParameter"></param>
|
/// <param name="locationCoordinate"></param>
|
/// <returns></returns>
|
public ZTPoint MapToScreenCoordinate(ZTPoint mapCoordinate, ParametersPoint locationCoor)
|
{
|
if (!LocationDic.ContainsKey(locationCoor.Parameter))
|
{
|
throw new ArgumentOutOfRangeException("不存在的定位点,parameter:" + locationCoor.Parameter.ToString());
|
}
|
|
//目标地图坐标-(定位点地图坐标-定位点屏幕坐标)
|
return mapCoordinate.Sub(LocationDic[locationCoor.Parameter].Sub(locationCoor.Point));
|
}
|
|
/// <summary>
|
/// 两点之间寻路
|
/// </summary>
|
/// <param name="start"></param>
|
/// <param name="end"></param>
|
public List<ZTPoint> FindPath(ZTPoint start, ZTPoint end)
|
{
|
if (start.Equals(end))
|
{
|
return new List<ZTPoint>();
|
}
|
|
//查询两点间是否连通
|
if (Iscross(start, end))
|
{
|
//两点直接连通
|
return new List<ZTPoint>() { end };
|
}
|
|
//确保两点不在障碍物里
|
ZTPoint startPathGuid = ZTPoint.Empty;
|
ZTPoint endPathGuid = ZTPoint.Empty;
|
bool inObstacle = EnsureNotInObstacle(out startPathGuid, start);
|
inObstacle = EnsureNotInObstacle(out endPathGuid, end) || inObstacle;
|
|
//查询两点间是否连通
|
if (inObstacle && Iscross(startPathGuid, endPathGuid))
|
{
|
//两点直接连通
|
List<ZTPoint> points = new List<ZTPoint>();
|
if (!start.Equals(startPathGuid))
|
{
|
points.Add(startPathGuid);
|
}
|
if (!end.Equals(endPathGuid))
|
{
|
points.Add(endPathGuid);
|
}
|
points.Add(end);
|
return points;
|
}
|
|
|
//把两点添加到寻路网中
|
AddConnectivityEdgeToFinder(startPathGuid, endPathGuid);
|
|
//寻路,组合路径
|
List<ZTPoint> paths = this.PathFinder.ShortestPath(startPathGuid, endPathGuid);
|
|
//去除寻路网中
|
RemoveStartAndEndVerticeFromFinder(endPathGuid, endPathGuid);
|
|
//生成的路径不包含第一个点,拟如果第一个点是路径引导,则加入路径
|
if (!start.Equals(startPathGuid))
|
{
|
paths.Insert(0, startPathGuid);
|
}
|
|
//如果最后一个点是路径引导点,测加上终点
|
if (!end.Equals(endPathGuid))
|
{
|
paths.Add(end);
|
}
|
|
return paths;
|
}
|
|
|
/// <summary>
|
/// 是否在下一关进门点区域内
|
/// </summary>
|
/// <param name="nextGatePoint"></param>
|
/// <param name="rolePosition"></param>
|
/// <returns></returns>
|
public bool IsInNextGatePoint(out ParametersPoint nextGatePoint, ZTPoint rolePosition)
|
{
|
nextGatePoint = ParametersPoint.Empty;
|
const Int32 X_OFFSET = 5;
|
const Int32 Y_OFFSET = 5;
|
for (Int32 i = 0; i < this.HousePathInfo.NextGates.Count; i++)
|
{
|
ParametersPoint nextGate = this.HousePathInfo.NextGates[i];
|
if (GeoHelper.IsInRect(rolePosition, new ZTRectangle(nextGate.Point.X- X_OFFSET, nextGate.Point.Y- Y_OFFSET, nextGate.Point.X+ X_OFFSET, nextGate.Point.Y+ Y_OFFSET)))
|
{
|
nextGatePoint = nextGate;
|
return true;
|
}
|
}
|
return false;
|
}
|
|
/// <summary>
|
/// 获取指定方向的进门点
|
/// </summary>
|
/// <param name="dir"></param>
|
/// <returns></returns>
|
public ZTPoint GetNextGatePoint(Direction dir)
|
{
|
int dirNumber = 0;
|
switch (dir)
|
{
|
case Direction.Up:
|
dirNumber = 0;
|
break;
|
case Direction.Right:
|
dirNumber = 1;
|
break;
|
case Direction.Bottom:
|
dirNumber = 2;
|
break;
|
case Direction.Left:
|
dirNumber = 3;
|
break;
|
}
|
for (int i = 0; i < this.HousePathInfo.NextGates.Count; i++)
|
{
|
if (dirNumber == this.HousePathInfo.NextGates[i].Parameter)
|
{
|
return this.HousePathInfo.NextGates[i].Point;
|
}
|
}
|
throw new ArgumentOutOfRangeException("house index:" + this.Index.ToString() + ",direction :" + dir.ToString() + " is not exists!~");
|
}
|
|
/// <summary>
|
/// 判断两点间是否连通
|
/// </summary>
|
/// <param name="start"></param>
|
/// <param name="end"></param>
|
/// <returns></returns>
|
private bool Iscross(ZTPoint start, ZTPoint end)
|
{
|
for (int i = 0; i < this.HousePathInfo.Obstacles.Count; i++)
|
{
|
Intersection interSection = GeoHelper.IntersectionOf(new ZTLinePoint(start, end), this.HousePathInfo.Obstacles[i]);
|
if (interSection != Intersection.None)
|
{
|
return false;
|
}
|
}
|
return true;
|
}
|
|
/// <summary>
|
/// 是否在障碍物里,如果在障碍物里则返回最近的不在障碍物点
|
/// </summary>
|
/// <param name="pathGuidePoint"></param>
|
/// <returns>true:在障碍物,false:不在障碍物里</returns>
|
private bool EnsureNotInObstacle(out ZTPoint pathGuidePoint,ZTPoint source)
|
{
|
pathGuidePoint = ZTPoint.Empty;
|
|
//点是否在障碍物里
|
ZTPolygon obstacle = ZTPolygon.Empty;
|
for (int i = 0; i < this.HousePathInfo.Obstacles.Count; i++)
|
{
|
ZTPolygon temp = this.HousePathInfo.Obstacles[i];
|
if (GeoHelper.IntersectionOf(source, temp) != Intersection.None)
|
{
|
obstacle = this.HousePathInfo.Obstacles[i];
|
break;
|
}
|
}
|
if (obstacle.Equals(ZTPolygon.Empty))
|
{
|
//不在障碍物内
|
pathGuidePoint = source;
|
return false;
|
}
|
|
//点是否在路径导引区域
|
for (int i = 0; i < this.HousePathInfo.PathGuides.Count; i++)
|
{
|
ZTTargetPolygon temp = this.HousePathInfo.PathGuides[i];
|
if (GeoHelper.IntersectionOf(source, temp.Polygon) != Intersection.None)
|
{
|
pathGuidePoint = temp.Target;
|
return true;
|
}
|
}
|
|
|
//计算距离障碍物外最近的距离
|
double distance = 0;
|
ZTPoint lastPoint = ZTPoint.Empty;
|
for (int i = 0; i < obstacle.Points.Length; i++)
|
{
|
if (i == 0)
|
{
|
lastPoint = obstacle.Points[i];
|
distance = GeoHelper.GetPointDistance(lastPoint, pathGuidePoint);
|
}
|
double lastDistance = GeoHelper.GetNearestDistance(new ZTLinePoint(lastPoint, obstacle[i]), pathGuidePoint);
|
if (lastDistance < distance)
|
{
|
distance = lastDistance;
|
}
|
if (distance <= 0)
|
{
|
distance = 0;
|
break;
|
}
|
}
|
|
//查找最近离开障碍物的点
|
ZTPoint testPoint = ZTPoint.Empty;
|
Int32 maxDistance = Math.Max(Math.Max(source.X, this.HousePathInfo.Width - source.X), Math.Max(source.Y, this.HousePathInfo.Height - source.Y));
|
for (int i = (Int32)distance; i < maxDistance; i++)
|
{
|
//下
|
if (source.Y + i <= this.HousePathInfo.Height)
|
{
|
testPoint = new ZTPoint(source.X, source.Y + i);
|
if (GeoHelper.IntersectionOf(testPoint, obstacle) == Intersection.None)
|
{
|
testPoint.Y += 10;
|
pathGuidePoint = testPoint;
|
break;
|
}
|
}
|
|
|
//右
|
if (source.X <= this.HousePathInfo.Width)
|
{
|
testPoint = new ZTPoint(source.X + i, source.Y);
|
if (GeoHelper.IntersectionOf(testPoint, obstacle) == Intersection.None)
|
{
|
testPoint.X += 10;
|
pathGuidePoint = testPoint;
|
break;
|
}
|
}
|
|
//左
|
if (source.X - i >= 0)
|
{
|
testPoint = new ZTPoint(source.X - i, source.Y);
|
if (GeoHelper.IntersectionOf(testPoint, obstacle) == Intersection.None)
|
{
|
testPoint.X -= 10;
|
pathGuidePoint = testPoint;
|
break;
|
}
|
}
|
|
//上
|
if (source.Y - i >= 0)
|
{
|
testPoint = new ZTPoint(source.X, source.Y - i);
|
if (GeoHelper.IntersectionOf(testPoint, obstacle) == Intersection.None)
|
{
|
testPoint.Y -= 10;
|
pathGuidePoint = testPoint;
|
break;
|
}
|
}
|
}
|
|
return true;
|
}
|
|
/// <summary>
|
/// 初始化寻路器
|
/// </summary>
|
private void InitPathInfo(Int32[] withoutNumber)
|
{
|
this.PathFinder = new Dijkstra<ZTPoint>();
|
|
//添加寻路路径
|
ZTLinePoint line;
|
for (int i = 0; i < this.HousePathInfo.FindPathLines.Count; i++)
|
{
|
line = this.HousePathInfo.FindPathLines[i];
|
this.PathFinder.AddEdge(line.P1, line.P2, line.GetDistance());
|
}
|
|
|
//定位点添加到字典
|
for (int i = 0; i < this.HousePathInfo.LocationPoints.Count; i++)
|
{
|
ParametersPoint pp = this.HousePathInfo.LocationPoints[i];
|
if (!this.LocationDic.ContainsKey(pp.Parameter))
|
{
|
this.LocationDic.Add(pp.Parameter, pp.Point);
|
}
|
}
|
|
//计算门朝向
|
doorDirection = new Direction[this.HousePathInfo.NextGates.Count];
|
for (Int32 i = 0; i < this.HousePathInfo.NextGates.Count; i++)
|
{
|
switch (this.HousePathInfo.NextGates[i].Parameter)
|
{
|
case 0:
|
doorDirection[i] = Direction.Up;
|
break;
|
case 1:
|
doorDirection[i] = Direction.Right;
|
break;
|
case 2:
|
doorDirection[i] = Direction.Bottom;
|
break;
|
case 3:
|
doorDirection[i] = Direction.Left;
|
break;
|
}
|
}
|
|
if (withoutNumber != null)
|
{
|
for (int i = 0; i < withoutNumber.Length; i++)
|
{
|
if (!this.WithoutNumber.ContainsKey(withoutNumber[i]))
|
{
|
this.WithoutNumber.Add(withoutNumber[i], true);
|
}
|
}
|
}
|
|
}
|
|
/// <summary>
|
/// 向查找器中添加起点和终点可连通的边
|
/// </summary>
|
/// <param name="start"></param>
|
/// <param name="end"></param>
|
private void AddConnectivityEdgeToFinder(ZTPoint start, ZTPoint end)
|
{
|
Int32 distance = 0;
|
ZTPoint point;
|
for (int i = 0; i < this.HousePathInfo.FindPathPoints.Count; i++)
|
{
|
point = this.HousePathInfo.FindPathPoints[i];
|
if (Iscross(start, point))
|
{
|
distance = (Int32)GeoHelper.GetPointDistance(start, point);
|
this.PathFinder.AddEdge(start, point, distance);
|
}
|
|
if (Iscross(end, point))
|
{
|
distance = (Int32)GeoHelper.GetPointDistance(end, point);
|
this.PathFinder.AddEdge(end, point, distance);
|
}
|
}
|
|
}
|
|
|
/// <summary>
|
/// 从查找器中移除起点和终点
|
/// </summary>
|
/// <param name="start"></param>
|
/// <param name="end"></param>
|
private void RemoveStartAndEndVerticeFromFinder(ZTPoint start, ZTPoint end)
|
{
|
this.PathFinder.RemoveEdge(start);
|
this.PathFinder.RemoveEdge(end);
|
}
|
}
|
}
|