void RecalculateHTarget (bool firstTime) {
// When pathsForAll is false
// then no heuristic should be used
if (!pathsForAll) {
heuristic = Heuristic.None;
heuristicScale = 0.0F;
return;
}
// Calculate a new hTarget and rebuild the open list if necessary
// Rebuilding the open list is necessary when the H score for nodes changes
switch (heuristicMode) {
case HeuristicMode.None:
heuristic = Heuristic.None;
heuristicScale = 0F;
break;
case HeuristicMode.Average:
if (!firstTime) return;
// No break
// The first time the implementation
// for Average and MovingAverage is identical
// so we just use fallthrough
goto case HeuristicMode.MovingAverage;
case HeuristicMode.MovingAverage:
// Pick the average position of all nodes that have not been found yet
var avg = Vector3.zero;
int count = 0;
for (int j = 0; j < targetPoints.Length; j++) {
if (!targetsFound[j]) {
avg += (Vector3)targetNodes[j].position;
count++;
}
}
// Should use asserts, but they were first added in Unity 5.1
// so I cannot use them because I want to keep compatibility with 4.6
// (as of 2015)
if (count == 0) throw new System.Exception("Should not happen");
avg /= count;
hTarget = (Int3)avg;
break;
case HeuristicMode.Midpoint:
if (!firstTime) return;
// No break
// The first time the implementation
// for Midpoint and MovingMidpoint is identical
// so we just use fallthrough
goto case HeuristicMode.MovingMidpoint;
case HeuristicMode.MovingMidpoint:
Vector3 min = Vector3.zero;
Vector3 max = Vector3.zero;
bool set = false;
// Pick the median of all points that have
// not been found yet
for (int j = 0; j < targetPoints.Length; j++) {
if (!targetsFound[j]) {
if (!set) {
min = (Vector3)targetNodes[j].position;
max = (Vector3)targetNodes[j].position;
set = true;
} else {
min = Vector3.Min((Vector3)targetNodes[j].position, min);
max = Vector3.Max((Vector3)targetNodes[j].position, max);
}
}
}
var midpoint = (Int3)((min+max)*0.5F);
hTarget = midpoint;
break;
case HeuristicMode.Sequential:
// The first time the hTarget should always be recalculated
// But other times we can skip it if we have not yet found the current target
// since then the hTarget would just be set to the same value again
if (!firstTime && !targetsFound[sequentialTarget]) {
return;
}
float dist = 0;
// Pick the target which is furthest away and has not been found yet
for (int j = 0; j < targetPoints.Length; j++) {
if (!targetsFound[j]) {
float d = (targetNodes[j].position-startNode.position).sqrMagnitude;
if (d > dist) {
dist = d;
hTarget = (Int3)targetPoints[j];
sequentialTarget = j;
}
}
}
break;
}
// Rebuild the open list since all the H scores have changed
// However the first time we can skip this since
// no nodes are added to the heap yet
if (!firstTime) {
RebuildOpenList();
}
}