@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,1318 @@
1
+ import {arrayCache, greenSplice, union} from '../utils/array.js';
2
+ import AABB from '../AABB.js';
3
+ import CollisionData from '../CollisionData.js';
4
+ import CollisionDataContainer from '../CollisionDataContainer.js';
5
+ import Data from '../Data.js';
6
+ import DataMap from '../DataMap.js';
7
+ import Vector from '../Vector.js';
8
+ import createComponentClass from '../factory.js';
9
+
10
+ const
11
+ BIT_16 = 0xffff,
12
+ combine = function (x, y) {
13
+ return (x << 16) | (y & BIT_16);
14
+ },
15
+ getBucketId = function (x, y, bits) {
16
+ return combine(x >> bits, y >> bits);
17
+ },
18
+ triggerMessage = {
19
+ entity: null,
20
+ target: null,
21
+ type: null,
22
+ x: 0,
23
+ y: 0,
24
+ hitType: null,
25
+ myType: null
26
+ },
27
+ groupSortBySize = function (a, b) {
28
+ return a.collisionGroup.getAllEntities() - b.collisionGroup.getAllEntities();
29
+ },
30
+ epsilon = 0.000001;
31
+
32
+ export default createComponentClass(/** @lends platypus.components.HandlerCollision.prototype */{
33
+ id: 'HandlerCollision',
34
+
35
+ properties: {
36
+ /**
37
+ *
38
+ */
39
+ gridBits: 8
40
+ },
41
+
42
+ /**
43
+ * This component checks for collisions between entities which typically have either a [CollisionTiles](platypus.components.CollisionTiles.html) component for tile maps or a [CollisionBasic](platypus.components.CollisionBasic.html) component for other entities. It uses `EntityContainer` component messages if triggered to add to its collision list and also listens for explicit add/remove messages (useful in the absence of an `EntityContainer` component).
44
+ *
45
+ * @memberof platypus.components
46
+ * @uses platypus.Component
47
+ * @constructs
48
+ * @listens platypus.Entity#add-collision-entity
49
+ * @listens platypus.Entity#check-collision-group
50
+ * @listens platypus.Entity#child-entity-added
51
+ * @listens platypus.Entity#child-entity-removed
52
+ * @listens platypus.Entity#child-entity-updated
53
+ * @listens platypus.Entity#remove-collision-entity
54
+ * @fires platypus.Entity#hit-by-*
55
+ * @fires platypus.Entity#relocate-entity
56
+ */
57
+ initialize: function () {
58
+ this.againstGrid = Data.setUp();
59
+
60
+ this.solidEntitiesLive = arrayCache.setUp();
61
+ this.softEntitiesLive = arrayCache.setUp();
62
+ this.allEntitiesLive = arrayCache.setUp();
63
+ this.groupsLive = arrayCache.setUp();
64
+ this.nonColliders = arrayCache.setUp();
65
+
66
+ this.terrains = [];
67
+ this.owner.previousX = this.owner.previousX || this.owner.x;
68
+ this.owner.previousY = this.owner.previousY || this.owner.y;
69
+
70
+ this.relocationMessage = Data.setUp(
71
+ "position", Vector.setUp(),
72
+ "relative", false
73
+ );
74
+ },
75
+
76
+ events: {
77
+ "child-entity-added": function (entity) {
78
+ if (!entity.collideOff) {
79
+ this.addCollisionEntity(entity);
80
+ }
81
+ },
82
+
83
+ "add-collision-entity": function (entity) {
84
+ this.addCollisionEntity(entity);
85
+ },
86
+
87
+ "child-entity-removed": function (entity) {
88
+ this.removeCollisionEntity(entity);
89
+ },
90
+
91
+ "remove-collision-entity": function (entity) {
92
+ this.removeCollisionEntity(entity);
93
+ },
94
+
95
+ "child-entity-updated": function (entity) {
96
+ this.removeCollisionEntity(entity);
97
+ this.addCollisionEntity(entity);
98
+ },
99
+
100
+ "check-collision-group": function (resp) {
101
+ this.checkCamera(resp.camera, resp.entities);
102
+ this.checkGroupCollisions();
103
+ this.checkSolidCollisions();
104
+ this.resolveNonCollisions();
105
+ this.checkSoftCollisions(resp);
106
+ }
107
+ },
108
+
109
+ methods: {
110
+ mapDown (aabb2) {
111
+ const
112
+ aabb1 = AABB.setUp(),
113
+ gb = this.gridBits;
114
+
115
+ return aabb1.setBounds(aabb2.left >> gb, aabb2.top >> gb, aabb2.right >> gb, aabb2.bottom >> gb);
116
+ },
117
+
118
+ getAgainstGrid (entity, sweep, types) {
119
+ const
120
+ aabb = this.mapDown(sweep),
121
+ data = Data.setUp(),
122
+ thisAgainstGrid = this.againstGrid;
123
+
124
+ if (entity && sweep.equals(entity.againstAABB)) {
125
+ return this.getEntityAgainstGrid(entity, types);
126
+ }
127
+
128
+ for (let x = aabb.left; x <= aabb.right; x++) {
129
+ for (let y = aabb.top; y <= aabb.bottom; y++) {
130
+ const
131
+ list = thisAgainstGrid[combine(x, y)];
132
+
133
+ if (list) {
134
+ this.mergeAGCell(list, data, types);
135
+ }
136
+ }
137
+ }
138
+
139
+ aabb.recycle();
140
+ return data;
141
+ },
142
+
143
+ getEntityAgainstGrid: function (entity, types) {
144
+ const
145
+ ag = entity.againstGrid,
146
+ data = Data.setUp();
147
+ let i = ag.length;
148
+
149
+ while (i--) {
150
+ this.mergeAGCell(ag[i], data, types);
151
+ }
152
+
153
+ return data;
154
+ },
155
+
156
+ mergeAGCell: function (list, data, types) {
157
+ let i = types.length;
158
+
159
+ while (i--) {
160
+ const
161
+ type = types[i],
162
+ arr = list.get(type);
163
+
164
+ if (arr?.length) {
165
+ const tList = data[type];
166
+ if (!tList) {
167
+ data[type] = union(arrayCache.setUp(), arr);
168
+ } else {
169
+ union(tList, arr);
170
+ }
171
+ }
172
+ }
173
+ },
174
+
175
+ removeAgainst (entity) {
176
+ const
177
+ {collisionTypes, againstGrid} = entity,
178
+ len = collisionTypes.length;
179
+ let i = againstGrid.length;
180
+
181
+ while (i--) {
182
+ const
183
+ list = againstGrid[i];
184
+ let j = len;
185
+
186
+ while (j--) {
187
+ const
188
+ arr = list.get(collisionTypes[j]);
189
+
190
+ if (arr) {
191
+ const
192
+ id = arr.indexOf(entity);
193
+
194
+ if (id >= 0) {
195
+ greenSplice(arr, id);
196
+ }
197
+ }
198
+ }
199
+ }
200
+ againstGrid.length = 0;
201
+ },
202
+
203
+ updateAgainst (entity) {
204
+ const
205
+ {againstAABB, againstGrid: entityAgainstGrid, collisionTypes} = entity,
206
+ aabb = this.mapDown(entity.getAABB()),
207
+ {againstGrid} = this;
208
+
209
+ if (!aabb.equals(againstAABB)) {
210
+ againstAABB.set(aabb);
211
+ this.removeAgainst(entity);
212
+
213
+ for (let x = aabb.left; x <= aabb.right; x++) {
214
+ for (let y = aabb.top; y <= aabb.bottom; y++) {
215
+ const
216
+ id = combine(x, y);
217
+ let list = againstGrid[id],
218
+ i = collisionTypes.length;
219
+
220
+ if (!list) {
221
+ list = againstGrid[id] = DataMap.setUp();
222
+ }
223
+ while (i--) {
224
+ const
225
+ type = collisionTypes[i],
226
+ arr = list.get(type) ?? list.set(type, arrayCache.setUp());
227
+
228
+ arr.push(entity);
229
+ }
230
+ entityAgainstGrid.push(list);
231
+ }
232
+ }
233
+ }
234
+
235
+ aabb.recycle();
236
+ },
237
+
238
+ addCollisionEntity: function (entity) {
239
+ if (entity.getTileShapes) { // Has a CollisionTiles component
240
+ this.terrains.push(entity);
241
+ } else if (entity.collisionTypes && !entity.againstGrid) {
242
+ entity.againstGrid = arrayCache.setUp();
243
+ entity.againstAABB = AABB.setUp();
244
+ this.updateAgainst(entity);
245
+ }
246
+ },
247
+
248
+ removeCollisionEntity: function (entity) {
249
+ if (entity.getTileShapes) { // Has a CollisionTiles component
250
+ const index = this.terrains.indexOf(entity);
251
+ if (index !== -1) {
252
+ this.terrains.splice(index, 1);
253
+ }
254
+ } if (entity.againstGrid) {
255
+ this.removeAgainst(entity);
256
+ arrayCache.recycle(entity.againstGrid);
257
+ entity.againstGrid = null;
258
+ entity.againstAABB.recycle();
259
+ entity.againstAABB = null;
260
+ }
261
+ },
262
+
263
+ checkCamera: function (camera, all) {
264
+ const
265
+ {allEntitiesLive, solidEntitiesLive, softEntitiesLive, nonColliders, groupsLive} = this;
266
+ let i = all.length;
267
+
268
+ allEntitiesLive.length = 0;
269
+ solidEntitiesLive.length = 0;
270
+ softEntitiesLive.length = 0;
271
+ nonColliders.length = 0;
272
+ groupsLive.length = 0;
273
+
274
+ while (i--) {
275
+ const
276
+ entity = all[i],
277
+ {collisionTypes, immobile} = entity;
278
+
279
+ if (!immobile && collisionTypes?.length) {
280
+ let collides = false,
281
+ j = collisionTypes.length;
282
+
283
+ allEntitiesLive.push(entity);
284
+
285
+ if (entity !== this.owner) {
286
+ let k = collisionTypes.length;
287
+
288
+ while (k--) {
289
+ if (entity.solidCollisionMap.get(collisionTypes[k]).length) {
290
+ solidEntitiesLive.push(entity);
291
+ collides = true;
292
+ break;
293
+ }
294
+ }
295
+ }
296
+
297
+ while (j--) {
298
+ if (entity.softCollisionMap.get(collisionTypes[j]).length) {
299
+ softEntitiesLive.push(entity);
300
+ break;
301
+ }
302
+ }
303
+
304
+ if (!collides) {
305
+ nonColliders.push(entity);
306
+ }
307
+
308
+ if (entity.collisionGroup) {
309
+ groupsLive.push(entity);
310
+ }
311
+ }
312
+ }
313
+
314
+ groupsLive.sort(groupSortBySize);
315
+ },
316
+
317
+ resolveNonCollisions: function () {
318
+ const
319
+ msg = this.relocationMessage,
320
+ nons = this.nonColliders;
321
+ let i = nons.length;
322
+
323
+ msg.relative = false;
324
+ while (i--) {
325
+ const
326
+ entity = nons[i];
327
+
328
+ if ((entity.position.x !== entity.previousPosition.x) || (entity.position.y !== entity.previousPosition.y)) {
329
+ msg.position.setVector(entity.position);
330
+ entity.triggerEvent('relocate-entity', msg);
331
+ this.updateAgainst(entity);
332
+ }
333
+ }
334
+ },
335
+
336
+ checkGroupCollisions: (function () {
337
+ /**
338
+ * When an entity collides with an entity of a listed collision-type, this message is triggered on the entity. * is the other entity's collision-type.
339
+ *
340
+ * @event platypus.Entity#hit-by-*
341
+ * @param collision {Object}
342
+ * @param collision.entity {Entity} The entity with which the collision occurred.
343
+ * @param collision.target {Entity} The entity that's receiving the collision event.
344
+ * @param collision.type {String} The collision type of the other entity.
345
+ * @param collision.shape {CollisionShape} This is the shape of the other entity that caused the collision.
346
+ * @param collision.x {number} Returns -1, 0, or 1 indicating on which side of this entity the collision occurred: left, neither, or right respectively.
347
+ * @param collision.y {number} Returns -1, 0, or 1 indicating on which side of this entity the collision occurred: top, neither, or bottom respectively.
348
+ */
349
+ const
350
+ triggerCollisionMessages = function (entity, otherEntity, thisType, thatType, x, y, hitType, vector) {
351
+ const
352
+ msg = triggerMessage;
353
+
354
+ msg.entity = otherEntity;
355
+ msg.target = entity;
356
+ msg.myType = thisType;
357
+ msg.type = thatType;
358
+ msg.x = x;
359
+ msg.y = y;
360
+ msg.direction = vector;
361
+ msg.hitType = hitType;
362
+ entity.triggerEvent('hit-by-' + thatType, msg);
363
+
364
+ if (otherEntity) {
365
+ msg.entity = entity;
366
+ msg.target = otherEntity;
367
+ msg.type = thisType;
368
+ msg.myType = thatType;
369
+ msg.x = -x;
370
+ msg.y = -y;
371
+ msg.direction = vector.getInverse();
372
+ msg.hitType = hitType;
373
+ otherEntity.triggerEvent('hit-by-' + thisType, msg);
374
+
375
+ msg.direction.recycle();
376
+ }
377
+ };
378
+
379
+ return function () {
380
+ const
381
+ entities = this.groupsLive;
382
+ let i = entities.length;
383
+
384
+ while (i--) {
385
+ const
386
+ entity = entities[i];
387
+
388
+ if (entity.collisionGroup.getSize() > 1) {
389
+ const
390
+ entityCDC = this.checkSolidEntityCollision(entity, entity.collisionGroup),
391
+ {xData, yData} = entityCDC;
392
+ let x = xData.length,
393
+ y = yData.length
394
+
395
+ while (x--) {
396
+ const
397
+ messageData = xData[x];
398
+ triggerCollisionMessages(messageData.thisShape.owner, messageData.thatShape.owner, messageData.thisShape.collisionType, messageData.thatShape.collisionType, messageData.direction, 0, 'solid', messageData.vector);
399
+ }
400
+
401
+ while (y--) {
402
+ const
403
+ messageData = yData[y];
404
+
405
+ triggerCollisionMessages(messageData.thisShape.owner, messageData.thatShape.owner, messageData.thisShape.collisionType, messageData.thatShape.collisionType, 0, messageData.direction, 'solid', messageData.vector);
406
+ }
407
+
408
+ entityCDC.recycle();
409
+ }
410
+ }
411
+ };
412
+ }()),
413
+
414
+ checkSolidCollisions: (function () {
415
+ const
416
+ triggerCollisionMessages = function (entity, otherEntity, thisType, thatType, x, y, hitType, vector) {
417
+ const
418
+ msg = triggerMessage;
419
+
420
+ msg.entity = otherEntity;
421
+ msg.target = entity;
422
+ msg.myType = thisType;
423
+ msg.type = thatType;
424
+ msg.x = x;
425
+ msg.y = y;
426
+ msg.direction = vector;
427
+ msg.hitType = hitType;
428
+ entity.triggerEvent('hit-by-' + thatType, msg);
429
+
430
+ if (otherEntity) {
431
+ msg.entity = entity;
432
+ msg.target = otherEntity;
433
+ msg.type = thisType;
434
+ msg.myType = thatType;
435
+ msg.x = -x;
436
+ msg.y = -y;
437
+ msg.direction = vector.getInverse();
438
+ msg.hitType = hitType;
439
+ otherEntity.triggerEvent('hit-by-' + thisType, msg);
440
+
441
+ msg.direction.recycle();
442
+ }
443
+ };
444
+
445
+ return function () {
446
+ const
447
+ entities = this.solidEntitiesLive;
448
+ let i = entities.length;
449
+
450
+ while (i--) {
451
+ const
452
+ entity = entities[i],
453
+ entityCDC = this.checkSolidEntityCollision(entity, entity),
454
+ {xData, yData} = entityCDC;
455
+ let x = xData.length,
456
+ y = yData.length
457
+
458
+ while (x--) {
459
+ const
460
+ messageData = xData[x];
461
+
462
+ triggerCollisionMessages(messageData.thisShape.owner, messageData.thatShape.owner, messageData.thisShape.collisionType, messageData.thatShape.collisionType, messageData.direction, 0, 'solid', messageData.vector);
463
+ }
464
+
465
+ while (y--) {
466
+ const
467
+ messageData = yData[y];
468
+
469
+ triggerCollisionMessages(messageData.thisShape.owner, messageData.thatShape.owner, messageData.thisShape.collisionType, messageData.thatShape.collisionType, 0, messageData.direction, 'solid', messageData.vector);
470
+ }
471
+
472
+ entityCDC.recycle();
473
+ }
474
+ };
475
+ }()),
476
+
477
+ checkSolidEntityCollision: function (ent, entityOrGroup) {
478
+ const
479
+ {bullet, collisionDirty, previousX, previousY, x, y} = ent,
480
+ collisionDataCollection = CollisionDataContainer.setUp(),
481
+ dX = x - previousX,
482
+ dY = y - previousY,
483
+ collisionTypes = entityOrGroup.getCollisionTypes(),
484
+ ignoredEntities = entityOrGroup.getSolidEntities?.() ?? false;
485
+ let finalMovementInfo = Vector.setUp(ent.position);
486
+
487
+ if (dX || dY || collisionDirty) {
488
+
489
+ if (bullet) {
490
+ let sW = Infinity,
491
+ sH = Infinity,
492
+ i = collisionTypes.length;
493
+
494
+ while (i--) {
495
+ const
496
+ aabb = entityOrGroup.getAABB(collisionTypes[i]);
497
+
498
+ sW = Math.min(sW, aabb.width);
499
+ sH = Math.min(sH, aabb.height);
500
+ }
501
+
502
+ {
503
+ const
504
+ //Stepping to catch really fast entities - this is not perfect, but should prevent the majority of fallthrough cases.
505
+ steps = Math.min(Math.ceil(Math.max(Math.abs(dX) / sW, Math.abs(dY) / sH)), 100), //Prevent memory overflow if things move exponentially far.
506
+ stepDX = dX / steps,
507
+ stepDY = dY / steps;
508
+ let step = steps;
509
+
510
+ while (step--) {
511
+ entityOrGroup.prepareCollision(ent.previousX + stepDX, ent.previousY + stepDY);
512
+
513
+ finalMovementInfo = this.processCollisionStep(ent, entityOrGroup, ignoredEntities, collisionDataCollection, finalMovementInfo.setVector(ent.position), stepDX, stepDY, collisionTypes);
514
+
515
+ if ((finalMovementInfo.x === ent.previousX) && (finalMovementInfo.y === ent.previousY)) {
516
+ entityOrGroup.relocateEntity(finalMovementInfo, collisionDataCollection);
517
+ //No more movement so we bail!
518
+ break;
519
+ } else {
520
+ entityOrGroup.relocateEntity(finalMovementInfo, collisionDataCollection);
521
+ }
522
+ }
523
+ }
524
+ } else {
525
+ entityOrGroup.prepareCollision(previousX + dX, previousY + dY);
526
+ finalMovementInfo = this.processCollisionStep(ent, entityOrGroup, ignoredEntities, collisionDataCollection, finalMovementInfo, dX, dY, collisionTypes);
527
+ entityOrGroup.relocateEntity(finalMovementInfo, collisionDataCollection);
528
+ }
529
+
530
+ if ((finalMovementInfo.x !== previousX) || (finalMovementInfo.y !== previousY)) {
531
+ this.updateAgainst(ent);
532
+
533
+ // Update children affected by this movement.
534
+ if (ent !== entityOrGroup) {
535
+ const
536
+ children = entityOrGroup.getSolidEntities();
537
+
538
+ for (let i = 0; i < children.length; i++) {
539
+ this.updateAgainst(children[i]);
540
+ }
541
+ }
542
+ }
543
+ }
544
+
545
+ finalMovementInfo.recycle();
546
+
547
+ return collisionDataCollection;
548
+ },
549
+
550
+ processCollisionStep: (function () {
551
+ const
552
+ sweeper = AABB.setUp(),
553
+ getJumpThroughNormal = function (shape) {
554
+ const
555
+ jt = shape.jumpThrough;
556
+
557
+ if (!jt) {
558
+ return null;
559
+ } else {
560
+ const
561
+ owner = shape.owner,
562
+ v = Vector.setUp(jt.x * (owner.scaleX || 1), jt.y * (owner.scaleY || 1));
563
+
564
+ if (owner.rotation) {
565
+ v.rotate(owner.rotation * Math.PI / 180);
566
+ }
567
+
568
+ return v;
569
+ }
570
+ },
571
+ shouldSkipJumpThroughCollision = function (platformEntity, movingAABB, platformAABB) {
572
+ //TODO: currently does not handle individual shape jumpThrough. That will need to happen a layer deeper.
573
+ const collisionTypes = platformEntity.collisionTypes;
574
+
575
+ if (!collisionTypes) {
576
+ return true;
577
+ }
578
+
579
+ let i = collisionTypes.length;
580
+
581
+ while (i--) {
582
+ const shapes = platformEntity.getShapes(collisionTypes[i]);
583
+
584
+ if (!shapes) {
585
+ continue;
586
+ }
587
+
588
+ let j = shapes.length;
589
+
590
+ while (j--) {
591
+ const
592
+ shape = shapes[j],
593
+ normal = getJumpThroughNormal(shape);
594
+
595
+ if (!normal) {
596
+ continue;
597
+ } else {
598
+ const
599
+ absx = Math.abs(normal.x),
600
+ absy = Math.abs(normal.y),
601
+ ignore = absy >= absx
602
+ ? ( // Primarily vertical normal
603
+ (normal.y < -epsilon && movingAABB.bottom > platformAABB.top) ||
604
+ (normal.y > epsilon && movingAABB.top < platformAABB.bottom)
605
+ )
606
+ : ( // Primarily horizontal normal
607
+ (normal.x < -epsilon && movingAABB.right > platformAABB.left) ||
608
+ (normal.x > epsilon && movingAABB.left < platformAABB.right)
609
+ )
610
+
611
+ normal.recycle();
612
+
613
+ if (ignore) {
614
+ return ignore;
615
+ }
616
+ }
617
+ }
618
+ }
619
+
620
+ return false;
621
+ },
622
+ includeEntity = function (thisEntity, aabb, otherEntity, otherAABB, ignoredEntities, sweepAABB) {
623
+ //Chop out all the special case entities we don't want to check against.
624
+ if (otherEntity === thisEntity) {
625
+ return false;
626
+ } else if (shouldSkipJumpThroughCollision(otherEntity, aabb, otherAABB)) {
627
+ return false;
628
+ } else if (shouldSkipJumpThroughCollision(thisEntity, otherAABB, aabb)) { // This will allow platforms to hit something solid sideways if it runs into them from the side even though originally they were above the top. - DDD
629
+ return false;
630
+ } else if (ignoredEntities) {
631
+ let i = ignoredEntities.length;
632
+
633
+ while (i--) {
634
+ if (otherEntity === ignoredEntities[i]) {
635
+ return false;
636
+ }
637
+ }
638
+ }
639
+
640
+ return sweepAABB.collides(otherAABB);
641
+ };
642
+
643
+ return function (ent, entityOrGroup, ignoredEntities, collisionDataCollection, finalMovementInfo, entityDeltaX, entityDeltaY, collisionTypes) {
644
+ const
645
+ potentialCollidingShapes = arrayCache.setUp(),
646
+ terrains = this.terrains,
647
+ solidCollisionMap = entityOrGroup.getSolidCollisions(),
648
+ sweepAABB = sweeper;
649
+ let i = collisionTypes.length,
650
+ potentialCollision = false;
651
+
652
+ while (i--) {
653
+ //Sweep the full movement of each collision type
654
+ const
655
+ pcsGroup = potentialCollidingShapes[i] = arrayCache.setUp(),
656
+ collisionType = collisionTypes[i],
657
+ previousAABB = entityOrGroup.getPreviousAABB(collisionType),
658
+ currentAABB = entityOrGroup.getAABB(collisionType),
659
+ collisionSubTypes = solidCollisionMap.get(collisionType);
660
+ let againstGrid = null,
661
+ j = collisionSubTypes.length;;
662
+
663
+ sweepAABB.set(currentAABB);
664
+ sweepAABB.include(previousAABB);
665
+
666
+ againstGrid = this.getAgainstGrid(ent, sweepAABB, collisionSubTypes);
667
+
668
+ while (j--) {
669
+ const
670
+ otherCollisionType = collisionSubTypes[j],
671
+ otherEntities = againstGrid[otherCollisionType];
672
+
673
+ if (otherEntities) {
674
+ let k = otherEntities.length;
675
+
676
+ while (k--) {
677
+ const
678
+ otherEntity = otherEntities[k],
679
+ otherAABB = otherEntity.getAABB(otherCollisionType);
680
+
681
+ //Do our sweep check against the AABB of the other object and add potentially colliding shapes to our list.
682
+ if (includeEntity(ent, previousAABB, otherEntity, otherAABB, ignoredEntities, sweepAABB)) {
683
+ const
684
+ otherShapes = otherEntity.getShapes(otherCollisionType);
685
+ let l = otherShapes.length;
686
+
687
+ while (l--) {
688
+ //Push the shapes on the end!
689
+ pcsGroup.push(otherShapes[l]);
690
+ }
691
+ potentialCollision = true;
692
+ }
693
+ }
694
+ arrayCache.recycle(otherEntities);
695
+ } else if (terrains.length) {
696
+ //Do our sweep check against the tiles and add potentially colliding shapes to our list.
697
+ let l = 0;
698
+
699
+ for (l = 0; l < terrains.length; l++) {
700
+ const otherShapes = terrains[l].getTileShapes(sweepAABB, previousAABB, otherCollisionType);
701
+ let k = otherShapes.length;
702
+
703
+ while (k--) {
704
+ //Push the shapes on the end!
705
+ pcsGroup.push(otherShapes[k]);
706
+ potentialCollision = true;
707
+ }
708
+ }
709
+ }
710
+ }
711
+ againstGrid.recycle();
712
+ }
713
+
714
+ if (potentialCollision) {
715
+ finalMovementInfo = this.resolveCollisionPosition(ent, entityOrGroup, finalMovementInfo, potentialCollidingShapes, collisionDataCollection, collisionTypes, entityDeltaX, entityDeltaY);
716
+ }
717
+
718
+ // Array recycling
719
+ arrayCache.recycle(potentialCollidingShapes, 2);
720
+
721
+ return finalMovementInfo;
722
+ };
723
+ }()),
724
+
725
+ resolveCollisionPosition: function (ent, entityOrGroup, finalMovementInfo, potentialCollidingShapes, collisionDataCollection, collisionTypes, entityDeltaX, entityDeltaY) {
726
+ if (entityDeltaX !== 0) {
727
+ let j = collisionTypes.length;
728
+
729
+ while (j--) {
730
+ //Move each collision type in X to find the min X movement
731
+ const
732
+ cd = this.findMinAxisMovement(ent, entityOrGroup, collisionTypes[j], 'x', potentialCollidingShapes[j]);
733
+
734
+ if (!cd.occurred || !collisionDataCollection.tryToAddX(cd)) {
735
+ cd.recycle();
736
+ }
737
+ }
738
+ }
739
+
740
+ {
741
+ const
742
+ cd = collisionDataCollection.xData[0];
743
+ if (cd) {
744
+ finalMovementInfo.x = ent.previousX + cd.deltaMovement * cd.direction;
745
+ } else {
746
+ finalMovementInfo.x = ent.x;
747
+ }
748
+ }
749
+
750
+ // This moves the previous position of everything so that the check in Y can begin.
751
+ entityOrGroup.movePreviousX(finalMovementInfo.x);
752
+
753
+ if (entityDeltaY !== 0) {
754
+ let j = collisionTypes.length;
755
+
756
+ while (j--) {
757
+ //Move each collision type in Y to find the min Y movement
758
+ const
759
+ cd = this.findMinAxisMovement(ent, entityOrGroup, collisionTypes[j], 'y', potentialCollidingShapes[j]);
760
+
761
+ if (!cd.occurred || !collisionDataCollection.tryToAddY(cd)) {
762
+ cd.recycle();
763
+ }
764
+ }
765
+ }
766
+
767
+ {
768
+ const
769
+ cd = collisionDataCollection.yData[0];
770
+ if (cd) {
771
+ finalMovementInfo.y = ent.previousY + cd.deltaMovement * cd.direction;
772
+ } else {
773
+ finalMovementInfo.y = ent.y;
774
+ }
775
+ }
776
+
777
+ return finalMovementInfo;
778
+ },
779
+
780
+ findMinAxisMovement: function (ent, entityOrGroup, collisionType, axis, potentialCollidingShapes) {
781
+ //Loop through my shapes of this type vs the colliding shapes and do precise collision returning the shortest movement in axis direction
782
+ const
783
+ shapes = entityOrGroup.getShapes(collisionType),
784
+ prevShapes = entityOrGroup.getPrevShapes(collisionType);
785
+ let bestCD = CollisionData.setUp(),
786
+ i = shapes.length;
787
+
788
+ while (i--) {
789
+ const
790
+ cd = this.findMinShapeMovementCollision(prevShapes[i], shapes[i], axis, potentialCollidingShapes);
791
+
792
+ if (cd.occurred && (!bestCD.occurred //if a collision occurred and we haven't already had a collision.
793
+ || (cd.deltaMovement < bestCD.deltaMovement))) { //if a collision occurred and the diff is smaller than our best diff.
794
+ bestCD.recycle();
795
+ bestCD = cd;
796
+ } else {
797
+ cd.recycle();
798
+ }
799
+ }
800
+
801
+ return bestCD;
802
+ },
803
+
804
+ /**
805
+ * Find the earliest point at which this shape collides with one of the potential colliding shapes along this axis.
806
+ * For example, cycles through shapes a, b, and c to find the earliest position:
807
+ *
808
+ * O----> [b] [a] [c]
809
+ *
810
+ * Returns collision location for:
811
+ *
812
+ * O[b]
813
+ *
814
+ */
815
+ findMinShapeMovementCollision: (function () {
816
+ const
817
+ returnInfo = {
818
+ position: 0,
819
+ contactVector: Vector.setUp()
820
+ },
821
+ getMovementDistance = (currentDistance, minimumDistance) => Math.sqrt((minimumDistance ** 2) - (currentDistance ** 2)),
822
+ getCorner = function (circlePos, rectanglePos, half) {
823
+ const
824
+ diff = circlePos - rectanglePos;
825
+
826
+ return diff - (diff / Math.abs(diff)) * half;
827
+ },
828
+ getOffsetForCircleVsAABBX = function (circle, rect, moving, direction, v) {
829
+ const
830
+ aabb = rect.aABB,
831
+ hw = aabb.halfWidth,
832
+ {x, y} = circle;
833
+
834
+ if (y >= aabb.top && y <= aabb.bottom) {
835
+ return hw + circle.radius;
836
+ } else {
837
+ const
838
+ cornerY = getCorner(y, rect.y, aabb.halfHeight),
839
+ newAxisPosition = hw + getMovementDistance(cornerY, circle.radius);
840
+
841
+ if (moving === circle) {
842
+ v.x = -getCorner(x - direction * newAxisPosition, rect.x, hw) / 2;
843
+ v.y = -cornerY;
844
+ } else {
845
+ v.x = getCorner(x, rect.x - direction * newAxisPosition, hw) / 2;
846
+ v.y = cornerY;
847
+ }
848
+ v.normalize();
849
+ return newAxisPosition;
850
+ }
851
+ },
852
+ getOffsetForCircleVsAABBY = function (circle, rect, moving, direction, v) {
853
+ const
854
+ aabb = rect.aABB,
855
+ hh = aabb.halfHeight,
856
+ {x, y} = circle;
857
+
858
+ if (x >= aabb.left && x <= aabb.right) {
859
+ return hh + circle.radius;
860
+ } else {
861
+ const
862
+ cornerX = getCorner(x, rect.x, aabb.halfWidth),
863
+ newAxisPosition = hh + getMovementDistance(cornerX, circle.radius);
864
+
865
+ if (moving === circle) {
866
+ v.x = -cornerX;
867
+ v.y = -getCorner(y - direction * newAxisPosition, rect.y, hh) / 2;
868
+ } else {
869
+ v.x = cornerX;
870
+ v.y = getCorner(y, rect.y - direction * newAxisPosition, hh) / 2;
871
+ }
872
+ v.normalize();
873
+ return newAxisPosition;
874
+ }
875
+ },
876
+ findAxisCollisionPosition = { // Decision tree for quicker access, optimized for mobile devices.
877
+ x: {
878
+ rectangle: {
879
+ rectangle: function (direction, thisShape, thatShape) {
880
+ const
881
+ ri = returnInfo;
882
+
883
+ ri.position = thatShape.x - direction * (thatShape.aABB.halfWidth + thisShape.aABB.halfWidth);
884
+ ri.contactVector.setXYZ(direction, 0);
885
+
886
+ return ri;
887
+ },
888
+ circle: function (direction, thisShape, thatShape) {
889
+ const
890
+ ri = returnInfo;
891
+
892
+ ri.position = thatShape.x - direction * getOffsetForCircleVsAABBX(thatShape, thisShape, thisShape, direction, ri.contactVector.setXYZ(direction, 0));
893
+
894
+ return ri;
895
+ }
896
+ },
897
+ circle: {
898
+ rectangle: function (direction, thisShape, thatShape) {
899
+ const
900
+ ri = returnInfo;
901
+
902
+ ri.position = thatShape.x - direction * getOffsetForCircleVsAABBX(thisShape, thatShape, thisShape, direction, ri.contactVector.setXYZ(direction, 0));
903
+
904
+ return ri;
905
+ },
906
+ circle: function (direction, thisShape, thatShape) {
907
+ const
908
+ y = thatShape.y - thisShape.y,
909
+ position = thatShape.x - direction * getMovementDistance(y, thisShape.radius + thatShape.radius),
910
+ ri = returnInfo;
911
+
912
+ ri.contactVector.setXYZ(thatShape.x - position, y).normalize();
913
+ ri.position = position;
914
+
915
+ return ri;
916
+ }
917
+ }
918
+ },
919
+ y: {
920
+ rectangle: {
921
+ rectangle: function (direction, thisShape, thatShape) {
922
+ const
923
+ ri = returnInfo;
924
+
925
+ ri.position = thatShape.y - direction * (thatShape.aABB.halfHeight + thisShape.aABB.halfHeight);
926
+ ri.contactVector.setXYZ(0, direction);
927
+
928
+ return ri;
929
+ },
930
+ circle: function (direction, thisShape, thatShape) {
931
+ const
932
+ ri = returnInfo;
933
+
934
+ ri.position = thatShape.y - direction * getOffsetForCircleVsAABBY(thatShape, thisShape, thisShape, direction, ri.contactVector.setXYZ(0, direction));
935
+
936
+ return ri;
937
+ }
938
+ },
939
+ circle: {
940
+ rectangle: function (direction, thisShape, thatShape) {
941
+ const
942
+ ri = returnInfo;
943
+
944
+ ri.position = thatShape.y - direction * getOffsetForCircleVsAABBY(thisShape, thatShape, thisShape, direction, ri.contactVector.setXYZ(0, direction));
945
+
946
+ return ri;
947
+ },
948
+ circle: function (direction, thisShape, thatShape) {
949
+ const
950
+ x = thatShape.x - thisShape.x,
951
+ position = thatShape.y - direction * getMovementDistance(x, thisShape.radius + thatShape.radius),
952
+ ri = returnInfo;
953
+
954
+ ri.contactVector.setXYZ(x, thatShape.y - position).normalize();
955
+ ri.position = position;
956
+
957
+ return ri;
958
+ }
959
+ }
960
+ }
961
+ };
962
+
963
+ return function (translatedShape, currentShape, axis, potentialCollidingShapes) {
964
+ const
965
+ initialPoint = translatedShape[axis],
966
+ goalPoint = currentShape[axis],
967
+ direction = ((initialPoint < goalPoint) ? 1 : -1),
968
+ cd = CollisionData.setUp();
969
+ let finalPosition = goalPoint;
970
+
971
+ if (initialPoint !== goalPoint) {
972
+ const
973
+ findACP = findAxisCollisionPosition[axis][translatedShape.type];
974
+ let i = potentialCollidingShapes.length
975
+
976
+ if (axis === 'x') {
977
+ translatedShape.moveX(goalPoint);
978
+ } else if (axis === 'y') {
979
+ translatedShape.moveY(goalPoint);
980
+ }
981
+
982
+ while (i--) {
983
+ const
984
+ pcShape = potentialCollidingShapes[i];
985
+
986
+ if (translatedShape.collides(pcShape)) {
987
+ const
988
+ collisionInfo = findACP[pcShape.type](direction, translatedShape, pcShape),
989
+ position = collisionInfo.position;
990
+
991
+ if (direction > 0) {
992
+ if (position < finalPosition) {
993
+ finalPosition = position < initialPoint ? initialPoint : position; // Reality check: I think this is necessary due to floating point inaccuracies. - DDD
994
+ cd.set(true, direction, finalPosition, Math.abs(finalPosition - initialPoint), pcShape.aABB, currentShape, pcShape, collisionInfo.contactVector, 0);
995
+ }
996
+ } else if (position > finalPosition) {
997
+ finalPosition = position > initialPoint ? initialPoint : position; // Reality check: I think this is necessary due to floating point inaccuracies. - DDD
998
+ cd.set(true, direction, finalPosition, Math.abs(finalPosition - initialPoint), pcShape.aABB, currentShape, pcShape, collisionInfo.contactVector, 0);
999
+ }
1000
+ }
1001
+ }
1002
+ }
1003
+
1004
+ return cd;
1005
+ };
1006
+ }()),
1007
+
1008
+ checkSoftCollisions () {
1009
+ const
1010
+ softs = this.softEntitiesLive;
1011
+ let i = softs.length;
1012
+
1013
+ while (i--) {
1014
+ const
1015
+ entity = softs[i];
1016
+
1017
+ this.checkEntityForSoftCollisions(entity, (collision) => {
1018
+ entity.triggerEvent('hit-by-' + collision.type, collision);
1019
+ });
1020
+ }
1021
+ },
1022
+
1023
+ checkEntityForSoftCollisions: function (ent, callback) {
1024
+ const
1025
+ message = triggerMessage,
1026
+ terrains = this.terrains;
1027
+ let i = ent.collisionTypes.length;
1028
+
1029
+ message.x = 0;
1030
+ message.y = 0;
1031
+
1032
+ while (i--) {
1033
+ const
1034
+ collisionType = ent.collisionTypes[i],
1035
+ softCollisionMap = ent.softCollisionMap.get(collisionType),
1036
+ againstGrid = this.getEntityAgainstGrid(ent, softCollisionMap);
1037
+ let j = softCollisionMap.length;
1038
+
1039
+ while (j--) {
1040
+ const
1041
+ otherCollisionType = softCollisionMap[j],
1042
+ otherEntities = againstGrid[otherCollisionType];
1043
+
1044
+ if (otherEntities) {
1045
+ let k = otherEntities.length;
1046
+
1047
+ while (k--) {
1048
+ const
1049
+ otherEntity = otherEntities[k];
1050
+
1051
+ if ((otherEntity !== ent) && (ent.getAABB(collisionType).collides(otherEntity.getAABB(otherCollisionType)))) {
1052
+ const
1053
+ shapes = ent.getShapes(collisionType),
1054
+ otherShapes = otherEntity.getShapes(otherCollisionType);
1055
+ let collisionFound = false,
1056
+ l = shapes.length;
1057
+
1058
+ while (l--) {
1059
+ let m = otherShapes.length;
1060
+
1061
+ while (m--) {
1062
+ if (shapes[l].collides(otherShapes[m])) {
1063
+ //TML - We're only reporting the first shape we hit even though there may be multiple that we could be hitting.
1064
+ message.entity = otherEntity;
1065
+ message.target = ent;
1066
+ message.type = otherCollisionType;
1067
+ message.myType = collisionType;
1068
+ message.shape = otherShapes[m];
1069
+ message.hitType = 'soft';
1070
+
1071
+ callback(message);
1072
+
1073
+ collisionFound = true;
1074
+ break;
1075
+ }
1076
+ }
1077
+ if (collisionFound) {
1078
+ break;
1079
+ }
1080
+ }
1081
+ }
1082
+ }
1083
+ arrayCache.recycle(otherEntities);
1084
+ }
1085
+
1086
+ if (terrains.length) {
1087
+ //Do our sweep check against the tiles and add potentially colliding shapes to our list.
1088
+ let l = 0;
1089
+
1090
+ for (l = 0; l < terrains.length; l++) {
1091
+ //Sending the same AABB twice because we don't do sweep or jumpThrough checks with soft collision.
1092
+ const entAABB = ent.getAABB(collisionType),
1093
+ otherShapes = terrains[l].getTileShapes(entAABB, entAABB, otherCollisionType);
1094
+ let k = otherShapes.length;
1095
+
1096
+ while (k--) {
1097
+ message.entity = terrains[l];
1098
+ message.target = ent;
1099
+ message.type = otherCollisionType;
1100
+ message.myType = collisionType;
1101
+ message.shape = otherShapes[k];
1102
+ message.hitType = 'soft';
1103
+
1104
+ callback(message);
1105
+ }
1106
+ }
1107
+
1108
+ }
1109
+ }
1110
+ againstGrid.recycle();
1111
+ }
1112
+ },
1113
+
1114
+
1115
+ checkShapeForCollisions: function (shape, softCollisionMap, callback) {
1116
+ const
1117
+ againstGrid = this.getAgainstGrid(null, shape.getAABB(), softCollisionMap),
1118
+ message = triggerMessage;
1119
+ let j = softCollisionMap.length;
1120
+
1121
+ message.x = 0;
1122
+ message.y = 0;
1123
+
1124
+ while (j--) {
1125
+ const
1126
+ otherCollisionType = softCollisionMap[j],
1127
+ otherEntities = againstGrid[otherCollisionType];
1128
+
1129
+ if (otherEntities) {
1130
+ let k = otherEntities.length;
1131
+
1132
+ while (k--) {
1133
+ const
1134
+ otherEntity = otherEntities[k];
1135
+
1136
+ if ((shape.getAABB().collides(otherEntity.getAABB(otherCollisionType)))) {
1137
+ const
1138
+ otherShapes = otherEntity.getShapes(otherCollisionType);
1139
+ let m = otherShapes.length;
1140
+
1141
+ while (m--) {
1142
+ if (shape.collides(otherShapes[m])) {
1143
+ //TML - We're only reporting the first shape we hit even though there may be multiple that we could be hitting.
1144
+ message.entity = otherEntity;
1145
+ message.target = null;
1146
+ message.type = otherCollisionType;
1147
+ message.myType = '';
1148
+ message.shape = otherShapes[m];
1149
+ message.hitType = 'soft';
1150
+
1151
+ callback(message);
1152
+ break;
1153
+ }
1154
+ }
1155
+ }
1156
+ }
1157
+ arrayCache.recycle(otherEntities);
1158
+ }
1159
+ }
1160
+ againstGrid.recycle();
1161
+ },
1162
+
1163
+
1164
+ checkPointForCollisions: function (x, y, collisions, callback) {
1165
+ const
1166
+ gb = this.gridBits,
1167
+ againstGrid = this.againstGrid[getBucketId(x, y, gb)],
1168
+ message = triggerMessage;
1169
+ let j = collisions.length;
1170
+
1171
+ message.x = 0;
1172
+ message.y = 0;
1173
+
1174
+ if (!againstGrid) {
1175
+ return;
1176
+ }
1177
+
1178
+ while (j--) {
1179
+ const
1180
+ otherCollisionType = collisions[j],
1181
+ otherEntities = againstGrid.get(otherCollisionType);
1182
+
1183
+ if (otherEntities) {
1184
+ let k = otherEntities.length;
1185
+
1186
+ while (k--) {
1187
+ const
1188
+ otherEntity = otherEntities[k];
1189
+
1190
+ if (otherEntity.getAABB(otherCollisionType).containsPoint(x, y)) {
1191
+ const
1192
+ otherShapes = otherEntity.getShapes(otherCollisionType);
1193
+ let m = otherShapes.length;
1194
+
1195
+ while (m--) {
1196
+ if (otherShapes[m].containsPoint(x, y)) {
1197
+ //TML - We're only reporting the first shape we hit even though there may be multiple that we could be hitting.
1198
+ message.entity = otherEntity;
1199
+ message.target = null;
1200
+ message.type = otherCollisionType;
1201
+ message.myType = '';
1202
+ message.shape = otherShapes[m];
1203
+ message.hitType = 'soft';
1204
+
1205
+ callback(message);
1206
+
1207
+ break;
1208
+ }
1209
+ }
1210
+ }
1211
+ }
1212
+ }
1213
+ }
1214
+ },
1215
+
1216
+ destroy: function () {
1217
+ const
1218
+ ag = this.againstGrid,
1219
+ keys = Object.keys(ag),
1220
+ {length} = keys;
1221
+
1222
+ arrayCache.recycle(this.groupsLive);
1223
+ arrayCache.recycle(this.nonColliders);
1224
+ arrayCache.recycle(this.allEntitiesLive);
1225
+ arrayCache.recycle(this.softEntitiesLive);
1226
+ arrayCache.recycle(this.solidEntitiesLive);
1227
+ this.relocationMessage.position.recycle();
1228
+ this.relocationMessage.recycle();
1229
+
1230
+ for (let i = 0; i < length; i++) {
1231
+ const
1232
+ data = ag[keys[i]],
1233
+ dataKeys = data.keys;
1234
+ let j = dataKeys.length;
1235
+
1236
+ while (j--) {
1237
+ arrayCache.recycle(data.get(dataKeys[j]));
1238
+ }
1239
+ data.recycle();
1240
+ }
1241
+ ag.recycle();
1242
+ this.againstGrid = null;
1243
+ }
1244
+ },
1245
+
1246
+ publicMethods: {
1247
+ /**
1248
+ * This method returns an object containing world entities.
1249
+ *
1250
+ * @method platypus.components.HandlerCollision#getWorldEntities
1251
+ * @return {Array} A list of all world collision entities.
1252
+ */
1253
+ getWorldEntities: function () {
1254
+ return this.allEntitiesLive;
1255
+ },
1256
+
1257
+ /**
1258
+ * This method returns an array of entities representing the collision maps of the world.
1259
+ *
1260
+ * @method platypus.components.HandlerCollision#getWorldTerrain
1261
+ * @return {Array.<platypus.Entity>} An array of entities describing the collision maps of the world. This entity typically includes a `CollisionTiles` component.
1262
+ */
1263
+ getWorldTerrain: function () {
1264
+ return this.terrains;
1265
+ },
1266
+
1267
+ /**
1268
+ * This method returns a list of collision objects describing soft collisions between an entity and a list of other entities.
1269
+ *
1270
+ * @method platypus.components.HandlerCollision#getEntityCollisions
1271
+ * @param entity {Entity} The entity to test against the world.
1272
+ * @return collisions {Array} This is a list of collision objects describing the soft collisions.
1273
+ */
1274
+ getEntityCollisions: function (entity) {
1275
+ const
1276
+ collisions = arrayCache.setUp();
1277
+
1278
+ this.checkEntityForSoftCollisions(entity, (collision) => collisions.push(Data.setUp(collision)));
1279
+
1280
+ return collisions;
1281
+ },
1282
+
1283
+ /**
1284
+ * This method returns a list of collision objects describing collisions between a shape and a list of other entities.
1285
+ *
1286
+ * @method platypus.components.HandlerCollision#getShapeCollisions
1287
+ * @param shape {CollisionShape} The shape to check for collisions.
1288
+ * @param collisionTypes {String[]} The collision types to check against.
1289
+ * @return collisions {Array} This is a list of collision objects describing the soft collisions.
1290
+ */
1291
+ getShapeCollisions: function (shape, collisionTypes) {
1292
+ const
1293
+ collisions = arrayCache.setUp();
1294
+
1295
+ this.checkShapeForCollisions(shape, collisionTypes, (collision) => collisions.push(Data.setUp(collision)));
1296
+
1297
+ return collisions;
1298
+ },
1299
+
1300
+ /**
1301
+ * This method returns a list of collision objects describing collisions between a point and a list of other entities.
1302
+ *
1303
+ * @method platypus.components.HandlerCollision#getPointCollisions
1304
+ * @param x {number} The x-axis value.
1305
+ * @param y {number} The y-axis value.
1306
+ * @param collisionTypes {String[]} The collision types to check against.
1307
+ * @return collisions {Array} This is a list of collision objects describing the soft collisions.
1308
+ */
1309
+ getPointCollisions: function (x, y, collisionTypes) {
1310
+ const
1311
+ collisions = arrayCache.setUp();
1312
+
1313
+ this.checkPointForCollisions(x, y, collisionTypes, (collision) => collisions.push(Data.setUp(collision)));
1314
+
1315
+ return collisions;
1316
+ }
1317
+ }
1318
+ });