/// <summary> /// Adds a Node to teh Heap /// </summary> /// <param name="d">A node used on the heap</param> public void Add(HeapNode d) { switch (this.direction) { case HeapDirection.LowPriority: { int i = this.length; int id2 = i / 2; while (i > 1 && this.list[id2].Priority > d.Priority) { this.list[i] = this.list[id2]; i = id2; id2 = i / 2; } this.list[i] = d; this.length++; break; } } }
/// <summary> /// Removes a Node from the Heap with the highest prioroty /// </summary> /// <returns>Returns a HeapNode object</returns> public HeapNode Remove() { switch (this.direction) { case HeapDirection.LowPriority: { if (this.length == 1) { return(null); } int j, i = 1; HeapNode d = this.list[1]; int hl1 = this.length - 1; int hl12 = hl1 / 2; HeapNode tmp = this.list[hl1]; while (i <= hl12) { j = i + i; if ((j < hl1) && this.list[j].Priority > this.list[j + 1].Priority) { j++; } if (this.list[j].Priority >= tmp.Priority) { break; } this.list[i] = this.list[j]; i = j; } this.list[i] = tmp; this.length--; return(d); } } return(null); }
/// <summary> /// Finds a Path to teh given Destination /// </summary> /// <param name="DestinationX">The destinations X System.Drawing.Point</param> /// <param name="DestinationY">The destinations Y System.Drawing.Point</param> /// <param name="StartX">The starting X System.Drawing.Point</param> /// <param name="StartY">The starting Y System.Drawing.Point</param> /// <returns>A Path object containg the Path's Coordinates</returns> public Path FindPath(int DestinationX, int DestinationY, int StartX, int StartY) { System.Drawing.Point dest = new System.Drawing.Point(DestinationX - this.map.X, DestinationY - this.map.Y); System.Drawing.Point start = new System.Drawing.Point(StartX - this.map.X, StartY - this.map.Y); double newg = 0; int cx = 0; int cy = 0; Node node; int vxvy; Node cnode; bool done = false; Heap openqueue = new Heap(500000, HeapDirection.LowPriority); //Node Array Node[,] ng = new Node[this.map.SizeX, this.map.SizeY]; Node enode = new Node(dest.X, dest.Y, false, false, null, 0, 0); Node snode = new Node(start.X, start.Y, false, true, null, 0, Distance.DiagShortcut(dest, start) * this.patherconfig.Factor); ng[snode.X, snode.Y] = snode; openqueue.Add(new HeapNode(snode, snode.F)); while (!done) { //Game.Print("In loop"); HeapNode tn = openqueue.Remove(); if (tn == null) { break; } node = (Node)tn.Item; if (node.X == enode.X && node.Y == enode.Y) { done = true; this.LastScore = node.F; //if(_reduc == 99) // return node.f; //BUILD PATH USING REFRENCED PARENTS //var donebuild = false; ArrayList ptd = new ArrayList(); ArrayList fp = new ArrayList(); ptd.Add(node); if (((Node)ptd[ptd.Count - 1]).Parent != null) { do { ptd.Add(((Node)ptd[ptd.Count - 1]).Parent); if (((Node)ptd[ptd.Count - 1]).Parent == null) { break; } } while (true); } //Adding padding for (int p = 0; p < ptd.Count; p++) { for (int px = -1; px < 2; px++) { for (int py = -1; py < 2; py++) { if ((px * py) != 0 && (px != 0 && py != 0)) { continue; //continue if diagonal or same coordinate } if (!this.map.IsWalkable(((Node)ptd[p]).X + px + this.map.X, ((Node)ptd[p]).Y + py + this.map.Y)) { ((Node)ptd[p]).X += (px * (-1)); // changed ((Node)ptd[p]).Y to ((Node)ptd[p]).X ((Node)ptd[p]).Y += (py * (-1)); } } } } //reverse the path now so we can work with it from start and reduce the points double vecanglelast = 0; double vecanglenew = 0; double vecdistance = 0; for (int d = ptd.Count - 1; d >= 0; d--) { if (d == ptd.Count - 1 && d > 0) { //add first point always fp.Add(ptd[d]); if (this.patherconfig.ReductionType == Reduction.WalkingReduction) { vecanglelast = Distance.GetAngle(((Node)fp[fp.Count - 1]).X, ((Node)fp[fp.Count - 1]).Y, ((Node)ptd[d - 1]).X, ((Node)ptd[d - 1]).Y); } else { vecanglelast = 0; } continue; } if (d == 0) { //add last point always fp.Add(ptd[d]); break; } if (this.patherconfig.ReductionType == Reduction.WalkingReduction) { vecanglenew = Distance.GetAngle(((Node)fp[fp.Count - 1]).X, ((Node)fp[fp.Count - 1]).Y, ((Node)ptd[d]).X, ((Node)ptd[d]).Y); } else { vecanglenew = 0; } vecdistance = Distance.Euclidian(((Node)fp[fp.Count - 1]).X, ((Node)fp[fp.Count - 1]).Y, ((Node)ptd[d]).X, ((Node)ptd[d]).Y); if (vecanglenew != vecanglelast || vecdistance > this.patherconfig.PathPointDistance) { fp.Add(ptd[d]); if (this.patherconfig.ReductionType == Reduction.WalkingReduction) { vecanglelast = Distance.GetAngle(((Node)fp[fp.Count - 1]).X, ((Node)fp[fp.Count - 1]).Y, ((Node)ptd[d - 1]).X, ((Node)ptd[d - 1]).Y); } else { vecanglelast = 0; } continue; } } this.path = new Path(); //Put the offset back in and move to path for (int d = 0; d < fp.Count; d++) { this.path.CoordinateList.Add(new System.Drawing.Point(((Node)fp[d]).X + this.map.X, ((Node)fp[d]).Y + this.map.Y)); } // print("OUT mlmap FindPath"); return(this.path); } else { // look for adjacent blocks that we attach to and add them to open for (int vy = -1; vy < 2; vy++) { for (int vx = -1; vx < 2; vx++) { if (vx == 0 && vy == 0) { continue; //continue if we are on the current node } cx = node.X + vx; cy = node.Y + vy; //Game.Print("cx, cy: " + cx.ToString() + ", " + cy.ToString()); vxvy = vx * vy; //check for map edge if (cy < 0 || cy > this.map.SizeY - 1 || cx < 0 || cx > this.map.SizeX - 1) { continue; } //check for walkability and small diagonal gaps that cant be passed if ((this.map.CollisionData[cx, cy] & 1) > 0) { continue; } //CHANGED 02-10-2004 as a test (commented out extra checks) if (vxvy != 0 && ((this.map.CollisionData[node.X, cy] & 1) > 0) && ((this.map.CollisionData[cx, node.Y] & 1) > 0)) { continue; } //if ((AreaData[cy][cx+1] & 1) || (AreaData[cy][cx-1] & 1) || // (AreaData[cy+1][cx] & 1) || (AreaData[cy-1][cx] & 1)) continue; //if (((AreaData[cy][cx+1] & 1) && (AreaData[cy][cx-1] & 1)) || // ((AreaData[cy+1][cx] & 1) && (AreaData[cy-1][cx] & 1))) continue; newg = node.G + SCORE[Math.Abs(vxvy)]; cnode = ng[cx, cy]; if (cnode == null) { cnode = new Node(cx, cy, false, false, node, newg, Distance.DiagShortcut(dest.X, dest.Y, cx, cy) * this.patherconfig.Factor); ng[cx, cy] = cnode; } else { if (cnode.G > newg) { cnode.IsClosed = false; cnode.G = newg; cnode.Parent = node; } else { continue; } } if (!cnode.IsOpen) { cnode.IsOpen = true; openqueue.Add(new HeapNode(cnode, cnode.F)); //AreaData[cnode.y][cnode.x] |= 0x200000; } } } node.IsOpen = false; node.IsClosed = true; //AreaData[node.y][node.x] |= 0x100000; } } throw new ApplicationException("Could not find a path to destination"); }