@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.
- package/CHANGELOG.md +31 -0
- package/README.md +3 -3
- package/lib/platypus.js +1 -1
- package/package.json +7 -6
- 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 +840 -0
- package/src/components/RenderSprite.js +527 -0
- package/src/components/RenderText.js +147 -0
- package/src/components/RenderTiles.js +1440 -0
- package/src/components/SceneChanger.js +128 -0
- package/src/components/TiledLoader.js +1459 -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
- package/lib/243.platypus.mjs +0 -1
- package/lib/platypus.mjs +0 -1
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import AABB from './AABB.js';
|
|
2
|
+
import Vector from './Vector.js';
|
|
3
|
+
import recycle from 'recycle';
|
|
4
|
+
|
|
5
|
+
const
|
|
6
|
+
circleRectCollision = function (circle, rect) {
|
|
7
|
+
const
|
|
8
|
+
rectAabb = rect.aABB,
|
|
9
|
+
hh = rectAabb.halfHeight,
|
|
10
|
+
hw = rectAabb.halfWidth,
|
|
11
|
+
shapeDistanceX = Math.abs(circle.x - rect.x),
|
|
12
|
+
shapeDistanceY = Math.abs(circle.y - rect.y),
|
|
13
|
+
radius = circle.radius;
|
|
14
|
+
|
|
15
|
+
/* This checks the following in order:
|
|
16
|
+
- Is the x or y distance between shapes less than half the width or height respectively of the rectangle? If so, we know they're colliding.
|
|
17
|
+
- Is the x or y distance between the shapes greater than the half width/height plus the radius of the circle? Then we know they're not colliding.
|
|
18
|
+
- Otherwise, we check the distance between a corner of the rectangle and the center of the circle. If that distance is less than the radius of the circle, we know that there is a collision; otherwise there is not.
|
|
19
|
+
*/
|
|
20
|
+
return (shapeDistanceX < hw) || (shapeDistanceY < hh) || ((shapeDistanceX < (hw + radius)) && (shapeDistanceY < (hh + radius)) && ((((shapeDistanceX - hw) ** 2) + ((shapeDistanceY - hh) ** 2)) < radius ** 2));
|
|
21
|
+
},
|
|
22
|
+
collidesCircle = function (shape) {
|
|
23
|
+
return this.aABB.collides(shape.aABB) && (
|
|
24
|
+
((shape.type === 'rectangle') && circleRectCollision(this, shape)) ||
|
|
25
|
+
((shape.type === 'circle') && ((((this.x - shape.x) ** 2) + ((this.y - shape.y) ** 2)) <= ((this.radius + shape.radius) ** 2)))
|
|
26
|
+
);
|
|
27
|
+
},
|
|
28
|
+
collidesDefault = function () {
|
|
29
|
+
return false;
|
|
30
|
+
},
|
|
31
|
+
collidesRectangle = function (shape) {
|
|
32
|
+
return this.aABB.collides(shape.aABB) && (
|
|
33
|
+
(shape.type === 'rectangle') ||
|
|
34
|
+
((shape.type === 'circle') && circleRectCollision(shape, this))
|
|
35
|
+
);
|
|
36
|
+
},
|
|
37
|
+
/**
|
|
38
|
+
* This class defines a collision shape, which defines the 'space' an entity occupies in the collision system. Currently only rectangle and circle shapes can be created. Collision shapes include an axis-aligned bounding box (AABB) that tightly wraps the shape. The AABB is used for initial collision checks.
|
|
39
|
+
*
|
|
40
|
+
* @memberof platypus
|
|
41
|
+
* @class CollisionShape
|
|
42
|
+
* @param owner {platypus.Entity} The entity that uses this shape.
|
|
43
|
+
* @param definition {Object} This is an object of key/value pairs describing the shape.
|
|
44
|
+
* @param definition.x {number} The x position of the shape. The x is always located in the center of the object.
|
|
45
|
+
* @param definition.y {number} The y position of the shape. The y is always located in the center of the object.
|
|
46
|
+
* @param [definition.type="rectangle"] {String} The type of shape this is. Currently this can be either "rectangle" or "circle".
|
|
47
|
+
* @param [definition.jumpThrough] {Object} x/y unit determining jump-through face.
|
|
48
|
+
* @param [definition.width] {number} The width of the shape if it's a rectangle.
|
|
49
|
+
* @param [definition.height] {number} The height of the shape if it's a rectangle.
|
|
50
|
+
* @param [definition.radius] {number} The radius of the shape if it's a circle.
|
|
51
|
+
* @param [definition.offsetX] {number} The x offset of the collision shape from the owner entity's location.
|
|
52
|
+
* @param [definition.offsetY] {number} The y offset of the collision shape from the owner entity's location.
|
|
53
|
+
* @param [definition.regX] {number} The registration x of the collision shape with the owner entity's location if offsetX is not provided.
|
|
54
|
+
* @param [definition.regY] {number} The registration y of the collision shape with the owner entity's location if offsetX is not provided.
|
|
55
|
+
* @param collisionType {String} A string describing the collision type of this shape.
|
|
56
|
+
*/
|
|
57
|
+
CollisionShape = function (owner, definition, collisionType) {
|
|
58
|
+
const
|
|
59
|
+
{x, y} = owner ?? definition,
|
|
60
|
+
{offsetX, offsetY, radius = 0, type = 'rectangle'} = definition,
|
|
61
|
+
diameter = radius * 2,
|
|
62
|
+
width = type === 'circle' ? diameter : definition.width ?? diameter,
|
|
63
|
+
height = type === 'circle' ? diameter : definition.height ?? diameter,
|
|
64
|
+
regX = definition.regX ?? (width / 2),
|
|
65
|
+
regY = definition.regY ?? (height / 2);
|
|
66
|
+
|
|
67
|
+
// If this shape is recycled, the vectors will already be in place.
|
|
68
|
+
if (!this.initialized) {
|
|
69
|
+
this.initialized = true;
|
|
70
|
+
Vector.assign(this, 'offset', 'offsetX', 'offsetY');
|
|
71
|
+
Vector.assign(this, 'position', 'x', 'y');
|
|
72
|
+
Vector.assign(this, 'size', 'width', 'height');
|
|
73
|
+
this.aABB = AABB.setUp();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
this.owner = owner;
|
|
77
|
+
this.collisionType = collisionType;
|
|
78
|
+
this.jumpThrough = definition.jumpThrough ? Vector.setUp(definition.jumpThrough.x, definition.jumpThrough.y) : null;
|
|
79
|
+
this.type = type;
|
|
80
|
+
this.subType = '';
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Determines whether shapes collide.
|
|
84
|
+
*
|
|
85
|
+
* @method platypus.CollisionShape#collides
|
|
86
|
+
* @param shape {platypus.CollisionShape} The shape to check against for collision.
|
|
87
|
+
* @return {Boolean} Whether the shapes collide.
|
|
88
|
+
*/
|
|
89
|
+
if (type === 'circle') {
|
|
90
|
+
this.collides = collidesCircle;
|
|
91
|
+
} else if (type === 'rectangle') {
|
|
92
|
+
this.collides = collidesRectangle;
|
|
93
|
+
} else {
|
|
94
|
+
this.collides = collidesDefault;
|
|
95
|
+
}
|
|
96
|
+
this.size.setXYZ(width, height);
|
|
97
|
+
this.radius = radius;
|
|
98
|
+
|
|
99
|
+
this.offset.setXYZ(offsetX ?? ((width / 2) - regX), offsetY ?? ((height / 2) - regY));
|
|
100
|
+
this.position.setXYZ(x, y).add(this.offset);
|
|
101
|
+
this.aABB.setAll(this.x, this.y, width, height);
|
|
102
|
+
},
|
|
103
|
+
proto = CollisionShape.prototype;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Updates the shape to match another shape.
|
|
107
|
+
*
|
|
108
|
+
* @method platypus.CollisionShape#updateAll
|
|
109
|
+
* @param updateAll {platypus.CollisionShape} The shape to copy into this one.
|
|
110
|
+
*/
|
|
111
|
+
proto.updateAll = function (shape) {
|
|
112
|
+
this.owner = shape.owner;
|
|
113
|
+
this.collisionType = shape.collisionType;
|
|
114
|
+
this.type = shape.type;
|
|
115
|
+
this.subType = shape.subType;
|
|
116
|
+
this.offset.x = shape.offset.x;
|
|
117
|
+
this.offset.y = shape.offset.y;
|
|
118
|
+
this.position.x = shape.position.x;
|
|
119
|
+
this.position.y = shape.position.y;
|
|
120
|
+
this.size.x = shape.size.x;
|
|
121
|
+
this.size.y = shape.size.y;
|
|
122
|
+
this.radius = shape.radius;
|
|
123
|
+
this.aABB.setAll(this.x, this.y, this.width, this.height);
|
|
124
|
+
if (this.type === 'circle') {
|
|
125
|
+
this.collides = collidesCircle;
|
|
126
|
+
} else if (this.type === 'rectangle') {
|
|
127
|
+
this.collides = collidesRectangle;
|
|
128
|
+
} else {
|
|
129
|
+
this.collides = collidesDefault;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Updates the location of the shape and AABB. The position you send should be that of the owner, the offset of the shape is added inside the function.
|
|
135
|
+
*
|
|
136
|
+
* @method platypus.CollisionShape#update
|
|
137
|
+
* @param ownerX {number} The x position of the owner.
|
|
138
|
+
* @param ownerY {number} The y position of the owner.
|
|
139
|
+
*/
|
|
140
|
+
proto.update = function (ownerX, ownerY) {
|
|
141
|
+
const
|
|
142
|
+
x = ownerX + this.offsetX,
|
|
143
|
+
y = ownerY + this.offsetY;
|
|
144
|
+
|
|
145
|
+
this.position.setXYZ(x, y);
|
|
146
|
+
this.aABB.move(x, y);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Move the shape's x position.
|
|
151
|
+
*
|
|
152
|
+
* @method platypus.CollisionShape#moveX
|
|
153
|
+
* @param x {number} The x position to which the shape should be moved.
|
|
154
|
+
*/
|
|
155
|
+
proto.moveX = function (x) {
|
|
156
|
+
this.x = x;
|
|
157
|
+
this.aABB.moveX(x);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Move the shape's y position.
|
|
162
|
+
*
|
|
163
|
+
* @method platypus.CollisionShape#moveY
|
|
164
|
+
* @param y {number} The y position to which the shape should be moved.
|
|
165
|
+
*/
|
|
166
|
+
proto.moveY = function (y) {
|
|
167
|
+
this.y = y;
|
|
168
|
+
this.aABB.moveY(y);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Move the shape's x and y position.
|
|
173
|
+
*
|
|
174
|
+
* @method platypus.CollisionShape#moveXY
|
|
175
|
+
* @param x {number} The x position to which the shape should be moved.
|
|
176
|
+
* @param y {number} The y position to which the shape should be moved.
|
|
177
|
+
*/
|
|
178
|
+
proto.moveXY = function (x, y) {
|
|
179
|
+
this.x = x;
|
|
180
|
+
this.y = y;
|
|
181
|
+
this.aABB.move(x, y);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Returns the axis-aligned bounding box of the shape.
|
|
186
|
+
*
|
|
187
|
+
* @method platypus.CollisionShape#getAABB
|
|
188
|
+
* @return {platypus.AABB} The AABB of the shape.
|
|
189
|
+
*/
|
|
190
|
+
proto.getAABB = function () {
|
|
191
|
+
return this.aABB;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Set the shape's position as if the entity's x position is in a certain location.
|
|
196
|
+
*
|
|
197
|
+
* @method platypus.CollisionShape#setXWithEntityX
|
|
198
|
+
* @param entityX {number} The x position of the entity.
|
|
199
|
+
*/
|
|
200
|
+
proto.setXWithEntityX = function (entityX) {
|
|
201
|
+
this.x = entityX + this.offsetX;
|
|
202
|
+
this.aABB.moveX(this.x);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Set the shape's position as if the entity's y position is in a certain location.
|
|
207
|
+
*
|
|
208
|
+
* @method platypus.CollisionShape#setYWithEntityY
|
|
209
|
+
* @param entityY {number} The y position of the entity.
|
|
210
|
+
*/
|
|
211
|
+
proto.setYWithEntityY = function (entityY) {
|
|
212
|
+
this.y = entityY + this.offsetY;
|
|
213
|
+
this.aABB.moveY(this.y);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Transform the shape using a matrix transformation.
|
|
218
|
+
*
|
|
219
|
+
* @method platypus.CollisionShape#multiply
|
|
220
|
+
* @param matrix {Array} A matrix used to transform the shape.
|
|
221
|
+
*/
|
|
222
|
+
proto.multiply = function (m) {
|
|
223
|
+
const
|
|
224
|
+
pos = this.position,
|
|
225
|
+
own = this.owner.position;
|
|
226
|
+
|
|
227
|
+
pos.subtractVector(own);
|
|
228
|
+
|
|
229
|
+
pos.multiply(m);
|
|
230
|
+
this.offset.multiply(m);
|
|
231
|
+
this.size.multiply(m);
|
|
232
|
+
|
|
233
|
+
pos.addVector(own);
|
|
234
|
+
this.width = Math.abs(this.width);
|
|
235
|
+
this.height = Math.abs(this.height);
|
|
236
|
+
|
|
237
|
+
this.aABB.setAll(this.x, this.y, this.width, this.height);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Expresses whether this shape contains the given point.
|
|
242
|
+
*
|
|
243
|
+
* @method platypus.CollisionShape#containsPoint
|
|
244
|
+
* @param x {number} The x-axis value.
|
|
245
|
+
* @param y {number} The y-axis value.
|
|
246
|
+
* @return {boolean} Returns `true` if this shape contains the point.
|
|
247
|
+
*/
|
|
248
|
+
proto.containsPoint = function (x, y) {
|
|
249
|
+
return this.aABB.containsPoint(x, y) && (
|
|
250
|
+
(this.type === 'rectangle') ||
|
|
251
|
+
((this.type === 'circle') && ((((this.x - x) ** 2) + ((this.y - y) ** 2)) <= this.radius ** 2))
|
|
252
|
+
);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Returns a JSON object describing the collision shape.
|
|
257
|
+
*
|
|
258
|
+
* @method platypus.CollisionShape#toJSON
|
|
259
|
+
* @return {Object} Returns a JSON definition that can be used to recreate the collision shape.
|
|
260
|
+
**/
|
|
261
|
+
proto.toJSON = function () {
|
|
262
|
+
const
|
|
263
|
+
json = {
|
|
264
|
+
type: this.type
|
|
265
|
+
},
|
|
266
|
+
width = this.size.width,
|
|
267
|
+
height = this.size.height;
|
|
268
|
+
|
|
269
|
+
if (width / 2 !== this.regX) {
|
|
270
|
+
json.regX = this.regX;
|
|
271
|
+
}
|
|
272
|
+
if (height / 2 !== this.regY) {
|
|
273
|
+
json.regY = this.regY;
|
|
274
|
+
}
|
|
275
|
+
if (this.offset.x !== ((width / 2) - this.regX)) {
|
|
276
|
+
json.offsetX = this.offset.x;
|
|
277
|
+
}
|
|
278
|
+
if (this.offset.y !== ((height / 2) - this.regY)) {
|
|
279
|
+
json.offsetY = this.offset.y;
|
|
280
|
+
}
|
|
281
|
+
if (this.type === 'circle') {
|
|
282
|
+
json.radius = this.radius;
|
|
283
|
+
} else {
|
|
284
|
+
json.width = width;
|
|
285
|
+
json.height = height;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return json;
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Returns an CollisionShape from cache or creates a new one if none are available.
|
|
293
|
+
*
|
|
294
|
+
* @method platypus.CollisionShape.setUp
|
|
295
|
+
* @return {platypus.CollisionShape} The instantiated CollisionShape.
|
|
296
|
+
*/
|
|
297
|
+
/**
|
|
298
|
+
* Returns a CollisionShape back to the cache.
|
|
299
|
+
*
|
|
300
|
+
* @method platypus.CollisionShape.recycle
|
|
301
|
+
* @param {platypus.CollisionShape} The CollisionShape to be recycled.
|
|
302
|
+
*/
|
|
303
|
+
/**
|
|
304
|
+
* Relinquishes properties of the CollisionShape and recycles it.
|
|
305
|
+
*
|
|
306
|
+
* @method platypus.CollisionShape#recycle
|
|
307
|
+
*/
|
|
308
|
+
recycle.add(CollisionShape, 'CollisionShape', CollisionShape, function () {
|
|
309
|
+
if (this.jumpThrough) {
|
|
310
|
+
this.jumpThrough.recycle();
|
|
311
|
+
}
|
|
312
|
+
this.jumpThrough = null;
|
|
313
|
+
}, true);
|
|
314
|
+
|
|
315
|
+
export default CollisionShape;
|
package/src/Component.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/*global platypus */
|
|
2
|
+
import {arrayCache, greenSplice} from './utils/array.js';
|
|
3
|
+
import Data from './Data.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This is the extendable Component class. Typically specific component classes should be created using `createComponentClass()`. This method accepts component definitions and creates component classes that can be used to create components by entities. It adds properties and methods that are common to all components so that component definitions can focus on unique properties and methods.
|
|
7
|
+
*
|
|
8
|
+
* To create an extended component class, use the following syntax:
|
|
9
|
+
*
|
|
10
|
+
* createComponentClass(componentDefinition, prototype);
|
|
11
|
+
*
|
|
12
|
+
* * `componentDefinition` is list of key/value pairs that describe the component's behavior.
|
|
13
|
+
* * `prototype` is an optional prototype that this component extends.
|
|
14
|
+
* See [component-template.js]("component-template"%20Component.html) for an example componentDefinition that can be sent into this component class factory.
|
|
15
|
+
*
|
|
16
|
+
* @memberof platypus
|
|
17
|
+
* @class Component
|
|
18
|
+
* @static
|
|
19
|
+
*/
|
|
20
|
+
export default class Component {
|
|
21
|
+
constructor (type, owner, id) {
|
|
22
|
+
this.type = type;
|
|
23
|
+
this.owner = owner;
|
|
24
|
+
this.id = id;
|
|
25
|
+
this.publicMethods = Data.setUp();
|
|
26
|
+
this.listener = Data.setUp(
|
|
27
|
+
"events", arrayCache.setUp(),
|
|
28
|
+
"messages", arrayCache.setUp()
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Called by constructor once the component is ready.
|
|
34
|
+
*
|
|
35
|
+
* @method platypus.Component#initialize
|
|
36
|
+
*/
|
|
37
|
+
initialize () {}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Returns a JSON object describing the component.
|
|
41
|
+
*
|
|
42
|
+
* @method platypus.Component#toJSON
|
|
43
|
+
* @return {Object} Returns a JSON definition that can be used to recreate the component.
|
|
44
|
+
**/
|
|
45
|
+
/* toJSON () {} */ // defined in factory.js
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Returns a string describing the component.
|
|
49
|
+
*
|
|
50
|
+
* @method platypus.Component#toString
|
|
51
|
+
* @return {String} Returns the component type as a string of the form "[Component ComponentType]".
|
|
52
|
+
**/
|
|
53
|
+
toString () {
|
|
54
|
+
return "[Component " + this.type + "]";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* This method cleans up listeners and methods that this component added to the entity. It should never be called by the component itself. Call this.owner.removeComponent(this) instead.
|
|
59
|
+
*
|
|
60
|
+
* @method platypus.Component#destroy
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
63
|
+
destroy () {
|
|
64
|
+
if (this.listener) {
|
|
65
|
+
const
|
|
66
|
+
publicMethods = this.publicMethods,
|
|
67
|
+
keys = Object.keys(publicMethods);
|
|
68
|
+
let i = keys.length;
|
|
69
|
+
|
|
70
|
+
// Handle component's destroy method before removing messaging and methods.
|
|
71
|
+
if (this._destroy) {
|
|
72
|
+
this._destroy();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Now remove event listeners and methods.
|
|
76
|
+
while (i--) {
|
|
77
|
+
this.removeMethod(keys[i]);
|
|
78
|
+
}
|
|
79
|
+
this.publicMethods.recycle();
|
|
80
|
+
|
|
81
|
+
this.removeEventListeners();
|
|
82
|
+
arrayCache.recycle(this.listener.events);
|
|
83
|
+
arrayCache.recycle(this.listener.messages);
|
|
84
|
+
this.listener.recycle();
|
|
85
|
+
this.listener = null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* This method removes multiple event listeners from the entity.
|
|
91
|
+
*
|
|
92
|
+
* @method platypus.Component#removeEventListeners
|
|
93
|
+
* @param [listeners] {Array} The list of listeners to remove. If not supplied, all event listeners are removed.
|
|
94
|
+
* @private
|
|
95
|
+
*/
|
|
96
|
+
removeEventListeners (listeners) {
|
|
97
|
+
if (!listeners) {
|
|
98
|
+
const
|
|
99
|
+
{listener, owner} = this,
|
|
100
|
+
{events, messages} = listener,
|
|
101
|
+
{length} = events;
|
|
102
|
+
|
|
103
|
+
for (let i = 0; i < length; i++) {
|
|
104
|
+
owner.off(events[i], messages[i]);
|
|
105
|
+
}
|
|
106
|
+
events.length = 0;
|
|
107
|
+
messages.length = 0;
|
|
108
|
+
} else {
|
|
109
|
+
for (let i = 0; i < listeners.length; i++) {
|
|
110
|
+
this.removeEventListener(listeners[i]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* This method adds an event listener to the entity.
|
|
117
|
+
*
|
|
118
|
+
* @method platypus.Component#addEventListener
|
|
119
|
+
* @param event {String} The event that this component should listen for.
|
|
120
|
+
* @param callback {Function} The handler for the event.
|
|
121
|
+
* @return handler {Function} A reference to the bound handler.
|
|
122
|
+
* @private
|
|
123
|
+
*/
|
|
124
|
+
addEventListener (event, callback, priority) {
|
|
125
|
+
const
|
|
126
|
+
handler = callback.bind(this); // <-- I think we need to stop doing this
|
|
127
|
+
|
|
128
|
+
this.listener.events.push(event);
|
|
129
|
+
this.listener.messages.push(handler);
|
|
130
|
+
this.owner.on(event, handler, priority);
|
|
131
|
+
|
|
132
|
+
return handler;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* This method adds one or more event listeners to the entity and returns a teardown function.
|
|
137
|
+
*
|
|
138
|
+
* @method platypus.Component#addEventListener
|
|
139
|
+
* @param eventsObject {Object} Key/value pairs with event names for keys and handlers as values.
|
|
140
|
+
* @return {Function} Handler teardown function.
|
|
141
|
+
* @private
|
|
142
|
+
*/
|
|
143
|
+
addEventListeners (eventsObject) {
|
|
144
|
+
const
|
|
145
|
+
{owner} = this,
|
|
146
|
+
{parent} = owner,
|
|
147
|
+
tds = Object.keys(eventsObject).map((key) => {
|
|
148
|
+
const
|
|
149
|
+
handler = this.addEventListener(key, eventsObject[key]);
|
|
150
|
+
|
|
151
|
+
return () => this.removeEventListener(key, handler);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
if (owner.state.get('loaded')) {
|
|
155
|
+
parent.triggerEvent?.('child-entity-updated', owner);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return () => {
|
|
159
|
+
tds.forEach((td) => td());
|
|
160
|
+
parent.triggerEvent?.('child-entity-updated', owner);
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* This method adds a method to the entity.
|
|
166
|
+
*
|
|
167
|
+
* @method platypus.Component#addMethod
|
|
168
|
+
* @param name {String} The name of the method. For example, if name is "turnYellow", the method is accessible on the entity as `entity.turnYellow()`.
|
|
169
|
+
* @param func {Function} The function describing the method.
|
|
170
|
+
* @private
|
|
171
|
+
*/
|
|
172
|
+
addMethod (name, func) {
|
|
173
|
+
if (this.owner[name]) {
|
|
174
|
+
platypus.debug.warn(this.owner.type + ': Entity already has a method called "' + name + '". Method not added.');
|
|
175
|
+
} else {
|
|
176
|
+
this.owner[name] = func.bind(this);
|
|
177
|
+
this.publicMethods[name] = func;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* This method removes an event listener from the entity.
|
|
183
|
+
*
|
|
184
|
+
* @method platypus.Component#removeEventListener
|
|
185
|
+
* @param event {String} The event for which to remove a listener.
|
|
186
|
+
* @param callback {Function} The listener to remove. If not supplied, all event listeners for the provided event are removed.
|
|
187
|
+
* @private
|
|
188
|
+
*/
|
|
189
|
+
removeEventListener (event, callback) {
|
|
190
|
+
const
|
|
191
|
+
{listener, owner} = this,
|
|
192
|
+
{events, messages} = listener;
|
|
193
|
+
|
|
194
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
195
|
+
if ((events[i] === event) && (!callback || (messages[i] === callback))) {
|
|
196
|
+
owner.off(event, messages[i]);
|
|
197
|
+
greenSplice(events, i);
|
|
198
|
+
greenSplice(messages, i);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* This method removes a method from the entity.
|
|
205
|
+
*
|
|
206
|
+
* @method platypus.Component#removeMethod
|
|
207
|
+
* @param name {String} The name of the method to be removed.
|
|
208
|
+
* @private
|
|
209
|
+
*/
|
|
210
|
+
removeMethod (name) {
|
|
211
|
+
if (!this.owner[name]) {
|
|
212
|
+
platypus.debug.warn(this.owner.type + ': Entity does not have a method called "' + name + '".');
|
|
213
|
+
} else {
|
|
214
|
+
delete this.owner[name];
|
|
215
|
+
}
|
|
216
|
+
delete this.publicMethods[name];
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* This method can be overwritten to provide the list of assets this component requires. This method is invoked when the list of game scenes is created to determine assets for each scene.
|
|
221
|
+
*
|
|
222
|
+
* @method platypus.Component#getAssetList
|
|
223
|
+
* @param definition {Object} The definition for the component.
|
|
224
|
+
* @param properties {Object} The properties of the Entity.
|
|
225
|
+
* @param defaultProperties {Object} The default properties of the Entity.
|
|
226
|
+
* @return {Array} A list of the necessary assets to load.
|
|
227
|
+
*/
|
|
228
|
+
static getAssetList () {
|
|
229
|
+
return arrayCache.setUp();
|
|
230
|
+
}
|
|
231
|
+
}
|
package/src/Data.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import recycle from 'recycle';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This class defines a generic data object to use for messaging. It includes recycle methods to encourage reuse.
|
|
5
|
+
*
|
|
6
|
+
* @memberof platypus
|
|
7
|
+
* @class Data
|
|
8
|
+
* @param {String|Object} first Can be an object of key/value pairs or the parameters can be an alternating list of keys and values.
|
|
9
|
+
* @return {Data} Returns the new Data object.
|
|
10
|
+
*/
|
|
11
|
+
const
|
|
12
|
+
Data = function (first) {
|
|
13
|
+
let i = arguments.length;
|
|
14
|
+
|
|
15
|
+
if (first) {
|
|
16
|
+
if (typeof first === 'string') {
|
|
17
|
+
if (i % 2) {
|
|
18
|
+
this[i] = null;
|
|
19
|
+
i -= 1;
|
|
20
|
+
}
|
|
21
|
+
while (i) {
|
|
22
|
+
this[arguments[i - 2]] = arguments[i - 1];
|
|
23
|
+
i -= 2;
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
const
|
|
27
|
+
keys = Object.keys(first);
|
|
28
|
+
let j = keys.length;
|
|
29
|
+
|
|
30
|
+
while (j--) {
|
|
31
|
+
this[keys[j]] = first[keys[j]];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns Data from cache or creates a new one if none are available.
|
|
39
|
+
*
|
|
40
|
+
* @method platypus.Data.setUp
|
|
41
|
+
* @return {platypus.Data} The instantiated Data.
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Returns Data back to the cache. Prefer the Data's recycle method since it recycles property objects as well.
|
|
45
|
+
*
|
|
46
|
+
* @method platypus.Data.recycle
|
|
47
|
+
* @param {platypus.Data} The Data to be recycled.
|
|
48
|
+
*/
|
|
49
|
+
/**
|
|
50
|
+
* Relinquishes Data properties and recycles it.
|
|
51
|
+
*
|
|
52
|
+
* @method platypus.Data#recycle
|
|
53
|
+
*/
|
|
54
|
+
recycle.add(Data, 'Data', Data, function () {
|
|
55
|
+
const
|
|
56
|
+
keys = Object.keys(this);
|
|
57
|
+
let i = keys.length;
|
|
58
|
+
|
|
59
|
+
while (i--) {
|
|
60
|
+
delete this[keys[i]];
|
|
61
|
+
}
|
|
62
|
+
}, true);
|
|
63
|
+
|
|
64
|
+
export default Data;
|