I have a pathfinder program using A* that i made following a tutorial. It works fine until i tried to make it multithread using async Task. The Thread works and the path is calculated, but when the path result is being passed to the Unit object, for some resaon only one or two Unit that receive the path array. where did i do wrong ?
ThreadRequestManager :
public class ThreadRequestManager : MonoBehaviour {
Queue<PathResult> results = new Queue<PathResult>();
static ThreadRequestManager instance;
ThreadPathfinding pathfinding;
private void Awake()
{
instance = this;
pathfinding = GetComponent<ThreadPathfinding>();
}
private void Update()
{
if (results.Count > 0)
{
int itemsInQueue = results.Count;
lock (results)
{
for(int i = 0; i < itemsInQueue; i++)
{
PathResult result = results.Dequeue();
result.callback(result.path, result.success);
}
}
}
}
public static async Task RequestPath(PathRequest request)
{
await Task.Run(() => instance.pathfinding.FindPath(request, instance.FinishedProcessingPath));
}
public void FinishedProcessingPath(PathResult result)
{
lock(results)
{
results.Enqueue(result);
}
}
}
public struct PathResult
{
public Vector3[] path;
public bool success;
public Action<Vector3[], bool> callback;
public PathResult(Vector3[] path, bool success, Action<Vector3[], bool> callback)
{
this.path = path;
this.success = success;
this.callback = callback;
}
}
public struct PathRequest
{
public Vector3 pathStart;
public Vector3 pathEnd;
public Action<Vector3[], bool> callback;
public PathRequest(Vector3 _start, Vector3 _end, Action<Vector3[], bool> _callback)
{
pathStart = _start;
pathEnd = _end;
callback = _callback;
}
}
Units :
public class ThreadUnits : MonoBehaviour {
public Transform target;
float speed = .5f;
public Vector3[] path;
int targetIndex;
// Use this for initialization
void Start()
{
ThreadRequestManager.RequestPath(new PathRequest(transform.position, target.position, OnPathFound));
}
public void OnPathFound(Vector3[] newPath, bool pathSuccess)
{
if (pathSuccess)
{
path = newPath;
// FollowPath();
StopCoroutine("FollowPath");
StartCoroutine("FollowPath");
}
}
IEnumerator FollowPath()
{
Vector3 currentWaypoint = path[0];
while (true)
{
if (transform.position == currentWaypoint)
{
targetIndex++;
if (targetIndex >= path.Length)
{
yield break;
}
currentWaypoint = path[targetIndex];
}
transform.position = Vector3.MoveTowards(transform.position, currentWaypoint, speed);
yield return null;
}
}
public void OnDrawGizmos()
{
if (path != null)
{
for (int i = targetIndex; i < path.Length; i++)
{
Gizmos.color = Color.black;
Gizmos.DrawCube(path*, Vector3.one);*
if (i == targetIndex)
{
Gizmos.DrawLine(transform.position, path*);*
}
else
{
Gizmos.DrawLine(path[i - 1], path*);*
}
}
}
}
}
Pathfinder :
public class ThreadPathfinding : MonoBehaviour {
Grid grid;
void Awake()
{
grid = GetComponent();
}
public void FindPath(PathRequest request, Action callback)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Vector3[] waypoint = new Vector3[0];
bool pathSuccess = false;
Node startNode = grid.NodeFromWorldPoint(request.pathStart);
Node targetNode = grid.NodeFromWorldPoint(request.pathEnd);
print(“thread :” + Thread.CurrentThread.ManagedThreadId);
if (startNode.walkable && targetNode.walkable)
{
Heap openSet = new Heap(grid.MaxSize);
HashSet closedSet = new HashSet();
openSet.Add(startNode);
while (openSet.Count > 0)
{
Node currentNode = openSet.RemoveFirst();
closedSet.Add(currentNode);
if (currentNode == targetNode)
{
sw.Stop();
print("path found: " + sw.ElapsedMilliseconds);
pathSuccess = true;
break;
}
foreach (Node neighbour in grid.GetNeighbours(currentNode))
{
if (!neighbour.walkable || closedSet.Contains(neighbour))
{
continue;
}
int newMovCostToNeighhbour = currentNode.gCost + GetDistance(currentNode, neighbour);
if (newMovCostToNeighhbour < neighbour.gCost || !openSet.Contains(neighbour))
{
neighbour.gCost = newMovCostToNeighhbour;
neighbour.hCost = GetDistance(neighbour, targetNode);
neighbour.parent = currentNode;
if (!openSet.Contains(neighbour))
{
openSet.Add(neighbour);
}
else
{
openSet.UpdateItem(neighbour);
}
}
}
}
}
if (pathSuccess)
{
waypoint = RetracePath(startNode, targetNode);
}
callback(new PathResult(waypoint, pathSuccess, request.callback));
}
Vector3[] RetracePath(Node startNode, Node endNode)
{
List path = new List();
Node currentNode = endNode;
while (currentNode != startNode)
{
path.Add(currentNode);
currentNode = currentNode.parent;
}
Vector3[] waypoints = SimplifyPath(path);
Array.Reverse(waypoints);
return waypoints;
}
Vector3[] SimplifyPath(List path)
{
List waypoints = new List();
Vector2 directOld = Vector2.zero;
for (int i = 1; i < path.Count; i++)
{
Vector2 directNew = new Vector2(path[i - 1].gridX - path_.gridX, path[i - 1].gridY - path*.gridY);
if (directNew != directOld)
{
waypoints.Add(path[i-1].worldPosition);
}
directOld = directNew;
}
return waypoints.ToArray();
}*_
int GetDistance(Node nodeA, Node nodeB)
{
int disX = Mathf.Abs(nodeA.gridX - nodeB.gridX);
int disY = Mathf.Abs(nodeA.gridY - nodeB.gridY);
if (disX > disY)
return 14 * disY + 10 * (disX - disY);
return 14 * disX + 10 * (disY - disX);
}
}