@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,524 @@
|
|
|
1
|
+
/* global atob, platypus */
|
|
2
|
+
import {arrayCache, greenSlice, greenSplice, union} from '../utils/array.js';
|
|
3
|
+
import createComponentClass from '../factory.js';
|
|
4
|
+
import {inflate} from 'pako';
|
|
5
|
+
import TiledLoader from './TiledLoader.js';
|
|
6
|
+
|
|
7
|
+
const
|
|
8
|
+
maskXFlip = 0x80000000,
|
|
9
|
+
decodeString = (str, index) => (((str.charCodeAt(index)) + (str.charCodeAt(index + 1) << 8) + (str.charCodeAt(index + 2) << 16) + (str.charCodeAt(index + 3) << 24 )) >>> 0),
|
|
10
|
+
decodeArray = (arr, index) => ((arr[index] + (arr[index + 1] << 8) + (arr[index + 2] << 16) + (arr[index + 3] << 24 )) >>> 0),
|
|
11
|
+
decodeBase64 = (data, compression) => {
|
|
12
|
+
const
|
|
13
|
+
arr = [],
|
|
14
|
+
compressed = compression === 'zlib',
|
|
15
|
+
step1 = window.atob(data.replace(/\\/g, '')),
|
|
16
|
+
step2 = compressed ? inflate(step1) : step1,
|
|
17
|
+
decode = compressed ? decodeArray : decodeString;
|
|
18
|
+
let index = 4;
|
|
19
|
+
|
|
20
|
+
while (index <= step2.length) {
|
|
21
|
+
arr.push(decode(step2, index - 4));
|
|
22
|
+
index += 4;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return arr;
|
|
26
|
+
},
|
|
27
|
+
decodeLayer = function (layer) {
|
|
28
|
+
if (layer.encoding === 'base64') {
|
|
29
|
+
layer.data = decodeBase64(layer.data, layer.compression);
|
|
30
|
+
layer.encoding = 'csv'; // So we won't have to decode again.
|
|
31
|
+
}
|
|
32
|
+
return layer;
|
|
33
|
+
},
|
|
34
|
+
mergeData = function (levelData, levelMergeAxisLength, segmentData, segmentMergeAxisLength, nonMergeAxisLength, mergeAxis) {
|
|
35
|
+
const
|
|
36
|
+
combined = greenSlice(levelData);
|
|
37
|
+
|
|
38
|
+
if (mergeAxis === 'horizontal') {
|
|
39
|
+
for (let y = nonMergeAxisLength - 1; y >= 0; y--) {
|
|
40
|
+
for (let x = y * segmentMergeAxisLength, z = 0; x < (y + 1) * segmentMergeAxisLength; x++, z++) {
|
|
41
|
+
combined.splice(((y + 1) * levelMergeAxisLength) + z, 0, segmentData[x]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return combined;
|
|
45
|
+
} else if (mergeAxis === 'vertical') {
|
|
46
|
+
return levelData.concat(segmentData);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return null;
|
|
50
|
+
},
|
|
51
|
+
mergeObjects = function (obj1s, obj2s, mergeAxisLength, mergeAxis) {
|
|
52
|
+
const
|
|
53
|
+
list = greenSlice(obj1s);
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < obj2s.length; i++) {
|
|
56
|
+
const
|
|
57
|
+
obj = {
|
|
58
|
+
...obj2s[i]
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (mergeAxis === 'horizontal') {
|
|
62
|
+
obj.x += mergeAxisLength;
|
|
63
|
+
} else if (mergeAxis === 'vertical') {
|
|
64
|
+
obj.y += mergeAxisLength;
|
|
65
|
+
}
|
|
66
|
+
list.push(obj);
|
|
67
|
+
}
|
|
68
|
+
return list;
|
|
69
|
+
},
|
|
70
|
+
mergeSegment = function (level, segment, mergeAxis) {
|
|
71
|
+
if (!level.tilewidth && !level.tileheight) {
|
|
72
|
+
//set level tile size data if it's not already set.
|
|
73
|
+
level.tilewidth = segment.tilewidth;
|
|
74
|
+
level.tileheight = segment.tileheight;
|
|
75
|
+
} else if (level.tilewidth !== segment.tilewidth || level.tileheight !== segment.tileheight) {
|
|
76
|
+
platypus.debug.warn('Component LevelBuilder: Your map has segments with different tile sizes. All tile sizes must match. Segment: ' + segment);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (mergeAxis === 'horizontal') {
|
|
80
|
+
if (level.height === 0) {
|
|
81
|
+
level.height = segment.height;
|
|
82
|
+
} else if (level.height !== segment.height) {
|
|
83
|
+
platypus.debug.warn('Component LevelBuilder: You are trying to merge segments with different heights. All segments need to have the same height. Level: ' + level + ' Segment: ' + segment);
|
|
84
|
+
}
|
|
85
|
+
} else if (mergeAxis === 'vertical') {
|
|
86
|
+
if (level.width === 0) {
|
|
87
|
+
level.width = segment.width;
|
|
88
|
+
} else if (level.width !== segment.width) {
|
|
89
|
+
platypus.debug.warn('Component LevelBuilder: You are trying to merge segments with different widths. All segments need to have the same width. Level: ' + level + ' Segment: ' + segment);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < segment.layers.length; i++) {
|
|
94
|
+
if (!level.layers[i]) {
|
|
95
|
+
//if the level doesn't have a layer yet, we're creating it and then copying it from the segment.
|
|
96
|
+
decodeLayer(segment.layers[i]);
|
|
97
|
+
|
|
98
|
+
const
|
|
99
|
+
layer = level.layers[i] = {
|
|
100
|
+
...segment.layers[i]
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// If we're adding objects, make sure that they're offset correctly.
|
|
104
|
+
if (layer.objects) {
|
|
105
|
+
if (mergeAxis === 'horizontal') {
|
|
106
|
+
layer.objects = mergeObjects([], layer.objects, level.width * level.tilewidth, mergeAxis);
|
|
107
|
+
} else if (mergeAxis === 'vertical') {
|
|
108
|
+
layer.objects = mergeObjects([], layer.objects, level.height * level.tileheight, mergeAxis);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} else if (level.layers[i].type === segment.layers[i].type) {
|
|
112
|
+
//if the level does have a layer, we're appending the new data to it.
|
|
113
|
+
if (level.layers[i].data && segment.layers[i].data) {
|
|
114
|
+
// Make sure we're not trying to merge compressed levels.
|
|
115
|
+
decodeLayer(segment.layers[i]);
|
|
116
|
+
|
|
117
|
+
if (mergeAxis === 'horizontal') {
|
|
118
|
+
level.layers[i].data = mergeData(level.layers[i].data, level.width, segment.layers[i].data, segment.width, level.height, mergeAxis);
|
|
119
|
+
level.layers[i].width += segment.width;
|
|
120
|
+
} else if (mergeAxis === 'vertical') {
|
|
121
|
+
level.layers[i].data = mergeData(level.layers[i].data, level.height, segment.layers[i].data, segment.height, level.width, mergeAxis);
|
|
122
|
+
level.layers[i].height += segment.height;
|
|
123
|
+
}
|
|
124
|
+
} else if (level.layers[i].objects && segment.layers[i].objects) {
|
|
125
|
+
if (mergeAxis === 'horizontal') {
|
|
126
|
+
level.layers[i].objects = mergeObjects(level.layers[i].objects, segment.layers[i].objects, level.width * level.tilewidth, mergeAxis);
|
|
127
|
+
} else if (mergeAxis === 'vertical') {
|
|
128
|
+
level.layers[i].objects = mergeObjects(level.layers[i].objects, segment.layers[i].objects, level.height * level.tileheight, mergeAxis);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
platypus.debug.warn('Component LevelBuilder: The layers in your level segments do not match. Level: ' + level + ' Segment: ' + segment);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (mergeAxis === 'horizontal') {
|
|
137
|
+
level.width += segment.width;
|
|
138
|
+
} else if (mergeAxis === 'vertical') {
|
|
139
|
+
level.height += segment.height;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
//Go through all the STUFF in segment and copy it to the level if it's not already there.
|
|
143
|
+
{
|
|
144
|
+
const
|
|
145
|
+
keys = Object.keys(segment),
|
|
146
|
+
{length} = keys;
|
|
147
|
+
|
|
148
|
+
for (let i = 0; i < length; i++) {
|
|
149
|
+
const
|
|
150
|
+
key = keys[i];
|
|
151
|
+
|
|
152
|
+
if (!level[key]) {
|
|
153
|
+
level[key] = segment[key];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
mergeLevels = function (levelSegments) {
|
|
159
|
+
const
|
|
160
|
+
levelDefinitions = platypus.game.settings.levels,
|
|
161
|
+
level = {
|
|
162
|
+
height: 0,
|
|
163
|
+
width: 0,
|
|
164
|
+
layers: []
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
for (let i = 0; i < levelSegments.length; i++) {
|
|
168
|
+
const
|
|
169
|
+
row = {
|
|
170
|
+
height: 0,
|
|
171
|
+
width: 0,
|
|
172
|
+
layers: []
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
for (let j = 0; j < levelSegments[i].length; j++) {
|
|
176
|
+
//Merge horizontally
|
|
177
|
+
if (typeof levelSegments[i][j] === 'string') {
|
|
178
|
+
const
|
|
179
|
+
levelDefinitionLabel = levelSegments[i][j],
|
|
180
|
+
transformIndex = levelDefinitionLabel.indexOf(':');
|
|
181
|
+
let levelDefinition = levelDefinitions[levelDefinitionLabel];
|
|
182
|
+
|
|
183
|
+
// check for transform
|
|
184
|
+
if (!levelDefinition && (transformIndex >= 0)) {
|
|
185
|
+
const transform = levelDefinitionLabel.substring(transformIndex + 1);
|
|
186
|
+
|
|
187
|
+
levelDefinition = levelDefinitions[levelDefinitionLabel.substring(0, transformIndex)];
|
|
188
|
+
if (transform === 'mirror') {
|
|
189
|
+
levelDefinition = levelDefinitions[levelDefinitionLabel] = mirrorSegment(levelDefinition);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
mergeSegment(row, levelDefinition, 'horizontal');
|
|
193
|
+
} else {
|
|
194
|
+
mergeSegment(row, levelSegments[i][j], 'horizontal');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//Then merge vertically
|
|
198
|
+
mergeSegment(level, row, 'vertical');
|
|
199
|
+
}
|
|
200
|
+
return level;
|
|
201
|
+
},
|
|
202
|
+
mirrorSegment = function (segment) {
|
|
203
|
+
const
|
|
204
|
+
newSegment = {
|
|
205
|
+
layers: []
|
|
206
|
+
},
|
|
207
|
+
width = segment.width * segment.tilewidth;
|
|
208
|
+
|
|
209
|
+
for (let i = 0; i < segment.layers.length; i++) {
|
|
210
|
+
decodeLayer(segment.layers[i]);
|
|
211
|
+
|
|
212
|
+
const
|
|
213
|
+
fromLayer = segment.layers[i],
|
|
214
|
+
toLayer = newSegment.layers[i] = {
|
|
215
|
+
...fromLayer
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
if (fromLayer.data) {
|
|
219
|
+
const
|
|
220
|
+
fromData = fromLayer.data,
|
|
221
|
+
segmentWidth = segment.width;
|
|
222
|
+
|
|
223
|
+
toLayer.data = fromData.map((value, index) => {
|
|
224
|
+
const
|
|
225
|
+
cell = fromData[segmentWidth * ((index / segmentWidth) >> 0) + segmentWidth - 1 - (index % segmentWidth)];
|
|
226
|
+
|
|
227
|
+
return cell ? maskXFlip ^ cell : 0;
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// If we're adding objects, make sure that they're mirrored correctly.
|
|
232
|
+
if (fromLayer.objects) {
|
|
233
|
+
const
|
|
234
|
+
fromObjects = fromLayer.objects,
|
|
235
|
+
toObjects = toLayer.objects = [];
|
|
236
|
+
|
|
237
|
+
for (let j = 0; j < fromObjects.length; j++) {
|
|
238
|
+
const
|
|
239
|
+
fromObject = fromObjects[j],
|
|
240
|
+
toObject = toObjects[j] = {
|
|
241
|
+
...fromObject
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
toObject.x = width - fromObject.x - (fromObject.width || 0); // subtract object width since its top-left corner is the origin.
|
|
245
|
+
if (fromObject.rotation) {
|
|
246
|
+
toObject.rotation = -fromObject.rotation;
|
|
247
|
+
}
|
|
248
|
+
if (fromObject.polygon) {
|
|
249
|
+
toObject.polygon = mirrorPoints(fromObject.polygon);
|
|
250
|
+
}
|
|
251
|
+
if (fromObject.polyline) {
|
|
252
|
+
toObject.polyline = mirrorPoints(fromObject.polyline);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
//Go through all the STUFF in segment and copy it to the level if it's not already there.
|
|
259
|
+
{
|
|
260
|
+
const
|
|
261
|
+
keys = Object.keys(segment),
|
|
262
|
+
{length} = keys;
|
|
263
|
+
|
|
264
|
+
for (let i = 0; i < length; i++) {
|
|
265
|
+
const
|
|
266
|
+
key = keys[i];
|
|
267
|
+
|
|
268
|
+
if (!newSegment[key]) {
|
|
269
|
+
newSegment[key] = segment[key];
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return newSegment;
|
|
275
|
+
},
|
|
276
|
+
mirrorPoints = function (points) {
|
|
277
|
+
const
|
|
278
|
+
arr = [];
|
|
279
|
+
let i = points.length;
|
|
280
|
+
|
|
281
|
+
while (i--) {
|
|
282
|
+
arr.push({
|
|
283
|
+
x: -points[i].x,
|
|
284
|
+
y: points[i].y
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
arr.unshift(arr.pop()); // so the same point is at the beginning.
|
|
288
|
+
|
|
289
|
+
return arr;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
export default createComponentClass(/** @lends platypus.components.LevelBuilder.prototype */{
|
|
293
|
+
id: 'LevelBuilder',
|
|
294
|
+
|
|
295
|
+
properties: {
|
|
296
|
+
/**
|
|
297
|
+
* If true, no single map piece is used twice in the creation of the combined map.
|
|
298
|
+
*
|
|
299
|
+
* @property useUniques
|
|
300
|
+
* @type Boolean
|
|
301
|
+
* @default true
|
|
302
|
+
*/
|
|
303
|
+
useUniques: true,
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* A 1D or 2D array of level piece ids. The template defines how the pieces will be arranged and which pieces can be used where. The template must be rectangular in dimensions.
|
|
307
|
+
*
|
|
308
|
+
* "levelTemplate": [ ["start", "forest"], ["forest", "end"] ]
|
|
309
|
+
*
|
|
310
|
+
* @property levelTemplate
|
|
311
|
+
* @type Array
|
|
312
|
+
* @default null
|
|
313
|
+
*/
|
|
314
|
+
levelTemplate: null,
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* This is an object of key/value pairs listing the pieces that map to an id in the level template. The value can be specified as a string or array. A piece will be randomly chosen from an array when that idea is used. If levelPieces is not defined, ids in the template map directly to level names.
|
|
318
|
+
*
|
|
319
|
+
* "levelPieces": {
|
|
320
|
+
* "start" : "start-map",
|
|
321
|
+
* "end" : "end-map",
|
|
322
|
+
* "forest" : ["forest-1", "forest-2", "forest-3"],
|
|
323
|
+
* "river": ["river-1", "river-1:mirror"] // adding ":mirror" takes the referenced map and flips it horizontally to add variety.
|
|
324
|
+
* }
|
|
325
|
+
*
|
|
326
|
+
* @property levelPieces
|
|
327
|
+
* @type Object
|
|
328
|
+
* @default null
|
|
329
|
+
*/
|
|
330
|
+
levelPieces: null
|
|
331
|
+
},
|
|
332
|
+
|
|
333
|
+
publicProperties: {
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* This component works in tandem with `TiledLoader` by taking several Tiled maps and combining them before `TiledLoader` processes them. Tiled maps must use the same tilesets for this to function correctly.
|
|
338
|
+
*
|
|
339
|
+
* Note: Set "manuallyLoad" to `true` in the `TiledLoader` component JSON definition so that it will wait for this component's "load-level" call.
|
|
340
|
+
*
|
|
341
|
+
* @memberof platypus.components
|
|
342
|
+
* @uses platypus.Component
|
|
343
|
+
* @constructs
|
|
344
|
+
* @listens platypus.Entity#layer-loaded
|
|
345
|
+
* @fires platypus.Entity#created-level
|
|
346
|
+
* @fires platypus.Entity#load-level
|
|
347
|
+
*/
|
|
348
|
+
initialize: function () {
|
|
349
|
+
this.levelMessage = {level: null, persistentData: null};
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
events: {
|
|
353
|
+
"layer-loaded": function (data) {
|
|
354
|
+
const
|
|
355
|
+
piecesToCopy = data?.levelPieces ?? this.levelPieces;
|
|
356
|
+
|
|
357
|
+
this.levelMessage.persistentData = data;
|
|
358
|
+
this.levelTemplate = data?.levelTemplate ?? this.levelTemplate;
|
|
359
|
+
this.useUniques = data?.useUniques ?? this.useUniques;
|
|
360
|
+
this.levelPieces = {};
|
|
361
|
+
if (piecesToCopy) {
|
|
362
|
+
const
|
|
363
|
+
keys = Object.keys(piecesToCopy),
|
|
364
|
+
{length} = keys;
|
|
365
|
+
|
|
366
|
+
for (let i = 0; i < length; i++) {
|
|
367
|
+
const
|
|
368
|
+
key = keys[i];
|
|
369
|
+
|
|
370
|
+
if (typeof piecesToCopy[key] === "string") {
|
|
371
|
+
this.levelPieces[key] = piecesToCopy[key];
|
|
372
|
+
} else if (Array.isArray(piecesToCopy[key])) {
|
|
373
|
+
this.levelPieces[key] = [
|
|
374
|
+
...piecesToCopy[key]
|
|
375
|
+
];
|
|
376
|
+
} else {
|
|
377
|
+
throw ('Level Builder: Level pieces of incorrect type: ' + piecesToCopy[key]);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (this.levelTemplate) {
|
|
383
|
+
if (this.levelTemplate) {
|
|
384
|
+
this.levelMessage.level = [];
|
|
385
|
+
for (let i = 0; i < this.levelTemplate.length; i++) {
|
|
386
|
+
const
|
|
387
|
+
templateRow = this.levelTemplate[i];
|
|
388
|
+
|
|
389
|
+
if (typeof templateRow === "string") {
|
|
390
|
+
this.levelMessage.level[i] = this.getLevelPiece(templateRow);
|
|
391
|
+
} else if (templateRow.length) {
|
|
392
|
+
this.levelMessage.level[i] = [];
|
|
393
|
+
for (let j = 0; j < templateRow.length; j++) {
|
|
394
|
+
this.levelMessage.level[i][j] = this.getLevelPiece(templateRow[j]);
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
throw ('Level Builder: Template row is neither a string or array. What is it?');
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
} else {
|
|
401
|
+
platypus.debug.warn('Level Builder: Template is not defined');
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
platypus.debug.warn('Level Builder: There is no level template.');
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (this.levelMessage.level) {
|
|
408
|
+
this.levelMessage.level = mergeLevels(this.levelMessage.level);
|
|
409
|
+
/**
|
|
410
|
+
* Dispatched when the scene has loaded and the level has been composited. This occurs before "load-level" to send out level before it's loaded in case it needs to be saved or edited before being loaded.
|
|
411
|
+
*
|
|
412
|
+
* @event platypus.Entity#created-level
|
|
413
|
+
* @param data {Object}
|
|
414
|
+
* @param data.level {Object} An object describing the level dimensions, tiles, and entities.
|
|
415
|
+
* @param data.persistentData {Object} The persistent data passed from the last scene. We add levelBuilder data to it to pass on.
|
|
416
|
+
* @param data.persistentData.levelTemplate {Object} A 1D or 2D array of level piece ids. The template defines how the pieces will be arranged and which pieces can be used where. The template must be rectangular in dimensions.
|
|
417
|
+
* @param data.persistentData.levelPieces {Object} An object of key/value pairs listing the pieces that map to an id in the level template.
|
|
418
|
+
* @param data.persistentData.useUniques {Boolean} If true, no single map piece is used twice in the creation of the combined map.
|
|
419
|
+
*/
|
|
420
|
+
this.owner.triggerEvent('created-level', this.levelMessage);
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Dispatched when the scene has loaded and the level has been composited so TileLoader can begin loading the level.
|
|
424
|
+
*
|
|
425
|
+
* @event platypus.Entity#load-level
|
|
426
|
+
* @param data {Object}
|
|
427
|
+
* @param data.level {Object} An object describing the level dimensions, tiles, and entities.
|
|
428
|
+
* @param data.persistentData {Object} The persistent data passed from the last scene. We add levelBuilder data to it to pass on.
|
|
429
|
+
* @param data.persistentData.levelTemplate {Object} A 1D or 2D array of level piece ids. The template defines how the pieces will be arranged and which pieces can be used where. The template must be rectangular in dimensions.
|
|
430
|
+
* @param data.persistentData.levelPieces {Object} An object of key/value pairs listing the pieces that map to an id in the level template.
|
|
431
|
+
* @param data.persistentData.useUniques {Boolean} If true, no single map piece is used twice in the creation of the combined map.
|
|
432
|
+
*/
|
|
433
|
+
this.owner.triggerEvent('load-level', this.levelMessage);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
|
|
438
|
+
methods: {// These are methods that are called by this component.
|
|
439
|
+
getLevelPiece: function (type) {
|
|
440
|
+
const
|
|
441
|
+
pieces = this.levelPieces[type] ?? type;
|
|
442
|
+
|
|
443
|
+
if (pieces) {
|
|
444
|
+
if (typeof pieces === "string") {
|
|
445
|
+
if (this.useUniques) {
|
|
446
|
+
this.levelPieces[type] = null;
|
|
447
|
+
}
|
|
448
|
+
return pieces;
|
|
449
|
+
} else if (pieces.length) {
|
|
450
|
+
const
|
|
451
|
+
random = Math.floor(Math.random() * pieces.length);
|
|
452
|
+
|
|
453
|
+
if (this.useUniques) {
|
|
454
|
+
return greenSplice(this.levelPieces[type], random);
|
|
455
|
+
} else {
|
|
456
|
+
return pieces[random];
|
|
457
|
+
}
|
|
458
|
+
} else {
|
|
459
|
+
throw new Error(`Level Builder: There are no MORE level pieces of type: ${type}`);
|
|
460
|
+
}
|
|
461
|
+
} else {
|
|
462
|
+
throw new Error(`Level Builder: There are no level pieces of type: ${type}`);
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
destroy: function () {
|
|
466
|
+
this.levelMessage.level = null;
|
|
467
|
+
this.levelMessage.persistentData = null;
|
|
468
|
+
this.levelMessage = null;
|
|
469
|
+
}
|
|
470
|
+
},
|
|
471
|
+
|
|
472
|
+
publicMethods: {
|
|
473
|
+
/**
|
|
474
|
+
* Accepts a list of levels to be merged and returns a level definition with the references combined.
|
|
475
|
+
*
|
|
476
|
+
* @memberof LevelBuilder.prototype
|
|
477
|
+
* @param {Array} levels
|
|
478
|
+
* @return {Object}
|
|
479
|
+
*/
|
|
480
|
+
mergeLevels: function (levels) {
|
|
481
|
+
return mergeLevels(levels);
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
|
|
485
|
+
getAssetList: function (def, props, defaultProps, data) {
|
|
486
|
+
const
|
|
487
|
+
assets = arrayCache.setUp(),
|
|
488
|
+
levels = def?.levelPieces ?? props?.levelPieces ?? defaultProps?.levelPieces ?? data?.levelPieces;
|
|
489
|
+
|
|
490
|
+
if (levels) {
|
|
491
|
+
const
|
|
492
|
+
keys = Object.keys(levels),
|
|
493
|
+
{length} = keys;
|
|
494
|
+
|
|
495
|
+
for (let i = 0; i < length; i++) {
|
|
496
|
+
const
|
|
497
|
+
key = keys[i];
|
|
498
|
+
|
|
499
|
+
// Offload to TiledLoader since it has level-parsing handling
|
|
500
|
+
if (Array.isArray(levels[key])) {
|
|
501
|
+
for (let j = 0; j < levels[key].length; j++) {
|
|
502
|
+
const
|
|
503
|
+
arr = TiledLoader.getAssetList({
|
|
504
|
+
level: levels[key][j]
|
|
505
|
+
}, props, defaultProps);
|
|
506
|
+
|
|
507
|
+
union(assets, arr);
|
|
508
|
+
arrayCache.recycle(arr);
|
|
509
|
+
}
|
|
510
|
+
} else {
|
|
511
|
+
const
|
|
512
|
+
arr = TiledLoader.getAssetList({
|
|
513
|
+
level: levels[key]
|
|
514
|
+
}, props, defaultProps);
|
|
515
|
+
|
|
516
|
+
union(assets, arr);
|
|
517
|
+
arrayCache.recycle(arr);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return assets;
|
|
523
|
+
}
|
|
524
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import {arrayCache} from '../utils/array.js';
|
|
2
|
+
import createComponentClass from '../factory.js';
|
|
3
|
+
|
|
4
|
+
export default (function () {
|
|
5
|
+
return createComponentClass(/** @lends platypus.components.LogicAngularMovement.prototype */{
|
|
6
|
+
|
|
7
|
+
id: 'LogicAngularMovement',
|
|
8
|
+
|
|
9
|
+
properties: {
|
|
10
|
+
/**
|
|
11
|
+
* The max velocity.
|
|
12
|
+
*
|
|
13
|
+
* @property maxVelocity
|
|
14
|
+
* @type Number
|
|
15
|
+
* @default 3
|
|
16
|
+
*/
|
|
17
|
+
maxVelocity: 3,
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The rate of acceleration.
|
|
21
|
+
*
|
|
22
|
+
* @property acceleration
|
|
23
|
+
* @type Number
|
|
24
|
+
* @default 0.01
|
|
25
|
+
*/
|
|
26
|
+
acceleration: 0.01,
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The offset between the rotation value of the entity and the rotation of the art.
|
|
30
|
+
*
|
|
31
|
+
* @property visualOffset
|
|
32
|
+
* @type Number
|
|
33
|
+
* @default 0
|
|
34
|
+
*/
|
|
35
|
+
visualOffset: 0,
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The starting heading at which the entity will accelerate. In radians.
|
|
39
|
+
*
|
|
40
|
+
* @property startAngle
|
|
41
|
+
* @type Number
|
|
42
|
+
* @default 0
|
|
43
|
+
*/
|
|
44
|
+
startAngle: 0
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
publicProperties: {
|
|
48
|
+
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* This component moves the entity in the direction of an internally stored angle value. When moving, the entity constantly accelerates the entity in a direction up to a max velocity.
|
|
53
|
+
*
|
|
54
|
+
* @memberof platypus.components
|
|
55
|
+
* @uses platypus.Component
|
|
56
|
+
* @constructs
|
|
57
|
+
* @listens platypus.Entity#handle-logic
|
|
58
|
+
* @listens platypus.Entity#move
|
|
59
|
+
* @listens platypus.Entity#set-angle
|
|
60
|
+
* @listens platypus.Entity#set-max-velocity
|
|
61
|
+
* @listens platypus.Entity#stop
|
|
62
|
+
*/
|
|
63
|
+
initialize: function () {
|
|
64
|
+
this.angle = this.startAngle;
|
|
65
|
+
this.v = arrayCache.setUp(0, 0);
|
|
66
|
+
this.moving = false;
|
|
67
|
+
this.piOverTwo = Math.PI / 2;
|
|
68
|
+
this.owner.rotation = this.owner.rotation || this.visualOffset;
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
events: {
|
|
72
|
+
"handle-logic": function ({delta}) {
|
|
73
|
+
const
|
|
74
|
+
{PI, sin, cos, min, max} = Math;
|
|
75
|
+
|
|
76
|
+
if (this.moving) {
|
|
77
|
+
let currentAngle = 0;
|
|
78
|
+
|
|
79
|
+
this.v[0] += this.acceleration * cos(this.angle) * delta;
|
|
80
|
+
this.v[1] += this.acceleration * sin(this.angle) * delta;
|
|
81
|
+
if (this.v[0] === 0) {
|
|
82
|
+
if (this.v[1] > 0) {
|
|
83
|
+
currentAngle = this.piOverTwo;
|
|
84
|
+
} else if (this.v[1] < 0) {
|
|
85
|
+
currentAngle = -this.piOverTwo;
|
|
86
|
+
} else {
|
|
87
|
+
currentAngle = this.angle;
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
currentAngle = Math.atan(this.v[1] / this.v[0]);
|
|
91
|
+
if (this.v[0] < 0) {
|
|
92
|
+
currentAngle = PI + currentAngle;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (this.v[0] >= 0) {
|
|
96
|
+
this.v[0] = min(this.v[0], this.maxVelocity * cos(currentAngle));
|
|
97
|
+
} else {
|
|
98
|
+
this.v[0] = max(this.v[0], this.maxVelocity * cos(currentAngle));
|
|
99
|
+
}
|
|
100
|
+
if (this.v[1] >= 0) {
|
|
101
|
+
this.v[1] = min(this.v[1], this.maxVelocity * sin(currentAngle));
|
|
102
|
+
} else {
|
|
103
|
+
this.v[1] = max(this.v[1], this.maxVelocity * sin(currentAngle));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
this.owner.x += this.v[0];
|
|
107
|
+
this.owner.y += this.v[1];
|
|
108
|
+
|
|
109
|
+
this.owner.rotation = (currentAngle * (180 / PI)) + this.visualOffset;
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
/**
|
|
113
|
+
* Sets the internal heading angle in the component.
|
|
114
|
+
*
|
|
115
|
+
* @event platypus.Entity#set-angle
|
|
116
|
+
* @param angle {Number} The value you want to set the angle to.
|
|
117
|
+
*/
|
|
118
|
+
"set-angle": function (angle) {
|
|
119
|
+
this.angle = angle;
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Start the entity accelerating toward the heading angle.
|
|
124
|
+
*
|
|
125
|
+
* @event platypus.Entity#move
|
|
126
|
+
*/
|
|
127
|
+
"move": function () {
|
|
128
|
+
this.moving = true;
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
"stop": function () {
|
|
132
|
+
this.moving = false;
|
|
133
|
+
this.v[0] = 0;
|
|
134
|
+
this.v[1] = 0;
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Set the max velocity.
|
|
139
|
+
*
|
|
140
|
+
* @event platypus.Entity#set-max-velocity
|
|
141
|
+
* @param newMaxV {Number} The max velocity value.
|
|
142
|
+
*/
|
|
143
|
+
"set-max-velocity": function (newMaxV) {
|
|
144
|
+
this.maxVelocity = newMaxV;
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
methods: {
|
|
149
|
+
destroy: function () {
|
|
150
|
+
this.v.recycle();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}());
|