using CommonLang; using System; using System.Collections.Generic; using System.Text; namespace CommonAI.RTS { public interface ITerrain : IDisposable where T : MapNode { void ForEachNodes(Action action); int TotalNodeCount { get; } } public abstract class MapNode : IDisposable { internal TempMapNode tempNode; /// /// 临近节点 /// public abstract MapNode[] Nexts { get; } /// /// 测试通过 /// /// /// public abstract bool TestCross(MapNode other); /// /// g(n) 是在状态空间中从初始节点到n节点的实际代价。值越大,优先级越低。 /// /// /// public abstract float GetG(MapNode target); /// /// h(n) 是从n到目标节点最佳路径的估计代价。值越大,优先级越低。 /// /// /// public abstract float GetH(MapNode father); /// /// 销毁节点 /// public abstract void Dispose(); } //----------------------------------------------------------------------------------------------------------------- public abstract class WayPoint : IDisposable { public object Tag { get; set; } public MapNode node { get; private set; } public WayPoint next { get; private set; } public WayPoint prev { get; private set; } public WayPoint tail { get { WayPoint wp = this; while (wp.next != null) { wp = wp.next; } return wp; } } /// /// 从当前节点开始算总长 /// public int count { get { int ret = 0; WayPoint wp = this; while (wp != null) { ret++; wp = wp.next; } return ret; } } public WayPoint(MapNode map_node) { this.node = map_node; } public virtual void Dispose() { this.node = null; this.next = null; this.prev = null; } public abstract WayPoint Clone(); public void LinkNext(WayPoint n) { if (this.next != null) { this.next.prev = null; } this.next = n; if (n != null) { n.prev = this; } } } //----------------------------------------------------------------------------------------------------------------- /// /// 抽象的A*寻路算法,子类可以自定义实现如何寻路。 /// @author WAZA /// public abstract class RTSAstar : Disposable where T : MapNode { private ITerrain terrain; private TempMapNodeList.OpenList src_open_list; private TempMapNodeList.CloseList src_close_list; public int TotalNodeCount { get { return terrain.TotalNodeCount; } } public void Init(ITerrain map) { this.terrain = map; this.src_open_list = new TempMapNodeList.OpenList(); this.src_close_list = new TempMapNodeList.CloseList(); terrain.ForEachNodes((node) => { var temp = new TempMapNode(node); node.tempNode = temp; }); } protected override void Disposing() { terrain.ForEachNodes((node) => { node.tempNode.Dispose(); }); terrain.Dispose(); terrain = null; src_open_list = null; src_close_list = null; } public abstract WayPoint GenWayPoint(MapNode node); public WayPoint findPath(MapNode src_node, MapNode dst_node) { return findPath(src_node.tempNode, dst_node.tempNode); } protected WayPoint findPath(TempMapNode src_node, TempMapNode dst_node) { WayPoint head = GenWayPoint(src_node.data); if (src_node.data.Equals(dst_node.data)) { return head; } src_open_list.clear(); src_close_list.clear(); src_node.setFather(src_node, dst_node); src_open_list.add(src_node); do { // search min F TempMapNode cur_node = src_open_list.getMinF(); // put the min F to closed src_open_list.remove(cur_node); src_close_list.add(cur_node); // find next node for (int i = cur_node.data.Nexts.Length - 1; i >= 0; --i) { TempMapNode near = cur_node.data.Nexts[i].tempNode; if (!near.data.TestCross(cur_node.data)) { continue; } // ignore what if the block can not across or already in close table if (src_close_list.contains(near)) { continue; } // push and if is not in open table if (!src_open_list.contains(near)) { near.setFather(cur_node, dst_node); src_open_list.add(near); } } // stop when : // 1. dst node already in close list if (cur_node.data.Equals(dst_node.data)) { // finded the path WayPoint end = null;//GenWayPoint(dst_node.data); for (int i = terrain.TotalNodeCount - 1; i >= 0; i--) { // linked to head if (cur_node.data.Equals(src_node.data) || (cur_node.s_father == cur_node)) { head.LinkNext(end); break; } else { WayPoint next = GenWayPoint(cur_node.data); next.LinkNext(end); end = next; } cur_node = cur_node.s_father; } break; } // 2. open list is empty if (src_open_list.isEmpty()) { // not find the path break; } } while (true); return head; } } //--------------------------------------------------------------------------------------------------------- public class TempMapNode : IDisposable { /**对应的地图数据*/ public MapNode data { get; private set; } /**每次寻路时,暂存的上一个节点*/ internal TempMapNode s_father = null; // 当前所在的列表 // internal TempMapNodeList m_curList = null; internal TempMapNode m_prev = null; internal TempMapNode m_next = null; private float s_g = 0; private float s_h = 0; private float s_f = 0; internal float F { get { return s_f; } } internal TempMapNode(MapNode data) { this.data = data; } /// /// F = G + H /// 这里: /// /// /// internal void setFather(TempMapNode father, TempMapNode target) { this.s_father = father; this.s_g = father.s_g + data.GetG(target.data); this.s_h = data.GetH(father.data); this.s_f = (s_g + s_h); } public void Dispose() { data = null; s_father = null; m_curList = null; m_prev = null; m_next = null; } } //--------------------------------------------------------------------------------------------------------- internal abstract class TempMapNodeList { private TempMapNode head = null; private TempMapNode last = null; internal class OpenList : TempMapNodeList { } //-------------------------------------------------------------------------- internal class CloseList : TempMapNodeList { } //-------------------------------------------------------------------------- internal TempMapNodeList() { } internal bool isEmpty() { return head == null; } internal bool contains(TempMapNode node) { return node.m_curList == this; } internal virtual TempMapNode getMinF() { float min = float.MaxValue; TempMapNode ret = null; for (TempMapNode a = head; a != null; a = a.m_next) { //float v = a.F; if (min > a.F) { ret = a; min = a.F; } } return ret; } internal virtual void add(TempMapNode node) { if (node.m_curList == null) { if (last == null) { head = last = node; } else { last.m_next = node; node.m_prev = last; last = node; } node.m_curList = this; } else { throw new Exception("Node is already in a List !"); } } internal virtual void remove(TempMapNode node) { if (node.m_curList == this) { if (head == node) { head = node.m_next; } if (last == node) { last = node.m_prev; } if (node.m_next != null) { node.m_next.m_prev = node.m_prev; } if (node.m_prev != null) { node.m_prev.m_next = node.m_next; } node.m_next = null; node.m_prev = null; node.m_curList = null; } else { throw new Exception("Node is not contains in this list !"); } } internal virtual void clear() { if (head != null) { for (TempMapNode i = head; i != null; i = i.m_next) { i.m_curList = null; } TempMapNode p = head; TempMapNode q = null; do { q = p.m_next; p.m_next = null; p = q; } while (p != null); p = last; do { q = p.m_prev; p.m_prev = null; p = q; } while (p != null); this.head = null; this.last = null; } } } //--------------------------------------------------------------------------------------------------------- }