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