@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,1440 @@
|
|
|
1
|
+
/* global platypus */
|
|
2
|
+
import {Container, Graphics, Rectangle, RenderTexture, Sprite} from 'pixi.js';
|
|
3
|
+
import {arrayCache, greenSlice, greenSplice, union} from '../utils/array.js';
|
|
4
|
+
import AABB from '../AABB.js';
|
|
5
|
+
import PIXIAnimation from '../PIXIAnimation.js';
|
|
6
|
+
import RenderContainer from './RenderContainer.js';
|
|
7
|
+
import createComponentClass from '../factory.js';
|
|
8
|
+
import recycle from 'recycle';
|
|
9
|
+
|
|
10
|
+
const
|
|
11
|
+
EDGE_BLEED = 1,
|
|
12
|
+
EDGES_BLEED = EDGE_BLEED * 2,
|
|
13
|
+
doNothing = function () {
|
|
14
|
+
return null;
|
|
15
|
+
},
|
|
16
|
+
tempCache = AABB.setUp(),
|
|
17
|
+
sort = function (a, b) {
|
|
18
|
+
return a.z - b.z;
|
|
19
|
+
},
|
|
20
|
+
getPowerOfTwo = function (amount) {
|
|
21
|
+
let x = 1;
|
|
22
|
+
|
|
23
|
+
while (x < amount) {
|
|
24
|
+
x *= 2;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return x;
|
|
28
|
+
},
|
|
29
|
+
transformCheck = function (v, tile) {
|
|
30
|
+
if (0x80000000 & v) {
|
|
31
|
+
tile.scale.x = -1;
|
|
32
|
+
}
|
|
33
|
+
if (0x40000000 & v) {
|
|
34
|
+
tile.scale.y = -1;
|
|
35
|
+
}
|
|
36
|
+
if (0x20000000 & v) {
|
|
37
|
+
const x = tile.scale.x;
|
|
38
|
+
tile.scale.x = tile.scale.y;
|
|
39
|
+
tile.scale.y = -x;
|
|
40
|
+
tile.rotation = Math.PI / 2;
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
createTeardown = (component, map) => {
|
|
44
|
+
const
|
|
45
|
+
tds = Object.keys(map).map((key) => {
|
|
46
|
+
const
|
|
47
|
+
handler = component.addEventListener(key, map[key]);
|
|
48
|
+
|
|
49
|
+
return () => component.removeEventListener(key, handler);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return () => {
|
|
53
|
+
tds.forEach((td) => td());
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
Template = function (tileSpriteSheet, id, uninitializedTiles) {
|
|
57
|
+
this.id = id;
|
|
58
|
+
this.instances = arrayCache.setUp();
|
|
59
|
+
this.index = 0;
|
|
60
|
+
|
|
61
|
+
// jit sprite
|
|
62
|
+
this.tileSpriteSheet = tileSpriteSheet;
|
|
63
|
+
this.getNext = this.initializeAndGetNext;
|
|
64
|
+
this.uninitializedTiles = uninitializedTiles;
|
|
65
|
+
uninitializedTiles.push(this);
|
|
66
|
+
},
|
|
67
|
+
nullTemplate = {
|
|
68
|
+
getNext: doNothing,
|
|
69
|
+
destroy: doNothing
|
|
70
|
+
},
|
|
71
|
+
prototype = Template.prototype;
|
|
72
|
+
|
|
73
|
+
prototype.initializeAndGetNext = function () {
|
|
74
|
+
this.initialize();
|
|
75
|
+
|
|
76
|
+
this.index += 1;
|
|
77
|
+
return this.instances[0];
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
prototype.initialize = function () {
|
|
81
|
+
const
|
|
82
|
+
index = +(this.id.substring(4)),
|
|
83
|
+
anim = 'tile' + (0x0fffffff & index),
|
|
84
|
+
tile = new Sprite((this.tileSpriteSheet._animations[anim] || this.tileSpriteSheet._animations.default).texture);
|
|
85
|
+
|
|
86
|
+
transformCheck(index, tile);
|
|
87
|
+
tile.template = this; // backwards reference for clearing index later.
|
|
88
|
+
this.instances.push(tile);
|
|
89
|
+
greenSplice(this.uninitializedTiles, this.uninitializedTiles.indexOf(this));
|
|
90
|
+
|
|
91
|
+
delete this.getNext;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
prototype.getNext = function () {
|
|
95
|
+
let instance = this.instances[this.index];
|
|
96
|
+
|
|
97
|
+
if (!instance) {
|
|
98
|
+
const
|
|
99
|
+
template = this.instances[0];
|
|
100
|
+
|
|
101
|
+
instance = this.instances[this.index] = new Sprite(template.texture);
|
|
102
|
+
|
|
103
|
+
// Copy properties
|
|
104
|
+
instance.scale = template.scale;
|
|
105
|
+
instance.rotation = template.rotation;
|
|
106
|
+
instance.anchor = template.anchor || template._animation.anchor;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
this.index += 1;
|
|
110
|
+
|
|
111
|
+
return instance;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
prototype.clear = function () {
|
|
115
|
+
this.index = 0;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
prototype.destroy = function () {
|
|
119
|
+
for (let i = 0; i < this.instances.length; i++) {
|
|
120
|
+
this.instances[i].destroy();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
arrayCache.recycle(this.instances);
|
|
124
|
+
this.recycle();
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
recycle.add(Template, 'Template', Template, null, true);
|
|
128
|
+
|
|
129
|
+
export default createComponentClass(/** @lends platypus.components.RenderTiles.prototype */{
|
|
130
|
+
|
|
131
|
+
id: 'RenderTiles',
|
|
132
|
+
|
|
133
|
+
properties: {
|
|
134
|
+
/**
|
|
135
|
+
* The amount of space in pixels around the edge of the camera that we include in the buffered image. If not set, largest buffer allowed by maximumBuffer is used.
|
|
136
|
+
*
|
|
137
|
+
* @property buffer
|
|
138
|
+
* @type number
|
|
139
|
+
* @default 0
|
|
140
|
+
*/
|
|
141
|
+
buffer: 0,
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Determines whether to cache the entire map across one or more texture caches. By default this is `false`; however, if the entire map fits on one or two texture caches, this is set to `true` since it is more efficient than dynamic buffering.
|
|
145
|
+
*
|
|
146
|
+
* @property cacheAll
|
|
147
|
+
* @type Boolean
|
|
148
|
+
* @default false
|
|
149
|
+
*/
|
|
150
|
+
cacheAll: false,
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Whether to cache entities on this layer if the entity's render component requests caching.
|
|
154
|
+
*
|
|
155
|
+
* @property entityCache
|
|
156
|
+
* @type boolean
|
|
157
|
+
* @default false
|
|
158
|
+
*/
|
|
159
|
+
entityCache: false,
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* This is a two dimensional array of the spritesheet indexes that describe the map that you're rendering.
|
|
163
|
+
*
|
|
164
|
+
* @property imageMap
|
|
165
|
+
* @type Array
|
|
166
|
+
* @default []
|
|
167
|
+
*/
|
|
168
|
+
imageMap: [],
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The amount of space that is buffered. Defaults to 2048 x 2048 or a smaller area that encloses the tile layer.
|
|
172
|
+
*
|
|
173
|
+
* @property maximumBuffer
|
|
174
|
+
* @type number
|
|
175
|
+
* @default 2048
|
|
176
|
+
*/
|
|
177
|
+
maximumBuffer: 2048,
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The acceptable buffer between camera viewport and cached tiles. This is needed when the camera contents are skewed or rotated to prevent cropping before refresh need is detected.
|
|
181
|
+
*
|
|
182
|
+
* @property refreshBuffer
|
|
183
|
+
* @type number
|
|
184
|
+
* @default 0
|
|
185
|
+
*/
|
|
186
|
+
refreshBuffer: 0,
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* The x-scale the tilemap is being displayed at.
|
|
190
|
+
*
|
|
191
|
+
* @property scaleX
|
|
192
|
+
* @type number
|
|
193
|
+
* @default 1
|
|
194
|
+
*/
|
|
195
|
+
scaleX: 1,
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The y-scale the tilemap is being displayed at.
|
|
199
|
+
*
|
|
200
|
+
* @property scaleY
|
|
201
|
+
* @type number
|
|
202
|
+
* @default 1
|
|
203
|
+
*/
|
|
204
|
+
scaleY: 1,
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* A sprite sheet describing all the tile images.
|
|
208
|
+
*
|
|
209
|
+
* Accepts an array of sprite sheet data since 0.8.4
|
|
210
|
+
*
|
|
211
|
+
* @property spriteSheet
|
|
212
|
+
* @type Object|Array|String
|
|
213
|
+
* @default null
|
|
214
|
+
*/
|
|
215
|
+
spriteSheet: null,
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Whether to cache the tile map to a large texture.
|
|
219
|
+
*
|
|
220
|
+
* @property tileCache
|
|
221
|
+
* @type boolean
|
|
222
|
+
* @default true
|
|
223
|
+
*/
|
|
224
|
+
tileCache: true,
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* This is the height in pixels of individual tiles.
|
|
228
|
+
*
|
|
229
|
+
* @property tileHeight
|
|
230
|
+
* @type number
|
|
231
|
+
* @default 10
|
|
232
|
+
*/
|
|
233
|
+
tileHeight: 10,
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* This is the width in pixels of individual tiles.
|
|
237
|
+
*
|
|
238
|
+
* @property tileWidth
|
|
239
|
+
* @type number
|
|
240
|
+
* @default 10
|
|
241
|
+
*/
|
|
242
|
+
tileWidth: 10,
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The map's top offset.
|
|
246
|
+
*
|
|
247
|
+
* @property top
|
|
248
|
+
* @type Number
|
|
249
|
+
* @default 0
|
|
250
|
+
*/
|
|
251
|
+
top: 0,
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* The map's left offset.
|
|
255
|
+
*
|
|
256
|
+
* @property left
|
|
257
|
+
* @type Number
|
|
258
|
+
* @default 0
|
|
259
|
+
*/
|
|
260
|
+
left: 0,
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Tiled parallax factor for horizontal scrolling. 1.0 scrolls with the camera; values less than 1.0 scroll slower (background); 0 is fixed to the screen.
|
|
264
|
+
*
|
|
265
|
+
* @property parallaxX
|
|
266
|
+
* @type number
|
|
267
|
+
* @default 1
|
|
268
|
+
*/
|
|
269
|
+
parallaxX: 1,
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Tiled parallax factor for vertical scrolling.
|
|
273
|
+
*
|
|
274
|
+
* @property parallaxY
|
|
275
|
+
* @type number
|
|
276
|
+
* @default 1
|
|
277
|
+
*/
|
|
278
|
+
parallaxY: 1,
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Map parallax origin X in world coordinates (Tiled `parallaxoriginx`, plus any map offset).
|
|
282
|
+
*
|
|
283
|
+
* @property parallaxOriginX
|
|
284
|
+
* @type number
|
|
285
|
+
* @default 0
|
|
286
|
+
*/
|
|
287
|
+
parallaxOriginX: 0,
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Map parallax origin Y in world coordinates (Tiled `parallaxoriginy`, plus any map offset).
|
|
291
|
+
*
|
|
292
|
+
* @property parallaxOriginY
|
|
293
|
+
* @type number
|
|
294
|
+
* @default 0
|
|
295
|
+
*/
|
|
296
|
+
parallaxOriginY: 0
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* This component handles rendering tile map backgrounds.
|
|
301
|
+
*
|
|
302
|
+
* When rendering the background, this component figures out what tiles are being displayed and caches them so they are rendered as one image rather than individually.
|
|
303
|
+
*
|
|
304
|
+
* As the camera moves, the cache is updated by blitting the relevant part of the old cached image into a new cache and then rendering tiles that have shifted into the camera's view into the cache.
|
|
305
|
+
*
|
|
306
|
+
* @memberof platypus.components
|
|
307
|
+
* @uses platypus.Component
|
|
308
|
+
* @constructs
|
|
309
|
+
* @listens platypus.Entity#add-tiles
|
|
310
|
+
* @listens platypus.Entity#cache-sprite
|
|
311
|
+
* @listens platypus.Entity#camera-loaded
|
|
312
|
+
* @listens platypus.Entity#camera-update
|
|
313
|
+
* @listens platypus.Entity#change-tile
|
|
314
|
+
* @listens platypus.Entity#handle-render
|
|
315
|
+
* @listens platypus.Entity#peer-entity-added
|
|
316
|
+
*/
|
|
317
|
+
initialize: function (definition) {
|
|
318
|
+
const
|
|
319
|
+
imgMap = this.imageMap,
|
|
320
|
+
handleRender = this.addEventListener('handle-render', function () {
|
|
321
|
+
// Pre-render any tiles left to be prerendered to reduce lag on camera movement
|
|
322
|
+
if (this.uninitializedTiles.length) {
|
|
323
|
+
this.uninitializedTiles[0].initialize();
|
|
324
|
+
} else {
|
|
325
|
+
this.removeEventListener('handle-render', handleRender);
|
|
326
|
+
this.owner.parent.triggerEvent('child-entity-updated', this.owner);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
this.doMap = null; //list of display objects that should overlay tile map.
|
|
331
|
+
this.cachedDisplayObjects = null;
|
|
332
|
+
this.populate = this.populateTiles;
|
|
333
|
+
|
|
334
|
+
this.tiles = {};
|
|
335
|
+
|
|
336
|
+
this.renderer = platypus.game.renderer;
|
|
337
|
+
this.tilesSprite = null;
|
|
338
|
+
this.cacheTexture = null;
|
|
339
|
+
this.mapContainer = null;
|
|
340
|
+
this.laxCam = AABB.setUp();
|
|
341
|
+
|
|
342
|
+
// temp values
|
|
343
|
+
this.worldWidth = this.tileWidth;
|
|
344
|
+
this.worldHeight = this.tileHeight;
|
|
345
|
+
|
|
346
|
+
this.cache = AABB.setUp();
|
|
347
|
+
this.cachePixels = AABB.setUp();
|
|
348
|
+
|
|
349
|
+
this.uninitializedTiles = arrayCache.setUp();
|
|
350
|
+
|
|
351
|
+
// Set up containers
|
|
352
|
+
this.spriteSheet = PIXIAnimation.formatSpriteSheet(this.spriteSheet);
|
|
353
|
+
this.tileSpriteSheet = new PIXIAnimation(this.spriteSheet);
|
|
354
|
+
this.tileContainer = new Container();
|
|
355
|
+
this.mapContainer = new Container();
|
|
356
|
+
this.mapContainer.addChild(this.tileContainer);
|
|
357
|
+
|
|
358
|
+
this.updateCache = false;
|
|
359
|
+
|
|
360
|
+
// Prepare map tiles
|
|
361
|
+
this.imageMap = arrayCache.setUp(this.createMap(imgMap));
|
|
362
|
+
|
|
363
|
+
this.tilesWidth = this.imageMap[0].length;
|
|
364
|
+
this.tilesHeight = this.imageMap[0][0].length;
|
|
365
|
+
this.layerWidth = this.tilesWidth * this.tileWidth;
|
|
366
|
+
this.layerHeight = this.tilesHeight * this.tileHeight;
|
|
367
|
+
|
|
368
|
+
this.edgeBleed = EDGE_BLEED;
|
|
369
|
+
this.edgesBleed = EDGES_BLEED;
|
|
370
|
+
|
|
371
|
+
// Set up buffer cache size
|
|
372
|
+
this.cacheWidth = Math.min(getPowerOfTwo(this.layerWidth + this.edgesBleed), this.maximumBuffer);
|
|
373
|
+
this.cacheHeight = Math.min(getPowerOfTwo(this.layerHeight + this.edgesBleed), this.maximumBuffer);
|
|
374
|
+
|
|
375
|
+
if (!this.owner.container) {
|
|
376
|
+
this.owner.addComponent(new RenderContainer(this.owner, definition));
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
this.container = this.owner.container;
|
|
380
|
+
|
|
381
|
+
if (!this.tileCache) {
|
|
382
|
+
this.teardown = this.setupNoCache();
|
|
383
|
+
} else if ((this.layerWidth <= this.cacheWidth) && (this.layerHeight <= this.cacheHeight)) { // We never need to recache.
|
|
384
|
+
this.teardown = this.setupSingleCache();
|
|
385
|
+
} else if (this.cacheAll || ((this.layerWidth <= this.cacheWidth * 2) && (this.layerHeight <= this.cacheHeight)) || ((this.layerWidth <= this.cacheWidth) && (this.layerHeight <= this.cacheHeight * 2))) { // We cache everything across several textures creating a cache grid.
|
|
386
|
+
this.teardown = this.setupFullCache();
|
|
387
|
+
} else {
|
|
388
|
+
this.teardown = this.setupPanningCache();
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
|
|
392
|
+
events: {
|
|
393
|
+
"cache-sprite": function (entity) {
|
|
394
|
+
this.cacheSprite(entity);
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
"refresh-cache": function () {
|
|
398
|
+
this.updateCache = true;
|
|
399
|
+
},
|
|
400
|
+
|
|
401
|
+
"peer-entity-added": function (entity) {
|
|
402
|
+
this.cacheSprite(entity);
|
|
403
|
+
},
|
|
404
|
+
|
|
405
|
+
"peer-entity-removed": function (entity) {
|
|
406
|
+
this.uncacheSprite(entity);
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* This event adds a layer of tiles to render on top of the existing layer of rendered tiles.
|
|
411
|
+
*
|
|
412
|
+
* @event platypus.Entity#add-tiles
|
|
413
|
+
* @param message.imageMap {Array} This is a 2D mapping of tile indexes to be rendered.
|
|
414
|
+
*/
|
|
415
|
+
"add-tiles": function (definition) {
|
|
416
|
+
const
|
|
417
|
+
map = definition.imageMap;
|
|
418
|
+
|
|
419
|
+
if (map) {
|
|
420
|
+
this.imageMap.push(this.createMap(map));
|
|
421
|
+
this.updateCache = true;
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* This event edits the tile index of a rendered tile.
|
|
427
|
+
*
|
|
428
|
+
* @event platypus.Entity#change-tile
|
|
429
|
+
* @param tile {String} A string representing the name of the tile to switch to.
|
|
430
|
+
* @param x {Number} The column of the tile to edit.
|
|
431
|
+
* @param y {Number} The row of the tile to edit.
|
|
432
|
+
* @param [z] {Number} If RenderTiles has multiple layers, this value specifies the layer, with `0` being the bottom-most layer.
|
|
433
|
+
*/
|
|
434
|
+
"change-tile": function (tile, x, y, z) {
|
|
435
|
+
const
|
|
436
|
+
map = this.imageMap;
|
|
437
|
+
|
|
438
|
+
if (map) {
|
|
439
|
+
this.updateTile(tile, map[z || 0], x, y);
|
|
440
|
+
// Only flag a re-render if the changed tile is within the currently
|
|
441
|
+
// cached region. Changes outside the cache will be drawn correctly
|
|
442
|
+
// the next time the camera pans to include them.
|
|
443
|
+
if (!this.cache.empty &&
|
|
444
|
+
x >= this.cache.left && x <= this.cache.right &&
|
|
445
|
+
y >= this.cache.top && y <= this.cache.bottom) {
|
|
446
|
+
this.updateCache = true;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
|
|
451
|
+
"camera-loaded": function (camera) {
|
|
452
|
+
this.worldWidth = camera.world.width;
|
|
453
|
+
this.worldHeight = camera.world.height;
|
|
454
|
+
|
|
455
|
+
if (this.buffer && !this.cacheAll) { // do this here to set the correct mask before the first caching.
|
|
456
|
+
this.updateBufferRegion(camera.viewport);
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Forces an immediate full re-render centered on the current camera
|
|
462
|
+
* position. Call this after bulk tile changes to ensure the display
|
|
463
|
+
* is up to date without requiring a camera pan.
|
|
464
|
+
*
|
|
465
|
+
* For the panning cache, we invalidate cachePixels and re-run the full
|
|
466
|
+
* camera-update recache logic using the last known camera, which correctly
|
|
467
|
+
* handles texture swapping, tile population, and sprite positioning.
|
|
468
|
+
*/
|
|
469
|
+
"force-render": function () {
|
|
470
|
+
if (this.cacheAll) {
|
|
471
|
+
// Single/full cache — re-render entire layer.
|
|
472
|
+
this.populateTiles(this.cache, null);
|
|
473
|
+
this.renderCache(this.cache, this.cacheTexture, this.mapContainer, this.mapContainerWrapper);
|
|
474
|
+
} else if (this.cacheTexture) {
|
|
475
|
+
// Panning cache — invalidate cachePixels so the recache branch
|
|
476
|
+
// runs, then execute the full camera-update recache inline.
|
|
477
|
+
const
|
|
478
|
+
{viewport: vp} = this.owner.parent.worldCamera,
|
|
479
|
+
{cache, cachePixels} = this,
|
|
480
|
+
tempC = tempCache,
|
|
481
|
+
ctw = this.cacheTilesWidth - 1,
|
|
482
|
+
cth = this.cacheTilesHeight - 1,
|
|
483
|
+
ctw2 = ctw / 2,
|
|
484
|
+
cth2 = cth / 2;
|
|
485
|
+
|
|
486
|
+
this.convertCamera(vp);
|
|
487
|
+
|
|
488
|
+
// Force the recache branch to run regardless of camera position.
|
|
489
|
+
cachePixels.empty = true;
|
|
490
|
+
|
|
491
|
+
tempC.setAll(
|
|
492
|
+
Math.round((this.laxCam.x - this.left) / this.tileWidth - ctw2) + ctw2,
|
|
493
|
+
Math.round((this.laxCam.y - this.top) / this.tileHeight - cth2) + cth2,
|
|
494
|
+
ctw, cth
|
|
495
|
+
);
|
|
496
|
+
if (tempC.left < 0) {
|
|
497
|
+
tempC.moveX(tempC.halfWidth);
|
|
498
|
+
} else if (tempC.right > this.tilesWidth - 1) {
|
|
499
|
+
tempC.moveX(this.tilesWidth - 1 - tempC.halfWidth);
|
|
500
|
+
}
|
|
501
|
+
if (tempC.top < 0) {
|
|
502
|
+
tempC.moveY(tempC.halfHeight);
|
|
503
|
+
} else if (tempC.bottom > this.tilesHeight - 1) {
|
|
504
|
+
tempC.moveY(this.tilesHeight - 1 - tempC.halfHeight);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
this.tilesSpriteCache.texture = this.cacheTexture;
|
|
508
|
+
this.cacheTexture = this.cacheTexture.alternate;
|
|
509
|
+
this.tilesSprite.texture = this.cacheTexture;
|
|
510
|
+
|
|
511
|
+
this.populateTiles(tempC, cache);
|
|
512
|
+
this.renderCache(tempC, this.cacheTexture, this.mapContainer, this.mapContainerWrapper, this.tilesSpriteCache);
|
|
513
|
+
cache.set(tempC);
|
|
514
|
+
|
|
515
|
+
cachePixels.setAll(
|
|
516
|
+
(cache.x + 0.5) * this.tileWidth + this.left,
|
|
517
|
+
(cache.y + 0.5) * this.tileHeight + this.top,
|
|
518
|
+
(cache.width + 1) * this.tileWidth,
|
|
519
|
+
(cache.height + 1) * this.tileHeight
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
this.tilesSprite.x = vp.left - this.laxCam.left + cache.left * this.tileWidth + this.left;
|
|
523
|
+
this.tilesSprite.y = vp.top - this.laxCam.top + cache.top * this.tileHeight + this.top;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
|
|
528
|
+
methods: {
|
|
529
|
+
setupSingleCache () {
|
|
530
|
+
const
|
|
531
|
+
{container, mapContainer, owner} = this,
|
|
532
|
+
{z} = owner,
|
|
533
|
+
cacheTexture = RenderTexture.create({
|
|
534
|
+
width: this.cacheWidth,
|
|
535
|
+
height: this.cacheHeight
|
|
536
|
+
}),
|
|
537
|
+
sprite = new Sprite(cacheTexture);
|
|
538
|
+
|
|
539
|
+
this.mapContainerWrapper = new Container();
|
|
540
|
+
this.mapContainerWrapper.addChild(mapContainer);
|
|
541
|
+
|
|
542
|
+
this.cacheAll = true;
|
|
543
|
+
this.edgeBleed = 0;
|
|
544
|
+
this.edgesBleed = 0;
|
|
545
|
+
this.updateRegion(0);
|
|
546
|
+
|
|
547
|
+
this.render = this.renderCache;
|
|
548
|
+
this.cacheTexture = cacheTexture;
|
|
549
|
+
|
|
550
|
+
this.tilesSprite = sprite;
|
|
551
|
+
sprite.scale.x = this.scaleX;
|
|
552
|
+
sprite.scale.y = this.scaleY;
|
|
553
|
+
sprite.z = z;
|
|
554
|
+
|
|
555
|
+
this.cache.setBounds(0, 0, this.tilesWidth - 1, this.tilesHeight - 1);
|
|
556
|
+
this.populateTiles(this.cache, null);
|
|
557
|
+
this.renderCache(this.cache, cacheTexture, this.mapContainer, this.mapContainerWrapper);
|
|
558
|
+
container.addChild(sprite);
|
|
559
|
+
|
|
560
|
+
return createTeardown(this, {
|
|
561
|
+
'camera-update': function (camera) {
|
|
562
|
+
const
|
|
563
|
+
{laxCam, left, top} = this,
|
|
564
|
+
{viewport: vp} = camera;
|
|
565
|
+
|
|
566
|
+
this.convertCamera(vp);
|
|
567
|
+
|
|
568
|
+
this.tilesSprite.x = vp.left - laxCam.left + this.cache.left * this.tileWidth + left;
|
|
569
|
+
this.tilesSprite.y = vp.top - laxCam.top + this.cache.top * this.tileHeight + top;
|
|
570
|
+
},
|
|
571
|
+
'handle-render': function () {
|
|
572
|
+
if (this.updateCache) {
|
|
573
|
+
this.updateCache = false;
|
|
574
|
+
this.populateTiles(this.cache, null);
|
|
575
|
+
this.renderCache(this.cache, this.cacheTexture, this.mapContainer, this.mapContainerWrapper);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
},
|
|
580
|
+
|
|
581
|
+
setupFullCache () {
|
|
582
|
+
const
|
|
583
|
+
extrusionMargin = 2,
|
|
584
|
+
{container, mapContainer, owner} = this,
|
|
585
|
+
{z} = owner;
|
|
586
|
+
|
|
587
|
+
this.mapContainerWrapper = new Container();
|
|
588
|
+
this.mapContainerWrapper.addChild(mapContainer);
|
|
589
|
+
|
|
590
|
+
this.cacheAll = true;
|
|
591
|
+
|
|
592
|
+
// Make sure there's room for the one-pixel extrusion around edges of caches
|
|
593
|
+
this.cacheWidth = Math.min(getPowerOfTwo(this.layerWidth + extrusionMargin), this.maximumBuffer);
|
|
594
|
+
this.cacheHeight = Math.min(getPowerOfTwo(this.layerHeight + extrusionMargin), this.maximumBuffer);
|
|
595
|
+
this.updateRegion(extrusionMargin);
|
|
596
|
+
|
|
597
|
+
this.tileContainer.x = -1; // due to extrusion.
|
|
598
|
+
this.tileContainer.y = -1;
|
|
599
|
+
this.render = this.renderCacheWithExtrusion;
|
|
600
|
+
this.cacheGrid = this.createGrid(container);
|
|
601
|
+
|
|
602
|
+
this.updateCache = true;
|
|
603
|
+
|
|
604
|
+
return createTeardown(this, {
|
|
605
|
+
'camera-update': function (camera) {
|
|
606
|
+
const
|
|
607
|
+
{cacheClipHeight, cacheClipWidth, cacheGrid, cachePixels, laxCam, left, top} = this,
|
|
608
|
+
{viewport: vp} = camera;
|
|
609
|
+
|
|
610
|
+
this.convertCamera(vp);
|
|
611
|
+
|
|
612
|
+
for (let x = 0; x < cacheGrid.length; x++) {
|
|
613
|
+
for (let y = 0; y < cacheGrid[x].length; y++) {
|
|
614
|
+
cachePixels.setAll((x + 0.5) * cacheClipWidth + left, (y + 0.5) * cacheClipHeight + top, cacheClipWidth, cacheClipHeight);
|
|
615
|
+
|
|
616
|
+
const
|
|
617
|
+
sprite = cacheGrid[x][y],
|
|
618
|
+
inFrame = cachePixels.intersects(laxCam);
|
|
619
|
+
|
|
620
|
+
if (sprite.visible && !inFrame) {
|
|
621
|
+
sprite.visible = false;
|
|
622
|
+
} else if (!sprite.visible && inFrame) {
|
|
623
|
+
sprite.visible = true;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
if (sprite.visible && inFrame) {
|
|
627
|
+
sprite.x = vp.left - laxCam.left + x * cacheClipWidth + left;
|
|
628
|
+
sprite.y = vp.top - laxCam.top + y * cacheClipHeight + top;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
'handle-render': function () {
|
|
634
|
+
if (this.updateCache) {
|
|
635
|
+
const
|
|
636
|
+
{cache, cacheGrid, cacheTilesHeight, cacheTilesWidth, tilesHeight, tilesWidth} = this,
|
|
637
|
+
tsh = tilesHeight - 1,
|
|
638
|
+
tsw = tilesWidth - 1;
|
|
639
|
+
|
|
640
|
+
this.updateCache = false;
|
|
641
|
+
|
|
642
|
+
for (let x = 0; x < cacheGrid.length; x++) {
|
|
643
|
+
for (let y = 0; y < cacheGrid[x].length; y++) {
|
|
644
|
+
cache.setBounds(x * cacheTilesWidth, y * cacheTilesHeight, Math.min((x + 1) * cacheTilesWidth, tsw), Math.min((y + 1) * cacheTilesHeight, tsh));
|
|
645
|
+
|
|
646
|
+
this.populateTiles(cache, null);
|
|
647
|
+
this.renderCacheWithExtrusion(cache, cacheGrid[x][y].texture, this.mapContainer, this.mapContainerWrapper);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
},
|
|
654
|
+
|
|
655
|
+
setupPanningCache () {
|
|
656
|
+
const
|
|
657
|
+
{container, mapContainer, owner} = this,
|
|
658
|
+
{z} = owner;
|
|
659
|
+
|
|
660
|
+
this.mapContainerWrapper = new Container();
|
|
661
|
+
this.mapContainerWrapper.addChild(mapContainer);
|
|
662
|
+
|
|
663
|
+
this.updateRegion(0);
|
|
664
|
+
this.render = this.renderCache;
|
|
665
|
+
this.cacheAll = false;
|
|
666
|
+
|
|
667
|
+
this.cacheTexture = RenderTexture.create({
|
|
668
|
+
width: this.cacheWidth,
|
|
669
|
+
height: this.cacheHeight
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
this.tilesSprite = new Sprite(this.cacheTexture);
|
|
673
|
+
this.tilesSprite.scale.x = this.scaleX;
|
|
674
|
+
this.tilesSprite.scale.y = this.scaleY;
|
|
675
|
+
this.tilesSprite.z = z;
|
|
676
|
+
|
|
677
|
+
// Set up copy buffer and circular pointers
|
|
678
|
+
this.cacheTexture.alternate = RenderTexture.create({
|
|
679
|
+
width: this.cacheWidth,
|
|
680
|
+
height: this.cacheHeight
|
|
681
|
+
});
|
|
682
|
+
this.tilesSpriteCache = new Sprite(this.cacheTexture.alternate);
|
|
683
|
+
|
|
684
|
+
this.cacheTexture.alternate.alternate = this.cacheTexture;
|
|
685
|
+
container.addChild(this.tilesSprite);
|
|
686
|
+
|
|
687
|
+
return createTeardown(this, {
|
|
688
|
+
'camera-update': function (camera) {
|
|
689
|
+
const
|
|
690
|
+
{buffer, cache, cachePixels, laxCam, refreshBuffer} = this,
|
|
691
|
+
{viewport: vp} = camera,
|
|
692
|
+
resized = (buffer && ((vp.width !== laxCam.width) || (vp.height !== laxCam.height))),
|
|
693
|
+
tempC = tempCache;
|
|
694
|
+
|
|
695
|
+
this.convertCamera(vp);
|
|
696
|
+
|
|
697
|
+
if ((cachePixels.empty || !cachePixels.contains(laxCam)) && (this.imageMap.length > 0)) {
|
|
698
|
+
if (resized) {
|
|
699
|
+
this.updateBufferRegion(laxCam);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
const
|
|
703
|
+
ctw = this.cacheTilesWidth - 1,
|
|
704
|
+
cth = this.cacheTilesHeight - 1,
|
|
705
|
+
ctw2 = ctw / 2,
|
|
706
|
+
cth2 = cth / 2;
|
|
707
|
+
|
|
708
|
+
//only attempt to draw children that are relevant
|
|
709
|
+
tempC.setAll(Math.round((laxCam.x - this.left) / this.tileWidth - ctw2) + ctw2, Math.round((laxCam.y - this.top) / this.tileHeight - cth2) + cth2, ctw, cth);
|
|
710
|
+
if (tempC.left < 0) {
|
|
711
|
+
tempC.moveX(tempC.halfWidth);
|
|
712
|
+
} else if (tempC.right > this.tilesWidth - 1) {
|
|
713
|
+
tempC.moveX(this.tilesWidth - 1 - tempC.halfWidth);
|
|
714
|
+
}
|
|
715
|
+
if (tempC.top < 0) {
|
|
716
|
+
tempC.moveY(tempC.halfHeight);
|
|
717
|
+
} else if (tempC.bottom > this.tilesHeight - 1) {
|
|
718
|
+
tempC.moveY(this.tilesHeight - 1 - tempC.halfHeight);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
this.tilesSpriteCache.texture = this.cacheTexture;
|
|
722
|
+
this.cacheTexture = this.cacheTexture.alternate;
|
|
723
|
+
this.tilesSprite.texture = this.cacheTexture;
|
|
724
|
+
|
|
725
|
+
this.populateTiles(tempC, cache);
|
|
726
|
+
this.renderCache(tempC, this.cacheTexture, this.mapContainer, this.mapContainerWrapper, this.tilesSpriteCache, cache);
|
|
727
|
+
cache.set(tempC);
|
|
728
|
+
|
|
729
|
+
// Store pixel bounding box for checking later.
|
|
730
|
+
cachePixels.setAll((cache.x + 0.5) * this.tileWidth + this.left, (cache.y + 0.5) * this.tileHeight + this.top, (cache.width + 1) * this.tileWidth, (cache.height + 1) * this.tileHeight);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
this.tilesSprite.x = vp.left - laxCam.left + cache.left * this.tileWidth + this.left;
|
|
734
|
+
this.tilesSprite.y = vp.top - laxCam.top + cache.top * this.tileHeight + this.top;
|
|
735
|
+
},
|
|
736
|
+
'handle-render': function () {
|
|
737
|
+
if (this.updateCache && !this.cache.empty) {
|
|
738
|
+
this.updateCache = false;
|
|
739
|
+
this.populateTiles(this.cache, null);
|
|
740
|
+
this.renderCacheClear(this.cache, this.cacheTexture, this.mapContainer, this.mapContainerWrapper);
|
|
741
|
+
this.tilesSpriteCache.texture = this.cacheTexture;
|
|
742
|
+
this.cachePixels.setAll(
|
|
743
|
+
(this.cache.x + 0.5) * this.tileWidth + this.left,
|
|
744
|
+
(this.cache.y + 0.5) * this.tileHeight + this.top,
|
|
745
|
+
(this.cache.width + 1) * this.tileWidth,
|
|
746
|
+
(this.cache.height + 1) * this.tileHeight
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
},
|
|
752
|
+
|
|
753
|
+
setupNoCache () {
|
|
754
|
+
const
|
|
755
|
+
{container, left, mapContainer, owner, scaleX, scaleY, top} = this,
|
|
756
|
+
{z} = owner;
|
|
757
|
+
|
|
758
|
+
this.updateRegion(0);
|
|
759
|
+
|
|
760
|
+
mapContainer.scale.x = scaleX;
|
|
761
|
+
mapContainer.scale.y = scaleY;
|
|
762
|
+
mapContainer.x = left;
|
|
763
|
+
mapContainer.y = top;
|
|
764
|
+
mapContainer.z = z;
|
|
765
|
+
container.addChild(mapContainer);
|
|
766
|
+
|
|
767
|
+
this.buffer = 0; // prevents buffer logic from running if tiles aren't being cached.
|
|
768
|
+
this.cacheAll = false; // so tiles are updated as camera moves.
|
|
769
|
+
|
|
770
|
+
return createTeardown(this, {
|
|
771
|
+
'camera-update': function (camera) {
|
|
772
|
+
const
|
|
773
|
+
{buffer, cache, cachePixels, laxCam} = this,
|
|
774
|
+
{viewport: vp} = camera,
|
|
775
|
+
resized = (buffer && ((vp.width !== laxCam.width) || (vp.height !== laxCam.height))),
|
|
776
|
+
tempC = tempCache;
|
|
777
|
+
|
|
778
|
+
this.convertCamera(vp);
|
|
779
|
+
|
|
780
|
+
if ((cachePixels.empty || !cachePixels.contains(laxCam)) && (this.imageMap.length > 0)) {
|
|
781
|
+
if (resized) {
|
|
782
|
+
this.updateBufferRegion(laxCam);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
const
|
|
786
|
+
ctw = this.cacheTilesWidth - 1,
|
|
787
|
+
cth = this.cacheTilesHeight - 1,
|
|
788
|
+
ctw2 = ctw / 2,
|
|
789
|
+
cth2 = cth / 2;
|
|
790
|
+
|
|
791
|
+
//only attempt to draw children that are relevant
|
|
792
|
+
tempC.setAll(Math.round((laxCam.x - this.left) / this.tileWidth - ctw2) + ctw2, Math.round((laxCam.y - this.top) / this.tileHeight - cth2) + cth2, ctw, cth);
|
|
793
|
+
if (tempC.left < 0) {
|
|
794
|
+
tempC.moveX(tempC.halfWidth);
|
|
795
|
+
} else if (tempC.right > this.tilesWidth - 1) {
|
|
796
|
+
tempC.moveX(this.tilesWidth - 1 - tempC.halfWidth);
|
|
797
|
+
}
|
|
798
|
+
if (tempC.top < 0) {
|
|
799
|
+
tempC.moveY(tempC.halfHeight);
|
|
800
|
+
} else if (tempC.bottom > this.tilesHeight - 1) {
|
|
801
|
+
tempC.moveY(this.tilesHeight - 1 - tempC.halfHeight);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
this.populateTiles(tempC, null);
|
|
805
|
+
cache.set(tempC);
|
|
806
|
+
|
|
807
|
+
// Store pixel bounding box for checking later.
|
|
808
|
+
cachePixels.setAll((cache.x + 0.5) * this.tileWidth + this.left, (cache.y + 0.5) * this.tileHeight + this.top, (cache.width + 1) * this.tileWidth, (cache.height + 1) * this.tileHeight);
|
|
809
|
+
}
|
|
810
|
+
},
|
|
811
|
+
'handle-render': function () {
|
|
812
|
+
if (this.updateCache) {
|
|
813
|
+
this.updateCache = false;
|
|
814
|
+
// Invalidate cachePixels so camera-update immediately re-runs
|
|
815
|
+
// populateTiles on the next tick rather than skipping because
|
|
816
|
+
// the old region still appears valid.
|
|
817
|
+
this.cachePixels.empty = true;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
});
|
|
821
|
+
},
|
|
822
|
+
|
|
823
|
+
cacheSprite: function (entity) {
|
|
824
|
+
const
|
|
825
|
+
object = entity.cacheRender;
|
|
826
|
+
|
|
827
|
+
// Determine whether to merge this image with the background.
|
|
828
|
+
if (this.entityCache && object) {
|
|
829
|
+
const
|
|
830
|
+
{x: boundsX, y: boundsY, width, height} = object.getBounds(object.transformMatrix),
|
|
831
|
+
offsetX = boundsX - this.left,
|
|
832
|
+
offsetY = boundsY - this.top,
|
|
833
|
+
top = Math.max(0, Math.floor(offsetY / this.tileHeight)),
|
|
834
|
+
bottom = Math.min(this.tilesHeight, Math.ceil((offsetY + height) / this.tileHeight)),
|
|
835
|
+
left = Math.max(0, Math.floor(offsetX / this.tileWidth)),
|
|
836
|
+
right = Math.min(this.tilesWidth, Math.ceil((offsetX + width) / this.tileWidth));
|
|
837
|
+
|
|
838
|
+
if (!this.doMap) {
|
|
839
|
+
this.doMap = arrayCache.setUp();
|
|
840
|
+
this.cachedDisplayObjects = arrayCache.setUp();
|
|
841
|
+
this.populate = this.populateTilesAndEntities;
|
|
842
|
+
}
|
|
843
|
+
this.cachedDisplayObjects.push(object);
|
|
844
|
+
|
|
845
|
+
// Find tiles that should include this display object
|
|
846
|
+
for (let x = left; x < right; x++) {
|
|
847
|
+
if (!this.doMap[x]) {
|
|
848
|
+
this.doMap[x] = arrayCache.setUp();
|
|
849
|
+
}
|
|
850
|
+
for (let y = top; y < bottom; y++) {
|
|
851
|
+
if (!this.doMap[x][y]) {
|
|
852
|
+
this.doMap[x][y] = arrayCache.setUp();
|
|
853
|
+
}
|
|
854
|
+
this.doMap[x][y].push(object);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// Prevent subsequent draws
|
|
859
|
+
entity.removeFromParentContainer();
|
|
860
|
+
|
|
861
|
+
this.updateCache = true; //TODO: This currently causes a blanket cache update - may be worthwhile to only recache if this entity's location is currently in a cache (either cacheGrid or the current viewable area).
|
|
862
|
+
}
|
|
863
|
+
},
|
|
864
|
+
|
|
865
|
+
uncacheSprite: function (entity) {
|
|
866
|
+
const
|
|
867
|
+
object = entity.cacheRender;
|
|
868
|
+
|
|
869
|
+
// Determine whether to merge this image with the background.
|
|
870
|
+
if (this.entityCache && object) {
|
|
871
|
+
const
|
|
872
|
+
{x: boundsX, y: boundsY, width, height} = object.getBounds(object.transformMatrix),
|
|
873
|
+
index = this.cachedDisplayObjects.indexOf(object),
|
|
874
|
+
offsetX = boundsX - this.left,
|
|
875
|
+
offsetY = boundsY - this.top,
|
|
876
|
+
top = Math.max(0, Math.floor(offsetY / this.tileHeight)),
|
|
877
|
+
bottom = Math.min(this.tilesHeight, Math.ceil((offsetY + height) / this.tileHeight)),
|
|
878
|
+
left = Math.max(0, Math.floor(offsetX / this.tileWidth)),
|
|
879
|
+
right = Math.min(this.tilesWidth, Math.ceil((offsetX + width) / this.tileWidth));
|
|
880
|
+
|
|
881
|
+
if (index >= 0) {
|
|
882
|
+
this.cachedDisplayObjects.splice(index, 1);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// Find tiles that should include this display object
|
|
886
|
+
for (let x = left; x < right; x++) {
|
|
887
|
+
for (let y = top; y < bottom; y++) {
|
|
888
|
+
if (this.doMap?.[x]?.[y]) {
|
|
889
|
+
const
|
|
890
|
+
index = this.doMap[x][y].indexOf(object);
|
|
891
|
+
|
|
892
|
+
if (index >= 0) {
|
|
893
|
+
this.doMap[x][y].splice(index, 1);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
this.updateCache = true;
|
|
900
|
+
}
|
|
901
|
+
},
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Computes a parallax-adjusted camera AABB (`laxCam`) for this layer.
|
|
905
|
+
*
|
|
906
|
+
* For layers smaller than the world, the layer must scroll slower so that
|
|
907
|
+
* it still covers the full world space as the camera travels edge-to-edge.
|
|
908
|
+
* The position is mapped proportionally: when the camera is at the start of
|
|
909
|
+
* its world travel, laxCam is at the start of the layer's travel, and
|
|
910
|
+
* likewise at the end.
|
|
911
|
+
*
|
|
912
|
+
* Tiled `parallaxx` / `parallaxy` factors are then applied relative to the
|
|
913
|
+
* map's parallax origin so the layer's effective render position is:
|
|
914
|
+
* `layerPos - (camera - parallaxOrigin) * (1 - parallaxFactor)`.
|
|
915
|
+
*
|
|
916
|
+
* IMPORTANT: laxCam is resized to the *actual viewport dimensions* (not
|
|
917
|
+
* viewport + refreshBuffer). Its purpose is solely to compute the parallax
|
|
918
|
+
* offset for sprite positioning (vp.left - laxCam.left). Inflating it with
|
|
919
|
+
* refreshBuffer caused sprite offsets to be wrong by `refreshBuffer` pixels
|
|
920
|
+
* on every camera update, breaking parallax for differently-sized layers.
|
|
921
|
+
*/
|
|
922
|
+
convertCamera: function (camera) {
|
|
923
|
+
const
|
|
924
|
+
worldWidth = this.worldWidth / this.scaleX,
|
|
925
|
+
worldPosX = worldWidth - camera.width,
|
|
926
|
+
worldHeight = this.worldHeight / this.scaleY,
|
|
927
|
+
worldPosY = worldHeight - camera.height,
|
|
928
|
+
laxCam = this.laxCam,
|
|
929
|
+
{parallaxOriginX, parallaxOriginY, parallaxX, parallaxY} = this;
|
|
930
|
+
|
|
931
|
+
if ((worldWidth === this.layerWidth) || !worldPosX) {
|
|
932
|
+
laxCam.moveX(camera.x);
|
|
933
|
+
} else {
|
|
934
|
+
laxCam.moveX((camera.left - this.left) * (this.layerWidth - camera.width) / worldPosX + camera.halfWidth + this.left);
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
if ((worldHeight === this.layerHeight) || !worldPosY) {
|
|
938
|
+
laxCam.moveY(camera.y);
|
|
939
|
+
} else {
|
|
940
|
+
laxCam.moveY((camera.top - this.top) * (this.layerHeight - camera.height) / worldPosY + camera.halfHeight + this.top);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
if (parallaxX !== 1) {
|
|
944
|
+
laxCam.moveX(laxCam.x + (camera.x - parallaxOriginX) * (1 - parallaxX));
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
if (parallaxY !== 1) {
|
|
948
|
+
laxCam.moveY(laxCam.y + (camera.y - parallaxOriginY) * (1 - parallaxY));
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// FIX: resize laxCam to the actual viewport size only — never camera + refreshBuffer.
|
|
952
|
+
if (camera.width !== laxCam.width || camera.height !== laxCam.height) {
|
|
953
|
+
laxCam.resize(camera.width, camera.height);
|
|
954
|
+
}
|
|
955
|
+
},
|
|
956
|
+
|
|
957
|
+
createTile: function (imageName) {
|
|
958
|
+
// "tile-1" is empty, so it remains a null reference.
|
|
959
|
+
if (imageName === 'tile-1') {
|
|
960
|
+
return nullTemplate;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
return Template.setUp(this.tileSpriteSheet, imageName, this.uninitializedTiles);
|
|
964
|
+
},
|
|
965
|
+
|
|
966
|
+
createMap: function (mapDefinition) {
|
|
967
|
+
if (typeof mapDefinition[0][0] !== 'string') { // This is not a map definition: it's an actual RenderTiles map.
|
|
968
|
+
return mapDefinition;
|
|
969
|
+
} else {
|
|
970
|
+
const
|
|
971
|
+
map = arrayCache.setUp();
|
|
972
|
+
|
|
973
|
+
for (let x = 0; x < mapDefinition.length; x++) {
|
|
974
|
+
map[x] = arrayCache.setUp();
|
|
975
|
+
for (let y = 0; y < mapDefinition[x].length; y++) {
|
|
976
|
+
this.updateTile(mapDefinition[x][y], map, x, y);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
return map;
|
|
981
|
+
}
|
|
982
|
+
},
|
|
983
|
+
|
|
984
|
+
updateTile: function (index, map, x, y) {
|
|
985
|
+
const
|
|
986
|
+
id = index.id ?? index,
|
|
987
|
+
{tiles} = this,
|
|
988
|
+
tile = tiles[id];
|
|
989
|
+
|
|
990
|
+
if (!tile && (tile !== null)) { // Empty grid spaces are null, so we needn't create a new tile.
|
|
991
|
+
map[x][y] = tiles[id] = this.createTile(id);
|
|
992
|
+
} else {
|
|
993
|
+
map[x][y] = tile;
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
|
|
997
|
+
createGrid: function (container) {
|
|
998
|
+
const
|
|
999
|
+
{edgeBleed: extrusion, edgesBleed: outerMargin} = this,
|
|
1000
|
+
ch = this.cacheHeight,
|
|
1001
|
+
cw = this.cacheWidth,
|
|
1002
|
+
cth = this.cacheTilesHeight,
|
|
1003
|
+
ctw = this.cacheTilesWidth,
|
|
1004
|
+
sx = this.scaleX,
|
|
1005
|
+
sy = this.scaleY,
|
|
1006
|
+
th = this.tileHeight,
|
|
1007
|
+
tw = this.tileWidth,
|
|
1008
|
+
tsh = this.tilesHeight,
|
|
1009
|
+
tsw = this.tilesWidth,
|
|
1010
|
+
cg = arrayCache.setUp();
|
|
1011
|
+
let ct = null,
|
|
1012
|
+
z = this.owner.z;
|
|
1013
|
+
|
|
1014
|
+
for (let x = 0; x < tsw; x += ctw) {
|
|
1015
|
+
const
|
|
1016
|
+
col = arrayCache.setUp();
|
|
1017
|
+
cg.push(col);
|
|
1018
|
+
for (let y = 0; y < tsh; y += cth) {
|
|
1019
|
+
// This prevents us from using too large of a cache for the right and bottom edges of the map.
|
|
1020
|
+
const
|
|
1021
|
+
width = Math.min(getPowerOfTwo((tsw - x) * tw + outerMargin), cw),
|
|
1022
|
+
height = Math.min(getPowerOfTwo((tsh - y) * th + outerMargin), ch),
|
|
1023
|
+
rt = RenderTexture.create({
|
|
1024
|
+
width,
|
|
1025
|
+
height
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
rt.frame = new Rectangle(extrusion, extrusion, (((width - outerMargin) / tw) >> 0) * tw + extrusion, (((height - outerMargin) / th) >> 0) * th + extrusion);
|
|
1029
|
+
ct = new Sprite(rt);
|
|
1030
|
+
ct.z = z;
|
|
1031
|
+
ct.scale.x = sx;
|
|
1032
|
+
ct.scale.y = sy;
|
|
1033
|
+
col.push(ct);
|
|
1034
|
+
container.addChild(ct);
|
|
1035
|
+
|
|
1036
|
+
z -= 0.000001; // so that tiles of large caches overlap consistently.
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
return cg;
|
|
1041
|
+
},
|
|
1042
|
+
|
|
1043
|
+
updateRegion: function (margin) {
|
|
1044
|
+
const
|
|
1045
|
+
{edgesBleed} = this,
|
|
1046
|
+
tw = this.tileWidth * this.scaleX,
|
|
1047
|
+
th = this.tileHeight * this.scaleY,
|
|
1048
|
+
ctw = Math.min(this.tilesWidth, ((this.cacheWidth - edgesBleed) / tw) >> 0),
|
|
1049
|
+
cth = Math.min(this.tilesHeight, ((this.cacheHeight - edgesBleed) / th) >> 0);
|
|
1050
|
+
|
|
1051
|
+
if (!ctw) {
|
|
1052
|
+
platypus.debug.warn('"' + this.owner.type + '" RenderTiles: The tiles are ' + tw + 'px wide which is larger than ' + (this.cacheWidth - edgesBleed) + 'px (maximum cache size of ' + this.cacheWidth + 'px minus a 2px edge bleed). Increase the maximum cache size or reduce tile size.');
|
|
1053
|
+
}
|
|
1054
|
+
if (!cth) {
|
|
1055
|
+
platypus.debug.warn('"' + this.owner.type + '" RenderTiles: The tiles are ' + th + 'px high which is larger than ' + (this.cacheHeight - edgesBleed) + 'px (maximum cache size of ' + this.cacheHeight + 'px minus a 2px edge bleed). Increase the maximum cache size or reduce tile size.');
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
this.cacheTilesWidth = ctw;
|
|
1059
|
+
this.cacheTilesHeight = cth;
|
|
1060
|
+
this.cacheClipWidth = ctw * tw;
|
|
1061
|
+
this.cacheClipHeight = cth * th;
|
|
1062
|
+
|
|
1063
|
+
if (this.tileCache) {
|
|
1064
|
+
this.mapContainer.mask = new Graphics().rect(0, 0, this.cacheClipWidth + margin, this.cacheClipHeight + margin).fill(0x000000);
|
|
1065
|
+
}
|
|
1066
|
+
},
|
|
1067
|
+
|
|
1068
|
+
updateBufferRegion: function (viewport) {
|
|
1069
|
+
const
|
|
1070
|
+
tw = this.tileWidth * this.scaleX,
|
|
1071
|
+
th = this.tileHeight * this.scaleY;
|
|
1072
|
+
|
|
1073
|
+
this.cacheTilesWidth = Math.min(this.tilesWidth, Math.ceil((viewport.width + this.buffer * 2) / tw), (this.cacheWidth / tw) >> 0);
|
|
1074
|
+
this.cacheTilesHeight = Math.min(this.tilesHeight, Math.ceil((viewport.height + this.buffer * 2) / th), (this.cacheHeight / th) >> 0);
|
|
1075
|
+
|
|
1076
|
+
this.cacheClipWidth = this.cacheTilesWidth * tw;
|
|
1077
|
+
this.cacheClipHeight = this.cacheTilesHeight * th;
|
|
1078
|
+
|
|
1079
|
+
this.mapContainer.mask = new Graphics().rect(0, 0, this.cacheClipWidth, this.cacheClipHeight).fill(0x000000);
|
|
1080
|
+
},
|
|
1081
|
+
|
|
1082
|
+
populateTiles: function (bounds, oldBounds) {
|
|
1083
|
+
const
|
|
1084
|
+
tiles = arrayCache.setUp();
|
|
1085
|
+
|
|
1086
|
+
this.tileContainer.removeChildren();
|
|
1087
|
+
for (let x = bounds.left; x <= bounds.right; x++) {
|
|
1088
|
+
for (let y = bounds.top; y <= bounds.bottom; y++) {
|
|
1089
|
+
if (!oldBounds || oldBounds.empty || (y > oldBounds.bottom) || (y < oldBounds.top) || (x > oldBounds.right) || (x < oldBounds.left)) {
|
|
1090
|
+
for (let layer = 0; layer < this.imageMap.length; layer++) {
|
|
1091
|
+
const
|
|
1092
|
+
tile = this.imageMap[layer][x][y].getNext();
|
|
1093
|
+
|
|
1094
|
+
if (tile) {
|
|
1095
|
+
if (tile.template) {
|
|
1096
|
+
tiles.push(tile.template);
|
|
1097
|
+
}
|
|
1098
|
+
tile.x = (x + 0.5) * this.tileWidth;
|
|
1099
|
+
tile.y = (y + 0.5) * this.tileHeight;
|
|
1100
|
+
this.tileContainer.addChild(tile);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// Clear out tile instances
|
|
1108
|
+
for (let z = 0; z < tiles.length; z++) {
|
|
1109
|
+
tiles[z].clear();
|
|
1110
|
+
}
|
|
1111
|
+
arrayCache.recycle(tiles);
|
|
1112
|
+
},
|
|
1113
|
+
|
|
1114
|
+
populateTilesAndEntities: function (bounds, oldBounds) {
|
|
1115
|
+
const
|
|
1116
|
+
ents = arrayCache.setUp(),
|
|
1117
|
+
tiles = arrayCache.setUp();
|
|
1118
|
+
|
|
1119
|
+
this.tileContainer.removeChildren();
|
|
1120
|
+
for (let x = bounds.left; x <= bounds.right; x++) {
|
|
1121
|
+
for (let y = bounds.top; y <= bounds.bottom; y++) {
|
|
1122
|
+
if (!oldBounds || oldBounds.empty || (y > oldBounds.bottom) || (y < oldBounds.top) || (x > oldBounds.right) || (x < oldBounds.left)) {
|
|
1123
|
+
// draw tiles
|
|
1124
|
+
for (let layer = 0; layer < this.imageMap.length; layer++) {
|
|
1125
|
+
const
|
|
1126
|
+
tile = this.imageMap[layer][x][y].getNext();
|
|
1127
|
+
|
|
1128
|
+
if (tile) {
|
|
1129
|
+
if (tile.template) {
|
|
1130
|
+
tiles.push(tile.template);
|
|
1131
|
+
}
|
|
1132
|
+
tile.x = (x + 0.5) * this.tileWidth;
|
|
1133
|
+
tile.y = (y + 0.5) * this.tileHeight;
|
|
1134
|
+
this.tileContainer.addChild(tile);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// check for cached entities
|
|
1139
|
+
if (this.doMap[x] && this.doMap[x][y]) {
|
|
1140
|
+
const
|
|
1141
|
+
oList = this.doMap[x][y];
|
|
1142
|
+
|
|
1143
|
+
for (let z = 0; z < oList.length; z++) {
|
|
1144
|
+
if (!oList[z].drawn) {
|
|
1145
|
+
oList[z].drawn = true;
|
|
1146
|
+
ents.push(oList[z]);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
this.mapContainer.removeChildren();
|
|
1155
|
+
this.mapContainer.addChild(this.tileContainer);
|
|
1156
|
+
|
|
1157
|
+
// Draw cached entities
|
|
1158
|
+
if (ents.length) {
|
|
1159
|
+
ents.sort(sort);
|
|
1160
|
+
for (let z = 0; z < ents.length; z++) {
|
|
1161
|
+
const
|
|
1162
|
+
ent = ents[z];
|
|
1163
|
+
|
|
1164
|
+
delete ent.drawn;
|
|
1165
|
+
this.mapContainer.addChild(ent);
|
|
1166
|
+
if (ent.mask) {
|
|
1167
|
+
this.mapContainer.addChild(ent.mask);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
// Clear out tile instances
|
|
1173
|
+
for (let z = 0; z < tiles.length; z++) {
|
|
1174
|
+
tiles[z].clear();
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
arrayCache.recycle(tiles);
|
|
1178
|
+
arrayCache.recycle(ents);
|
|
1179
|
+
},
|
|
1180
|
+
|
|
1181
|
+
renderCache: function (bounds, renderTexture, src, wrapper, oldCache, oldBounds) {
|
|
1182
|
+
const
|
|
1183
|
+
{renderer} = this;
|
|
1184
|
+
|
|
1185
|
+
if (oldCache && oldBounds && !oldBounds.empty) {
|
|
1186
|
+
oldCache.x = oldBounds.left * this.tileWidth;
|
|
1187
|
+
oldCache.y = oldBounds.top * this.tileHeight;
|
|
1188
|
+
src.addChild(oldCache); // To copy last rendering over.
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
src.x = -bounds.left * this.tileWidth;
|
|
1192
|
+
src.y = -bounds.top * this.tileHeight;
|
|
1193
|
+
renderer.render({
|
|
1194
|
+
container: wrapper,
|
|
1195
|
+
target: renderTexture
|
|
1196
|
+
});
|
|
1197
|
+
renderTexture.requiresUpdate = true;
|
|
1198
|
+
},
|
|
1199
|
+
|
|
1200
|
+
renderCacheClear: function (bounds, renderTexture, src, wrapper) {
|
|
1201
|
+
const
|
|
1202
|
+
{renderer} = this;
|
|
1203
|
+
|
|
1204
|
+
src.x = -bounds.left * this.tileWidth;
|
|
1205
|
+
src.y = -bounds.top * this.tileHeight;
|
|
1206
|
+
renderer.render({
|
|
1207
|
+
container: wrapper,
|
|
1208
|
+
target: renderTexture,
|
|
1209
|
+
clear: true
|
|
1210
|
+
});
|
|
1211
|
+
renderTexture.requiresUpdate = true;
|
|
1212
|
+
},
|
|
1213
|
+
|
|
1214
|
+
renderCacheWithExtrusion: function (bounds, renderTexture, src, wrapper) {
|
|
1215
|
+
const
|
|
1216
|
+
extrusion = 1,
|
|
1217
|
+
border = new Graphics(),
|
|
1218
|
+
{renderer} = this,
|
|
1219
|
+
rendering = {
|
|
1220
|
+
container: wrapper,
|
|
1221
|
+
target: renderTexture
|
|
1222
|
+
};
|
|
1223
|
+
|
|
1224
|
+
// This mask makes only the extruded border drawn for the next 4 draws so that inner holes aren't extruded in addition to the outer rim.
|
|
1225
|
+
border.rect(0.5, 0.5, this.cacheClipWidth + 1, this.cacheClipHeight + 1);
|
|
1226
|
+
border.stroke({
|
|
1227
|
+
width: 1,
|
|
1228
|
+
color: 0x000000
|
|
1229
|
+
});
|
|
1230
|
+
|
|
1231
|
+
// There is probably a better way to do this. Currently for the extrusion, everything is rendered once offset in the n, s, e, w directions and then once in the middle to create the effect.
|
|
1232
|
+
wrapper.mask = border;
|
|
1233
|
+
src.x = -bounds.left * this.tileWidth;
|
|
1234
|
+
src.y = -bounds.top * this.tileHeight + extrusion;
|
|
1235
|
+
renderer.render(rendering);
|
|
1236
|
+
src.x = -bounds.left * this.tileWidth + extrusion;
|
|
1237
|
+
src.y = -bounds.top * this.tileHeight;
|
|
1238
|
+
renderer.render(rendering);
|
|
1239
|
+
src.x = -bounds.left * this.tileWidth + extrusion * 2;
|
|
1240
|
+
src.y = -bounds.top * this.tileHeight + extrusion;
|
|
1241
|
+
renderer.render(rendering);
|
|
1242
|
+
src.x = -bounds.left * this.tileWidth + extrusion;
|
|
1243
|
+
src.y = -bounds.top * this.tileHeight + extrusion * 2;
|
|
1244
|
+
renderer.render(rendering);
|
|
1245
|
+
wrapper.mask = null;
|
|
1246
|
+
src.x = -bounds.left * this.tileWidth + extrusion;
|
|
1247
|
+
src.y = -bounds.top * this.tileHeight + extrusion;
|
|
1248
|
+
renderer.render(rendering);
|
|
1249
|
+
renderTexture.requiresUpdate = true;
|
|
1250
|
+
},
|
|
1251
|
+
|
|
1252
|
+
toJSON: function () {
|
|
1253
|
+
const
|
|
1254
|
+
imageMap = this.imageMap[0],
|
|
1255
|
+
imgMap = [];
|
|
1256
|
+
let x = imageMap.length;
|
|
1257
|
+
|
|
1258
|
+
while (x--) {
|
|
1259
|
+
let y = imageMap[x].length;
|
|
1260
|
+
|
|
1261
|
+
imgMap[x] = [];
|
|
1262
|
+
while (y--) {
|
|
1263
|
+
imgMap[x][y] = imageMap[x][y].id;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
return {
|
|
1268
|
+
type: 'RenderTiles',
|
|
1269
|
+
buffer: this.buffer,
|
|
1270
|
+
cacheAll: this.cacheAll,
|
|
1271
|
+
entityCache: this.entityCache,
|
|
1272
|
+
imageMap: imgMap,
|
|
1273
|
+
maximumBuffer: this.maximumBuffer,
|
|
1274
|
+
scaleX: this.scaleX,
|
|
1275
|
+
scaleY: this.scaleY,
|
|
1276
|
+
spriteSheet: this.spriteSheet,
|
|
1277
|
+
tileCache: this.tileCache,
|
|
1278
|
+
tileHeight: this.tileHeight,
|
|
1279
|
+
tileWidth: this.tileWidth,
|
|
1280
|
+
top: this.top,
|
|
1281
|
+
left: this.left
|
|
1282
|
+
};
|
|
1283
|
+
},
|
|
1284
|
+
|
|
1285
|
+
destroy: function () {
|
|
1286
|
+
const
|
|
1287
|
+
grid = this.cacheGrid,
|
|
1288
|
+
map = this.doMap,
|
|
1289
|
+
img = this.imageMap,
|
|
1290
|
+
keys = Object.keys(this.tiles),
|
|
1291
|
+
{length} = keys;
|
|
1292
|
+
|
|
1293
|
+
if (grid) {
|
|
1294
|
+
for (let x = 0; x < grid.length; x++) {
|
|
1295
|
+
for (let y = 0; y < grid[x].length; y++) {
|
|
1296
|
+
grid[x][y].texture.destroy(true);
|
|
1297
|
+
this.container.removeChild(grid[x][y]);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
arrayCache.recycle(grid, 2);
|
|
1301
|
+
delete this.cacheGrid;
|
|
1302
|
+
} else if (this.tilesSprite) {
|
|
1303
|
+
if (this.tilesSprite.texture.alternate) {
|
|
1304
|
+
this.tilesSprite.texture.alternate.destroy(true);
|
|
1305
|
+
}
|
|
1306
|
+
this.tilesSprite.texture.destroy(true);
|
|
1307
|
+
this.container.removeChild(this.tilesSprite);
|
|
1308
|
+
} else {
|
|
1309
|
+
this.container.removeChild(this.mapContainer);
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
arrayCache.recycle(img, 2);
|
|
1313
|
+
|
|
1314
|
+
for (let i = 0; i < length; i++) {
|
|
1315
|
+
this.tiles[keys[i]].destroy();
|
|
1316
|
+
}
|
|
1317
|
+
this.tiles = null;
|
|
1318
|
+
this.container = null;
|
|
1319
|
+
this.tilesSprite = null;
|
|
1320
|
+
this.spriteSheet.recycleSpriteSheet();
|
|
1321
|
+
|
|
1322
|
+
if (map) {
|
|
1323
|
+
for (let x = 0; x < this.cachedDisplayObjects.length; x++) {
|
|
1324
|
+
this.cachedDisplayObjects[x].destroy();
|
|
1325
|
+
}
|
|
1326
|
+
arrayCache.recycle(this.cachedDisplayObjects);
|
|
1327
|
+
|
|
1328
|
+
for (let x = 0; x < map.length; x++) {
|
|
1329
|
+
if (map[x]) {
|
|
1330
|
+
for (let y = 0; y < map[x].length; y++) {
|
|
1331
|
+
if (map[x][y]) {
|
|
1332
|
+
arrayCache.recycle(map[x][y]);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
arrayCache.recycle(map[x]);
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
arrayCache.recycle(map);
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
this.laxCam.recycle();
|
|
1342
|
+
this.cache.recycle();
|
|
1343
|
+
this.cachePixels.recycle();
|
|
1344
|
+
arrayCache.recycle(this.uninitializedTiles);
|
|
1345
|
+
|
|
1346
|
+
this.teardown?.();
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1349
|
+
|
|
1350
|
+
publicMethods: {
|
|
1351
|
+
getMapDimensions: function () {
|
|
1352
|
+
return {
|
|
1353
|
+
tilesWidth: this.tilesWidth,
|
|
1354
|
+
tilesHeight: this.tilesHeight,
|
|
1355
|
+
layerWidth: this.layerWidth,
|
|
1356
|
+
layerHeight: this.layerHeight
|
|
1357
|
+
}
|
|
1358
|
+
},
|
|
1359
|
+
getTileAt: function (x, y, z) {
|
|
1360
|
+
return this.imageMap[z][x][y];
|
|
1361
|
+
},
|
|
1362
|
+
getRootTileIndex: function (tileId) {
|
|
1363
|
+
const nonTransformData = ~(0x80000000 + 0x40000000 + 0x20000000);
|
|
1364
|
+
let index = tileId;
|
|
1365
|
+
|
|
1366
|
+
if (typeof tileId === 'string') {
|
|
1367
|
+
index = +tileId.slice(('tile').length);
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
return index & nonTransformData;
|
|
1371
|
+
},
|
|
1372
|
+
getTileVariants: function (tileId) {
|
|
1373
|
+
// FIX: each transform flag must use its own distinct bitmask constant.
|
|
1374
|
+
// Previously all three were 0x80000000 (X-flip), making variants 2-7
|
|
1375
|
+
// all duplicates of each other. Correct values:
|
|
1376
|
+
// transformA = 0x80000000 (X-flip / horizontal mirror)
|
|
1377
|
+
// transformB = 0x40000000 (Y-flip / vertical mirror)
|
|
1378
|
+
// transformC = 0x20000000 (diagonal / rotate)
|
|
1379
|
+
const transformA = 0x80000000,
|
|
1380
|
+
transformB = 0x40000000,
|
|
1381
|
+
transformC = 0x20000000;
|
|
1382
|
+
let index = this.getRootTileIndex(tileId);
|
|
1383
|
+
|
|
1384
|
+
return [
|
|
1385
|
+
index,
|
|
1386
|
+
index + transformA,
|
|
1387
|
+
index + transformB,
|
|
1388
|
+
index + transformC,
|
|
1389
|
+
index + transformA + transformB,
|
|
1390
|
+
index + transformA + transformC,
|
|
1391
|
+
index + transformB + transformC,
|
|
1392
|
+
index + transformA + transformB + transformC
|
|
1393
|
+
];
|
|
1394
|
+
}
|
|
1395
|
+
},
|
|
1396
|
+
|
|
1397
|
+
getAssetList: (function () {
|
|
1398
|
+
const
|
|
1399
|
+
getImages = function (ss, spriteSheets) {
|
|
1400
|
+
if (ss) {
|
|
1401
|
+
if (typeof ss === 'string') {
|
|
1402
|
+
return getImages(spriteSheets[ss], spriteSheets);
|
|
1403
|
+
} else if (ss.images) {
|
|
1404
|
+
return greenSlice(ss.images);
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
return arrayCache.setUp();
|
|
1409
|
+
};
|
|
1410
|
+
|
|
1411
|
+
return function (component, props, defaultProps) {
|
|
1412
|
+
const
|
|
1413
|
+
spriteSheets = platypus.game.settings.spriteSheets,
|
|
1414
|
+
ss = component?.spriteSheet ?? props?.spriteSheet ?? defaultProps?.spriteSheet;
|
|
1415
|
+
|
|
1416
|
+
if (ss) {
|
|
1417
|
+
if (typeof ss === 'string' && (ss !== 'import')) {
|
|
1418
|
+
return getImages(ss, spriteSheets);
|
|
1419
|
+
} else if (Array.isArray(ss)) {
|
|
1420
|
+
const
|
|
1421
|
+
images = arrayCache.setUp();
|
|
1422
|
+
let i = ss.length;
|
|
1423
|
+
|
|
1424
|
+
while (i--) {
|
|
1425
|
+
const
|
|
1426
|
+
arr = getImages(ss[i], spriteSheets);
|
|
1427
|
+
|
|
1428
|
+
union(images, arr);
|
|
1429
|
+
arrayCache.recycle(arr);
|
|
1430
|
+
}
|
|
1431
|
+
return images;
|
|
1432
|
+
} else if (ss.images) {
|
|
1433
|
+
return greenSlice(ss.images);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
return arrayCache.setUp();
|
|
1438
|
+
};
|
|
1439
|
+
}())
|
|
1440
|
+
});
|