-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPathfinding.cpp
More file actions
266 lines (220 loc) · 5.64 KB
/
Pathfinding.cpp
File metadata and controls
266 lines (220 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
// ---------------------------------------------------------------------
// Pathfinding Implementation
// ---------------------------------------------------------------------
#include "Pathfinding.h"
#include <iostream>
// Namespace use
using namespace std;
using namespace CoreStructures;
// ---------------------------------------------------------------------
// PRIVATE
// ---------------------------------------------------------------------
// Set start and end nodes
void Pathfinding::SetStartAndEnd(Node startNode, Node endNode)
{
//Create start and end cells
start = new Node( startNode.x, startNode.z, NULL);
end = new Node( endNode.x, endNode.z, &endNode );
start->G = NULL; // we havent moved so this is 0
start->H = start->EuclidianDistance( end ); // set the hueristic to the end goal
start->parent = NULL; // just started, has no parent
// place the start node on the open list ready for inquiry
open.push_back(start);
}
// Path Opened
void Pathfinding::PathOpened(int x, int z, float newCost, Node* parent)
{
// If cell block function is not initialised,
// output error
if(isCellBlocked(x, z))
{
return;
}
// z * ( number of cell in a column/row ) + number of x cells - gives a sequential block number for a grid of WORLD_SIZE * WORLD_SIZE
int id = z * WORLD_SIZE + x;
for( int i = 0; i < closed.size(); i++ )
{
// if the cell is already in the visited list, abort
if( id == closed[i]->ID )
{
return;
}
}
// If the cell is not blocked or already in the visited list then continue
Node* newChild = new Node(x, z, parent);
newChild->G = newCost;
newChild->H = parent->EuclidianDistance(end);
// for all open list cells
for( int i = 0; i < open.size(); i++ )
{
if( id == open[i]->ID )
{
float newF = newChild->G + newCost + open[i]->H;
if( open[i]->getF() > newF )
{
open[i]->G = newChild->G + newCost;
open[i]->parent = newChild;
}
else // if F is not better
{
delete newChild;
return;
}
}
}
open.push_back(newChild);
}
// Get the next best node in the path
Node* Pathfinding::GetNextNode()
{
float bestF = 999999.0f; // need a default high value to get next best in path and 'start the ball rolling'
int nodeIndex = -1;
Node* nextNode = NULL;
// Find next best cell
for( int i = 0; i < open.size(); i ++ )
{
if( open[i]->getF() < bestF )
{
bestF = open[i]->getF();
nodeIndex = i;
}
}
// Update lists for best cell
if( nodeIndex >= 0 )
{
nextNode = open[nodeIndex]; // grab the best cell from the above index
closed.push_back(nextNode); // add it to the visited(closed) list
open.erase(open.begin() + nodeIndex); // remove it from the open list
}
return nextNode;
}
// Continue path
void Pathfinding::ContinuePath()
{
if( open.empty() )
{
return;
}
Node* currentNode = GetNextNode();
if(currentNode->ID == end->ID)
{
end->parent = currentNode->parent;
Node* getPath;
// gets the shortest path to the goal
for(getPath = end; getPath != NULL; getPath = getPath->parent)
{
path.push_back( new GUVector4( getPath->x, 0, getPath->z ) );
}
endFound = true;
current = path.size() - 1;
return;
}
else
{
// South Node
PathOpened( currentNode->x, currentNode->z + 1, currentNode->G + 1, currentNode );
// East Node
PathOpened( currentNode->x + 1, currentNode->z, currentNode->G + 1, currentNode );
// North Node
PathOpened( currentNode->x, currentNode->z - 1, currentNode->G + 1, currentNode );
// West Node
PathOpened( currentNode->x - 1, currentNode->z, currentNode->G + 1, currentNode );
for( int i = 0; i < open.size(); i++ )
{
if( currentNode->ID == open[i]->ID )
{
open.erase( open.begin() + i );
}
}
// Continue until full path is found
ContinuePath();
}
}
// ---------------------------------------------------------------------
// PUBLIC
// ---------------------------------------------------------------------
// Constructor
Pathfinding::Pathfinding()
{
startInitComplete = 0;
endFound = 0;
current = 0;
}
// Deconstructor
Pathfinding::~Pathfinding()
{
// EMPTY
}
// Find Path
void Pathfinding::FindPath(GUVector4 currentPos, GUVector4 endPos)
{
// if the start and end goal are not initialised
if( !startInitComplete )
{
// loop through open list and delete (if any) all items
for( int i = 0; i < open.size(); i++ )
{
delete open[i];
}
// Clear open list
open.clear();
// loop through visited list and delete (if any) all items
for( int i = 0; i < closed.size(); i++ )
{
delete closed[i];
}
// Clear closed list
closed.clear();
// loop through path list and delete (if any) all items
for( int i = 0; i < path.size(); i++ )
{
delete path[i];
}
// Clear path list
path.clear();
// Initialise start
Node sNode;
sNode.x = currentPos.x;
sNode.z = currentPos.z;
// Initialise goal
Node eNode;
eNode.x = endPos.x;
eNode.z = endPos.z;
SetStartAndEnd( sNode, eNode );
// Start initialisation complete
startInitComplete = 1;
}
//If start and end goal are initialised then continue the path
if(startInitComplete)
{
ContinuePath();
}
}
// Reset path
void Pathfinding::ResetPath()
{
current = path.size() - 1;
}
// Next Path Position
GUVector4 Pathfinding::GetNextPosition()
{
GUVector4 nextPos = GUVector4(19.0, 0.0, 19.0);
if(path.size())
{
if(current > 0)
{
nextPos = GUVector4(path[current]->x, 0, path[current]->z);
current -= 1;
}
else
nextPos = GUVector4(path[0]->x, 0, path[0]->z);
}
return nextPos;
}
// Attach checker function
void Pathfinding::attachMapCheck(checkMap func)
{
// This function is used to attach a map checker function,
// allowing the algorithm to be portable and encapsulated.
isCellBlocked = func;
}