Code:
using NexusAPI;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace API_ROOMS.Classes.Pathfinding
{
public static class Pathfinder
{
private static short[,] mapping = new short[8, 2] { { 0, -1 }, { 0, 1 }, { -1, 0 }, { 1, 0 }, { -1, -1 }, { 1, -1 }, { -1, 1 }, { 1, 1 } };
// be aware that this function will terminate the thread!
public static ConcurrentQueue<Coord> calculate(Coord start, Coord end, HeightMapData[,] data)
{
try
{
ConcurrentDictionary<Coord, PathfinderNode> openNodes = new ConcurrentDictionary<Coord, PathfinderNode>();
ConcurrentDictionary<Coord, PathfinderNode> closedNodes = new ConcurrentDictionary<Coord, PathfinderNode>();
PathfinderNode processingNode = new PathfinderNode() { location = start };
closedNodes.TryAdd(processingNode.location, processingNode);
do
{
ConcurrentBag<Coord> nodeChilds = processingNode.location.getChilds(Pathfinder.mapping);
foreach (Coord child in nodeChilds)
{
if (child.x < 0 || child.y < 0 || child.x >= data.GetLength(0) || child.y >= data.GetLength(1))
{
continue;
}
if (closedNodes.ContainsKey(child))
{
continue;
}
HeightMapData childData = data[child.x, child.y];
if (childData.state == TileState.BLOCKED)
{
continue;
}
PathfinderNode node = null;
if (!openNodes.TryGetValue(child, out node))
{
node = new PathfinderNode();
node.location = child;
node.parent = processingNode;
node.H = manhattanHeuristic(child, end);
node.G = pythagoras(child, start);
bool added = openNodes.TryAdd(node.location, node);
}
else
{
int gCheck = processingNode.G + pythagoras(processingNode.location, node.location);
if (gCheck < node.G)
{
node.G = gCheck;
node.parent = processingNode;
}
}
}
PathfinderNode removeNode;
bool remove = openNodes.TryRemove(processingNode.location, out removeNode);
if (remove)
{
bool moved = closedNodes.TryAdd(removeNode.location, removeNode);
}
PathfinderNode nextNode = openNodes.Values.OrderBy(obj => obj.G).OrderBy(obj => obj.F).FirstOrDefault();
if (nextNode != null)
{
processingNode = nextNode;
}
else
{
return null;
}
}
while (processingNode != null && processingNode.location != end);
ConcurrentBag<Coord> output = new ConcurrentBag<Coord>() { processingNode.location };
PathfinderNode tracingNode = processingNode;
do
{
PathfinderNode parentNode = tracingNode.parent;
if (parentNode.location == start)
{
break;
}
output.Add(parentNode.location);
tracingNode = parentNode;
}
while (tracingNode != null && tracingNode.location != start);
return new ConcurrentQueue<Coord>(output);
}
catch (Exception ex)
{
ApplicationPool.handleException(ex);
}
return null;
}
public static int getRotation(Coord a, Coord b)
{
try
{
float xDiff = b.x - a.x;
float yDiff = b.y - a.y;
double angle = Math.Atan2(yDiff, xDiff) * 180 / Math.PI;
double absolute = Math.Abs(angle);
switch ((int)angle)
{
default:
case -135:
return 7;
case -180:
return 8;
case -90:
return 0;
case -45:
return 1;
case 0:
return 2;
case 45:
return 3;
case 90:
return 4;
case 135:
return 5;
case 180:
return 6;
}
}
catch (Exception ex)
{
ApplicationPool.handleException(ex);
}
return 0;
}
private static int pythagoras(Coord a, Coord b)
{
double quad1 = Math.Pow(Math.Abs(a.x - b.x), 2.0),
quad2 = Math.Pow(Math.Abs(a.y - b.y), 2.0);
double pythagoras = Math.Sqrt(quad1 + quad2) * 10;
//pythagoras = Math.Floor(pythagoras / 10) * 10;
return Convert.ToInt32(pythagoras);
}
private static int manhattanHeuristic(Coord a, Coord b)
{
int ab1 = a.x - b.x,
ab2 = a.y - b.y;
int heuristic = Math.Abs(ab1) + Math.Abs(ab2);
return heuristic;
}
}
public class PathfinderNode
{
public Coord location;
public PathfinderNode parent;
public int G;
public int H;
public int F
{
get
{
return G + H;
}
}
}
public struct Coord
{
public int x, y;
public Coord(int x, int y)
{
this.x = x;
this.y = y;
}
public static Coord Empty
{
get
{
return new Coord(-1, -1);
}
}
public static bool operator ==(Coord a, Coord b)
{
return a.x == b.x && a.y == b.y;
}
public static bool operator !=(Coord a, Coord b)
{
return a.x != b.x || a.y != b.y;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public override bool Equals(object obj)
{
try
{
if (obj is Coord)
{
Coord coord = (Coord)obj;
return coord.x == this.x && coord.y == this.y;
}
return obj == (object)this;
}
catch (Exception ex)
{
ApplicationPool.handleException(ex);
}
return false;
}
public ConcurrentBag<Coord> getChilds(short[,] mapping)
{
try
{
ConcurrentBag<Coord> output = new ConcurrentBag<Coord>();
for (short i = 0; i < mapping.GetLength(0); i++)
{
int x = (this.x + mapping[i, 0]);
int y = (this.y + mapping[i, 1]);
Coord coord = new Coord(x, y);
output.Add(coord);
// check height ..
}
return output;
}
catch (Exception ex)
{
ApplicationPool.handleException(ex);
}
return null;
}
}
}
The new pathfinder code. (needs cleanup)