using System; using System.Collections.Generic; using System.Text; using CommonAI.RTS; using CommonLang.Vector; using CommonLang; using CommonLang.Concurrent; namespace CommonAI.RTS.Manhattan { partial class AstarManhattan { //--------------------------------------------------------------------------------------------------------------------- internal class MTerrain : ITerrain { internal readonly IManhattanMap map_data; internal readonly AstarManhattan manhattan; internal readonly bool is_inclined; internal readonly int xcount; internal readonly int ycount; private int nodes_count; private MMapNode[,] all_nodes_map; public int TotalNodeCount { get { return nodes_count; } } internal MTerrain(AstarManhattan manhattan, IManhattanMap map, bool inclined) { this.manhattan = manhattan; this.map_data = map; this.is_inclined = inclined; this.xcount = map.XCount; this.ycount = map.YCount; this.nodes_count = 0; this.all_nodes_map = new MMapNode[xcount, ycount]; for (int y = 0; y < ycount; y++) { for (int x = 0; x < xcount; x++) { if (map.TestBlock(x, y) == false) { all_nodes_map[x, y] = map.CreateMapNode(); nodes_count++; } } } for (int y = 0; y < ycount; y++) { for (int x = 0; x < xcount; x++) { MMapNode node = all_nodes_map[x, y]; if (node != null) { node.Init(this, x, y); } } } for (int y = 0; y < ycount; y++) { for (int x = 0; x < xcount; x++) { MMapNode node = all_nodes_map[x, y]; if (node != null) { node.resetNextNodes(this); } } } } public void Dispose() { for (int y = 0; y < ycount; y++) { for (int x = 0; x < xcount; x++) { MMapNode node = all_nodes_map[x, y]; if (node != null) { node.Dispose(); } } } this.map_data.Dispose(); this.all_nodes_map = null; } public void ForEachNodes(Action action) { for (int y = 0; y < ycount; y++) { for (int x = 0; x < xcount; x++) { MMapNode node = all_nodes_map[x, y]; if (node != null) { action(node); } } } } public MMapNode getMapNode(int bx, int by) { return all_nodes_map[bx, by]; } public bool touchMapBlock(int bx, int by) { if (bx < 0 || bx >= xcount) return true; if (by < 0 || by >= ycount) return true; var node = all_nodes_map[bx, by]; if (node != null) { return node.Blocked; } return true; } } public class MMapNode : MapNode { /// /// 实例数量 /// public static int ActiveObjectCount { get { return s_active_object_count.Value; } } private static AtomicInteger s_active_object_count = new AtomicInteger(0); private static MMapNode[] ZeroNexts = new MMapNode[0]; internal Action OnResetValue; internal byte area = 0; internal MMapNode[] nextnodes = ZeroNexts; //private BitSet8 bitset; private bool mBlocked; private bool mAllCross; private ushort bx, by; private float px, py; private int value; private BlockMesh mesh; private float complexity; public override MapNode[] Nexts { get { return nextnodes; } } public BlockMesh Mesh { get { return mesh; } } public int BX { get { return bx; } } public int BY { get { return by; } } public float PosX { get { return px; } } public float PosY { get { return py; } } //public bool Blocked { get { return bitset.Get(0); } private set { bitset.Set(0, value); } } //public bool IsAllCross { get { return bitset.Get(1); } private set { bitset.Set(1, value); } } public bool Blocked { get { return mBlocked; } private set { mBlocked = value; } } public bool IsAllCross { get { return mAllCross; } private set { mAllCross = value; } } public byte AreaValue { get { return area; } } public int Value { get { return value; } } public MMapNode() { s_active_object_count++; } ~MMapNode() { s_active_object_count--; } internal void Init(MTerrain map, int x, int y) { this.bx = (ushort)x; this.by = (ushort)y; this.px = bx * map.map_data.CellW + map.map_data.CellW / 2; this.py = by * map.map_data.CellH + map.map_data.CellH / 2; this.value = map.map_data.GetValue(BX, BY); //this.Blocked = map.map_data.TestBlock(BX, BY); this.Blocked = map.map_data.TestBlock(BX, BY); } public override void Dispose() { mesh = null; nextnodes = null; OnResetValue = null; } internal bool resetValue(MTerrain mmap) { this.value = mmap.map_data.GetValue(BX, BY); var block = mmap.map_data.TestBlock(BX, BY); if (this.Blocked != block) { this.Blocked = block; if (OnResetValue != null) { OnResetValue.Invoke(this); } return true; } return false; } internal void resetNextNodes(MTerrain mmap) { this.mesh = BlockMesh.CreateMesh(bx, by, mmap); if (Blocked) { this.nextnodes = ZeroNexts; this.IsAllCross = false; this.complexity = 0; } else { int[][] near_table = GetNearTables(mmap.is_inclined); using (var nexts = ListObjectPool.AllocAutoRelease()) { foreach (int[] offset in near_table) { int dx = bx + offset[0]; int dy = by + offset[1]; if (dx >= 0 && dx < mmap.xcount && dy >= 0 && dy < mmap.ycount) { MMapNode near = mmap.getMapNode(dx, dy); if (near != null && !near.Blocked) { nexts.Add(near); } } } this.nextnodes = nexts.ToArray(); } this.IsAllCross = (near_table.Length == nextnodes.Length); this.complexity = mmap.manhattan.cell_sqrt * (near_table.Length - nextnodes.Length); } } public override bool TestCross(MapNode father) { return !Blocked; } public override float GetG(MapNode target) { MMapNode t = (MMapNode)target; float ndx = this.bx - t.bx; float ndy = this.by - t.by; //sqrt (ndx * ndx + ndy * ndy)// return (float)Math.Sqrt((ndx * ndx) + (ndy * ndy)) + this.complexity; } public override float GetH(MapNode father) { if (father == this) return 0; MMapNode t = (MMapNode)father; if (this.bx != t.bx && this.by != t.by) { //sqrt (1 * 1 + 1 * 1)// return SQRT_TOW + t.complexity;// SQRT_TOW; } return SQRT_ONE + t.complexity; } private readonly static float SQRT_TOW = (float)Math.Sqrt(2); private readonly static float SQRT_ONE = 1; //---------------------------------------------------------------------------------------------------------------------------- /// /// 和矩形碰撞 /// /// /// /// /// /// public bool TouchRect(float x1, float y1, float x2, float y2) { return (mesh != null && mesh.TouchRect(x1, y1, x2, y2)); } /// /// 和线段检测碰撞 /// /// /// /// /// /// /// public bool TouchLine(float x1, float y1, float x2, float y2) { return (mesh != null && mesh.TouchLine(x1, y1, x2, y2)); } /// /// 获得线段和此碰撞最近的焦点 /// /// public bool GetLineTouchPoint(float sx, float sy, float dx, float dy, out float touch_x, out float touch_y, out float touch_distance) { if (mesh != null) { return mesh.GetLineTouchPoint(sx, sy, dx, dy, out touch_x, out touch_y, out touch_distance); } touch_x = 0; touch_y = 0; touch_distance = 0; return false; } /// /// 单元格碰撞网格 /// public class BlockMesh { /// /// 实例数量 /// public static int ActiveObjectCount { get { return s_active_object_count.Value; } } private static AtomicInteger s_active_object_count = new AtomicInteger(0); private BlockMesh() { s_active_object_count++; } ~BlockMesh() { s_active_object_count--; } private BitSet8 c_block = new BitSet8(0xFF); private CommonLang.Geometry.Vector2 c_point_TL; private CommonLang.Geometry.Vector2 c_point_TR; private CommonLang.Geometry.Vector2 c_point_BR; private CommonLang.Geometry.Vector2 c_point_BL; private bool c_block_T { get { return c_block.Get(0); } set { c_block.Set(0, value); } } private bool c_block_L { get { return c_block.Get(1); } set { c_block.Set(1, value); } } private bool c_block_R { get { return c_block.Get(2); } set { c_block.Set(2, value); } } private bool c_block_B { get { return c_block.Get(3); } set { c_block.Set(3, value); } } public bool IsTestTop { get { return c_block_T; } } public bool IsTestLeft { get { return c_block_L; } } public bool IsTestRight { get { return c_block_R; } } public bool IsTestBottom { get { return c_block_B; } } internal static BlockMesh CreateMesh(int bx, int by, MTerrain mmap) { bool c_block_L = mmap.touchMapBlock(bx - 1, by); bool c_block_R = mmap.touchMapBlock(bx + 1, by); bool c_block_T = mmap.touchMapBlock(bx, by - 1); bool c_block_B = mmap.touchMapBlock(bx, by + 1); // 四周全部阻挡,忽略 // if (c_block_L && c_block_R && c_block_T && c_block_B) { return null; } // 四周全部非阻挡,忽略 // if (!c_block_L && !c_block_R && !c_block_T && !c_block_B) { return null; } BlockMesh ret = new BlockMesh(); float cellw = mmap.map_data.CellW; float cellh = mmap.map_data.CellH; float c_sx = bx * cellw; float c_sy = by * cellh; float c_dx = c_sx + cellw; float c_dy = c_sy + cellh; ret.c_point_TL = new CommonLang.Geometry.Vector2(c_sx, c_sy); ret.c_point_TR = new CommonLang.Geometry.Vector2(c_dx, c_sy); ret.c_point_BR = new CommonLang.Geometry.Vector2(c_dx, c_dy); ret.c_point_BL = new CommonLang.Geometry.Vector2(c_sx, c_dy); ret.c_block_L = c_block_L; ret.c_block_R = c_block_R; ret.c_block_T = c_block_T; ret.c_block_B = c_block_B; return ret; } /// /// 和矩形碰撞 /// /// /// /// /// /// public bool TouchRect(float x1, float y1, float x2, float y2) { return CMath.intersectRect(c_point_TL.X, c_point_TL.Y, c_point_BR.X, c_point_BR.Y, x1, y1, x2, y2); } /// /// 和线段检测碰撞 /// /// public bool TouchLine(float x1, float y1, float x2, float y2) { // T if (c_block_T && CMath.intersectLine(c_point_TL.X, c_point_TL.Y, c_point_TR.X, c_point_TR.Y, x1, y1, x2, y2)) { return true; } // L if (c_block_L && CMath.intersectLine(c_point_TL.X, c_point_TL.Y, c_point_BL.X, c_point_BL.Y, x1, y1, x2, y2)) { return true; } // R if (c_block_R && CMath.intersectLine(c_point_TR.X, c_point_TR.Y, c_point_BR.X, c_point_BR.Y, x1, y1, x2, y2)) { return true; } // B if (c_block_B && CMath.intersectLine(c_point_BL.X, c_point_BL.Y, c_point_BR.X, c_point_BR.Y, x1, y1, x2, y2)) { return true; } return false; } /// /// 获得线段和此碰撞最近的焦点 /// /// public bool GetLineTouchPoint(float sx, float sy, float dx, float dy, out float touch_x, out float touch_y, out float touch_distance) { CommonLang.Geometry.Vector2 p0 = new CommonLang.Geometry.Vector2(sx, sy); CommonLang.Geometry.Vector2 p1 = new CommonLang.Geometry.Vector2(dx, dy); CommonLang.Geometry.Vector2 touch = p0; CommonLang.Geometry.Vector2 min_p = p0; float min_d = float.MaxValue; bool ret = false; // T if (c_block_T && LineLineIntersect(ref p0, ref p1, ref c_point_TL, ref c_point_TR, ref touch, ref min_p, ref min_d)) { ret = true; } // R if (c_block_R && LineLineIntersect(ref p0, ref p1, ref c_point_TR, ref c_point_BR, ref touch, ref min_p, ref min_d)) { ret = true; } // B if (c_block_B && LineLineIntersect(ref p0, ref p1, ref c_point_BL, ref c_point_BR, ref touch, ref min_p, ref min_d)) { ret = true; } // L if (c_block_L && LineLineIntersect(ref p0, ref p1, ref c_point_TL, ref c_point_BL, ref touch, ref min_p, ref min_d)) { ret = true; } touch_x = min_p.X; touch_y = min_p.Y; touch_distance = min_d; return ret; } public void ToLines(List ret) { if (c_block_T) { ret.Add(new CommonLang.Geometry.Line2(c_point_TL, c_point_TR)); } if (c_block_R) { ret.Add(new CommonLang.Geometry.Line2(c_point_TR, c_point_BR)); } if (c_block_B) { ret.Add(new CommonLang.Geometry.Line2(c_point_BL, c_point_BR)); } if (c_block_L) { ret.Add(new CommonLang.Geometry.Line2(c_point_TL, c_point_BL)); } } private bool LineLineIntersect( ref CommonLang.Geometry.Vector2 sp0, ref CommonLang.Geometry.Vector2 sp1, ref CommonLang.Geometry.Vector2 dp0, ref CommonLang.Geometry.Vector2 dp1, ref CommonLang.Geometry.Vector2 out_touch, ref CommonLang.Geometry.Vector2 out_min_p, ref float out_min_d) { if (CommonLang.Geometry.CollisionMath.LineLineIntersect(sp0, sp1, dp0, dp1, out out_touch)) { float d = (out_touch - sp0).LengthSquared(); if (d < out_min_d) { out_min_p = out_touch; out_min_d = d; return true; } } return false; } } } /// /// 曼哈顿寻路路点 /// public class MWayPoint : WayPoint, IEnumerable { /// /// 实例数量 /// public static int ActiveObjectCount { get { return s_active_object_count.Value; } } private static AtomicInteger s_active_object_count = new AtomicInteger(0); private float _px, _py; private bool _center; public int BX { get; private set; } public int BY { get; private set; } public MWayPoint Next { get { return base.next as MWayPoint; } } public MWayPoint Tail { get { return base.tail as MWayPoint; } } public float PosX { get { return _px; } } public float PosY { get { return _py; } } public bool IsCenter { get { return _center; } } internal MWayPoint(MMapNode node) : base(node) { s_active_object_count++; this.BX = node.BX; this.BY = node.BY; this._px = node.PosX; this._py = node.PosY; this._center = true; } ~MWayPoint() { s_active_object_count--; } internal void SetPos(float x, float y) { this._px = x; this._py = y; this._center = (_px == (node as MMapNode).PosX && _py == (node as MMapNode).PosY); } public override void Dispose() { base.Dispose(); } public override WayPoint Clone() { var ret = new MWayPoint(this.node as MMapNode); ret._px = this._px; ret._px = this._px; if (this.next != null) { ret.LinkNext(this.next.Clone()); } return ret; } public float GetTotalDistance() { float ret = 0; MWayPoint cur = this; while (cur != null) { MWayPoint nex = cur.Next; if (cur != null && nex != null) { ret += CMath.getDistance(cur.PosX, cur.PosY, nex.PosX, nex.PosY); } cur = nex; } return ret; } #region IEnumerable IEnumerator IEnumerable.GetEnumerator() { return new Iterator(this); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return new Iterator(this); } private struct Iterator : IEnumerator { private MWayPoint root; private MWayPoint current; public MWayPoint Current { get { return current; } } object System.Collections.IEnumerator.Current { get { return current; } } public Iterator(MWayPoint root) { this.root = root; this.current = null; } public void Dispose() { this.current = null; } public bool MoveNext() { if (current == null) { this.current = root; } else { this.current = current.Next; } return current != null; } public void Reset() { this.current = null; } } #endregion } } }