@makefully/platypus 4.1.10 → 4.1.11
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 +14 -0
- package/lib/platypus.js +1 -1
- package/package.json +1 -1
- package/src/AssetManager.js +2 -0
- package/src/PIXIAnimation.js +102 -23
- package/src/components/LevelBuilder.js +219 -48
- package/src/components/Render.js +11 -5
- package/src/components/RenderSprite.js +10 -1
package/package.json
CHANGED
package/src/AssetManager.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
/* global platypus, setTimeout */
|
|
8
8
|
import Data from './Data.js';
|
|
9
9
|
import DataMap from './DataMap.js';
|
|
10
|
+
import PIXIAnimation from './PIXIAnimation.js';
|
|
10
11
|
import {Assets} from 'pixi.js';
|
|
11
12
|
import {arrayCache} from './utils/array.js';
|
|
12
13
|
|
|
@@ -58,6 +59,7 @@ export default class AssetManager {
|
|
|
58
59
|
asset.src = '';
|
|
59
60
|
}
|
|
60
61
|
assets.delete(alias);
|
|
62
|
+
PIXIAnimation.invalidateTextureSources(alias);
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
return !counts[alias];
|
package/src/PIXIAnimation.js
CHANGED
|
@@ -4,15 +4,74 @@ import {arrayCache, greenSlice} from './utils/array.js';
|
|
|
4
4
|
import Data from './Data.js';
|
|
5
5
|
|
|
6
6
|
const
|
|
7
|
-
MAX_KEY_LENGTH_PER_IMAGE = 128,
|
|
8
7
|
animationCache = {},
|
|
9
8
|
textureSourceCache = {},
|
|
10
9
|
doNothing = function () {},
|
|
11
10
|
emptyFrame = Texture.EMPTY,
|
|
12
|
-
|
|
11
|
+
imageBasename = /([\w-\.]+)\.(\w+)$/,
|
|
12
|
+
hashString = function (value) {
|
|
13
|
+
const
|
|
14
|
+
str = typeof value === 'string' ? value : JSON.stringify(value);
|
|
15
|
+
let hash = 5381;
|
|
16
|
+
|
|
17
|
+
for (let i = 0; i < str.length; i++) {
|
|
18
|
+
hash = ((hash << 5) + hash) ^ str.charCodeAt(i);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (hash >>> 0).toString(36);
|
|
22
|
+
},
|
|
23
|
+
getTextureCacheKey = function (path) {
|
|
24
|
+
return platypus.assetCache?.getFileId ? platypus.assetCache.getFileId(path) : path;
|
|
25
|
+
},
|
|
26
|
+
resolveTextureAsset = function (path) {
|
|
27
|
+
const
|
|
28
|
+
assetCache = platypus.assetCache;
|
|
29
|
+
|
|
30
|
+
if (!assetCache) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let asset = assetCache.get(path);
|
|
35
|
+
|
|
36
|
+
if (asset) {
|
|
37
|
+
return asset;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const
|
|
41
|
+
basename = typeof path === 'string' ? path.match(imageBasename) : null;
|
|
42
|
+
|
|
43
|
+
if (basename) {
|
|
44
|
+
asset = assetCache.get(basename[1]);
|
|
45
|
+
|
|
46
|
+
if (asset) {
|
|
47
|
+
return asset;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return null;
|
|
52
|
+
},
|
|
53
|
+
getTextureSourceAliases = function (alias) {
|
|
54
|
+
const
|
|
55
|
+
aliases = arrayCache.setUp(alias),
|
|
56
|
+
basename = typeof alias === 'string' ? alias.match(imageBasename) : null;
|
|
57
|
+
|
|
58
|
+
if (platypus.assetCache?.getFileId) {
|
|
59
|
+
const
|
|
60
|
+
fileId = platypus.assetCache.getFileId(alias);
|
|
61
|
+
|
|
62
|
+
if (fileId !== alias) {
|
|
63
|
+
aliases.push(fileId);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (basename) {
|
|
68
|
+
aliases.push(basename[1]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return aliases;
|
|
72
|
+
},
|
|
13
73
|
getTextureSources = function (images) {
|
|
14
74
|
const
|
|
15
|
-
assetCache = platypus.assetCache,
|
|
16
75
|
bts = arrayCache.setUp();
|
|
17
76
|
|
|
18
77
|
for (let i = 0; i < images.length; i++) {
|
|
@@ -20,17 +79,21 @@ const
|
|
|
20
79
|
path = images[i];
|
|
21
80
|
|
|
22
81
|
if (typeof path === 'string') {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
82
|
+
const
|
|
83
|
+
cacheKey = getTextureCacheKey(path),
|
|
84
|
+
asset = resolveTextureAsset(path);
|
|
26
85
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
86
|
+
if (!asset) {
|
|
87
|
+
delete textureSourceCache[cacheKey];
|
|
88
|
+
platypus.debug.warn(`PIXIAnimation: "${path}" is not a loaded asset.`);
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (textureSourceCache[cacheKey] !== asset.source) {
|
|
93
|
+
textureSourceCache[cacheKey] = asset.source;
|
|
32
94
|
}
|
|
33
|
-
|
|
95
|
+
|
|
96
|
+
bts.push(textureSourceCache[cacheKey]);
|
|
34
97
|
} else {
|
|
35
98
|
bts.push(new TextureSource(path));
|
|
36
99
|
}
|
|
@@ -49,9 +112,7 @@ const
|
|
|
49
112
|
}
|
|
50
113
|
}
|
|
51
114
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return spriteSheet.id;
|
|
115
|
+
return `ss-${hashString(spriteSheet)}`;
|
|
55
116
|
},
|
|
56
117
|
getDefaultAnimation = function (length, textures) {
|
|
57
118
|
const
|
|
@@ -397,6 +458,29 @@ const
|
|
|
397
458
|
};
|
|
398
459
|
}
|
|
399
460
|
|
|
461
|
+
/**
|
|
462
|
+
* Removes cached texture sources for an unloaded asset alias.
|
|
463
|
+
*
|
|
464
|
+
* @method platypus.PIXIAnimation.invalidateTextureSources
|
|
465
|
+
* @param {*} alias Asset alias or path used when the texture was cached.
|
|
466
|
+
*/
|
|
467
|
+
static invalidateTextureSources (alias) {
|
|
468
|
+
const
|
|
469
|
+
aliases = getTextureSourceAliases(alias),
|
|
470
|
+
cacheKey = getTextureCacheKey(alias);
|
|
471
|
+
let i = aliases.length;
|
|
472
|
+
|
|
473
|
+
if (aliases.indexOf(cacheKey) === -1) {
|
|
474
|
+
aliases.push(cacheKey);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
while (i--) {
|
|
478
|
+
delete textureSourceCache[aliases[i]];
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
arrayCache.recycle(aliases);
|
|
482
|
+
}
|
|
483
|
+
|
|
400
484
|
/**
|
|
401
485
|
* This method formats a provided value into a valid PIXIAnimation Sprite Sheet. This includes accepting the EaselJS spec, strings mapping to Platypus sprite sheets, or arrays of either.
|
|
402
486
|
*
|
|
@@ -406,7 +490,6 @@ const
|
|
|
406
490
|
*/
|
|
407
491
|
static formatSpriteSheet (spriteSheet) {
|
|
408
492
|
const
|
|
409
|
-
imageParts = /([\w-\.]+)\.(\w+)$/,
|
|
410
493
|
addAnimations = function (source = {}, destination, speedRatio, firstFrameIndex, id) {
|
|
411
494
|
const
|
|
412
495
|
keys = Object.keys(source),
|
|
@@ -458,7 +541,6 @@ const
|
|
|
458
541
|
));
|
|
459
542
|
}
|
|
460
543
|
},
|
|
461
|
-
createId = (images) => images.map((image) => (image.src ?? image).substring(0, MAX_KEY_LENGTH_PER_IMAGE)).join(','),
|
|
462
544
|
format = function (source, destination) {
|
|
463
545
|
const
|
|
464
546
|
{
|
|
@@ -479,11 +561,8 @@ const
|
|
|
479
561
|
firstImageIndex = dImages.length,
|
|
480
562
|
firstFrameIndex = dFrames.length;
|
|
481
563
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
destination.id = `${dID};${sID ?? createId(sImages)}`;
|
|
485
|
-
} else {
|
|
486
|
-
destination.id = sID ?? createId(sImages);
|
|
564
|
+
if (sID) {
|
|
565
|
+
destination.id = dID ? `${dID};${sID}` : sID;
|
|
487
566
|
}
|
|
488
567
|
|
|
489
568
|
// Set up images array
|
|
@@ -546,7 +625,7 @@ const
|
|
|
546
625
|
formatImages = function (name) {
|
|
547
626
|
if (typeof name === 'string') {
|
|
548
627
|
const
|
|
549
|
-
match = name.match(
|
|
628
|
+
match = name.match(imageBasename);
|
|
550
629
|
|
|
551
630
|
if (match) {
|
|
552
631
|
return match[1];
|
|
@@ -6,6 +6,176 @@ import {inflate} from 'pako';
|
|
|
6
6
|
import TiledLoader from './TiledLoader.js';
|
|
7
7
|
|
|
8
8
|
const
|
|
9
|
+
assertLevelPiece = function (piece, label) {
|
|
10
|
+
if (piece == null) {
|
|
11
|
+
throw new Error(`Level Builder: Level piece "${label}" is undefined. Check that it is defined in platypus.game.settings.levels or levelPieces.`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof piece !== 'object') {
|
|
15
|
+
throw new Error(`Level Builder: Level piece "${label}" must be a level definition object, received ${typeof piece}.`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (piece.width == null) {
|
|
19
|
+
throw new Error(`Level Builder: Level piece "${label}" is missing width.`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (piece.height == null) {
|
|
23
|
+
throw new Error(`Level Builder: Level piece "${label}" is missing height.`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (piece.tilewidth == null) {
|
|
27
|
+
throw new Error(`Level Builder: Level piece "${label}" is missing tilewidth.`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (piece.tileheight == null) {
|
|
31
|
+
throw new Error(`Level Builder: Level piece "${label}" is missing tileheight.`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (piece.layers == null) {
|
|
35
|
+
throw new Error(`Level Builder: Level piece "${label}" is missing a layers array.`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!Array.isArray(piece.layers)) {
|
|
39
|
+
throw new Error(`Level Builder: Level piece "${label}" layers must be an array.`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return piece;
|
|
43
|
+
},
|
|
44
|
+
assertLevelTemplate = function (template) {
|
|
45
|
+
if (template == null) {
|
|
46
|
+
throw new Error(`Level Builder: levelTemplate is required but was not provided.`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!Array.isArray(template)) {
|
|
50
|
+
throw new Error(`Level Builder: levelTemplate must be an array, received ${typeof template}.`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (template.length === 0) {
|
|
54
|
+
throw new Error(`Level Builder: levelTemplate cannot be empty.`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let rowLength = null;
|
|
58
|
+
|
|
59
|
+
for (let i = 0; i < template.length; i++) {
|
|
60
|
+
const
|
|
61
|
+
row = template[i];
|
|
62
|
+
|
|
63
|
+
if (typeof row === 'string') {
|
|
64
|
+
if (!row) {
|
|
65
|
+
throw new Error(`Level Builder: levelTemplate[${i}] is an empty string.`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (rowLength != null && rowLength !== '1d') {
|
|
69
|
+
throw new Error(`Level Builder: levelTemplate is not rectangular: row 0 has ${rowLength} columns but row ${i} is a string.`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
rowLength = '1d';
|
|
73
|
+
} else if (Array.isArray(row)) {
|
|
74
|
+
if (row.length === 0) {
|
|
75
|
+
throw new Error(`Level Builder: levelTemplate row ${i} is empty.`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (rowLength === '1d') {
|
|
79
|
+
throw new Error(`Level Builder: levelTemplate is not rectangular: row 0 is a string but row ${i} is an array.`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (rowLength == null) {
|
|
83
|
+
rowLength = row.length;
|
|
84
|
+
} else if (rowLength !== row.length) {
|
|
85
|
+
throw new Error(`Level Builder: levelTemplate is not rectangular: row 0 has ${rowLength} columns but row ${i} has ${row.length}.`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for (let j = 0; j < row.length; j++) {
|
|
89
|
+
if (typeof row[j] !== 'string') {
|
|
90
|
+
throw new Error(`Level Builder: levelTemplate[${i}][${j}] must be a piece id string, received ${typeof row[j]}.`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!row[j]) {
|
|
94
|
+
throw new Error(`Level Builder: levelTemplate[${i}][${j}] is an empty string.`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
throw new Error(`Level Builder: levelTemplate[${i}] must be a string or array of strings, received ${typeof row}.`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return template;
|
|
103
|
+
},
|
|
104
|
+
assertLevelPieces = function (pieces) {
|
|
105
|
+
if (pieces == null) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (typeof pieces !== 'object' || Array.isArray(pieces)) {
|
|
110
|
+
throw new Error(`Level Builder: levelPieces must be an object, received ${Array.isArray(pieces) ? 'array' : typeof pieces}.`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const
|
|
114
|
+
keys = Object.keys(pieces),
|
|
115
|
+
{length} = keys;
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < length; i++) {
|
|
118
|
+
const
|
|
119
|
+
key = keys[i],
|
|
120
|
+
value = pieces[key];
|
|
121
|
+
|
|
122
|
+
if (typeof value === 'string') {
|
|
123
|
+
if (!value) {
|
|
124
|
+
throw new Error(`Level Builder: levelPieces["${key}"] is an empty string.`);
|
|
125
|
+
}
|
|
126
|
+
} else if (Array.isArray(value)) {
|
|
127
|
+
if (value.length === 0) {
|
|
128
|
+
throw new Error(`Level Builder: levelPieces["${key}"] is an empty array. Provide at least one level piece id.`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
for (let j = 0; j < value.length; j++) {
|
|
132
|
+
if (typeof value[j] !== 'string') {
|
|
133
|
+
throw new Error(`Level Builder: levelPieces["${key}"][${j}] must be a string level id, received ${typeof value[j]}.`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!value[j]) {
|
|
137
|
+
throw new Error(`Level Builder: levelPieces["${key}"][${j}] is an empty string.`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
throw new Error(`Level Builder: levelPieces["${key}"] must be a string or array of strings, received ${typeof value}.`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
resolveLevelPiece = function (piece, label) {
|
|
146
|
+
if (typeof piece === 'string') {
|
|
147
|
+
const
|
|
148
|
+
levelDefinitions = platypus.game.settings.levels,
|
|
149
|
+
transformIndex = piece.indexOf(':');
|
|
150
|
+
let levelDefinition = levelDefinitions?.[piece];
|
|
151
|
+
|
|
152
|
+
if (!levelDefinition && transformIndex >= 0) {
|
|
153
|
+
const
|
|
154
|
+
baseLabel = piece.substring(0, transformIndex),
|
|
155
|
+
transform = piece.substring(transformIndex + 1);
|
|
156
|
+
|
|
157
|
+
levelDefinition = levelDefinitions?.[baseLabel];
|
|
158
|
+
|
|
159
|
+
if (!levelDefinition) {
|
|
160
|
+
throw new Error(`Level Builder: Level piece "${baseLabel}" (from "${piece}") was not found in platypus.game.settings.levels.`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (transform === 'mirror') {
|
|
164
|
+
return levelDefinitions[piece] = mirrorSegment(assertLevelPiece(levelDefinition, baseLabel));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
throw new Error(`Level Builder: Unknown transform "${transform}" in level piece "${piece}". Supported transforms: mirror.`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (!levelDefinition) {
|
|
171
|
+
throw new Error(`Level Builder: Level piece "${piece}" was not found in platypus.game.settings.levels.`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return assertLevelPiece(levelDefinition, piece);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return assertLevelPiece(piece, label);
|
|
178
|
+
},
|
|
9
179
|
maskXFlip = 0x80000000,
|
|
10
180
|
decodeString = (str, index) => (((str.charCodeAt(index)) + (str.charCodeAt(index + 1) << 8) + (str.charCodeAt(index + 2) << 16) + (str.charCodeAt(index + 3) << 24 )) >>> 0),
|
|
11
181
|
decodeArray = (arr, index) => ((arr[index] + (arr[index + 1] << 8) + (arr[index + 2] << 16) + (arr[index + 3] << 24 )) >>> 0),
|
|
@@ -25,7 +195,11 @@ const
|
|
|
25
195
|
|
|
26
196
|
return arr;
|
|
27
197
|
},
|
|
28
|
-
decodeLayer = function (layer) {
|
|
198
|
+
decodeLayer = function (layer, label) {
|
|
199
|
+
if (layer == null) {
|
|
200
|
+
throw new Error(`Level Builder: Cannot decode layer${label ? ` in "${label}"` : ''}: layer is undefined.`);
|
|
201
|
+
}
|
|
202
|
+
|
|
29
203
|
if (layer.encoding === 'base64') {
|
|
30
204
|
layer.data = decodeBase64(layer.data, layer.compression);
|
|
31
205
|
layer.encoding = 'csv'; // So we won't have to decode again.
|
|
@@ -81,8 +255,8 @@ const
|
|
|
81
255
|
}
|
|
82
256
|
return list;
|
|
83
257
|
},
|
|
84
|
-
mergeSegment = function (level, segment, mergeAxis) {
|
|
85
|
-
segment = cloneLevelDefinition(segment);
|
|
258
|
+
mergeSegment = function (level, segment, mergeAxis, segmentLabel) {
|
|
259
|
+
segment = cloneLevelDefinition(assertLevelPiece(segment, segmentLabel ?? 'segment'));
|
|
86
260
|
|
|
87
261
|
if (!level.tilewidth && !level.tileheight) {
|
|
88
262
|
//set level tile size data if it's not already set.
|
|
@@ -107,9 +281,13 @@ const
|
|
|
107
281
|
}
|
|
108
282
|
|
|
109
283
|
for (let i = 0; i < segment.layers.length; i++) {
|
|
284
|
+
if (segment.layers[i] == null) {
|
|
285
|
+
throw new Error(`Level Builder: Level piece "${segmentLabel ?? 'segment'}" layer ${i} is undefined.`);
|
|
286
|
+
}
|
|
287
|
+
|
|
110
288
|
if (!level.layers[i]) {
|
|
111
289
|
//if the level doesn't have a layer yet, we're creating it and then copying it from the segment.
|
|
112
|
-
decodeLayer(segment.layers[i]);
|
|
290
|
+
decodeLayer(segment.layers[i], segmentLabel);
|
|
113
291
|
|
|
114
292
|
const
|
|
115
293
|
layer = level.layers[i] = cloneLevelDefinition(segment.layers[i]);
|
|
@@ -126,7 +304,7 @@ const
|
|
|
126
304
|
//if the level does have a layer, we're appending the new data to it.
|
|
127
305
|
if (level.layers[i].data && segment.layers[i].data) {
|
|
128
306
|
// Make sure we're not trying to merge compressed levels.
|
|
129
|
-
decodeLayer(segment.layers[i]);
|
|
307
|
+
decodeLayer(segment.layers[i], segmentLabel);
|
|
130
308
|
|
|
131
309
|
if (mergeAxis === 'horizontal') {
|
|
132
310
|
level.layers[i].data = mergeData(level.layers[i].data, level.width, segment.layers[i].data, segment.width, level.height, mergeAxis);
|
|
@@ -169,7 +347,6 @@ const
|
|
|
169
347
|
},
|
|
170
348
|
mergeLevels = function (levelSegments) {
|
|
171
349
|
const
|
|
172
|
-
levelDefinitions = platypus.game.settings.levels,
|
|
173
350
|
level = {
|
|
174
351
|
height: 0,
|
|
175
352
|
width: 0,
|
|
@@ -184,35 +361,25 @@ const
|
|
|
184
361
|
layers: []
|
|
185
362
|
};
|
|
186
363
|
|
|
364
|
+
if (!Array.isArray(levelSegments[i])) {
|
|
365
|
+
throw new Error(`Level Builder: mergeLevels row ${i} must be an array of level pieces, received ${typeof levelSegments[i]}.`);
|
|
366
|
+
}
|
|
367
|
+
|
|
187
368
|
for (let j = 0; j < levelSegments[i].length; j++) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
levelDefinitionLabel = levelSegments[i][j],
|
|
192
|
-
transformIndex = levelDefinitionLabel.indexOf(':');
|
|
193
|
-
let levelDefinition = levelDefinitions[levelDefinitionLabel];
|
|
194
|
-
|
|
195
|
-
// check for transform
|
|
196
|
-
if (!levelDefinition && (transformIndex >= 0)) {
|
|
197
|
-
const transform = levelDefinitionLabel.substring(transformIndex + 1);
|
|
369
|
+
const
|
|
370
|
+
piece = levelSegments[i][j],
|
|
371
|
+
pieceLabel = typeof piece === 'string' ? piece : `row ${i}, column ${j}`;
|
|
198
372
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
levelDefinition = levelDefinitions[levelDefinitionLabel] = mirrorSegment(levelDefinition);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
mergeSegment(row, levelDefinition, 'horizontal');
|
|
205
|
-
} else {
|
|
206
|
-
mergeSegment(row, levelSegments[i][j], 'horizontal');
|
|
207
|
-
}
|
|
373
|
+
//Merge horizontally
|
|
374
|
+
mergeSegment(row, resolveLevelPiece(piece, pieceLabel), 'horizontal', pieceLabel);
|
|
208
375
|
}
|
|
209
376
|
//Then merge vertically
|
|
210
|
-
mergeSegment(level, row, 'vertical');
|
|
377
|
+
mergeSegment(level, row, 'vertical', `row ${i}`);
|
|
211
378
|
}
|
|
212
379
|
return level;
|
|
213
380
|
},
|
|
214
|
-
mirrorSegment = function (segment) {
|
|
215
|
-
segment = cloneLevelDefinition(segment);
|
|
381
|
+
mirrorSegment = function (segment, segmentLabel) {
|
|
382
|
+
segment = cloneLevelDefinition(assertLevelPiece(segment, segmentLabel ?? 'segment'));
|
|
216
383
|
|
|
217
384
|
const
|
|
218
385
|
newSegment = {
|
|
@@ -221,7 +388,11 @@ const
|
|
|
221
388
|
width = segment.width * segment.tilewidth;
|
|
222
389
|
|
|
223
390
|
for (let i = 0; i < segment.layers.length; i++) {
|
|
224
|
-
|
|
391
|
+
if (segment.layers[i] == null) {
|
|
392
|
+
throw new Error(`Level Builder: Level piece "${segmentLabel ?? 'segment'}" layer ${i} is undefined.`);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
decodeLayer(segment.layers[i], segmentLabel);
|
|
225
396
|
|
|
226
397
|
const
|
|
227
398
|
fromLayer = segment.layers[i],
|
|
@@ -369,6 +540,8 @@ export default createComponentClass(/** @lends platypus.components.LevelBuilder.
|
|
|
369
540
|
this.levelMessage.persistentData = data;
|
|
370
541
|
this.levelTemplate = data?.levelTemplate ?? this.levelTemplate;
|
|
371
542
|
this.useUniques = data?.useUniques ?? this.useUniques;
|
|
543
|
+
assertLevelPieces(piecesToCopy);
|
|
544
|
+
|
|
372
545
|
this.levelPieces = {};
|
|
373
546
|
if (piecesToCopy) {
|
|
374
547
|
const
|
|
@@ -385,32 +558,26 @@ export default createComponentClass(/** @lends platypus.components.LevelBuilder.
|
|
|
385
558
|
this.levelPieces[key] = [
|
|
386
559
|
...piecesToCopy[key]
|
|
387
560
|
];
|
|
388
|
-
} else {
|
|
389
|
-
throw ('Level Builder: Level pieces of incorrect type: ' + piecesToCopy[key]);
|
|
390
561
|
}
|
|
391
562
|
}
|
|
392
563
|
}
|
|
393
564
|
|
|
394
565
|
if (this.levelTemplate) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
} else {
|
|
409
|
-
throw ('Level Builder: Template row is neither a string or array. What is it?');
|
|
566
|
+
assertLevelTemplate(this.levelTemplate);
|
|
567
|
+
|
|
568
|
+
this.levelMessage.level = [];
|
|
569
|
+
for (let i = 0; i < this.levelTemplate.length; i++) {
|
|
570
|
+
const
|
|
571
|
+
templateRow = this.levelTemplate[i];
|
|
572
|
+
|
|
573
|
+
if (typeof templateRow === "string") {
|
|
574
|
+
this.levelMessage.level[i] = this.getLevelPiece(templateRow);
|
|
575
|
+
} else {
|
|
576
|
+
this.levelMessage.level[i] = [];
|
|
577
|
+
for (let j = 0; j < templateRow.length; j++) {
|
|
578
|
+
this.levelMessage.level[i][j] = this.getLevelPiece(templateRow[j]);
|
|
410
579
|
}
|
|
411
580
|
}
|
|
412
|
-
} else {
|
|
413
|
-
platypus.debug.warn('Level Builder: Template is not defined');
|
|
414
581
|
}
|
|
415
582
|
} else {
|
|
416
583
|
platypus.debug.warn('Level Builder: There is no level template.');
|
|
@@ -452,6 +619,10 @@ export default createComponentClass(/** @lends platypus.components.LevelBuilder.
|
|
|
452
619
|
|
|
453
620
|
methods: {// These are methods that are called by this component.
|
|
454
621
|
getLevelPiece: function (type) {
|
|
622
|
+
if (type == null || type === '') {
|
|
623
|
+
throw new Error(`Level Builder: Template references an invalid piece id: ${type}.`);
|
|
624
|
+
}
|
|
625
|
+
|
|
455
626
|
const
|
|
456
627
|
pieces = this.levelPieces[type] ?? type;
|
|
457
628
|
|
package/src/components/Render.js
CHANGED
|
@@ -178,11 +178,17 @@ export default createComponentClass(/** @lends platypus.components.RenderSprite.
|
|
|
178
178
|
|
|
179
179
|
getAssetList (a, b, c) {
|
|
180
180
|
const
|
|
181
|
-
image = a?.image ?? b?.image ?? c?.image
|
|
181
|
+
image = a?.image ?? b?.image ?? c?.image,
|
|
182
|
+
formatImageAsset = (src) => {
|
|
183
|
+
const
|
|
184
|
+
alias = platypus.assetCache?.getFileId ? platypus.assetCache.getFileId(src) : src;
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
alias: [alias],
|
|
188
|
+
src
|
|
189
|
+
};
|
|
190
|
+
};
|
|
182
191
|
|
|
183
|
-
return (image ? [image] : a?.images ?? b?.images ?? c?.images ?? []).map(
|
|
184
|
-
alias: [src],
|
|
185
|
-
src
|
|
186
|
-
}));
|
|
192
|
+
return (image ? [image] : a?.images ?? b?.images ?? c?.images ?? []).map(formatImageAsset);
|
|
187
193
|
}
|
|
188
194
|
});
|
|
@@ -489,12 +489,21 @@ export default createComponentClass(/** @lends platypus.components.RenderSprite.
|
|
|
489
489
|
|
|
490
490
|
getAssetList: (function () {
|
|
491
491
|
const
|
|
492
|
+
formatImageAsset = function (src) {
|
|
493
|
+
const
|
|
494
|
+
alias = platypus.assetCache?.getFileId ? platypus.assetCache.getFileId(src) : src;
|
|
495
|
+
|
|
496
|
+
return {
|
|
497
|
+
alias: [alias],
|
|
498
|
+
src
|
|
499
|
+
};
|
|
500
|
+
},
|
|
492
501
|
getImages = function (ss, spriteSheets) {
|
|
493
502
|
if (ss) {
|
|
494
503
|
if (typeof ss === 'string') {
|
|
495
504
|
return getImages(spriteSheets[ss], spriteSheets);
|
|
496
505
|
} else if (ss.images) {
|
|
497
|
-
return greenSlice(ss.images);
|
|
506
|
+
return greenSlice(ss.images).map(formatImageAsset);
|
|
498
507
|
}
|
|
499
508
|
}
|
|
500
509
|
|