3
3
#include "ai_local.h"
4
4
5
5
//==========================================
6
- //
7
- //
6
+ // Related data:
7
+ // pLinks - links or connections between nodes loaded from file that are used for pathfinding (determining distance/cost between nodes)
8
+ // nodes - data structures loaded from file that have map coordinates of nodes
8
9
//==========================================
9
10
10
- static int alist [MAX_NODES ]; //list contains all studied nodes, Open and Closed together
11
- static int alist_numNodes ;
11
+ static int alist [MAX_NODES ]; //list contains indexes (node numbers) of all studied nodes, Open and Closed together
12
+ static int alist_numNodes ; //number of nodes in list
12
13
13
14
enum {
14
- NOLIST ,
15
- OPENLIST ,
16
- CLOSEDLIST
15
+ NOLIST , //unprocessed nodes to be added to OPENLIST
16
+ OPENLIST , //nodes to explore and then move to CLOSEDLIST
17
+ CLOSEDLIST //nodes explored--stop when end (target/destination) node is added
17
18
};
18
19
19
20
typedef struct
20
21
{
21
- int parent ;
22
- int G ;
23
- int H ;
22
+ int parent ; //previous link in path chain (start<-end)
23
+ int G ; //(pLink) distance between current node and the start node
24
+ int H ; //heuristic - estimated distance from the current node to the end node
24
25
25
- int list ;
26
+ int list ; //which list node is currently in, i.e. NOLIST/OPENLIST/CLOSEDLIST
26
27
27
28
} astarnode_t ;
28
29
29
- astarnode_t astarnodes [MAX_NODES ];
30
+ astarnode_t astarnodes [MAX_NODES ]; //working list of nodes being processed by A* algo
31
+
32
+ // note: Apath is populated by AStar_ListsToPath and this is copied to (astarpath_t)path to determine the cost of path traversal via AI_FindCost
33
+ static int Apath [MAX_NODES ]; //array of node#s (node indexes) from start to end
34
+ static int Apath_numNodes ; //number of nodes in path
30
35
31
- static int Apath [MAX_NODES ];
32
- static int Apath_numNodes ;
33
36
//==========================================
34
37
//
35
38
//
36
39
//==========================================
37
- static int originNode ;
38
- static int goalNode ;
39
- static int currentNode ;
40
+ static int originNode ; //starting node closest to origin of search and beginning of path
41
+ static int goalNode ; //ending node closest to destination
42
+ static int currentNode ; //current node being processed by A* algo
40
43
41
44
int ValidLinksMask ;
42
45
#define DEFAULT_MOVETYPES_MASK (LINK_MOVE|LINK_STAIRS|LINK_FALL|LINK_WATER|LINK_WATERJUMP|LINK_JUMPPAD|LINK_PLATFORM|LINK_TELEPORT);
@@ -78,6 +81,11 @@ int AStar_nodeIsInOpen( int node )
78
81
return 0 ;
79
82
}
80
83
84
+ //==========================================
85
+ // Reset values of astarnodes, Apath, and alist
86
+ // Moves all nodes to NOLIST
87
+ // Run before a new path is generated
88
+ //==========================================
81
89
static void AStar_InitLists (void )
82
90
{
83
91
int i ;
@@ -224,14 +232,20 @@ static int AStar_FindInOpen_BestF ( void )
224
232
best = node ;
225
233
}
226
234
}
227
- //printf ("BEST:%i\n", best);
235
+ //gi.dprintf ("BEST:%i\n", best);
228
236
return best ;
229
237
}
230
238
239
+ //==========================================
240
+ // Called after A* path has been computed on astarnodes[]
241
+ // Works backwards from end (goalNode) and copies parent node indices to Apath[]
242
+ // Apath[] will then contain a list of node#s (indexes) for the path from start to end
243
+ //==========================================
231
244
static void AStar_ListsToPath ( void )
232
245
{
233
246
int count = 0 ;
234
247
int cur = goalNode ;
248
+ qboolean Spath_added = false;//GHz
235
249
236
250
while ( cur != originNode )
237
251
{
@@ -244,9 +258,91 @@ static void AStar_ListsToPath ( void )
244
258
{
245
259
Apath [count ] = cur ;
246
260
Apath_numNodes ++ ;
261
+ //GHz
262
+ // save to list to speed up future searches
263
+ if (Spath_numNodes < MAX_SPATH )
264
+ {
265
+ Spath [Spath_numNodes ].path [count ] = cur ;
266
+ Spath [Spath_numNodes ].numNodes ++ ;
267
+ Spath_added = true;
268
+ }
269
+ //GHz
247
270
count -- ;
248
271
cur = astarnodes [cur ].parent ;
249
272
}
273
+ //GHz
274
+ if (Spath_added )
275
+ Spath_numNodes ++ ;
276
+ //GHz
277
+ }
278
+
279
+ // copies saved path (Spath.path) data to Apath
280
+ // Spath_index is the index in Spath with the data you want copied to Apath
281
+ // path_index_start is the starting index in Spath.path with the data you want copied
282
+ // path_index_end is the ending index in Spath.path
283
+ // path_index_start and path_index_end tell the function which subset of the path you want copied
284
+ static void AStar_UseSavedPath (int Spath_index , int path_index_start , int path_index_end )
285
+ {
286
+ int i , cur = 0 , len = abs (path_index_end - path_index_start ) + 1 ;
287
+
288
+ if (path_index_start > path_index_end )
289
+ {
290
+ // starting index is higher than ending index, so copy backwards from this index
291
+ cur = path_index_start ;
292
+ for (i = 0 ;i < len ;i ++ )
293
+ {
294
+ Apath [i ] = Spath [Spath_index ].path [cur ];
295
+ Apath_numNodes ++ ;
296
+ cur -- ;
297
+ }
298
+ }
299
+ else
300
+ {
301
+ cur = path_index_start ;
302
+ for (i = 0 ;i < len ;i ++ )
303
+ {
304
+ Apath [i ] = Spath [Spath_index ].path [cur ];
305
+ Apath_numNodes ++ ;
306
+ cur ++ ;
307
+ }
308
+ }
309
+ //gi.dprintf("AStar_UseSavedPath\n");
310
+ }
311
+
312
+ // searches saved path array for a path that contains start and end nodes
313
+ // if found, it copies the indexes to Apath and returns true
314
+ static qboolean AStar_FindSavedPath (int start_node , int end_node )
315
+ {
316
+ int i , j ;
317
+
318
+ for (i = 0 ;i < Spath_numNodes ;i ++ )
319
+ {
320
+ int start_index = 0 , end_index = 0 ;
321
+ qboolean found_start = false, found_end = false;
322
+ for (j = 0 ;j < Spath [i ].numNodes ;j ++ )
323
+ {
324
+ if (Spath [i ].path [j ] == start_node )
325
+ {
326
+ start_index = j ;
327
+ found_start = true;
328
+ }
329
+ else if (Spath [i ].path [j ] == end_node )
330
+ {
331
+ end_index = j ;
332
+ found_end = true;
333
+ }
334
+ if (found_start && found_end
335
+ && end_index > start_index ) //GHz: reverse order is disabled for now because jump links would be impossible to do backwards!
336
+ {
337
+ //if (start_index != 0)
338
+ // gi.dprintf("saved path found in subset of data!\n");
339
+ //gi.dprintf("saved path found! index: %d, start: %d end: %d %d->%d\n", i, start_index, end_index, start_node, end_node);
340
+ AStar_UseSavedPath (i , start_index , end_index );
341
+ return true;
342
+ }
343
+ }
344
+ }
345
+ return false;
250
346
}
251
347
252
348
static int AStar_FillLists ( void )
@@ -265,25 +361,35 @@ static int AStar_FillLists ( void )
265
361
266
362
int AStar_ResolvePath ( int n1 , int n2 , int movetypes )
267
363
{
364
+ //int i=0;//GHz
268
365
ValidLinksMask = movetypes ;
366
+
269
367
if ( !ValidLinksMask )
270
368
ValidLinksMask = DEFAULT_MOVETYPES_MASK ;
271
369
272
370
AStar_InitLists ();
273
371
372
+ if (AStar_FindSavedPath (n1 , n2 ))//GHz
373
+ return 1 ;
374
+
274
375
originNode = n1 ;
275
376
goalNode = n2 ;
276
377
currentNode = originNode ;
277
378
278
379
while ( !AStar_nodeIsInOpen (goalNode ) )
279
380
{
381
+ //i++;//GHz
280
382
if ( !AStar_FillLists () )
281
383
return 0 ; //failed
282
384
}
283
385
284
386
AStar_ListsToPath ();
285
387
286
- // printf("RESULT:\n Origin:%i\n Goal:%i\n numNodes:%i\n FirstInPath:%i\n LastInPath:%i\n", originNode, goalNode, Apath_numNodes, Apath[0], Apath[Apath_numNodes-1]);
388
+ //GHz: debugging A* perf issues
389
+ //gi.dprintf("RESULT:\n Origin:%i\n Goal:%i\n numNodes:%i\n FirstInPath:%i\n LastInPath:%i\n", originNode, goalNode, Apath_numNodes, Apath[0], Apath[Apath_numNodes-1]);
390
+ //gi.dprintf("AStar_FillLists() ran %d times\n", i);
391
+ //gi.dprintf("Spath[%d]: start:%d end:%d length:%d\n",
392
+ // Spath_numNodes-1, Spath[Spath_numNodes-1].path[0], Spath[Spath_numNodes-1].path[Spath[Spath_numNodes - 1].numNodes-1], Spath[Spath_numNodes-1].numNodes);
287
393
288
394
return 1 ;
289
395
}
0 commit comments