Hi, all. First note: If you spend the time to read this post, you have my respect. If you take the time to locate the error, you rock.
So, after about 20 hours of research and four failed attempts, I managed to produce the below script (you’ll have to copy it into your favorite code editor for it to make any sense, the styling on here is awful):
using UnityEngine;
using System.Collections;
public class SmartMove : MonoBehaviour {
public Transform[] CalculatePath(Transform startingNode, Transform destinationNode) {
Node startNode = startingNode.GetComponent<Node>();
Node endNode = destinationNode.GetComponent<Node>();
startNode.G = 0;
startNode.H = EuclideanHeuristic(startingNode, destinationNode);
startNode.F = startNode.H;
Hashtable openList = new Hashtable();
Hashtable closedList = new Hashtable();
openList.Add("startNode", startingNode);
string currentNodeString;
while(1 > 0) {
currentNodeString = ReturnLowestF(openList);
SwitchList(currentNodeString, openList, closedList);
Transform currentNodeObject = (Transform)closedList[currentNodeString];
Node currentNode = currentNodeObject.GetComponent<Node>();
Transform[] children = currentNode.children;
foreach(Transform child in children) {
if(child!=null) {
Node childNode = child.GetComponent<Node>();
if(childNode.isWalkable !closedList.ContainsValue(child)) {
if(!openList.ContainsValue(child)) {
openList.Add((Random.value*Random.value + Time.deltaTime).ToString(), child);
childNode.G = currentNode.G+childNode.movementCost;
childNode.H = EuclideanHeuristic(child, destinationNode);
childNode.F = childNode.G + childNode.H;
childNode.parent = currentNodeObject;
}
if(openList.ContainsValue(child)) {
float tempG = currentNode.G + childNode.movementCost;
if(tempG < currentNode.G) {
childNode.parent = currentNodeObject;
childNode.G = currentNode.G + childNode.movementCost;
childNode.F = childNode.G + childNode.H;
}
}
}
}
}
if(closedList.ContainsValue(destinationNode))
break;
if (openList.Count == 0)
break;
}
Hashtable pathNodes = new Hashtable();
Node currentPathNode = endNode;
int i = 0;
while(1>0) {
if (currentPathNode.parent==null)
break;
pathNodes.Add(i, currentPathNode.GetComponent<Transform>());
currentPathNode = currentPathNode.parent.GetComponent<Node>();
i++;
}
Transform[] path = new Transform[pathNodes.Count];
pathNodes.Values.CopyTo(path, 0);
return path;
}
string ReturnLowestF(Hashtable list) {
float lowestF = Mathf.Pow(10,100);
string lowestKey = "ah";
foreach(DictionaryEntry currentEntry in list) {
Transform currentEntryObject = (Transform)list[currentEntry.Key];
float currentF = currentEntryObject.GetComponent<Node>().F;
if (lowestF == 0)
lowestF = currentF;
if (currentF < lowestF lowestF != 0) {
lowestF = currentF;
lowestKey = (string)currentEntry.Key;
}
}
return lowestKey;
}
bool CheckAgainstList(Hashtable list, Transform searchItem) {
bool isOnList = false;
foreach(DictionaryEntry currentEntry in list) {
if((Transform)list[currentEntry.Key]==searchItem) {
isOnList = true;
}
}
return isOnList;
}
void RemoveFromList(Hashtable list, string key) {
list.Remove(key);
}
void SwitchList(string key, Hashtable listToRemoveFrom, Hashtable listToAddTo) {
listToAddTo.Add(key, listToRemoveFrom[key]);
listToRemoveFrom.Remove(key);
}
float EuclideanHeuristic(Transform start, Transform end) {
float distance = Mathf.Sqrt(Mathf.Pow((start.transform.position.x - end.transform.position.x),2)
+ Mathf.Pow((start.transform.position.z - end.transform.position.z),2));
return distance;
}
}
Here’s where I call the function from (again, copy into code editor of choice):
public SmartMove smartMove;
public Transform pathEndNode;
public Transform pathStartNode;
public Transform[] path;
void Update () {
if(Input.GetButtonDown("Fire1")) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast (ray, out hit)) {
pathStartNode = hit.collider.transform;
path = new Transform[0];
}
}
if(Input.GetButtonUp("Fire1")) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast (ray, out hit)) {
pathEndNode = hit.collider.transform;
path = smartMove.CalculatePath(pathStartNode, pathEndNode);
}
}
}
Now, when I run my program, everything works fine. The first time I calculate a path (click, drag, release) it calculates fine and I get my path. The second time, however, Unity crashes. I’ve spent so long on this script, I feel like I just need somebody else to scan it really quick and point out the error. It’s unoptimized, messy, and uncommented, so if you don’t feel like reading it that’s fine. If you do, though, you’ll have my eternal gratitude.
Thanks a lot, Havoc