@makefully/platypus 4.1.5 → 4.1.8

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.
Files changed (136) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +3 -3
  3. package/lib/platypus.js +1 -1
  4. package/package.json +7 -6
  5. package/src/AABB.js +685 -0
  6. package/src/ActionState.js +121 -0
  7. package/src/AssetManager.js +206 -0
  8. package/src/CollisionData.js +96 -0
  9. package/src/CollisionDataContainer.js +127 -0
  10. package/src/CollisionShape.js +315 -0
  11. package/src/Component.js +231 -0
  12. package/src/Data.js +64 -0
  13. package/src/DataMap.js +204 -0
  14. package/src/Entity.js +404 -0
  15. package/src/EntityLinker.js +113 -0
  16. package/src/EventHandler.js +115 -0
  17. package/src/EventHandlerList.js +251 -0
  18. package/src/Game.js +840 -0
  19. package/src/Gamepad.js +175 -0
  20. package/src/ID3CaptionPlayer.js +61 -0
  21. package/src/Messenger.js +365 -0
  22. package/src/PIXIAnimation.js +622 -0
  23. package/src/RandomSet.js +140 -0
  24. package/src/SFXPlayer.js +120 -0
  25. package/src/StateMap.js +252 -0
  26. package/src/Storage.js +152 -0
  27. package/src/TickerClient.js +48 -0
  28. package/src/TickerServer.js +23 -0
  29. package/src/TimeEvent.js +50 -0
  30. package/src/TimeEventList.js +100 -0
  31. package/src/VOPlayer.js +684 -0
  32. package/src/Vector.js +702 -0
  33. package/src/components/AIChaser.js +161 -0
  34. package/src/components/AIPacer.js +107 -0
  35. package/src/components/AudioMusic.js +151 -0
  36. package/src/components/AudioSFX.js +673 -0
  37. package/src/components/AudioVO.js +301 -0
  38. package/src/components/CollisionBasic.js +826 -0
  39. package/src/components/CollisionFilter.js +74 -0
  40. package/src/components/CollisionGroup.js +448 -0
  41. package/src/components/CollisionTiles.js +608 -0
  42. package/src/components/ComponentSwitcher.js +173 -0
  43. package/src/components/ControllerInput.js +65 -0
  44. package/src/components/Counter.js +165 -0
  45. package/src/components/EntityCamera.js +215 -0
  46. package/src/components/EntityContainer.js +549 -0
  47. package/src/components/EntityController.js +541 -0
  48. package/src/components/HandlerCamera.js +1052 -0
  49. package/src/components/HandlerCollision.js +1318 -0
  50. package/src/components/HandlerController.js +291 -0
  51. package/src/components/HandlerLogic.js +394 -0
  52. package/src/components/HandlerRender.js +217 -0
  53. package/src/components/Interactive.js +502 -0
  54. package/src/components/LevelBuilder.js +524 -0
  55. package/src/components/LogicAngularMovement.js +154 -0
  56. package/src/components/LogicAttachment.js +265 -0
  57. package/src/components/LogicButton.js +466 -0
  58. package/src/components/LogicCarrier.js +39 -0
  59. package/src/components/LogicDestroyMe.js +58 -0
  60. package/src/components/LogicDirectionalMovement.js +325 -0
  61. package/src/components/LogicDragDrop.js +371 -0
  62. package/src/components/LogicImpactLaunch.js +144 -0
  63. package/src/components/LogicPacingPlatform.js +64 -0
  64. package/src/components/LogicPortable.js +112 -0
  65. package/src/components/LogicPortal.js +115 -0
  66. package/src/components/LogicPushable.js +98 -0
  67. package/src/components/LogicRebounder.js +136 -0
  68. package/src/components/LogicRegionSpawner.js +139 -0
  69. package/src/components/LogicRotationalMovement.js +205 -0
  70. package/src/components/LogicSpawner.js +159 -0
  71. package/src/components/LogicStateMachine.js +382 -0
  72. package/src/components/LogicSwitch.js +77 -0
  73. package/src/components/LogicTeleportee.js +68 -0
  74. package/src/components/LogicTeleporter.js +93 -0
  75. package/src/components/LogicTimer.js +178 -0
  76. package/src/components/LogicWindUpRacer.js +179 -0
  77. package/src/components/Motion.js +371 -0
  78. package/src/components/Mover.js +566 -0
  79. package/src/components/Node.js +289 -0
  80. package/src/components/NodeMap.js +295 -0
  81. package/src/components/NodeResident.js +636 -0
  82. package/src/components/Orientation.js +697 -0
  83. package/src/components/RandomEvents.js +73 -0
  84. package/src/components/RelativePosition.js +204 -0
  85. package/src/components/RelayFamily.js +106 -0
  86. package/src/components/RelayGame.js +53 -0
  87. package/src/components/RelayLinker.js +94 -0
  88. package/src/components/RelayParent.js +57 -0
  89. package/src/components/RelaySelf.js +55 -0
  90. package/src/components/Render.js +178 -0
  91. package/src/components/RenderAnimator.js +275 -0
  92. package/src/components/RenderContainer.js +646 -0
  93. package/src/components/RenderDebug.js +319 -0
  94. package/src/components/RenderDestroyMe.js +59 -0
  95. package/src/components/RenderLottie.js +149 -0
  96. package/src/components/RenderProgress.js +120 -0
  97. package/src/components/RenderSpine.js +840 -0
  98. package/src/components/RenderSprite.js +527 -0
  99. package/src/components/RenderText.js +147 -0
  100. package/src/components/RenderTiles.js +1440 -0
  101. package/src/components/SceneChanger.js +128 -0
  102. package/src/components/TiledLoader.js +1459 -0
  103. package/src/components/Timeline.js +314 -0
  104. package/src/components/Tutorial.js +267 -0
  105. package/src/components/Tween.js +296 -0
  106. package/src/components/VoiceOver.js +373 -0
  107. package/src/components/XHR.js +129 -0
  108. package/src/components/index.js +79 -0
  109. package/src/factory.js +305 -0
  110. package/src/index.js +159 -0
  111. package/src/mixins/PIXI.Graphics.js +41 -0
  112. package/src/platypus.css +68 -0
  113. package/src/sayHello.js +50 -0
  114. package/src/shapes/Capsule.js +74 -0
  115. package/src/shapes/Circle.js +43 -0
  116. package/src/shapes/Ellipse.js +117 -0
  117. package/src/shapes/Point.js +191 -0
  118. package/src/shapes/Polygon.js +112 -0
  119. package/src/shapes/Polyline.js +97 -0
  120. package/src/shapes/Rectangle.js +78 -0
  121. package/src/shapes/RoundedRectangle.js +33 -0
  122. package/src/shapes/Segment.js +346 -0
  123. package/src/shapes/adjustedXY.js +19 -0
  124. package/src/shapes/castFromBox2D.js +92 -0
  125. package/src/shapes/castFromObject.js +53 -0
  126. package/src/shapes/castFromPixiGraphics.js +6 -0
  127. package/src/shapes/castFromPixiShape.js +89 -0
  128. package/src/shapes/castToBox2D.js +190 -0
  129. package/src/shapes/castToPixiGraphics.js +100 -0
  130. package/src/shapes/castToPixiShape.js +61 -0
  131. package/src/shapes/checkPointsMap.js +313 -0
  132. package/src/shapes/index.js +35 -0
  133. package/src/utils/array.js +73 -0
  134. package/src/utils/string.js +39 -0
  135. package/lib/243.platypus.mjs +0 -1
  136. package/lib/platypus.mjs +0 -1
