@makefully/platypus 4.1.4 → 4.1.6
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/CHANGELOG.md +20 -0
- package/README.md +4 -2
- package/lib/platypus.js +1 -1
- package/package.json +7 -2
- package/src/AABB.js +685 -0
- package/src/ActionState.js +121 -0
- package/src/AssetManager.js +206 -0
- package/src/CollisionData.js +96 -0
- package/src/CollisionDataContainer.js +127 -0
- package/src/CollisionShape.js +315 -0
- package/src/Component.js +231 -0
- package/src/Data.js +64 -0
- package/src/DataMap.js +204 -0
- package/src/Entity.js +404 -0
- package/src/EntityLinker.js +113 -0
- package/src/EventHandler.js +115 -0
- package/src/EventHandlerList.js +251 -0
- package/src/Game.js +840 -0
- package/src/Gamepad.js +175 -0
- package/src/ID3CaptionPlayer.js +61 -0
- package/src/Messenger.js +365 -0
- package/src/PIXIAnimation.js +622 -0
- package/src/RandomSet.js +140 -0
- package/src/SFXPlayer.js +120 -0
- package/src/StateMap.js +252 -0
- package/src/Storage.js +152 -0
- package/src/TickerClient.js +48 -0
- package/src/TickerServer.js +23 -0
- package/src/TimeEvent.js +50 -0
- package/src/TimeEventList.js +100 -0
- package/src/VOPlayer.js +684 -0
- package/src/Vector.js +702 -0
- package/src/components/AIChaser.js +161 -0
- package/src/components/AIPacer.js +107 -0
- package/src/components/AudioMusic.js +151 -0
- package/src/components/AudioSFX.js +673 -0
- package/src/components/AudioVO.js +301 -0
- package/src/components/CollisionBasic.js +826 -0
- package/src/components/CollisionFilter.js +74 -0
- package/src/components/CollisionGroup.js +448 -0
- package/src/components/CollisionTiles.js +608 -0
- package/src/components/ComponentSwitcher.js +173 -0
- package/src/components/ControllerInput.js +65 -0
- package/src/components/Counter.js +165 -0
- package/src/components/EntityCamera.js +215 -0
- package/src/components/EntityContainer.js +549 -0
- package/src/components/EntityController.js +541 -0
- package/src/components/HandlerCamera.js +1052 -0
- package/src/components/HandlerCollision.js +1318 -0
- package/src/components/HandlerController.js +291 -0
- package/src/components/HandlerLogic.js +394 -0
- package/src/components/HandlerRender.js +217 -0
- package/src/components/Interactive.js +502 -0
- package/src/components/LevelBuilder.js +524 -0
- package/src/components/LogicAngularMovement.js +154 -0
- package/src/components/LogicAttachment.js +265 -0
- package/src/components/LogicButton.js +466 -0
- package/src/components/LogicCarrier.js +39 -0
- package/src/components/LogicDestroyMe.js +58 -0
- package/src/components/LogicDirectionalMovement.js +325 -0
- package/src/components/LogicDragDrop.js +371 -0
- package/src/components/LogicImpactLaunch.js +144 -0
- package/src/components/LogicPacingPlatform.js +64 -0
- package/src/components/LogicPortable.js +112 -0
- package/src/components/LogicPortal.js +115 -0
- package/src/components/LogicPushable.js +98 -0
- package/src/components/LogicRebounder.js +136 -0
- package/src/components/LogicRegionSpawner.js +139 -0
- package/src/components/LogicRotationalMovement.js +205 -0
- package/src/components/LogicSpawner.js +159 -0
- package/src/components/LogicStateMachine.js +382 -0
- package/src/components/LogicSwitch.js +77 -0
- package/src/components/LogicTeleportee.js +68 -0
- package/src/components/LogicTeleporter.js +93 -0
- package/src/components/LogicTimer.js +178 -0
- package/src/components/LogicWindUpRacer.js +179 -0
- package/src/components/Motion.js +371 -0
- package/src/components/Mover.js +566 -0
- package/src/components/Node.js +289 -0
- package/src/components/NodeMap.js +295 -0
- package/src/components/NodeResident.js +636 -0
- package/src/components/Orientation.js +697 -0
- package/src/components/RandomEvents.js +73 -0
- package/src/components/RelativePosition.js +204 -0
- package/src/components/RelayFamily.js +106 -0
- package/src/components/RelayGame.js +53 -0
- package/src/components/RelayLinker.js +94 -0
- package/src/components/RelayParent.js +57 -0
- package/src/components/RelaySelf.js +55 -0
- package/src/components/Render.js +178 -0
- package/src/components/RenderAnimator.js +275 -0
- package/src/components/RenderContainer.js +646 -0
- package/src/components/RenderDebug.js +319 -0
- package/src/components/RenderDestroyMe.js +59 -0
- package/src/components/RenderLottie.js +149 -0
- package/src/components/RenderProgress.js +120 -0
- package/src/components/RenderSpine.js +833 -0
- package/src/components/RenderSprite.js +527 -0
- package/src/components/RenderText.js +147 -0
- package/src/components/RenderTiles.js +1391 -0
- package/src/components/SceneChanger.js +128 -0
- package/src/components/TiledLoader.js +1451 -0
- package/src/components/Timeline.js +314 -0
- package/src/components/Tutorial.js +267 -0
- package/src/components/Tween.js +296 -0
- package/src/components/VoiceOver.js +373 -0
- package/src/components/XHR.js +129 -0
- package/src/components/index.js +79 -0
- package/src/factory.js +305 -0
- package/src/index.js +159 -0
- package/src/mixins/PIXI.Graphics.js +41 -0
- package/src/platypus.css +68 -0
- package/src/sayHello.js +50 -0
- package/src/shapes/Capsule.js +74 -0
- package/src/shapes/Circle.js +43 -0
- package/src/shapes/Ellipse.js +117 -0
- package/src/shapes/Point.js +191 -0
- package/src/shapes/Polygon.js +112 -0
- package/src/shapes/Polyline.js +97 -0
- package/src/shapes/Rectangle.js +78 -0
- package/src/shapes/RoundedRectangle.js +33 -0
- package/src/shapes/Segment.js +346 -0
- package/src/shapes/adjustedXY.js +19 -0
- package/src/shapes/castFromBox2D.js +92 -0
- package/src/shapes/castFromObject.js +53 -0
- package/src/shapes/castFromPixiGraphics.js +6 -0
- package/src/shapes/castFromPixiShape.js +89 -0
- package/src/shapes/castToBox2D.js +190 -0
- package/src/shapes/castToPixiGraphics.js +100 -0
- package/src/shapes/castToPixiShape.js +61 -0
- package/src/shapes/checkPointsMap.js +313 -0
- package/src/shapes/index.js +35 -0
- package/src/utils/array.js +73 -0
- package/src/utils/string.js +39 -0
|
@@ -0,0 +1,826 @@
|
|
|
1
|
+
import {arrayCache, greenSplice} from '../utils/array.js';
|
|
2
|
+
import AABB from '../AABB.js';
|
|
3
|
+
import CollisionShape from '../CollisionShape.js';
|
|
4
|
+
import Data from '../Data.js';
|
|
5
|
+
import DataMap from '../DataMap.js';
|
|
6
|
+
import Vector from '../Vector.js';
|
|
7
|
+
import createComponentClass from '../factory.js';
|
|
8
|
+
|
|
9
|
+
const
|
|
10
|
+
entityBroadcast = (function () {
|
|
11
|
+
const
|
|
12
|
+
stringBroadcast = function (event, collisionType, solidOrSoft, value) {
|
|
13
|
+
if (value.myType === collisionType) {
|
|
14
|
+
if (value.hitType === solidOrSoft) {
|
|
15
|
+
this.owner.triggerEvent(event, value);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
arrayBroadcast = function (event, collisionType, solidOrSoft, value) {
|
|
20
|
+
if (value.myType === collisionType) {
|
|
21
|
+
if (value.hitType === solidOrSoft) {
|
|
22
|
+
for (let i = 0; i < event.length; i++) {
|
|
23
|
+
this.owner.triggerEvent(event[i], value);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
directionalBroadcast = function (event, collisionType, solidOrSoft, collisionInfo) {
|
|
29
|
+
let dx = collisionInfo.x,
|
|
30
|
+
dy = collisionInfo.y;
|
|
31
|
+
|
|
32
|
+
if (collisionInfo.entity && !(dx || dy)) {
|
|
33
|
+
dx = collisionInfo.entity.x - this.owner.x;
|
|
34
|
+
dy = collisionInfo.entity.y - this.owner.y;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (collisionInfo.myType === collisionType) {
|
|
38
|
+
if (collisionInfo.hitType === solidOrSoft) {
|
|
39
|
+
if ((dy > 0) && event.bottom) {
|
|
40
|
+
this.owner.trigger(event.bottom, collisionInfo);
|
|
41
|
+
} else if ((dy < 0) && event.top) {
|
|
42
|
+
this.owner.trigger(event.top, collisionInfo);
|
|
43
|
+
}
|
|
44
|
+
if ((dx > 0) && event.right) {
|
|
45
|
+
this.owner.trigger(event.right, collisionInfo);
|
|
46
|
+
} else if ((dx < 0) && event.left) {
|
|
47
|
+
this.owner.trigger(event.left, collisionInfo);
|
|
48
|
+
}
|
|
49
|
+
if (event.all) {
|
|
50
|
+
this.owner.trigger(event.all, collisionInfo);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return function (self, event, solidOrSoft) {
|
|
57
|
+
if (typeof event === 'string') {
|
|
58
|
+
return stringBroadcast.bind(self, event, self.collisionType, solidOrSoft);
|
|
59
|
+
} else if (Array.isArray(event)) {
|
|
60
|
+
return arrayBroadcast.bind(self, event, self.collisionType, solidOrSoft);
|
|
61
|
+
} else {
|
|
62
|
+
return directionalBroadcast.bind(self, event, self.collisionType, solidOrSoft);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}()),
|
|
66
|
+
setupCollisionFunctions = (function () {
|
|
67
|
+
const
|
|
68
|
+
entityGetAABB = function (aabb, colFuncs, collisionType) {
|
|
69
|
+
if (!collisionType) {
|
|
70
|
+
const
|
|
71
|
+
{keys} = colFuncs;
|
|
72
|
+
let i = keys.length
|
|
73
|
+
|
|
74
|
+
aabb.reset();
|
|
75
|
+
while (i--) {
|
|
76
|
+
aabb.include(colFuncs.get(keys[i]).getAABB());
|
|
77
|
+
}
|
|
78
|
+
return aabb;
|
|
79
|
+
} else {
|
|
80
|
+
const
|
|
81
|
+
funcs = colFuncs.get(collisionType);
|
|
82
|
+
|
|
83
|
+
if (funcs) {
|
|
84
|
+
return funcs.getAABB();
|
|
85
|
+
} else {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
entityGetPreviousAABB = function (colFuncs, collisionType) {
|
|
91
|
+
const
|
|
92
|
+
colFunc = colFuncs.get(collisionType);
|
|
93
|
+
|
|
94
|
+
if (colFunc) {
|
|
95
|
+
return colFunc.getPreviousAABB();
|
|
96
|
+
} else {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
entityGetShapes = function (colFuncs, collisionType) {
|
|
101
|
+
const
|
|
102
|
+
colFunc = colFuncs.get(collisionType);
|
|
103
|
+
|
|
104
|
+
if (colFunc) {
|
|
105
|
+
return colFunc.getShapes();
|
|
106
|
+
} else {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
entityGetPrevShapes = function (colFuncs, collisionType) {
|
|
111
|
+
const
|
|
112
|
+
colFunc = colFuncs.get(collisionType);
|
|
113
|
+
|
|
114
|
+
if (colFunc) {
|
|
115
|
+
return colFunc.getPrevShapes();
|
|
116
|
+
} else {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
entityPrepareCollision = function (colFuncs, x, y) {
|
|
121
|
+
const
|
|
122
|
+
keys = colFuncs.keys;
|
|
123
|
+
let i = keys.length;
|
|
124
|
+
|
|
125
|
+
while (i--) {
|
|
126
|
+
colFuncs.get(keys[i]).prepareCollision(x, y);
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
entityRelocateEntity = (function () {
|
|
130
|
+
const
|
|
131
|
+
handleStuck = function (position, data, owner) {
|
|
132
|
+
let s = data.stuck;
|
|
133
|
+
|
|
134
|
+
if (s) {
|
|
135
|
+
const
|
|
136
|
+
m = position.magnitude();
|
|
137
|
+
|
|
138
|
+
if (data.thatShape.owner && (Math.abs(s) > 1)) {
|
|
139
|
+
s *= 0.05;
|
|
140
|
+
}
|
|
141
|
+
if (!m || (m > Math.abs(s))) {
|
|
142
|
+
if (data.vector.x) {
|
|
143
|
+
position.x = s;
|
|
144
|
+
position.y = 0;
|
|
145
|
+
}
|
|
146
|
+
if (data.vector.y) {
|
|
147
|
+
position.x = 0;
|
|
148
|
+
position.y = s;
|
|
149
|
+
}
|
|
150
|
+
if (owner.stuckWith) {
|
|
151
|
+
owner.stuckWith.recycle();
|
|
152
|
+
}
|
|
153
|
+
owner.stuckWith = Vector.setUp(data.thatShape.x, data.thatShape.y);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
message = {
|
|
158
|
+
position: null,
|
|
159
|
+
unstick: null
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
return function (vector, collisionData) {
|
|
163
|
+
const
|
|
164
|
+
colX = collisionData.xData[0],
|
|
165
|
+
colY = collisionData.yData[0],
|
|
166
|
+
msg = message;
|
|
167
|
+
let v = null;
|
|
168
|
+
|
|
169
|
+
if (colX) {
|
|
170
|
+
v = Vector.setUp(0, 0, 0);
|
|
171
|
+
handleStuck(v, colX, this);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (colY) {
|
|
175
|
+
v = v ?? Vector.setUp(0, 0, 0);
|
|
176
|
+
handleStuck(v, colY, this);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
msg.position = vector;
|
|
180
|
+
msg.unstick = v;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* This message causes the entity's x,y coordinates to update. (Usually after collision checks, but can be used to avoid collision checks during logic handling.)
|
|
184
|
+
*
|
|
185
|
+
* @event platypus.Entity#relocate-entity
|
|
186
|
+
* @param location {Object|platypus.Vector} The new coordinates.
|
|
187
|
+
* @param [location.position] {platypus.Vector} If specified, this vector is used instead of the passed-in object as the location.
|
|
188
|
+
* @param [location.relative=false] {boolean} Determines whether the provided x,y coordinates are relative to the entity's current position.
|
|
189
|
+
* @param [location.unstick=null] {platypus.Vector} Where the entity should be moved to unstick from collision contact.
|
|
190
|
+
* @param [relative] If `location.relative` is not specified, this parameter is also checked.
|
|
191
|
+
*/
|
|
192
|
+
this.triggerEvent('relocate-entity', msg);
|
|
193
|
+
|
|
194
|
+
if (v) {
|
|
195
|
+
v.recycle();
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}()),
|
|
199
|
+
entityMovePreviousX = function (colFuncs, x) {
|
|
200
|
+
const
|
|
201
|
+
{keys} = colFuncs;
|
|
202
|
+
let i = keys.length;
|
|
203
|
+
|
|
204
|
+
while (i--) {
|
|
205
|
+
colFuncs.get(keys[i]).movePreviousX(x);
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
entityGetCollisionTypes = function () {
|
|
209
|
+
return this.collisionTypes;
|
|
210
|
+
},
|
|
211
|
+
entityGetSolidCollisions = function () {
|
|
212
|
+
return this.solidCollisionMap;
|
|
213
|
+
},
|
|
214
|
+
getAABB = function () {
|
|
215
|
+
return this.getAABB();
|
|
216
|
+
},
|
|
217
|
+
getPreviousAABB = function () {
|
|
218
|
+
return this.getPreviousAABB();
|
|
219
|
+
},
|
|
220
|
+
getShapes = function () {
|
|
221
|
+
return this.getShapes();
|
|
222
|
+
},
|
|
223
|
+
getPrevShapes = function () {
|
|
224
|
+
return this.getPrevShapes();
|
|
225
|
+
},
|
|
226
|
+
prepareCollision = function (x, y) {
|
|
227
|
+
this.prepareCollision(x, y);
|
|
228
|
+
},
|
|
229
|
+
movePreviousX = function (x) {
|
|
230
|
+
this.movePreviousX(x);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
return function (self, entity) {
|
|
234
|
+
let colFuncs = entity.collisionFunctions;
|
|
235
|
+
|
|
236
|
+
// This allows the same component type to be added multiple times.
|
|
237
|
+
if (!colFuncs) {
|
|
238
|
+
colFuncs = entity.collisionFunctions = DataMap.setUp();
|
|
239
|
+
entity.aabb = AABB.setUp();
|
|
240
|
+
entity.getAABB = entityGetAABB.bind(entity, entity.aabb, colFuncs);
|
|
241
|
+
entity.getPreviousAABB = entityGetPreviousAABB.bind(entity, colFuncs);
|
|
242
|
+
entity.getShapes = entityGetShapes.bind(entity, colFuncs);
|
|
243
|
+
entity.getPrevShapes = entityGetPrevShapes.bind(entity, colFuncs);
|
|
244
|
+
entity.prepareCollision = entityPrepareCollision.bind(entity, colFuncs);
|
|
245
|
+
entity.relocateEntity = entityRelocateEntity.bind(entity);
|
|
246
|
+
entity.movePreviousX = entityMovePreviousX.bind(entity, colFuncs);
|
|
247
|
+
entity.getCollisionTypes = entityGetCollisionTypes.bind(entity);
|
|
248
|
+
entity.getSolidCollisions = entityGetSolidCollisions.bind(entity);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
colFuncs.set(self.collisionType, Data.setUp(
|
|
252
|
+
"getAABB", getAABB.bind(self),
|
|
253
|
+
"getPreviousAABB", getPreviousAABB.bind(self),
|
|
254
|
+
"getShapes", getShapes.bind(self),
|
|
255
|
+
"getPrevShapes", getPrevShapes.bind(self),
|
|
256
|
+
"prepareCollision", prepareCollision.bind(self),
|
|
257
|
+
"movePreviousX", movePreviousX.bind(self)
|
|
258
|
+
));
|
|
259
|
+
};
|
|
260
|
+
}()),
|
|
261
|
+
updateShapesFull = function (shapes, prevs, aabb, x, y) {
|
|
262
|
+
let i = shapes.length;
|
|
263
|
+
|
|
264
|
+
while (i--) {
|
|
265
|
+
const shape = shapes[i];
|
|
266
|
+
shape.updateAll(prevs[i]);
|
|
267
|
+
shape.update(x, y);
|
|
268
|
+
aabb.include(shape.aABB);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Done with the full update; back to fast!
|
|
272
|
+
this.updateShapes = updateShapesFast;
|
|
273
|
+
},
|
|
274
|
+
updateShapesFast = function (shapes, prevs, aabb, x, y) {
|
|
275
|
+
let i = shapes.length;
|
|
276
|
+
|
|
277
|
+
while (i--) {
|
|
278
|
+
const shape = shapes[i];
|
|
279
|
+
shape.update(x, y);
|
|
280
|
+
aabb.include(shape.aABB);
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
normalizeJumpThrough = function (jt) {
|
|
284
|
+
if (jt === true) {
|
|
285
|
+
return {
|
|
286
|
+
x: 0,
|
|
287
|
+
y: -1
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (!jt) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
x: jt.x || 0,
|
|
297
|
+
y: jt.y || 0
|
|
298
|
+
};
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
export default createComponentClass(/** @lends platypus.components.CollisionBasic.prototype */{
|
|
302
|
+
|
|
303
|
+
id: 'CollisionBasic',
|
|
304
|
+
|
|
305
|
+
properties: {
|
|
306
|
+
/**
|
|
307
|
+
* Defines how this entity should be recognized by other colliding entities.
|
|
308
|
+
*
|
|
309
|
+
* @property collisionType
|
|
310
|
+
* @type String
|
|
311
|
+
* @default "none"
|
|
312
|
+
*/
|
|
313
|
+
collisionType: "none",
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Defines the type of colliding shape.
|
|
317
|
+
*
|
|
318
|
+
* @property shapeType
|
|
319
|
+
* @type String
|
|
320
|
+
* @default "rectangle"
|
|
321
|
+
*/
|
|
322
|
+
shapeType: "rectangle",
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Determines whether the collision area should transform on orientation changes.
|
|
326
|
+
*
|
|
327
|
+
* @property ignoreOrientation
|
|
328
|
+
* @type boolean
|
|
329
|
+
* @default false
|
|
330
|
+
*/
|
|
331
|
+
ignoreOrientation: false,
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Determines the x-axis center of the collision shape.
|
|
335
|
+
*
|
|
336
|
+
* @property regX
|
|
337
|
+
* @type number
|
|
338
|
+
* @default width / 2
|
|
339
|
+
*/
|
|
340
|
+
regX: null,
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Determines the y-axis center of the collision shape.
|
|
344
|
+
*
|
|
345
|
+
* @property regY
|
|
346
|
+
* @type number
|
|
347
|
+
* @default height / 2
|
|
348
|
+
*/
|
|
349
|
+
regY: null,
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Sets the width of the collision area in world coordinates.
|
|
353
|
+
*
|
|
354
|
+
* @property width
|
|
355
|
+
* @type number
|
|
356
|
+
* @default 0
|
|
357
|
+
*/
|
|
358
|
+
width: 0,
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Sets the height of the collision area in world coordinates.
|
|
362
|
+
*
|
|
363
|
+
* @property height
|
|
364
|
+
* @type number
|
|
365
|
+
* @default 0
|
|
366
|
+
*/
|
|
367
|
+
height: 0,
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Sets the radius of a circle collision area in world coordinates.
|
|
371
|
+
*
|
|
372
|
+
* @property radius
|
|
373
|
+
* @type number
|
|
374
|
+
* @default 0
|
|
375
|
+
*/
|
|
376
|
+
radius: 0,
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Determines which collision types this entity should consider soft, meaning this entity may pass through them, but triggers collision messages on doing so. Example:
|
|
380
|
+
*
|
|
381
|
+
* {
|
|
382
|
+
* "water": "soaked", // This triggers a "soaked" message on the entity when it passes over a "water" collision-type entity.
|
|
383
|
+
* "lava": ["burn", "ouch"] // This triggers both messages on the entity when it passes over a "lava" collision-type entity.
|
|
384
|
+
* }
|
|
385
|
+
*
|
|
386
|
+
* @property softCollisions
|
|
387
|
+
* @type Object
|
|
388
|
+
* @default null
|
|
389
|
+
*/
|
|
390
|
+
softCollisions: null,
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Determines which collision types this entity should consider solid, meaning this entity should not pass through them. Example:
|
|
394
|
+
*
|
|
395
|
+
* {
|
|
396
|
+
* "boulder": "", // This specifies that this entity should not pass through other "boulder" collision-type entities.
|
|
397
|
+
* "diamond": "crack-up", // This specifies that this entity should not pass through "diamond" collision-type entities, but if it touches one, it triggers a "crack-up" message on the entity.
|
|
398
|
+
* "marble": ["flip", "dance", "crawl"] // This specifies that this entity should not pass through "marble" collision-type entities, but if it touches one, it triggers all three specified messages on the entity.
|
|
399
|
+
* }
|
|
400
|
+
*
|
|
401
|
+
* @property solidCollisions
|
|
402
|
+
* @type Object
|
|
403
|
+
* @default null
|
|
404
|
+
*/
|
|
405
|
+
solidCollisions: null,
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* This is the margin around the entity's width and height. This is an alternative method for specifying the collision shape in terms of the size of the entity. Can also pass in an object specifying the following parameters if the margins vary per side: top, bottom, left, and right.
|
|
409
|
+
*
|
|
410
|
+
* @property margin
|
|
411
|
+
* @type number|Object
|
|
412
|
+
* @default 0
|
|
413
|
+
*/
|
|
414
|
+
margin: 0,
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Defines one or more shapes to create the collision area. Defaults to a single shape with the width, height, regX, and regY properties of the entity if not specified. See [CollisionShape](CollisionShape.html) for the full list of properties.
|
|
418
|
+
*
|
|
419
|
+
* @property shapes
|
|
420
|
+
* @type Array
|
|
421
|
+
* @default null
|
|
422
|
+
*/
|
|
423
|
+
shapes: null
|
|
424
|
+
},
|
|
425
|
+
|
|
426
|
+
publicProperties: {
|
|
427
|
+
collisionDirty: false,
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* This property should be set to true if entity doesn't move for better optimization. This causes other entities to check against this entity, but this entity performs no checks of its own. Available on the entity as `entity.immobile`.
|
|
431
|
+
*
|
|
432
|
+
* @property immobile
|
|
433
|
+
* @type boolean
|
|
434
|
+
* @default false
|
|
435
|
+
*/
|
|
436
|
+
immobile: false,
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Whether this entity should be tested across its entire movement path. This is necessary for fast-moving entities, but shouldn't be used for others due to the processing overhead. Available on the entity as `entity.bullet`.
|
|
440
|
+
*
|
|
441
|
+
* @property bullet
|
|
442
|
+
* @type boolean
|
|
443
|
+
* @default false
|
|
444
|
+
*/
|
|
445
|
+
bullet: false,
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Whether the entity is only solid when being collided with from the top.
|
|
449
|
+
*
|
|
450
|
+
* @property jumpThrough
|
|
451
|
+
* @type boolean
|
|
452
|
+
* @default: false
|
|
453
|
+
*/
|
|
454
|
+
jumpThrough: false
|
|
455
|
+
},
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* This component causes this entity to collide with other entities. It must be part of a collision group and will receive messages when colliding with other entities in the collision group.
|
|
459
|
+
*
|
|
460
|
+
* Multiple collision components may be added to a single entity if distinct messages should be triggered for certain collision areas on the entity or if the soft collision area is a different shape from the solid collision area. Be aware that too many additional collision areas may adversely affect performance.
|
|
461
|
+
*
|
|
462
|
+
* On receiving a 'hit-by' message, custom messages may be triggered on the entity corresponding with the component's `solidCollisions` and `softCollisions` key/value mappings.
|
|
463
|
+
*
|
|
464
|
+
* @memberof platypus.components
|
|
465
|
+
* @uses platypus.Component
|
|
466
|
+
* @constructs
|
|
467
|
+
* @listens platypus.Entity#collide-off
|
|
468
|
+
* @listens platypus.Entity#collide-on
|
|
469
|
+
* @listens platypus.Entity#handle-logic
|
|
470
|
+
* @listens platypus.Entity#hit-by-*
|
|
471
|
+
* @listens platypus.Entity#orientation-updated
|
|
472
|
+
* @listens platypus.Entity#relocate-entity
|
|
473
|
+
* @fires platypus.Entity#add-collision-entity
|
|
474
|
+
* @fires platypus.Entity#relocate-entity
|
|
475
|
+
* @fires platypus.Entity#remove-collision-entity
|
|
476
|
+
*/
|
|
477
|
+
initialize: function (definition) {
|
|
478
|
+
const
|
|
479
|
+
{
|
|
480
|
+
height,
|
|
481
|
+
margin = 0,
|
|
482
|
+
owner,
|
|
483
|
+
radius,
|
|
484
|
+
regX = this.width / 2,
|
|
485
|
+
regY = this.height / 2,
|
|
486
|
+
width
|
|
487
|
+
} = this,
|
|
488
|
+
marginLeft = margin.left ?? margin,
|
|
489
|
+
marginRight = margin.right ?? margin,
|
|
490
|
+
marginTop = margin.top ?? margin,
|
|
491
|
+
marginBottom = margin.bottom ?? margin;
|
|
492
|
+
let shapes = null;
|
|
493
|
+
|
|
494
|
+
Vector.assign(this.owner, 'position', 'x', 'y', 'z');
|
|
495
|
+
Vector.assign(this.owner, 'previousPosition', 'previousX', 'previousY', 'previousZ');
|
|
496
|
+
this.owner.previousX = this.owner.previousX || this.owner.x;
|
|
497
|
+
this.owner.previousY = this.owner.previousY || this.owner.y;
|
|
498
|
+
|
|
499
|
+
this.aabb = AABB.setUp();
|
|
500
|
+
this.prevAABB = AABB.setUp();
|
|
501
|
+
|
|
502
|
+
if (this.shapes) {
|
|
503
|
+
shapes = this.shapes;
|
|
504
|
+
} else if (this.shapeType === 'circle') {
|
|
505
|
+
const
|
|
506
|
+
shapeRadius = radius || (((width || 0) + (height || 0)) / 4);
|
|
507
|
+
|
|
508
|
+
shapes = [{
|
|
509
|
+
regX: (isNaN(regX) ? shapeRadius : regX) - (marginRight - marginLeft) / 2,
|
|
510
|
+
regY: (isNaN(regY) ? shapeRadius : regY) - (marginBottom - marginTop) / 2,
|
|
511
|
+
radius: shapeRadius,
|
|
512
|
+
type: this.shapeType
|
|
513
|
+
}];
|
|
514
|
+
} else {
|
|
515
|
+
shapes = [{
|
|
516
|
+
//regX: (isNaN(regX) ? (width || 0) / 2 : regX) - (marginRight - marginLeft) / 2,
|
|
517
|
+
//regY: (isNaN(regY) ? (height || 0) / 2 : regY) - (marginBottom - marginTop) / 2,
|
|
518
|
+
regX: (isNaN(regX) ? (width || 0) / 2 : regX) + marginLeft,
|
|
519
|
+
regY: (isNaN(regY) ? (height || 0) / 2 : regY) + marginTop,
|
|
520
|
+
points: definition.points,
|
|
521
|
+
width: (width || 0) + marginLeft + marginRight,
|
|
522
|
+
height: (height || 0) + marginTop + marginBottom,
|
|
523
|
+
type: this.shapeType
|
|
524
|
+
}];
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
this.owner.collisionTypes = this.owner.collisionTypes || arrayCache.setUp();
|
|
528
|
+
this.owner.collisionTypes.push(this.collisionType);
|
|
529
|
+
|
|
530
|
+
this.shapes = arrayCache.setUp();
|
|
531
|
+
this.prevShapes = arrayCache.setUp();
|
|
532
|
+
this.entities = null;
|
|
533
|
+
for (let x = 0; x < shapes.length; x++) {
|
|
534
|
+
const
|
|
535
|
+
shape = shapes[x],
|
|
536
|
+
shapeDefinition = {
|
|
537
|
+
...shape,
|
|
538
|
+
jumpThrough: normalizeJumpThrough(typeof shape.jumpThrough === 'undefined' ? this.jumpThrough : shape.jumpThrough)
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
this.shapes.push(CollisionShape.setUp(this.owner, shapeDefinition, this.collisionType));
|
|
542
|
+
this.prevShapes.push(CollisionShape.setUp(this.owner, shapeDefinition, this.collisionType));
|
|
543
|
+
this.prevAABB.include(this.prevShapes[x].aABB);
|
|
544
|
+
this.aabb.include(this.shapes[x].aABB);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
this.updateShapes = updateShapesFast;
|
|
548
|
+
|
|
549
|
+
setupCollisionFunctions(this, this.owner);
|
|
550
|
+
|
|
551
|
+
owner.softCollisionMap = owner.softCollisionMap ?? DataMap.setUp();
|
|
552
|
+
owner.solidCollisionMap = owner.solidCollisionMap ?? DataMap.setUp();
|
|
553
|
+
{
|
|
554
|
+
const
|
|
555
|
+
softCollisions = this.softCollisions,
|
|
556
|
+
keys = softCollisions ? Object.keys(softCollisions) : arrayCache.setUp(),
|
|
557
|
+
{length} = keys;
|
|
558
|
+
|
|
559
|
+
for (let i = 0; i < length; i++) {
|
|
560
|
+
const
|
|
561
|
+
key = keys[i];
|
|
562
|
+
|
|
563
|
+
if (softCollisions[key]) { // To make sure it's not an empty string.
|
|
564
|
+
this.addEventListener(`hit-by-${key}`, entityBroadcast(this, softCollisions[key], 'soft'));
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
owner.softCollisionMap.set(this.collisionType, keys);
|
|
568
|
+
}
|
|
569
|
+
{
|
|
570
|
+
const
|
|
571
|
+
solidCollisions = this.solidCollisions,
|
|
572
|
+
keys = solidCollisions ? Object.keys(solidCollisions) : arrayCache.setUp(),
|
|
573
|
+
{length} = keys;
|
|
574
|
+
|
|
575
|
+
for (let i = 0; i < length; i++) {
|
|
576
|
+
const
|
|
577
|
+
key = keys[i];
|
|
578
|
+
|
|
579
|
+
if (solidCollisions[key]) { // To make sure it's not an empty string.
|
|
580
|
+
this.addEventListener(`hit-by-${key}`, entityBroadcast(this, solidCollisions[key], 'solid'));
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
owner.solidCollisionMap.set(this.collisionType, keys);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
this.active = true;
|
|
587
|
+
this.stuck = false;
|
|
588
|
+
},
|
|
589
|
+
|
|
590
|
+
events: {
|
|
591
|
+
/**
|
|
592
|
+
* On receiving this message, the component triggers `add-collision-entity` on the parent.
|
|
593
|
+
*
|
|
594
|
+
* @event platypus.Entity#collide-on
|
|
595
|
+
* @param type {String} If specified, only collision components of this type are added to the collision list.
|
|
596
|
+
*/
|
|
597
|
+
"collide-on": function (type) {
|
|
598
|
+
const
|
|
599
|
+
{collisionType, owner} = this,
|
|
600
|
+
{collisionTypes} = owner;
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* On receiving 'collide-on', this message is triggered on the parent to turn on collision.
|
|
604
|
+
*
|
|
605
|
+
* @event platypus.Entity#add-collision-entity
|
|
606
|
+
* @param {platypus.Entity} entity The entity this component is attached to.
|
|
607
|
+
*/
|
|
608
|
+
if (!this.active && ((typeof type !== 'string') || (type === collisionType))) {
|
|
609
|
+
owner.parent.triggerEvent('remove-collision-entity', owner);
|
|
610
|
+
if (collisionTypes.indexOf(collisionType) === -1) {
|
|
611
|
+
collisionTypes.push(collisionType);
|
|
612
|
+
}
|
|
613
|
+
owner.parent.triggerEvent('add-collision-entity', owner);
|
|
614
|
+
this.active = true;
|
|
615
|
+
this.collisionDirty = true;
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* On receiving this message, the component triggers `remove-collision-entity` on the parent.
|
|
621
|
+
*
|
|
622
|
+
* @event platypus.Entity#collide-off
|
|
623
|
+
* @param type {String} If specified, only collision components of this type are removed from the collision list.
|
|
624
|
+
*/
|
|
625
|
+
"collide-off": function (type) {
|
|
626
|
+
const
|
|
627
|
+
{collisionType, owner} = this,
|
|
628
|
+
{collisionTypes, parent} = owner;
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* On receiving 'collide-off', this message is triggered on the parent to turn off collision.
|
|
632
|
+
*
|
|
633
|
+
* @event platypus.Entity#remove-collision-entity
|
|
634
|
+
* @param {platypus.Entity} entity The entity this component is attached to.
|
|
635
|
+
*/
|
|
636
|
+
if (this.active && ((typeof type !== 'string') || (type === collisionType))) {
|
|
637
|
+
parent.triggerEvent('remove-collision-entity', owner);
|
|
638
|
+
const
|
|
639
|
+
index = collisionTypes.indexOf(collisionType);
|
|
640
|
+
|
|
641
|
+
if (index >= 0) {
|
|
642
|
+
greenSplice(collisionTypes, index);
|
|
643
|
+
}
|
|
644
|
+
this.active = false;
|
|
645
|
+
|
|
646
|
+
if (collisionTypes.length) {
|
|
647
|
+
parent.triggerEvent('add-collision-entity', owner);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
},
|
|
651
|
+
|
|
652
|
+
"relocate-entity": function (location, relative) {
|
|
653
|
+
const
|
|
654
|
+
{aabb, owner, shapes} = this,
|
|
655
|
+
unstick = location.unstick,
|
|
656
|
+
um = unstick?.magnitude() ?? 0,
|
|
657
|
+
v = location.position ?? location;
|
|
658
|
+
let i = shapes.length,
|
|
659
|
+
x = 0,
|
|
660
|
+
y = 0;
|
|
661
|
+
|
|
662
|
+
if (this.move) {
|
|
663
|
+
this.move.recycle();
|
|
664
|
+
this.move = null;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
if (location.relative || relative) {
|
|
668
|
+
owner.position.setVector(owner.previousPosition).add(v);
|
|
669
|
+
} else {
|
|
670
|
+
owner.position.setVector(v);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (this.stuck) {
|
|
674
|
+
if (um > 0) {
|
|
675
|
+
owner.position.add(unstick);
|
|
676
|
+
} else {
|
|
677
|
+
this.stuck = false;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
x = owner.x;
|
|
682
|
+
y = owner.y;
|
|
683
|
+
|
|
684
|
+
aabb.reset();
|
|
685
|
+
i = shapes.length;
|
|
686
|
+
while (i--) {
|
|
687
|
+
const
|
|
688
|
+
shape = shapes[i];
|
|
689
|
+
|
|
690
|
+
shape.update(x, y);
|
|
691
|
+
aabb.include(shape.aABB);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
owner.previousPosition.setVector(owner.position);
|
|
695
|
+
|
|
696
|
+
if (um > 0) { // to force check in all directions for ultimate stuck resolution (esp. for stationary entities)
|
|
697
|
+
if (!this.stuck) {
|
|
698
|
+
this.stuck = true;
|
|
699
|
+
}
|
|
700
|
+
this.move = owner.stuckWith.copy().add(-x, -y).normalize();
|
|
701
|
+
}
|
|
702
|
+
},
|
|
703
|
+
|
|
704
|
+
"handle-logic": function () {
|
|
705
|
+
if (this.move) {
|
|
706
|
+
this.owner.position.add(this.move); // By trying to move into it, we should get pushed back out.
|
|
707
|
+
}
|
|
708
|
+
},
|
|
709
|
+
|
|
710
|
+
"orientation-updated": function (matrix) {
|
|
711
|
+
if (!this.ignoreOrientation) {
|
|
712
|
+
for (let i = 0; i < this.shapes.length; i++) {
|
|
713
|
+
this.shapes[i].multiply(matrix);
|
|
714
|
+
}
|
|
715
|
+
this.updateShapes = updateShapesFull;
|
|
716
|
+
this.collisionDirty = true;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
},
|
|
720
|
+
|
|
721
|
+
methods: {
|
|
722
|
+
getAABB: function () {
|
|
723
|
+
return this.aabb;
|
|
724
|
+
},
|
|
725
|
+
|
|
726
|
+
getPreviousAABB: function () {
|
|
727
|
+
return this.prevAABB;
|
|
728
|
+
},
|
|
729
|
+
|
|
730
|
+
getShapes: function () {
|
|
731
|
+
return this.shapes;
|
|
732
|
+
},
|
|
733
|
+
|
|
734
|
+
getPrevShapes: function () {
|
|
735
|
+
return this.prevShapes;
|
|
736
|
+
},
|
|
737
|
+
|
|
738
|
+
prepareCollision: function (x, y) {
|
|
739
|
+
const
|
|
740
|
+
prevShapes = this.shapes,
|
|
741
|
+
shapes = this.prevShapes,
|
|
742
|
+
aabb = this.aabb;
|
|
743
|
+
|
|
744
|
+
this.owner.x = x;
|
|
745
|
+
this.owner.y = y;
|
|
746
|
+
|
|
747
|
+
this.prevShapes = prevShapes;
|
|
748
|
+
this.shapes = shapes;
|
|
749
|
+
|
|
750
|
+
this.prevAABB.set(aabb);
|
|
751
|
+
aabb.reset();
|
|
752
|
+
|
|
753
|
+
this.updateShapes(shapes, prevShapes, aabb, x, y);
|
|
754
|
+
|
|
755
|
+
if (this.collisionDirty) {
|
|
756
|
+
this.collisionDirty = false;
|
|
757
|
+
}
|
|
758
|
+
},
|
|
759
|
+
|
|
760
|
+
movePreviousX: function (x) {
|
|
761
|
+
this.prevAABB.moveX(x);
|
|
762
|
+
for (let i = 0; i < this.prevShapes.length; i++) {
|
|
763
|
+
this.prevShapes[i].setXWithEntityX(x);
|
|
764
|
+
}
|
|
765
|
+
},
|
|
766
|
+
|
|
767
|
+
destroy: function () {
|
|
768
|
+
const
|
|
769
|
+
{collisionType, owner} = this,
|
|
770
|
+
{collisionFunctions, collisionTypes, parent, softCollisionMap, solidCollisionMap} = owner;
|
|
771
|
+
let i = collisionTypes ? collisionTypes.indexOf(collisionType) : -1;
|
|
772
|
+
|
|
773
|
+
parent.triggerEvent('remove-collision-entity', owner);
|
|
774
|
+
|
|
775
|
+
this.aabb.recycle();
|
|
776
|
+
delete this.aabb;
|
|
777
|
+
this.prevAABB.recycle();
|
|
778
|
+
delete this.prevAABB;
|
|
779
|
+
|
|
780
|
+
if (i >= 0) {
|
|
781
|
+
greenSplice(collisionTypes, i);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
if (collisionTypes) {
|
|
785
|
+
if (solidCollisionMap.has(collisionType)) {
|
|
786
|
+
arrayCache.recycle(solidCollisionMap.delete(collisionType));
|
|
787
|
+
}
|
|
788
|
+
if (softCollisionMap.has(collisionType)) {
|
|
789
|
+
arrayCache.recycle(softCollisionMap.delete(collisionType));
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
collisionFunctions.delete(collisionType).recycle();
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
i = this.shapes.length;
|
|
796
|
+
while (i--) {
|
|
797
|
+
this.shapes[i].recycle();
|
|
798
|
+
this.prevShapes[i].recycle();
|
|
799
|
+
}
|
|
800
|
+
arrayCache.recycle(this.shapes);
|
|
801
|
+
arrayCache.recycle(this.prevShapes);
|
|
802
|
+
this.shapes = null;
|
|
803
|
+
this.prevShapes = null;
|
|
804
|
+
|
|
805
|
+
this.entities = null;
|
|
806
|
+
|
|
807
|
+
if (collisionTypes) {
|
|
808
|
+
if (collisionTypes.length) {
|
|
809
|
+
parent.triggerEvent('add-collision-entity', owner);
|
|
810
|
+
} else { //remove collision functions
|
|
811
|
+
collisionFunctions.recycle();
|
|
812
|
+
owner.collisionFunctions = null;
|
|
813
|
+
solidCollisionMap.recycle();
|
|
814
|
+
owner.solidCollisionMap = null;
|
|
815
|
+
softCollisionMap.recycle();
|
|
816
|
+
owner.softCollisionMap = null;
|
|
817
|
+
owner.aabb.recycle();
|
|
818
|
+
owner.aabb = null;
|
|
819
|
+
arrayCache.recycle(collisionTypes);
|
|
820
|
+
owner.collisionTypes = null;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
|