using System;
using System.Collections.Generic;
using System.Text;
using CommonAI.RTS;
using CommonLang.Vector;
using CommonLang;
using CommonLang.Concurrent;
using CommonAI.ZoneServer.JSGModule;
using static CommonAI.ZoneServer.JSGModule.MSpaceNodeCache;
namespace CommonAI.RTS.Manhattan
{
partial class AstarManhattan
{
//----------------------------------------------------------------------------------------------------------------------------
///
/// 十字链表,预先寻路
///
public class MSpaceAStar : RTSAstar
{
private readonly MSpaceMap smap;
private readonly int div_size;
private readonly AstarManhattan manhattan;
private DirtyNodes dirty_space_nodes = new DirtyNodes();
public MSpaceMap SpaceMap
{
get { return smap; }
}
internal MSpaceAStar(int uniqueID, AstarManhattan astar, int div_size)
{
this.manhattan = astar;
this.div_size = div_size;
this.smap = new MSpaceMap(uniqueID, astar, div_size);
base.Init(smap);
this.manhattan.terrain_map.ForEachNodes((mn) =>
{
mn.OnResetValue = onNodeValueReset;
});
}
protected override void Disposing()
{
base.Disposing();
dirty_space_nodes.Clear();
}
public MSpaceNode getSpaceNode(int cx, int cy)
{
return smap.getSpaceNode(cx, cy);
}
public MSpaceNode getSpaceNodeByBlock(int bx, int by)
{
int cx, cy;
smap.Space.ToSpaceBlock(bx, by, out cx, out cy);
return smap.getSpaceNode(cx, cy);
}
public override WayPoint GenWayPoint(MapNode node)
{
var wp = (node as MSpaceNode).WayPoint;
wp.LinkNext(null);
return wp;
}
//------------------------------------------------------------------------
///
/// 当地表数据改变
///
///
private void onNodeValueReset(MMapNode node)
{
var mn = getSpaceNodeByBlock(node.BX, node.BY);
if (mn != null)
{
dirty_space_nodes.AddDirty(mn);
}
}
internal void beginFindPath()
{
if (dirty_space_nodes.Count > 0)
{
using (var list = ListObjectPool.AllocAutoRelease(dirty_space_nodes.Values))
{
var near_table = GetNearTables(manhattan.IsInclined);
foreach (var dn in list)
{
foreach (var offset in near_table)
{
var sn = getSpaceNode(dn.CX + offset[0], dn.CY + offset[1]);
if (sn != null)
{
dirty_space_nodes.AddDirty(sn);
}
}
}
}
using (var list = ListObjectPool.AllocAutoRelease(dirty_space_nodes.Values))
{
foreach (var mn in list)
{
mn.ResetCenterAnchor();
}
foreach (var mn in list)
{
mn.ResetNext();
}
}
dirty_space_nodes.Clear();
}
}
//------------------------------------------------------------------------
public class MSpaceMap : ITerrain
{
internal readonly AstarManhattan manhattan;
internal readonly SpaceDivision space;
public readonly float space_full_cell_w;
public readonly float space_full_cell_h;
private int nodes_count;
private MSpaceNodeItem nodes_matrix = new MSpaceNodeItem();
public SpaceDivision Space
{
get { return space; }
}
public int TotalNodeCount
{
get { return nodes_count; }
}
internal MSpaceMap(int uniqueID, AstarManhattan mmap, int divSize)
{
this.manhattan = mmap;
this.space = new SpaceDivision(
mmap.manhattan_map.XCount,
mmap.manhattan_map.YCount,
divSize,
divSize);
this.space_full_cell_w = space.SpaceCellW * manhattan.cellw;
this.space_full_cell_h = space.SpaceCellH * manhattan.cellh;
this.nodes_count = space.SpaceXCount * space.SpaceYCount;
nodes_matrix.data = new MSpaceNode[space.SpaceXCount, space.SpaceYCount];
for (int cx = 0; cx < space.SpaceXCount; cx++)
{
for (int cy = 0; cy < space.SpaceYCount; cy++)
{
nodes_matrix.data[cx, cy] = new MSpaceNode(this, space.GetSpaceCellNodeByBlock(cx, cy));
}
}
for (int cx = 0; cx < space.SpaceXCount; cx++)
{
for (int cy = 0; cy < space.SpaceYCount; cy++)
{
nodes_matrix.data[cx, cy].ResetNext();
}
}
}
public MSpaceNode getSpaceNode(int cx, int cy)
{
if (cx < space.SpaceXCount && cx >= 0 && cy < space.SpaceYCount && cy >= 0)
{
return nodes_matrix.data[cx, cy];
}
return null;
}
public void ForEachNodes(Action action)
{
for (int cx = 0; cx < space.SpaceXCount; cx++)
{
for (int cy = 0; cy < space.SpaceYCount; cy++)
{
action(nodes_matrix.data[cx, cy]);
}
}
}
public void Dispose()
{
this.space.Dispose();
}
}
public class MSpaceNode : MapNode
{
class NextInfo
{
public readonly float distance;
public readonly MWayPoint path;
public NextInfo(MWayPoint path)
{
this.path = path;
this.distance = path.GetTotalDistance();
}
}
//private readonly AstarManhattan manhattan;
//private readonly SpaceDivision space;
private readonly MSpaceMap map;
private readonly SpaceDivision.SpaceCellNode space_node;
private readonly HashMap next_links = new HashMap();
private readonly MSpaceWayPoint way_point;
private MMapNode center_anchor;
private MSpaceNode[] nexts;
///
/// 没有阻挡
///
private bool no_blocks;
///
/// 没有空地
///
private bool no_cross;
///
/// 复杂度,阻挡块越多,越复杂
///
private float complexity;
public int CX { get { return space_node.BX; } }
public int CY { get { return space_node.BY; } }
public override MapNode[] Nexts { get { return nexts; } }
public MSpaceNode[] NextsSpaceNode { get { return nexts; } }
public MMapNode AnchorNode { get { return center_anchor; } }
internal MSpaceWayPoint WayPoint { get { return way_point; } }
internal MSpaceNode(MSpaceMap map, SpaceDivision.SpaceCellNode space_node)
{
this.space_node = space_node;
this.map = map;
this.way_point = new MSpaceWayPoint(this);
this.ResetCenterAnchor();
}
internal void ResetCenterAnchor()
{
int sx = (int)(space_node.BX * map.space.SpaceCellW);
int sy = (int)(space_node.BY * map.space.SpaceCellH);
int sw = (int)(map.space.SpaceCellW);
int sh = (int)(map.space.SpaceCellH);
// 检测没有空地 //
this.no_cross = map.manhattan.CheckNearExpectByBlock(sx, sy, sw, sh, true);
if (no_cross)
{
this.center_anchor = null;
this.no_blocks = false;
this.complexity = 0;
}
else
{
this.center_anchor = map.manhattan.FindNearMoveableNodeByBlock(sx, sy, sw, sh);
//检测没有阻挡//
this.no_blocks = map.manhattan.CheckNearExpectByBlock(sx, sy, sw, sh, false);
//检测阻挡块数量//
int bc = map.manhattan.GetNearExpectCountByBlock(sx, sy, sw, sh, true);
this.complexity = map.manhattan.cell_sqrt * bc;
}
this.next_links.Clear();
}
internal void ResetNext()
{
if (this.center_anchor != null)
{
var near_table = GetNearTables(map.manhattan.IsInclined);
foreach (var offset in near_table)
{
var next = map.getSpaceNode(CX + offset[0], CY + offset[1]);
if (next != null && next.center_anchor != null)
{
if (this.center_anchor.AreaValue != next.center_anchor.AreaValue)
{
//两块区域不同(存在洞)//
continue;
}
else if (this.no_blocks && next.no_blocks)
{
//两块都没有阻挡块,则不需要寻路//
MWayPoint path = new MWayPoint(center_anchor);
path.LinkNext(new MWayPoint(next.center_anchor));
next_links.Put(next, new NextInfo(path));
}
else if (!map.manhattan.TouchMapLine(
this.center_anchor.PosX,
this.center_anchor.PosY,
next.center_anchor.PosX,
next.center_anchor.PosY))
{
//两块直接连线通过,则不需要寻路//
MWayPoint path = new MWayPoint(center_anchor);
path.LinkNext(new MWayPoint(next.center_anchor));
next_links.Put(next, new NextInfo(path));
}
else
{
//两块之间寻路//
MWayPoint path = map.manhattan.findPathInternal(this.center_anchor, next.center_anchor);
if (path != null)
{
NextInfo info = new NextInfo(path);
if (info.distance <= (map.space_full_cell_w + map.space_full_cell_h))
{
next_links.Put(next, info);
}
}
}
}
}
}
this.nexts = new MSpaceNode[next_links.Count];
this.next_links.Keys.CopyTo(nexts, 0);
}
internal void Clone(MSpaceNode data)
{
this.next_links.PutAll(data.next_links);
this.nexts = new MSpaceNode[this.next_links.Count];
this.next_links.Keys.CopyTo(this.nexts, 0);
}
public MWayPoint GetNextLink(MSpaceNode next)
{
var ret = next_links.Get(next);
if (ret != null)
{
return ret.path;
}
return null;
}
public override bool TestCross(MapNode other)
{
return next_links.ContainsKey(other);
}
public override void Dispose()
{
next_links.Clear();
nexts = null;
}
public override float GetG(MapNode target)
{
var t = (MSpaceNode)target;
var ret = this.next_links.Get(t);
if (ret != null)
{
return ret.distance + this.complexity;
}
else
{
float ndx = (t.AnchorNode.BX - this.AnchorNode.BX) * map.manhattan.cellw;
float ndy = (t.AnchorNode.BY - this.AnchorNode.BY) * map.manhattan.cellh;
return (float)Math.Sqrt((ndx * ndx) + (ndy * ndy)) + this.complexity;
}
}
public override float GetH(MapNode father)
{
if (this == father)
{
return 0;
}
else
{
var t = (MSpaceNode)father;
var ret = this.next_links.Get(t);
if (ret != null)
{
return ret.distance + t.complexity;
}
else
{
return 0;
}
}
}
}
public class MSpaceWayPoint : WayPoint
{
public MSpaceNode SpaceNode
{
get { return base.node as MSpaceNode; }
}
public MSpaceWayPoint Next
{
get { return base.next as MSpaceWayPoint; }
}
public MSpaceWayPoint Tail
{
get { return base.tail as MSpaceWayPoint; }
}
internal MSpaceWayPoint(MapNode map_node)
: base(map_node)
{
}
public override WayPoint Clone()
{
var ret = new MSpaceWayPoint(this.node);
if (this.next != null)
{
ret.LinkNext(this.next.Clone());
}
return ret;
}
public AstarManhattan.MWayPoint ToLinkWayPoint()
{
if (next != null)
{
var ret = SpaceNode.GetNextLink(next.node as MSpaceNode);
if (ret != null)
{
ret = ret.Clone() as AstarManhattan.MWayPoint;
ret.Tail.LinkNext(this.Next.ToLinkWayPoint());
return ret;
}
}
return null;
}
}
}
}
}