@@ -0,0 +1,636 @@
1
+ /**
2
+ # COMPONENT **NodeResident**
3
+
4
+ ### Local Broadcasts:
5
+ - **next-to-[entity-type]** - This message is triggered when the entity is placed on a node. It will trigger on all neighboring entities, as well as on itself on behalf of neighboring entities.
6
+ - @param entity (Entity) - The entity that is next to the listening entity.
7
+ - **with-[entity-type]** - This message is triggered when the entity is placed on a node. It will trigger on all entities residing on the same node, as well as on itself on behalf of all resident entities.
8
+ - @param entity (Entity) - The entity that is with the listening entity.
9
+ - **left-node** - Triggered when the entity leaves a node.
10
+ - @param node (Node) - The node that the entity just left.
11
+ - **[Messages specified in definition]** - When the entity is placed on a node, it checks out the type of node and triggers a message on the entity if an event is listed for the current node type.
12
+
13
+ ## States
14
+ - **on-node** - This state is true when the entity is on a node.
15
+ - **moving** - This state is true when the entity is moving from one node to another.
16
+ - **going-[direction]** - This state is true when the entity is moving (or has just moved) in a direction (determined by the NodeMap) from one node to another.
17
+
18
+ ## JSON Definition
19
+ {
20
+ "type": "NodeResident",
21
+
22
+ "nodeId": "city-hall",
23
+ // Optional. The id of the node that this entity should start on. Uses the entity's nodeId property if not set here.
24
+
25
+ "friendlyNodes": {"path": "walking", "sidewalk": "walking", "road": "driving"],
26
+ // Optional. This is a list of node types that this entity can reside on. If not set, entity can reside on any type of node.
27
+
28
+ "friendlyEntities": ['friends','neighbors','city-council-members'],
29
+ // Optional. This is a list of entities that this entity can reside with on the same node. If not set, this entity can reside with any entities on the same node.
30
+
31
+ "speed": 5,
32
+ // Optional. Sets the speed with which the entity moves along an edge to an adjacent node. Default is 0 (instantaneous movement).
33
+
34
+ "updateOrientation": true
35
+ // Optional. Determines whether the entity's orientation is updated by movement across the NodeMap. Default is false.
36
+ }
37
+ */
38
+ import {arrayCache, greenSlice} from '../utils/array.js';
39
+ import createComponentClass from '../factory.js';
40
+
41
+ const
42
+ createGateway = function (nodeDefinition, map, gateway) {
43
+ return function () {
44
+ // ensure it's a node if one is available at this gateway
45
+ const
46
+ node = map.getNode(nodeDefinition);
47
+
48
+ if (this.isPassable(node)) {
49
+ this.destinationNodes.length = 0;
50
+ this.destinationNodes.push(node);
51
+
52
+ if (this.node) {
53
+ this.onEdge(node);
54
+ } else {
55
+ this.distance = 0;
56
+ }
57
+ this.progress = 0;
58
+
59
+ this.setState('going-' + gateway);
60
+ return true;
61
+ }
62
+
63
+ return false;
64
+ };
65
+ },
66
+ distance = function (origin, destination) {
67
+ const
68
+ x = destination.x - origin.x,
69
+ y = destination.y - origin.y,
70
+ z = destination.z - origin.z;
71
+
72
+ return Math.sqrt(x * x + y * y + z * z);
73
+ },
74
+ angle = function (origin, destination, distance, ratio) {
75
+ if (origin.rotation && destination.rotation) {
76
+ const
77
+ x = (origin.rotation + 180) % 360,
78
+ y = (destination.rotation + 180) % 360;
79
+
80
+ return (x * (1 - ratio) + y * ratio + 180) % 360;
81
+ } else {
82
+ const
83
+ x = destination.x - origin.x,
84
+ y = destination.y - origin.y;
85
+ let a = 0;
86
+
87
+ if (!distance) {
88
+ return a;
89
+ }
90
+
91
+ a = Math.acos(x / distance);
92
+ if (y < 0) {
93
+ a = (Math.PI * 2) - a;
94
+ }
95
+ return a * 180 / Math.PI;
96
+ }
97
+ },
98
+ axisProgress = function (r, o, d, f) {
99
+ return o * (1 - r) + d * r + f;
100
+ },
101
+ isFriendly = function (entities, kinds) {
102
+
103
+ if (kinds !== null) {
104
+ let found = false;
105
+
106
+ for (let x = 0; x < entities.length; x++) {
107
+ for (let y = 0; y < kinds.length; y++) {
108
+ if (entities[x].type === kinds[y]) {
109
+ found = true;
110
+ }
111
+ }
112
+ if (!found) {
113
+ return false;
114
+ } else {
115
+ found = false;
116
+ }
117
+ }
118
+ }
119
+
120
+ return true;
121
+ };
122
+
123
+ export default createComponentClass(/** @lends platypus.components.NodeResident.prototype */{
124
+
125
+ id: 'NodeResident',
126
+
127
+ properties: {
128
+ algorithm: distance,
129
+
130
+ /**
131
+ * This sets the resident's initial node.
132
+ *
133
+ * @property node
134
+ * @type Object
135
+ * @default null
136
+ */
137
+ node: null,
138
+
139
+ offset: {},
140
+
141
+ snapToNodes: false,
142
+
143
+ updateOrientation: false
144
+ },
145
+
146
+ publicProperties: {
147
+ friendlyNodes: null,
148
+
149
+ friendlyEntities: null,
150
+
151
+ nodeId: '',
152
+
153
+ /**
154
+ * This describes the rate at which a node resident should progress along an edge to another node. This property is set on the entity itself and can be manipulated in real-time.
155
+ *
156
+ * @property speed
157
+ * @type Number
158
+ * @default 0
159
+ */
160
+ speed: 0
161
+ },
162
+
163
+ /**
164
+ * This component connects an entity to its parent's [[NodeMap]]. It manages navigating the NodeMap and triggering events on the entity related to its position.
165
+ *
166
+ * @memberof platypus.components
167
+ * @uses platypus.Component
168
+ * @constructs
169
+ * @listens platypus.Entity#handle-logic
170
+ * @fires platypus.Entity#in-location
171
+ */
172
+ initialize: function () {
173
+ const
174
+ offset = this.offset,
175
+ startingNode = this.node;
176
+
177
+ this.neighbors = {};
178
+
179
+ this.distance = 0;
180
+ this.progress = 0;
181
+ this.offset = {
182
+ x: offset.x || 0,
183
+ y: offset.y || 0,
184
+ z: offset.z || 0
185
+ };
186
+ this.destinationNodes = arrayCache.setUp();
187
+
188
+ this.state = this.owner.state;
189
+ this.state.set('moving', false);
190
+ this.state.set('on-node', false);
191
+ this.currentState = '';
192
+
193
+ Object.defineProperty(this.owner, 'node', {
194
+ get: () => this.node,
195
+ set: (value) => {
196
+ if (value) {
197
+ this.getOnNode(value);
198
+ } else {
199
+ this.getOffNode();
200
+ }
201
+ }
202
+ });
203
+ this.owner.node = startingNode;
204
+ },
205
+
206
+ events: {
207
+ "set-algorithm": function (algorithm) {
208
+ this.algorithm = algorithm || distance;
209
+ },
210
+ "handle-logic": function (resp) {
211
+ let ratio = 0,
212
+ momentum = 0;
213
+
214
+ if (!this.owner.node) {
215
+ const
216
+ arr = arrayCache.setUp(this.owner.x, this.owner.y);
217
+
218
+ this.owner.node = this.owner.parent.getClosestNode(arr);
219
+ arrayCache.recycle(arr);
220
+
221
+ /**
222
+ * This event is triggered if the entity is placed on the map but not assigned a node. It is moved to the nearest node and "in-location" is triggered.
223
+ *
224
+ * @event platypus.Entity#in-location
225
+ * @param entity {platypus.Entity} The entity that is in location.
226
+ */
227
+ this.owner.triggerEvent('in-location', this.owner);
228
+ }
229
+
230
+ if (this.followEntity) {
231
+ const
232
+ node = this.followEntity.node || this.followEntity;
233
+
234
+ if (node && node.isNode && (node !== this.node)) {
235
+ this.lag = 0;
236
+ this.state.set('moving', this.gotoNode());
237
+ if (this.followDistance) {
238
+ momentum = this.lag;
239
+ }
240
+ } else {
241
+ this.followEntity = null;
242
+ }
243
+ } else {
244
+ momentum = this.speed * resp.delta;
245
+ }
246
+
247
+ // if goto-node was blocked, try again.
248
+ if (this.blocked) {
249
+ this.blocked = false;
250
+ if (this.goingToNode) {
251
+ this.owner.triggerEvent('goto-closest-node', this.goingToNode);
252
+ }
253
+ }
254
+
255
+ if (this.destinationNodes.length) {
256
+ this.state.set('moving', (this.speed !== 0));
257
+ if (this.node) {
258
+ this.onEdge(this.destinationNodes[0]);
259
+ } else if (!this.lastNode) {
260
+ this.owner.node = this.destinationNodes[0];
261
+ this.destinationNodes.shift();
262
+ if (!this.destinationNodes.length) {
263
+ this.state.set('moving', false);
264
+ return;
265
+ }
266
+ }
267
+
268
+ if (this.snapToNodes) {
269
+ for (let i = 0; i < this.destinationNodes.length; i++) {
270
+ this.owner.node = this.destinationNodes[i];
271
+ }
272
+ this.destinationNodes.length = 0;
273
+ } else {
274
+ while (this.destinationNodes.length && momentum) {
275
+ if ((this.progress + momentum) >= this.distance) {
276
+ const
277
+ node = this.destinationNodes[0];
278
+
279
+ momentum -= (this.distance - this.progress);
280
+ this.progress = 0;
281
+ this.destinationNodes.shift();
282
+ this.owner.node = node;
283
+ if (this.destinationNodes.length && momentum) {
284
+ this.onEdge(this.destinationNodes[0]);
285
+ }
286
+ } else {
287
+ this.progress += momentum;
288
+ ratio = this.progress / this.distance;
289
+ this.owner.x = axisProgress(ratio, this.lastNode.x, this.destinationNodes[0].x, this.offset.x);
290
+ this.owner.y = axisProgress(ratio, this.lastNode.y, this.destinationNodes[0].y, this.offset.y);
291
+ this.owner.z = axisProgress(ratio, this.lastNode.z, this.destinationNodes[0].z, this.offset.z);
292
+ if (this.updateOrientation) {
293
+ this.owner.rotation = angle(this.lastNode, this.destinationNodes[0], this.distance, ratio);
294
+ }
295
+ momentum = 0;
296
+ }
297
+ }
298
+ }
299
+ } else {
300
+ this.state.set('moving', false);
301
+ }
302
+ },
303
+ "goto-node": function (node) {
304
+ this.gotoNode(node);
305
+ },
306
+ "follow": function (entityOrNode) {
307
+ if (entityOrNode.entity) {
308
+ this.followDistance = entityOrNode.distance;
309
+ this.followEntity = entityOrNode.entity;
310
+ } else {
311
+ this.followDistance = 0;
312
+ this.followEntity = entityOrNode;
313
+ }
314
+ },
315
+ "goto-closest-node": (function () {
316
+ const
317
+ checkList = (here, list) => list.indexOf(here) >= 0,
318
+ checkType = (here, type) => here.type === type,
319
+ checkObjectType = (here, node) => here.type === node.type;
320
+
321
+ return function (nodesOrNodeType) {
322
+ const
323
+ origin = this.node ?? this.lastNode,
324
+ test = (typeof nodesOrNodeType === 'string') ? checkType : (typeof nodesOrNodeType.type === 'string') ? checkObjectType : checkList,
325
+ steps = nodesOrNodeType.steps ?? 0;
326
+
327
+ this.goingToNode = nodesOrNodeType;
328
+
329
+ if (origin && nodesOrNodeType && !test(origin, nodesOrNodeType)) {
330
+ const
331
+ nodes = arrayCache.setUp(),
332
+ travResp = this.traverseNode({
333
+ depth: 20, //arbitrary limit
334
+ origin: origin,
335
+ position: origin,
336
+ test,
337
+ destination: nodesOrNodeType,
338
+ nodes: nodes,
339
+ shortestPath: Infinity,
340
+ distance: 0,
341
+ found: false,
342
+ algorithm: this.algorithm,
343
+ blocked: false
344
+ });
345
+
346
+ travResp.distance -= this.progress;
347
+
348
+ if (travResp.found) {
349
+ //TODO: should probably set this up apart from this containing function
350
+ if (this.followEntity) {
351
+ if (!this.followDistance) {
352
+ this.setPath(travResp, steps);
353
+ } else if ((travResp.distance + (this.followEntity.progress || 0)) > this.followDistance) {
354
+ this.lag = travResp.distance + (this.followEntity.progress || 0) - this.followDistance;
355
+ this.setPath(travResp, steps);
356
+ } else {
357
+ this.lag = 0;
358
+ }
359
+ } else {
360
+ this.setPath(travResp, steps);
361
+ }
362
+ } else if (travResp.blocked) {
363
+ this.blocked = true;
364
+ }
365
+
366
+ arrayCache.recycle(nodes);
367
+ }
368
+ };
369
+ }()),
370
+ "set-directions": function () {
371
+ const
372
+ node = this.node,
373
+ nodeNeighbors = node.neighbors,
374
+ keys = Object.keys(nodeNeighbors),
375
+ {length} = keys;
376
+
377
+ this.owner.triggerEvent('remove-directions');
378
+
379
+ for (let i = 0; i < length; i++) {
380
+ const
381
+ key = keys[i],
382
+ nodeNeighbor = nodeNeighbors[key],
383
+ nextNode = node.map.getNode(nodeNeighbor),
384
+ gateway = this.neighbors[key] = createGateway(nodeNeighbor, node.map, i);
385
+
386
+ this.addEventListener(key, gateway);
387
+
388
+ //trigger "next-to" events
389
+ if (nextNode) {
390
+ const
391
+ entities = nextNode.contains;
392
+
393
+ for (let j = 0; j < entities.length; j++) {
394
+ entities[j].triggerEvent("next-to-" + this.owner.type, this.owner);
395
+ this.owner.triggerEvent("next-to-" + entities[j].type, entities[j]);
396
+ }
397
+ }
398
+ }
399
+ },
400
+ "remove-directions": function () {
401
+ const
402
+ neighbors = this.neighbors,
403
+ keys = Object.keys(neighbors),
404
+ {length} = keys;
405
+
406
+ for (let i = 0; i < length; i++) {
407
+ const
408
+ key = keys[i];
409
+
410
+ this.removeEventListener(key, neighbors[key]);
411
+ delete neighbors[key];
412
+ }
413
+ }
414
+ },
415
+
416
+ methods: {
417
+ gotoNode (node) {
418
+ const
419
+ origin = this.node ?? this.lastNode;
420
+ let moving = false;
421
+
422
+ if (!node && this.followEntity) {
423
+ node = this.followEntity.node ?? this.followEntity.lastNode ?? this.followEntity;
424
+ }
425
+
426
+ if (origin && node && (this.node !== node)) {
427
+ const
428
+ nodes = arrayCache.setUp(),
429
+ travResp = this.traverseNode({
430
+ depth: 20, //arbitrary limit
431
+ origin,
432
+ position: origin,
433
+ test: (here, there) => here === there,
434
+ destination: node,
435
+ nodes,
436
+ shortestPath: Infinity,
437
+ distance: 0,
438
+ found: false,
439
+ algorithm: this.algorithm,
440
+ blocked: false
441
+ });
442
+
443
+ travResp.distance -= this.progress;
444
+
445
+ if (travResp.found) {
446
+ //TODO: should probably set this up apart from this containing function
447
+ if (this.followEntity) {
448
+ if (!this.followDistance) {
449
+ this.setPath(travResp);
450
+ moving = true;
451
+ } else if ((travResp.distance + (this.followEntity.progress || 0)) > this.followDistance) {
452
+ this.lag = travResp.distance + (this.followEntity.progress || 0) - this.followDistance;
453
+ this.setPath(travResp);
454
+ moving = true;
455
+ } else {
456
+ this.lag = 0;
457
+ }
458
+ } else {
459
+ this.setPath(travResp);
460
+ moving = true;
461
+ }
462
+ } else if (travResp.blocked) {
463
+ this.blocked = true;
464
+ }
465
+
466
+ arrayCache.recycle(nodes);
467
+ }
468
+
469
+ return moving;
470
+ },
471
+
472
+ getOnNode (node) {
473
+ const
474
+ entities = node.contains;
475
+
476
+ this.getOffNode();
477
+ this.node = node;
478
+ if (this.node?.removeFromEdge) {
479
+ this.node.removeFromEdge(this.owner);
480
+ }
481
+ if (this.lastNode?.removeFromEdge) {
482
+ this.lastNode.removeFromEdge(this.owner);
483
+ }
484
+ this.node.addToNode(this.owner);
485
+
486
+ this.setState('on-node');
487
+
488
+ this.owner.x = this.node.x + this.offset.x;
489
+ this.owner.y = this.node.y + this.offset.y;
490
+ this.owner.z = this.node.z + this.offset.z;
491
+ if (this.updateOrientation && this.node.rotation) {
492
+ this.owner.rotation = this.node.rotation;
493
+ }
494
+
495
+ //add listeners for directions
496
+ this.owner.triggerEvent('set-directions');
497
+
498
+ //trigger mapped messages for node types
499
+ if (this.friendlyNodes && this.friendlyNodes[node.type]) {
500
+ this.owner.trigger(this.friendlyNodes[node.type], node);
501
+ }
502
+
503
+ //trigger "with" events
504
+ for (let j = 0; j < entities.length; j++) {
505
+ if (this.owner !== entities[j]) {
506
+ entities[j].triggerEvent("with-" + this.owner.type, this.owner);
507
+ this.owner.triggerEvent("with-" + entities[j].type, entities[j]);
508
+ }
509
+ }
510
+
511
+ this.owner.triggerEvent('on-node', node);
512
+ },
513
+
514
+ getOffNode: function () {
515
+ if (this.node) {
516
+ this.node.removeFromNode(this.owner);
517
+ this.owner.triggerEvent('left-node', this.node);
518
+ this.owner.triggerEvent('remove-directions');
519
+ }
520
+ this.lastNode = this.node;
521
+ this.node = null;
522
+ },
523
+
524
+ isPassable: function (node) {
525
+ return node && (this.node !== node) && (!this.friendlyNodes || (typeof this.friendlyNodes[node.type] !== 'undefined')) && (!node.contains.length || isFriendly(node.contains, this.friendlyEntities));
526
+ },
527
+ traverseNode: function (record) {
528
+ //TODO: may want to make this use A*. Currently node traversal order is arbitrary and essentially searches entire graph, but does clip out paths that are too long.
529
+ const
530
+ {position, test} = record;
531
+
532
+ if ((record.depth === 0) || (record.distance > record.shortestPath)) {
533
+ // if we've reached our search depth or are following a path longer than our recorded successful distance, bail
534
+ return record;
535
+ } else if (test(position, record.destination)) {
536
+ // if we've reached our destination, set shortest path information and bail.
537
+ record.found = true;
538
+ record.shortestPath = record.distance;
539
+ return record;
540
+ } else if (record.nodes.includes(position, 1)) { //Make sure we do not trace an infinite node loop.
541
+ return record;
542
+ } else {
543
+ const
544
+ algorithm = record.algorithm || distance,
545
+ map = position.map,
546
+ neighbors = position.neighbors,
547
+ keys = Object.keys(neighbors),
548
+ {length} = keys,
549
+ savedResp = {
550
+ shortestPath: Infinity,
551
+ found: false,
552
+ blocked: false
553
+ };
554
+ let blocked = true,
555
+ hasNeighbor = false;
556
+
557
+ for (let i = 0; i < length; i++) {
558
+ const
559
+ key = keys[i],
560
+ node = map.getNode(neighbors[key]);
561
+
562
+ hasNeighbor = true;
563
+
564
+ if (this.isPassable(node)) {
565
+ const
566
+ nodeList = [
567
+ ...record.nodes,
568
+ node
569
+ ],
570
+ resp = this.traverseNode({
571
+ depth: record.depth - 1,
572
+ origin: record.origin,
573
+ position: node,
574
+ destination: record.destination,
575
+ test,
576
+ algorithm: algorithm,
577
+ nodes: nodeList,
578
+ shortestPath: record.shortestPath,
579
+ distance: record.distance + algorithm(position, node),
580
+ gateway: record.gateway || key,
581
+ found: false,
582
+ blocked: false
583
+ });
584
+
585
+ if (resp.found && (savedResp.shortestPath > resp.shortestPath)) {
586
+ savedResp = resp;
587
+ }
588
+ blocked = false;
589
+ }
590
+ }
591
+ savedResp.blocked = (hasNeighbor && blocked);
592
+ return savedResp;
593
+ }
594
+ },
595
+ setPath: function (resp, steps) {
596
+ if (resp.nodes[0] === this.node) {
597
+ resp.nodes.shift();
598
+ }
599
+ arrayCache.recycle(this.destinationNodes);
600
+ this.destinationNodes = greenSlice(resp.nodes);
601
+ if (steps) {
602
+ this.destinationNodes.length = Math.min(steps, this.destinationNodes.length);
603
+ }
604
+ },
605
+ setState: function (state) {
606
+ if (state === 'on-node') {
607
+ this.state.set('on-node', true);
608
+ } else {
609
+ this.state.set('on-node', false);
610
+ if (this.currentState) {
611
+ this.state.set(this.currentState, false);
612
+ }
613
+ this.currentState = state;
614
+ this.state.set(state, true);
615
+ }
616
+ },
617
+ onEdge: function (toNode) {
618
+ this.distance = distance(this.node, toNode);
619
+ if (this.updateOrientation) {
620
+ this.owner.rotation = angle(this.node, toNode, this.distance, this.progress / this.distance);
621
+ }
622
+ if (this.node.addToEdge) {
623
+ this.node.addToEdge(this.owner);
624
+ }
625
+ if (toNode.addToEdge) {
626
+ toNode.addToEdge(this.owner);
627
+ }
628
+ this.owner.node = null;
629
+ },
630
+ destroy: function () {
631
+ arrayCache.recycle(this.destinationNodes);
632
+ this.destinationNodes = null;
633
+ this.state = null;
634
+ }
635
+ }
636
+ });