forked from mozilla/BrowserQuest
-
Notifications
You must be signed in to change notification settings - Fork 219
/
pathfinder.js
99 lines (83 loc) · 3.07 KB
/
pathfinder.js
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
define(['lib/astar'], function(AStar) {
var Pathfinder = Class.extend({
init: function(width, height) {
this.width = width;
this.height = height;
this.grid = null;
this.blankGrid = [];
this.initBlankGrid_();
this.ignored = [];
},
initBlankGrid_: function() {
for(var i=0; i < this.height; i += 1) {
this.blankGrid[i] = [];
for(var j=0; j < this.width; j += 1) {
this.blankGrid[i][j] = 0;
}
}
},
findPath: function(grid, entity, x, y, findIncomplete) {
var start = [entity.gridX, entity.gridY],
end = [x, y],
path;
this.grid = grid;
this.applyIgnoreList_(true);
path = AStar(this.grid, start, end);
if(path.length === 0 && findIncomplete === true) {
// If no path was found, try and find an incomplete one
// to at least get closer to destination.
path = this.findIncompletePath_(start, end);
}
return path;
},
/**
* Finds a path which leads the closest possible to an unreachable x, y position.
*
* Whenever A* returns an empty path, it means that the destination tile is unreachable.
* We would like the entities to move the closest possible to it though, instead of
* staying where they are without moving at all. That's why we have this function which
* returns an incomplete path to the chosen destination.
*
* @private
* @returns {Array} The incomplete path towards the end position
*/
findIncompletePath_: function(start, end) {
var perfect, x, y,
incomplete = [];
perfect = AStar(this.blankGrid, start, end);
for(var i=perfect.length-1; i > 0; i -= 1) {
x = perfect[i][0];
y = perfect[i][1];
if(this.grid[y][x] === 0) {
incomplete = AStar(this.grid, start, [x, y]);
break;
}
}
return incomplete;
},
/**
* Removes colliding tiles corresponding to the given entity's position in the pathing grid.
*/
ignoreEntity: function(entity) {
if(entity) {
this.ignored.push(entity);
}
},
applyIgnoreList_: function(ignored) {
var self = this,
x, y;
_.each(this.ignored, function(entity) {
x = entity.isMoving() ? entity.nextGridX : entity.gridX;
y = entity.isMoving() ? entity.nextGridY : entity.gridY;
if(x >= 0 && y >= 0) {
self.grid[y][x] = ignored ? 0 : 1;
}
});
},
clearIgnoreList: function() {
this.applyIgnoreList_(false);
this.ignored = [];
}
});
return Pathfinder;
});