mrpas 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/cjs/index.js +245 -0
- package/{src → dist/esm}/index.d.ts +3 -3
- package/dist/esm/index.js +241 -0
- package/dist/esm/package.json +3 -0
- package/package.json +25 -9
- package/CHANGELOG.md +0 -20
- package/src/index.js +0 -181
- /package/{LICENCE.md → LICENSE} +0 -0
package/README.md
CHANGED
|
@@ -17,11 +17,17 @@ Or grab the code from the [repository](https://bitbucket.org/umbraprojekt/mrpas)
|
|
|
17
17
|
Instantiate a `Mrpas` object by passing it the map dimensions and a callback for determining map cell transparency:
|
|
18
18
|
|
|
19
19
|
```
|
|
20
|
-
const Mrpas = require("mrpas")
|
|
20
|
+
const { Mrpas } = require("mrpas");
|
|
21
21
|
|
|
22
22
|
const fov = new Mrpas(20, 20, (x, y) => map[x][y].transparent);
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
ES modules can import the same named export:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
import { Mrpas } from "mrpas";
|
|
29
|
+
```
|
|
30
|
+
|
|
25
31
|
### Compute FOV
|
|
26
32
|
|
|
27
33
|
Compute the field of view for any set of coordinates by calling the `Mrpas#compute()` method and passing it the origin coordinates, FOV calculation radius and two callbacks: one for determining whether a call has been marked as visible, and the othe for marking it as visible:
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Mrpas = void 0;
|
|
4
|
+
class Mrpas {
|
|
5
|
+
mapWidth;
|
|
6
|
+
mapHeight;
|
|
7
|
+
isTransparent;
|
|
8
|
+
constructor(mapWidth, mapHeight, isTransparent) {
|
|
9
|
+
this.mapWidth = mapWidth;
|
|
10
|
+
this.mapHeight = mapHeight;
|
|
11
|
+
this.isTransparent = isTransparent;
|
|
12
|
+
}
|
|
13
|
+
computeOctantY(deltaX, deltaY, data) {
|
|
14
|
+
const startSlopes = [];
|
|
15
|
+
const endSlopes = [];
|
|
16
|
+
const minX = data.minX;
|
|
17
|
+
const maxX = data.maxX;
|
|
18
|
+
const minY = data.minY;
|
|
19
|
+
const maxY = data.maxY;
|
|
20
|
+
const originX = data.originX;
|
|
21
|
+
const originY = data.originY;
|
|
22
|
+
const isTransparent = this.isTransparent;
|
|
23
|
+
const isVisible = data.isVisible;
|
|
24
|
+
const setVisible = data.setVisible;
|
|
25
|
+
let iteration = 1;
|
|
26
|
+
let totalObstacles = 0;
|
|
27
|
+
let obstaclesInLastLine = 0;
|
|
28
|
+
let minSlope = 0;
|
|
29
|
+
let x;
|
|
30
|
+
let y;
|
|
31
|
+
let halfSlope;
|
|
32
|
+
let processedCell;
|
|
33
|
+
let visible;
|
|
34
|
+
let extended;
|
|
35
|
+
let centreSlope;
|
|
36
|
+
let startSlope;
|
|
37
|
+
let endSlope;
|
|
38
|
+
let previousEndSlope;
|
|
39
|
+
let cellTransparent = false;
|
|
40
|
+
let transparencyChecked;
|
|
41
|
+
let firstCell;
|
|
42
|
+
let behindOpen = false;
|
|
43
|
+
let diagonalOpen;
|
|
44
|
+
for (y = originY + deltaY; y >= minY && y <= maxY; y += deltaY, obstaclesInLastLine = totalObstacles, ++iteration) {
|
|
45
|
+
halfSlope = 0.5 / iteration;
|
|
46
|
+
previousEndSlope = -1;
|
|
47
|
+
for (firstCell = processedCell = Math.floor(minSlope * iteration + 0.5), x = originX + (processedCell * deltaX); processedCell <= iteration && x >= minX && x <= maxX; x += deltaX, ++processedCell, previousEndSlope = endSlope) {
|
|
48
|
+
visible = true;
|
|
49
|
+
extended = false;
|
|
50
|
+
centreSlope = processedCell / iteration;
|
|
51
|
+
startSlope = previousEndSlope;
|
|
52
|
+
endSlope = centreSlope + halfSlope;
|
|
53
|
+
transparencyChecked = false;
|
|
54
|
+
if (obstaclesInLastLine > 0) {
|
|
55
|
+
diagonalOpen = behindOpen;
|
|
56
|
+
behindOpen = isVisible(x, y - deltaY) && isTransparent(x, y - deltaY);
|
|
57
|
+
if (!behindOpen &&
|
|
58
|
+
!(processedCell > firstCell
|
|
59
|
+
? diagonalOpen
|
|
60
|
+
: isVisible(x - deltaX, y - deltaY) && isTransparent(x - deltaX, y - deltaY))) {
|
|
61
|
+
visible = false;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
for (var idx = 0; idx < obstaclesInLastLine && visible; ++idx) {
|
|
65
|
+
if (startSlope <= endSlopes[idx] && endSlope >= startSlopes[idx]) {
|
|
66
|
+
if (!transparencyChecked) {
|
|
67
|
+
cellTransparent = isTransparent(x, y);
|
|
68
|
+
transparencyChecked = true;
|
|
69
|
+
}
|
|
70
|
+
if (cellTransparent) {
|
|
71
|
+
if (centreSlope > startSlopes[idx] && centreSlope < endSlopes[idx]) {
|
|
72
|
+
visible = false;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
if (startSlope >= startSlopes[idx] && endSlope <= endSlopes[idx]) {
|
|
78
|
+
visible = false;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
if (startSlope < startSlopes[idx]) {
|
|
83
|
+
startSlopes[idx] = startSlope;
|
|
84
|
+
}
|
|
85
|
+
if (endSlope > endSlopes[idx]) {
|
|
86
|
+
endSlopes[idx] = endSlope;
|
|
87
|
+
}
|
|
88
|
+
extended = true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (visible) {
|
|
96
|
+
setVisible(x, y);
|
|
97
|
+
if (!transparencyChecked) {
|
|
98
|
+
cellTransparent = isTransparent(x, y);
|
|
99
|
+
}
|
|
100
|
+
if (!cellTransparent) {
|
|
101
|
+
if (minSlope >= startSlope) {
|
|
102
|
+
minSlope = endSlope;
|
|
103
|
+
}
|
|
104
|
+
else if (!extended) {
|
|
105
|
+
startSlopes[totalObstacles] = startSlope;
|
|
106
|
+
endSlopes[totalObstacles++] = endSlope;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (minSlope > 1) {
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
computeOctantX(deltaX, deltaY, data) {
|
|
117
|
+
const startSlopes = [];
|
|
118
|
+
const endSlopes = [];
|
|
119
|
+
const minX = data.minX;
|
|
120
|
+
const maxX = data.maxX;
|
|
121
|
+
const minY = data.minY;
|
|
122
|
+
const maxY = data.maxY;
|
|
123
|
+
const originX = data.originX;
|
|
124
|
+
const originY = data.originY;
|
|
125
|
+
const isTransparent = this.isTransparent;
|
|
126
|
+
const isVisible = data.isVisible;
|
|
127
|
+
const setVisible = data.setVisible;
|
|
128
|
+
let iteration = 1;
|
|
129
|
+
let totalObstacles = 0;
|
|
130
|
+
let obstaclesInLastLine = 0;
|
|
131
|
+
let minSlope = 0;
|
|
132
|
+
let x;
|
|
133
|
+
let y;
|
|
134
|
+
let halfSlope;
|
|
135
|
+
let processedCell;
|
|
136
|
+
let visible;
|
|
137
|
+
let extended;
|
|
138
|
+
let centreSlope;
|
|
139
|
+
let startSlope;
|
|
140
|
+
let endSlope;
|
|
141
|
+
let previousEndSlope;
|
|
142
|
+
let cellTransparent = false;
|
|
143
|
+
let transparencyChecked;
|
|
144
|
+
let firstCell;
|
|
145
|
+
let behindOpen = false;
|
|
146
|
+
let diagonalOpen;
|
|
147
|
+
for (x = originX + deltaX; x >= minX && x <= maxX; x += deltaX, obstaclesInLastLine = totalObstacles, ++iteration) {
|
|
148
|
+
halfSlope = 0.5 / iteration;
|
|
149
|
+
previousEndSlope = -1;
|
|
150
|
+
for (firstCell = processedCell = Math.floor(minSlope * iteration + 0.5), y = originY + (processedCell * deltaY); processedCell <= iteration && y >= minY && y <= maxY; y += deltaY, ++processedCell, previousEndSlope = endSlope) {
|
|
151
|
+
visible = true;
|
|
152
|
+
extended = false;
|
|
153
|
+
centreSlope = processedCell / iteration;
|
|
154
|
+
startSlope = previousEndSlope;
|
|
155
|
+
endSlope = centreSlope + halfSlope;
|
|
156
|
+
transparencyChecked = false;
|
|
157
|
+
if (obstaclesInLastLine > 0) {
|
|
158
|
+
diagonalOpen = behindOpen;
|
|
159
|
+
behindOpen = isVisible(x - deltaX, y) && isTransparent(x - deltaX, y);
|
|
160
|
+
if (!behindOpen &&
|
|
161
|
+
!(processedCell > firstCell
|
|
162
|
+
? diagonalOpen
|
|
163
|
+
: isVisible(x - deltaX, y - deltaY) && isTransparent(x - deltaX, y - deltaY))) {
|
|
164
|
+
visible = false;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
for (var idx = 0; idx < obstaclesInLastLine && visible; ++idx) {
|
|
168
|
+
if (startSlope <= endSlopes[idx] && endSlope >= startSlopes[idx]) {
|
|
169
|
+
if (!transparencyChecked) {
|
|
170
|
+
cellTransparent = isTransparent(x, y);
|
|
171
|
+
transparencyChecked = true;
|
|
172
|
+
}
|
|
173
|
+
if (cellTransparent) {
|
|
174
|
+
if (centreSlope > startSlopes[idx] && centreSlope < endSlopes[idx]) {
|
|
175
|
+
visible = false;
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
if (startSlope >= startSlopes[idx] && endSlope <= endSlopes[idx]) {
|
|
181
|
+
visible = false;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
if (startSlope < startSlopes[idx]) {
|
|
186
|
+
startSlopes[idx] = startSlope;
|
|
187
|
+
}
|
|
188
|
+
if (endSlope > endSlopes[idx]) {
|
|
189
|
+
endSlopes[idx] = endSlope;
|
|
190
|
+
}
|
|
191
|
+
extended = true;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (visible) {
|
|
199
|
+
setVisible(x, y);
|
|
200
|
+
if (!transparencyChecked) {
|
|
201
|
+
cellTransparent = isTransparent(x, y);
|
|
202
|
+
}
|
|
203
|
+
if (!cellTransparent) {
|
|
204
|
+
if (minSlope >= startSlope) {
|
|
205
|
+
minSlope = endSlope;
|
|
206
|
+
}
|
|
207
|
+
else if (!extended) {
|
|
208
|
+
startSlopes[totalObstacles] = startSlope;
|
|
209
|
+
endSlopes[totalObstacles++] = endSlope;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (minSlope > 1) {
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
setMapDimensions(mapWidth, mapHeight) {
|
|
220
|
+
this.mapWidth = mapWidth;
|
|
221
|
+
this.mapHeight = mapHeight;
|
|
222
|
+
}
|
|
223
|
+
compute(originX, originY, radius, isVisible, setVisible) {
|
|
224
|
+
setVisible(originX, originY);
|
|
225
|
+
const data = {
|
|
226
|
+
minX: Math.max(0, originX - radius),
|
|
227
|
+
minY: Math.max(0, originY - radius),
|
|
228
|
+
maxX: Math.min(this.mapWidth - 1, originX + radius),
|
|
229
|
+
maxY: Math.min(this.mapHeight - 1, originY + radius),
|
|
230
|
+
originX: originX,
|
|
231
|
+
originY: originY,
|
|
232
|
+
isVisible: isVisible,
|
|
233
|
+
setVisible: setVisible
|
|
234
|
+
};
|
|
235
|
+
this.computeOctantY(1, 1, data);
|
|
236
|
+
this.computeOctantX(1, 1, data);
|
|
237
|
+
this.computeOctantY(1, -1, data);
|
|
238
|
+
this.computeOctantX(1, -1, data);
|
|
239
|
+
this.computeOctantY(-1, 1, data);
|
|
240
|
+
this.computeOctantX(-1, 1, data);
|
|
241
|
+
this.computeOctantY(-1, -1, data);
|
|
242
|
+
this.computeOctantX(-1, -1, data);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
exports.Mrpas = Mrpas;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
export type IsTransparentFunc = (x: number, y: number) => boolean;
|
|
2
|
+
export type IsVisibleFunc = (x: number, y: number) => boolean;
|
|
3
|
+
export type SetVisibleFunc = (x: number, y: number) => void;
|
|
4
4
|
export declare class Mrpas {
|
|
5
5
|
private mapWidth;
|
|
6
6
|
private mapHeight;
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
export class Mrpas {
|
|
2
|
+
mapWidth;
|
|
3
|
+
mapHeight;
|
|
4
|
+
isTransparent;
|
|
5
|
+
constructor(mapWidth, mapHeight, isTransparent) {
|
|
6
|
+
this.mapWidth = mapWidth;
|
|
7
|
+
this.mapHeight = mapHeight;
|
|
8
|
+
this.isTransparent = isTransparent;
|
|
9
|
+
}
|
|
10
|
+
computeOctantY(deltaX, deltaY, data) {
|
|
11
|
+
const startSlopes = [];
|
|
12
|
+
const endSlopes = [];
|
|
13
|
+
const minX = data.minX;
|
|
14
|
+
const maxX = data.maxX;
|
|
15
|
+
const minY = data.minY;
|
|
16
|
+
const maxY = data.maxY;
|
|
17
|
+
const originX = data.originX;
|
|
18
|
+
const originY = data.originY;
|
|
19
|
+
const isTransparent = this.isTransparent;
|
|
20
|
+
const isVisible = data.isVisible;
|
|
21
|
+
const setVisible = data.setVisible;
|
|
22
|
+
let iteration = 1;
|
|
23
|
+
let totalObstacles = 0;
|
|
24
|
+
let obstaclesInLastLine = 0;
|
|
25
|
+
let minSlope = 0;
|
|
26
|
+
let x;
|
|
27
|
+
let y;
|
|
28
|
+
let halfSlope;
|
|
29
|
+
let processedCell;
|
|
30
|
+
let visible;
|
|
31
|
+
let extended;
|
|
32
|
+
let centreSlope;
|
|
33
|
+
let startSlope;
|
|
34
|
+
let endSlope;
|
|
35
|
+
let previousEndSlope;
|
|
36
|
+
let cellTransparent = false;
|
|
37
|
+
let transparencyChecked;
|
|
38
|
+
let firstCell;
|
|
39
|
+
let behindOpen = false;
|
|
40
|
+
let diagonalOpen;
|
|
41
|
+
for (y = originY + deltaY; y >= minY && y <= maxY; y += deltaY, obstaclesInLastLine = totalObstacles, ++iteration) {
|
|
42
|
+
halfSlope = 0.5 / iteration;
|
|
43
|
+
previousEndSlope = -1;
|
|
44
|
+
for (firstCell = processedCell = Math.floor(minSlope * iteration + 0.5), x = originX + (processedCell * deltaX); processedCell <= iteration && x >= minX && x <= maxX; x += deltaX, ++processedCell, previousEndSlope = endSlope) {
|
|
45
|
+
visible = true;
|
|
46
|
+
extended = false;
|
|
47
|
+
centreSlope = processedCell / iteration;
|
|
48
|
+
startSlope = previousEndSlope;
|
|
49
|
+
endSlope = centreSlope + halfSlope;
|
|
50
|
+
transparencyChecked = false;
|
|
51
|
+
if (obstaclesInLastLine > 0) {
|
|
52
|
+
diagonalOpen = behindOpen;
|
|
53
|
+
behindOpen = isVisible(x, y - deltaY) && isTransparent(x, y - deltaY);
|
|
54
|
+
if (!behindOpen &&
|
|
55
|
+
!(processedCell > firstCell
|
|
56
|
+
? diagonalOpen
|
|
57
|
+
: isVisible(x - deltaX, y - deltaY) && isTransparent(x - deltaX, y - deltaY))) {
|
|
58
|
+
visible = false;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
for (var idx = 0; idx < obstaclesInLastLine && visible; ++idx) {
|
|
62
|
+
if (startSlope <= endSlopes[idx] && endSlope >= startSlopes[idx]) {
|
|
63
|
+
if (!transparencyChecked) {
|
|
64
|
+
cellTransparent = isTransparent(x, y);
|
|
65
|
+
transparencyChecked = true;
|
|
66
|
+
}
|
|
67
|
+
if (cellTransparent) {
|
|
68
|
+
if (centreSlope > startSlopes[idx] && centreSlope < endSlopes[idx]) {
|
|
69
|
+
visible = false;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
if (startSlope >= startSlopes[idx] && endSlope <= endSlopes[idx]) {
|
|
75
|
+
visible = false;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
if (startSlope < startSlopes[idx]) {
|
|
80
|
+
startSlopes[idx] = startSlope;
|
|
81
|
+
}
|
|
82
|
+
if (endSlope > endSlopes[idx]) {
|
|
83
|
+
endSlopes[idx] = endSlope;
|
|
84
|
+
}
|
|
85
|
+
extended = true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (visible) {
|
|
93
|
+
setVisible(x, y);
|
|
94
|
+
if (!transparencyChecked) {
|
|
95
|
+
cellTransparent = isTransparent(x, y);
|
|
96
|
+
}
|
|
97
|
+
if (!cellTransparent) {
|
|
98
|
+
if (minSlope >= startSlope) {
|
|
99
|
+
minSlope = endSlope;
|
|
100
|
+
}
|
|
101
|
+
else if (!extended) {
|
|
102
|
+
startSlopes[totalObstacles] = startSlope;
|
|
103
|
+
endSlopes[totalObstacles++] = endSlope;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (minSlope > 1) {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
computeOctantX(deltaX, deltaY, data) {
|
|
114
|
+
const startSlopes = [];
|
|
115
|
+
const endSlopes = [];
|
|
116
|
+
const minX = data.minX;
|
|
117
|
+
const maxX = data.maxX;
|
|
118
|
+
const minY = data.minY;
|
|
119
|
+
const maxY = data.maxY;
|
|
120
|
+
const originX = data.originX;
|
|
121
|
+
const originY = data.originY;
|
|
122
|
+
const isTransparent = this.isTransparent;
|
|
123
|
+
const isVisible = data.isVisible;
|
|
124
|
+
const setVisible = data.setVisible;
|
|
125
|
+
let iteration = 1;
|
|
126
|
+
let totalObstacles = 0;
|
|
127
|
+
let obstaclesInLastLine = 0;
|
|
128
|
+
let minSlope = 0;
|
|
129
|
+
let x;
|
|
130
|
+
let y;
|
|
131
|
+
let halfSlope;
|
|
132
|
+
let processedCell;
|
|
133
|
+
let visible;
|
|
134
|
+
let extended;
|
|
135
|
+
let centreSlope;
|
|
136
|
+
let startSlope;
|
|
137
|
+
let endSlope;
|
|
138
|
+
let previousEndSlope;
|
|
139
|
+
let cellTransparent = false;
|
|
140
|
+
let transparencyChecked;
|
|
141
|
+
let firstCell;
|
|
142
|
+
let behindOpen = false;
|
|
143
|
+
let diagonalOpen;
|
|
144
|
+
for (x = originX + deltaX; x >= minX && x <= maxX; x += deltaX, obstaclesInLastLine = totalObstacles, ++iteration) {
|
|
145
|
+
halfSlope = 0.5 / iteration;
|
|
146
|
+
previousEndSlope = -1;
|
|
147
|
+
for (firstCell = processedCell = Math.floor(minSlope * iteration + 0.5), y = originY + (processedCell * deltaY); processedCell <= iteration && y >= minY && y <= maxY; y += deltaY, ++processedCell, previousEndSlope = endSlope) {
|
|
148
|
+
visible = true;
|
|
149
|
+
extended = false;
|
|
150
|
+
centreSlope = processedCell / iteration;
|
|
151
|
+
startSlope = previousEndSlope;
|
|
152
|
+
endSlope = centreSlope + halfSlope;
|
|
153
|
+
transparencyChecked = false;
|
|
154
|
+
if (obstaclesInLastLine > 0) {
|
|
155
|
+
diagonalOpen = behindOpen;
|
|
156
|
+
behindOpen = isVisible(x - deltaX, y) && isTransparent(x - deltaX, y);
|
|
157
|
+
if (!behindOpen &&
|
|
158
|
+
!(processedCell > firstCell
|
|
159
|
+
? diagonalOpen
|
|
160
|
+
: isVisible(x - deltaX, y - deltaY) && isTransparent(x - deltaX, y - deltaY))) {
|
|
161
|
+
visible = false;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
for (var idx = 0; idx < obstaclesInLastLine && visible; ++idx) {
|
|
165
|
+
if (startSlope <= endSlopes[idx] && endSlope >= startSlopes[idx]) {
|
|
166
|
+
if (!transparencyChecked) {
|
|
167
|
+
cellTransparent = isTransparent(x, y);
|
|
168
|
+
transparencyChecked = true;
|
|
169
|
+
}
|
|
170
|
+
if (cellTransparent) {
|
|
171
|
+
if (centreSlope > startSlopes[idx] && centreSlope < endSlopes[idx]) {
|
|
172
|
+
visible = false;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
if (startSlope >= startSlopes[idx] && endSlope <= endSlopes[idx]) {
|
|
178
|
+
visible = false;
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
if (startSlope < startSlopes[idx]) {
|
|
183
|
+
startSlopes[idx] = startSlope;
|
|
184
|
+
}
|
|
185
|
+
if (endSlope > endSlopes[idx]) {
|
|
186
|
+
endSlopes[idx] = endSlope;
|
|
187
|
+
}
|
|
188
|
+
extended = true;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (visible) {
|
|
196
|
+
setVisible(x, y);
|
|
197
|
+
if (!transparencyChecked) {
|
|
198
|
+
cellTransparent = isTransparent(x, y);
|
|
199
|
+
}
|
|
200
|
+
if (!cellTransparent) {
|
|
201
|
+
if (minSlope >= startSlope) {
|
|
202
|
+
minSlope = endSlope;
|
|
203
|
+
}
|
|
204
|
+
else if (!extended) {
|
|
205
|
+
startSlopes[totalObstacles] = startSlope;
|
|
206
|
+
endSlopes[totalObstacles++] = endSlope;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (minSlope > 1) {
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
setMapDimensions(mapWidth, mapHeight) {
|
|
217
|
+
this.mapWidth = mapWidth;
|
|
218
|
+
this.mapHeight = mapHeight;
|
|
219
|
+
}
|
|
220
|
+
compute(originX, originY, radius, isVisible, setVisible) {
|
|
221
|
+
setVisible(originX, originY);
|
|
222
|
+
const data = {
|
|
223
|
+
minX: Math.max(0, originX - radius),
|
|
224
|
+
minY: Math.max(0, originY - radius),
|
|
225
|
+
maxX: Math.min(this.mapWidth - 1, originX + radius),
|
|
226
|
+
maxY: Math.min(this.mapHeight - 1, originY + radius),
|
|
227
|
+
originX: originX,
|
|
228
|
+
originY: originY,
|
|
229
|
+
isVisible: isVisible,
|
|
230
|
+
setVisible: setVisible
|
|
231
|
+
};
|
|
232
|
+
this.computeOctantY(1, 1, data);
|
|
233
|
+
this.computeOctantX(1, 1, data);
|
|
234
|
+
this.computeOctantY(1, -1, data);
|
|
235
|
+
this.computeOctantX(1, -1, data);
|
|
236
|
+
this.computeOctantY(-1, 1, data);
|
|
237
|
+
this.computeOctantX(-1, 1, data);
|
|
238
|
+
this.computeOctantY(-1, -1, data);
|
|
239
|
+
this.computeOctantX(-1, -1, data);
|
|
240
|
+
}
|
|
241
|
+
}
|
package/package.json
CHANGED
|
@@ -1,25 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mrpas",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "A Field of View (FOV) computation algorithm.",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/esm/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/esm/index.d.ts",
|
|
11
|
+
"import": "./dist/esm/index.js",
|
|
12
|
+
"require": "./dist/cjs/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
6
18
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
"build": "tsc"
|
|
19
|
+
"build": "npm run build:esm && npm run build:cjs",
|
|
20
|
+
"build:esm": "tsc -p tsconfig.esm.json",
|
|
21
|
+
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
22
|
+
"watch": "tsc --watch -p tsconfig.esm.json"
|
|
9
23
|
},
|
|
10
|
-
"typings": "src/index.d.ts",
|
|
11
24
|
"repository": {
|
|
12
25
|
"type": "git",
|
|
13
|
-
"url": "https://
|
|
26
|
+
"url": "git+https://github.com/mingos777/mrpas.git"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/mingos777/mrpas/issues"
|
|
14
30
|
},
|
|
15
31
|
"keywords": [
|
|
16
32
|
"fov",
|
|
17
33
|
"roguelike"
|
|
18
34
|
],
|
|
19
|
-
"author": "Dominik Marczuk <mingos.nospam@gmail.com> (
|
|
35
|
+
"author": "Dominik Marczuk <mingos.nospam@gmail.com> (https://dominikmarczuk.pl)",
|
|
20
36
|
"license": "BSD-2-Clause",
|
|
21
|
-
"homepage": "https://
|
|
37
|
+
"homepage": "https://github.com/mingos777/mrpas",
|
|
22
38
|
"devDependencies": {
|
|
23
|
-
"typescript": "^
|
|
39
|
+
"typescript": "^7.0.2"
|
|
24
40
|
}
|
|
25
41
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## 2.0.0
|
|
4
|
-
### Bugfixes
|
|
5
|
-
* fixed iterator increment again
|
|
6
|
-
* fixed floating point logic in determining initial processed cell per octant row/column
|
|
7
|
-
### Modified features
|
|
8
|
-
* refactored code for brevity and readability
|
|
9
|
-
### New features
|
|
10
|
-
* ported to TypeScript
|
|
11
|
-
### API break
|
|
12
|
-
* exported module is now named. Call `require("mrpas").Mrpas` to import.
|
|
13
|
-
|
|
14
|
-
## 1.2.1 (2017-02-20)
|
|
15
|
-
### Bugfixes
|
|
16
|
-
* fixed iterator being incremented twice, causing incorrect FOV shape in ES5 version
|
|
17
|
-
|
|
18
|
-
## 1.2.0 (2017-02-18)
|
|
19
|
-
* Initial release, based on C code available in [libtcod](https://bitbucket.org/libtcod/libtcod).
|
|
20
|
-
* Created ES5 and ES6 versions.
|
package/src/index.js
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
var Mrpas = (function () {
|
|
4
|
-
function Mrpas(mapWidth, mapHeight, isTransparent) {
|
|
5
|
-
this.mapWidth = mapWidth;
|
|
6
|
-
this.mapHeight = mapHeight;
|
|
7
|
-
this.isTransparent = isTransparent;
|
|
8
|
-
}
|
|
9
|
-
Mrpas.prototype.computeOctantY = function (deltaX, deltaY, data) {
|
|
10
|
-
var startSlopes = [];
|
|
11
|
-
var endSlopes = [];
|
|
12
|
-
var iteration = 1;
|
|
13
|
-
var totalObstacles = 0;
|
|
14
|
-
var obstaclesInLastLine = 0;
|
|
15
|
-
var minSlope = 0;
|
|
16
|
-
var x;
|
|
17
|
-
var y;
|
|
18
|
-
var halfSlope;
|
|
19
|
-
var processedCell;
|
|
20
|
-
var visible;
|
|
21
|
-
var extended;
|
|
22
|
-
var centreSlope;
|
|
23
|
-
var startSlope;
|
|
24
|
-
var endSlope;
|
|
25
|
-
var previousEndSlope;
|
|
26
|
-
for (y = data.originY + deltaY; y >= data.minY && y <= data.maxY; y += deltaY, obstaclesInLastLine = totalObstacles, ++iteration) {
|
|
27
|
-
halfSlope = 0.5 / iteration;
|
|
28
|
-
previousEndSlope = -1;
|
|
29
|
-
for (processedCell = Math.floor(minSlope * iteration + 0.5), x = data.originX + (processedCell * deltaX); processedCell <= iteration && x >= data.minX && x <= data.maxX; x += deltaX, ++processedCell, previousEndSlope = endSlope) {
|
|
30
|
-
visible = true;
|
|
31
|
-
extended = false;
|
|
32
|
-
centreSlope = processedCell / iteration;
|
|
33
|
-
startSlope = previousEndSlope;
|
|
34
|
-
endSlope = centreSlope + halfSlope;
|
|
35
|
-
if (obstaclesInLastLine > 0) {
|
|
36
|
-
if (!(data.isVisible(x, y - deltaY) &&
|
|
37
|
-
this.isTransparent(x, y - deltaY)) &&
|
|
38
|
-
!(data.isVisible(x - deltaX, y - deltaY) &&
|
|
39
|
-
this.isTransparent(x - deltaX, y - deltaY))) {
|
|
40
|
-
visible = false;
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
for (var idx = 0; idx < obstaclesInLastLine && visible; ++idx) {
|
|
44
|
-
if (startSlope <= endSlopes[idx] && endSlope >= startSlopes[idx]) {
|
|
45
|
-
if (this.isTransparent(x, y)) {
|
|
46
|
-
if (centreSlope > startSlopes[idx] && centreSlope < endSlopes[idx]) {
|
|
47
|
-
visible = false;
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
if (startSlope >= startSlopes[idx] && endSlope <= endSlopes[idx]) {
|
|
53
|
-
visible = false;
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
startSlopes[idx] = Math.min(startSlopes[idx], startSlope);
|
|
58
|
-
endSlopes[idx] = Math.max(endSlopes[idx], endSlope);
|
|
59
|
-
extended = true;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
if (visible) {
|
|
67
|
-
data.setVisible(x, y);
|
|
68
|
-
if (!this.isTransparent(x, y)) {
|
|
69
|
-
if (minSlope >= startSlope) {
|
|
70
|
-
minSlope = endSlope;
|
|
71
|
-
}
|
|
72
|
-
else if (!extended) {
|
|
73
|
-
startSlopes[totalObstacles] = startSlope;
|
|
74
|
-
endSlopes[totalObstacles++] = endSlope;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
Mrpas.prototype.computeOctantX = function (deltaX, deltaY, data) {
|
|
82
|
-
var startSlopes = [];
|
|
83
|
-
var endSlopes = [];
|
|
84
|
-
var iteration = 1;
|
|
85
|
-
var totalObstacles = 0;
|
|
86
|
-
var obstaclesInLastLine = 0;
|
|
87
|
-
var minSlope = 0;
|
|
88
|
-
var x;
|
|
89
|
-
var y;
|
|
90
|
-
var halfSlope;
|
|
91
|
-
var processedCell;
|
|
92
|
-
var visible;
|
|
93
|
-
var extended;
|
|
94
|
-
var centreSlope;
|
|
95
|
-
var startSlope;
|
|
96
|
-
var endSlope;
|
|
97
|
-
var previousEndSlope;
|
|
98
|
-
for (x = data.originX + deltaX; x >= data.minX && x <= data.maxX; x += deltaX, obstaclesInLastLine = totalObstacles, ++iteration) {
|
|
99
|
-
halfSlope = 0.5 / iteration;
|
|
100
|
-
previousEndSlope = -1;
|
|
101
|
-
for (processedCell = Math.floor(minSlope * iteration + 0.5), y = data.originY + (processedCell * deltaY); processedCell <= iteration && y >= data.minY && y <= data.maxY; y += deltaY, ++processedCell, previousEndSlope = endSlope) {
|
|
102
|
-
visible = true;
|
|
103
|
-
extended = false;
|
|
104
|
-
centreSlope = processedCell / iteration;
|
|
105
|
-
startSlope = previousEndSlope;
|
|
106
|
-
endSlope = centreSlope + halfSlope;
|
|
107
|
-
if (obstaclesInLastLine > 0) {
|
|
108
|
-
if (!(data.isVisible(x - deltaX, y) &&
|
|
109
|
-
this.isTransparent(x - deltaX, y)) &&
|
|
110
|
-
!(data.isVisible(x - deltaX, y - deltaY) &&
|
|
111
|
-
this.isTransparent(x - deltaX, y - deltaY))) {
|
|
112
|
-
visible = false;
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
for (var idx = 0; idx < obstaclesInLastLine && visible; ++idx) {
|
|
116
|
-
if (startSlope <= endSlopes[idx] && endSlope >= startSlopes[idx]) {
|
|
117
|
-
if (this.isTransparent(x, y)) {
|
|
118
|
-
if (centreSlope > startSlopes[idx] && centreSlope < endSlopes[idx]) {
|
|
119
|
-
visible = false;
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
if (startSlope >= startSlopes[idx] && endSlope <= endSlopes[idx]) {
|
|
125
|
-
visible = false;
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
startSlopes[idx] = Math.min(startSlopes[idx], startSlope);
|
|
130
|
-
endSlopes[idx] = Math.max(endSlopes[idx], endSlope);
|
|
131
|
-
extended = true;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (visible) {
|
|
139
|
-
data.setVisible(x, y);
|
|
140
|
-
if (!this.isTransparent(x, y)) {
|
|
141
|
-
if (minSlope >= startSlope) {
|
|
142
|
-
minSlope = endSlope;
|
|
143
|
-
}
|
|
144
|
-
else if (!extended) {
|
|
145
|
-
startSlopes[totalObstacles] = startSlope;
|
|
146
|
-
endSlopes[totalObstacles++] = endSlope;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
Mrpas.prototype.setMapDimensions = function (mapWidth, mapHeight) {
|
|
154
|
-
this.mapWidth = mapWidth;
|
|
155
|
-
this.mapHeight = mapHeight;
|
|
156
|
-
};
|
|
157
|
-
Mrpas.prototype.compute = function (originX, originY, radius, isVisible, setVisible) {
|
|
158
|
-
setVisible(originX, originY);
|
|
159
|
-
var data = {
|
|
160
|
-
minX: Math.max(0, originX - radius),
|
|
161
|
-
minY: Math.max(0, originY - radius),
|
|
162
|
-
maxX: Math.min(this.mapWidth - 1, originX + radius),
|
|
163
|
-
maxY: Math.min(this.mapHeight - 1, originY + radius),
|
|
164
|
-
originX: originX,
|
|
165
|
-
originY: originY,
|
|
166
|
-
radius: radius,
|
|
167
|
-
isVisible: isVisible,
|
|
168
|
-
setVisible: setVisible
|
|
169
|
-
};
|
|
170
|
-
this.computeOctantY(1, 1, data);
|
|
171
|
-
this.computeOctantX(1, 1, data);
|
|
172
|
-
this.computeOctantY(1, -1, data);
|
|
173
|
-
this.computeOctantX(1, -1, data);
|
|
174
|
-
this.computeOctantY(-1, 1, data);
|
|
175
|
-
this.computeOctantX(-1, 1, data);
|
|
176
|
-
this.computeOctantY(-1, -1, data);
|
|
177
|
-
this.computeOctantX(-1, -1, data);
|
|
178
|
-
};
|
|
179
|
-
return Mrpas;
|
|
180
|
-
}());
|
|
181
|
-
exports.Mrpas = Mrpas;
|
/package/{LICENCE.md → LICENSE}
RENAMED
|
File without changes
|