Hi guys,
Because i have a lot of nodes, instead of StartCoroutine(), i am trying to use Thread.
I create a Thread for finding shortest path, but seems it blocks the main thread of unity. I said this, because I can’t move my object until my thread finish his job.
Can you help me?
Here is my code:
DRAWPATH
private void Start()
{
PathRequestManager.RequestPath(new PathRequest(StartNode, EndNode, OnPathFound));
}
public void OnPathFound(List<Waypoint> waypoints, bool pathSuccessful)
{
if (pathSuccessful)
{
path = new List<Waypoint>(waypoints);
Line = GetComponent<LineRenderer>();
Line.transform.position = this.transform.position;
Line.positionCount = path.Count;
for (int i = 0; i < path.Count; ++i)
{
Line.SetPosition(i, path[i].transform.position);
}
}
}
private void FixedUpdate()
{
Dijkstra();
}
private void Dijkstra()
{
if ((path.Count > 0) && (GetDistance(path[0].transform.position) < 10))
{
path.Remove(path[0]);
PathRequestManager.RequestPath(new PathRequest(path[0], EndNode, OnPathFound));
}
}
PATH REQUEST MANAGER
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
public class PathRequestManager : MonoBehaviour
{
Queue<PathResult> results = new Queue<PathResult>();
static PathRequestManager instance;
PathFinding pathFinding;
void Awake()
{
instance = this;
pathFinding = GetComponent<PathFinding>();
}
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 void RequestPath(PathRequest request)
{
ThreadStart threadStart = delegate {
instance.pathFinding.FindPath(request, instance.FinishedProcessingPath);
};
threadStart.Invoke();
}
public void FinishedProcessingPath(PathResult result)
{
lock (results)
{
results.Enqueue(result);
}
}
}
public struct PathResult
{
public List<Waypoint> path;
public bool success;
public Action<List<Waypoint>, bool> callback;
public PathResult(List<Waypoint> path, bool success, Action<List<Waypoint>, bool> callback)
{
this.path = path;
this.success = success;
this.callback = callback;
}
}
public struct PathRequest
{
public Waypoint pathStart;
public Waypoint pathEnd;
public Action<List<Waypoint>, bool> callback;
public PathRequest(Waypoint start, Waypoint end, Action<List<Waypoint>, bool> callback)
{
this.pathStart = start;
this.pathEnd = end;
this.callback = callback;
}
}
PATHFINDING
using UnityEngine;
using System.Collections.Generic;
using System.Diagnostics;
using System;
using System.Linq;
public class PathFinding : MonoBehaviour
{
public GameObject Cluster;
public static List<Waypoint> Graph;
private void Awake()
{
Graph = new List<Waypoint>();
foreach (Transform child in Cluster.transform)
{
Graph.Add(child.gameObject.GetComponent<Waypoint>());
}
}
public void FindPath(PathRequest request, Action<PathResult> callback)
{
Vector3[] waypoints = new Vector3[0];
Waypoint startNode = request.pathStart;
Waypoint targetNode = request.pathEnd;
List<Waypoint> shortestPath = Dijsktra(startNode, targetNode);
callback(new PathResult(shortestPath, true, request.callback));
}
public static List<Waypoint> Dijsktra(Waypoint start, Waypoint end)
{
// We don't accept null arguments
if (start == null || end == null)
return null;
// The final path
List<Waypoint> path = new List<Waypoint>();
// If the start and end are same node, we can return the start node
if (start == end)
{
path.Add(start);
return path;
}
// The list of unvisited nodes
List<Waypoint> unvisited = new List<Waypoint>();
// Previous nodes in optimal path from source
Dictionary<Waypoint, Waypoint> previous = new Dictionary<Waypoint, Waypoint>();
// The calculated distances, set all to Infinity at start, except the start Node
Dictionary<Waypoint, float> distances = new Dictionary<Waypoint, float>();
for (int i = 0; i < Graph.Count; i++)
{
Waypoint node;
node = Graph[i];
unvisited.Add(node);
// Setting the node distance to Infinity
distances.Add(node, float.MaxValue);
}
// Set the starting Node distance to zero
distances[start] = 0f;
while (unvisited.Count != 0)
{
// Ordering the unvisited list by distance, smallest distance at start and largest at end
unvisited = unvisited.OrderBy(node => distances[node]).ToList();
// Getting the Node with smallest distance
Waypoint current = unvisited[0];
// Remove the current node from unvisisted list
unvisited.Remove(current);
// When the current node is equal to the end node, then we can break and return the path
if (current == end)
{
// Construct the shortest path
while (previous.ContainsKey(current))
{
// Insert the node onto the final result
path.Insert(0, current);
// Traverse from start to end
current = previous[current];
}
// Insert the source onto the final result
path.Insert(0, current);
break;
}
// Looping through the Node connections (neighbors) and where the connection (neighbor) is available at unvisited list
for (int i = 0; i < current.nodes.Count; i++)
{
Waypoint neighbor = current.nodes[i].waypoint;
// Getting the distance between the current node and the connection (neighbor)
float length = current.nodes[i].Distance;
// The distance from start node to this connection (neighbor) of current node
float fullLength = distances[current] + length;
// A shorter path to the connection (neighbor) has been found
if (fullLength < distances[neighbor])
{
distances[neighbor] = fullLength;
previous[neighbor] = current;
}
}
}
return path;
}
}