@makefully/platypus 4.1.6 → 4.1.9
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 +37 -0
- package/lib/platypus.js +1 -1
- package/package.json +2 -2
- package/src/components/RenderSpine.js +13 -6
- package/src/components/RenderTiles.js +214 -134
- package/src/components/TiledLoader.js +16 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@makefully/platypus",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.9",
|
|
4
4
|
"description": "2D tile-based HTML5 game engine with a component-based entity model",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"contributors": [
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"webpack-dev-server": "^5.2.2"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"@esotericsoftware/spine-pixi-v8": "^4.
|
|
76
|
+
"@esotericsoftware/spine-pixi-v8": "^4.3.7",
|
|
77
77
|
"@pixi/sound": "github:Makefully-Studios/sound#feature/media-file",
|
|
78
78
|
"@tweenjs/tween.js": "^23.1.1",
|
|
79
79
|
"pako": "^2.1.0",
|
|
@@ -376,9 +376,17 @@ export default createComponentClass(/** @lends platypus.components.RenderSpine.p
|
|
|
376
376
|
spineAtlas = platypus.assetCache.get(this.atlas),
|
|
377
377
|
spineJsonParser = new SkeletonJson(new AtlasAttachmentLoader(spineAtlas)),
|
|
378
378
|
skeletonData = spineJsonParser.readSkeletonData(skeleton),
|
|
379
|
-
spine = this.spine = new Spine(skeletonData),
|
|
379
|
+
spine = this.spine = new Spine({skeletonData, autoUpdate: false}),
|
|
380
380
|
map = createAnimationMap(this.animationMap, skeleton.animations);
|
|
381
381
|
|
|
382
|
+
// Spine 4.3 inherits Pixi container world-transform deltas into skeleton physics by default.
|
|
383
|
+
// Platypus pans the camera by moving the world container, which shifts every entity's world
|
|
384
|
+
// transform even when owner.x/y are unchanged — causing unwanted physics on stationary characters.
|
|
385
|
+
// Use the `apply-spine-physics` event for intentional movement-driven physics instead.
|
|
386
|
+
spine.setPhysicsPositionInheritanceFactor(0, 0);
|
|
387
|
+
spine.physicsRotationInheritanceFactor = 0;
|
|
388
|
+
spine.resetPhysicsTransform();
|
|
389
|
+
|
|
382
390
|
let animation = '';
|
|
383
391
|
|
|
384
392
|
spine.state.addListener({
|
|
@@ -414,7 +422,6 @@ export default createComponentClass(/** @lends platypus.components.RenderSpine.p
|
|
|
414
422
|
this.owner.triggerEvent('animation-ended', animationName);
|
|
415
423
|
}
|
|
416
424
|
});
|
|
417
|
-
spine.autoUpdate = false;
|
|
418
425
|
|
|
419
426
|
this.stateBased = map && this.stateBased;
|
|
420
427
|
this.eventBased = map && this.eventBased;
|
|
@@ -621,7 +628,7 @@ export default createComponentClass(/** @lends platypus.components.RenderSpine.p
|
|
|
621
628
|
for (x = 0; x < slots.length; x++) {
|
|
622
629
|
slot = this.spine.skeleton.findSlot(slots[x]);
|
|
623
630
|
if (slot) {
|
|
624
|
-
slot.color.setFromString(color);
|
|
631
|
+
slot.pose.color.setFromString(color);
|
|
625
632
|
}
|
|
626
633
|
}
|
|
627
634
|
},
|
|
@@ -660,7 +667,7 @@ export default createComponentClass(/** @lends platypus.components.RenderSpine.p
|
|
|
660
667
|
* rotate: {x: 0, y: 0, degrees: 0}
|
|
661
668
|
* }
|
|
662
669
|
*
|
|
663
|
-
* Has known vibration issues.
|
|
670
|
+
* Has known vibration issues at low frame rates. Spine 4.3 improves physics constraint stability.
|
|
664
671
|
* Potential fixes: https://esotericsoftware.com/forum/d/28093-jittering-when-applying-physicstranslate-pixispine/5
|
|
665
672
|
*
|
|
666
673
|
* @event platypus.Entity#apply-spine-physics
|
|
@@ -672,7 +679,7 @@ export default createComponentClass(/** @lends platypus.components.RenderSpine.p
|
|
|
672
679
|
}
|
|
673
680
|
|
|
674
681
|
if (changes.rotate) {
|
|
675
|
-
this.spine.skeleton.
|
|
682
|
+
this.spine.skeleton.physicsRotate(changes.rotate.x, changes.rotate.y, changes.rotate.degrees);
|
|
676
683
|
}
|
|
677
684
|
}
|
|
678
685
|
},
|
|
@@ -698,7 +705,7 @@ export default createComponentClass(/** @lends platypus.components.RenderSpine.p
|
|
|
698
705
|
}
|
|
699
706
|
|
|
700
707
|
this.spine.skeleton.setSkin(skin);
|
|
701
|
-
this.spine.skeleton.
|
|
708
|
+
this.spine.skeleton.setupPoseSlots();
|
|
702
709
|
},
|
|
703
710
|
addToContainer: function () {
|
|
704
711
|
this.owner.container.cullable = false;
|
|
@@ -257,7 +257,43 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
257
257
|
* @type Number
|
|
258
258
|
* @default 0
|
|
259
259
|
*/
|
|
260
|
-
left: 0
|
|
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
|
|
261
297
|
},
|
|
262
298
|
|
|
263
299
|
/**
|
|
@@ -401,14 +437,7 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
401
437
|
|
|
402
438
|
if (map) {
|
|
403
439
|
this.updateTile(tile, map[z || 0], x, y);
|
|
404
|
-
|
|
405
|
-
// cached region. Changes outside the cache will be drawn correctly
|
|
406
|
-
// the next time the camera pans to include them.
|
|
407
|
-
if (!this.cache.empty &&
|
|
408
|
-
x >= this.cache.left && x <= this.cache.right &&
|
|
409
|
-
y >= this.cache.top && y <= this.cache.bottom) {
|
|
410
|
-
this.updateCache = true;
|
|
411
|
-
}
|
|
440
|
+
this.updateCache = true;
|
|
412
441
|
}
|
|
413
442
|
},
|
|
414
443
|
|
|
@@ -422,70 +451,13 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
422
451
|
},
|
|
423
452
|
|
|
424
453
|
/**
|
|
425
|
-
* Forces an immediate full re-render
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
* For the panning cache, we invalidate cachePixels and re-run the full
|
|
430
|
-
* camera-update recache logic using the last known camera, which correctly
|
|
431
|
-
* handles texture swapping, tile population, and sprite positioning.
|
|
454
|
+
* Forces an immediate full re-render of all cached tile textures.
|
|
455
|
+
* Call this after bulk tile changes to ensure the display is up to date
|
|
456
|
+
* without requiring a camera pan.
|
|
432
457
|
*/
|
|
433
458
|
"force-render": function () {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
this.populateTiles(this.cache, null);
|
|
437
|
-
this.renderCache(this.cache, this.cacheTexture, this.mapContainer, this.mapContainerWrapper);
|
|
438
|
-
} else if (this.cacheTexture) {
|
|
439
|
-
// Panning cache — invalidate cachePixels so the recache branch
|
|
440
|
-
// runs, then execute the full camera-update recache inline.
|
|
441
|
-
const
|
|
442
|
-
{viewport: vp} = this.owner.parent.worldCamera,
|
|
443
|
-
{cache, cachePixels} = this,
|
|
444
|
-
tempC = tempCache,
|
|
445
|
-
ctw = this.cacheTilesWidth - 1,
|
|
446
|
-
cth = this.cacheTilesHeight - 1,
|
|
447
|
-
ctw2 = ctw / 2,
|
|
448
|
-
cth2 = cth / 2;
|
|
449
|
-
|
|
450
|
-
this.convertCamera(vp);
|
|
451
|
-
|
|
452
|
-
// Force the recache branch to run regardless of camera position.
|
|
453
|
-
cachePixels.empty = true;
|
|
454
|
-
|
|
455
|
-
tempC.setAll(
|
|
456
|
-
Math.round((this.laxCam.x - this.left) / this.tileWidth - ctw2) + ctw2,
|
|
457
|
-
Math.round((this.laxCam.y - this.top) / this.tileHeight - cth2) + cth2,
|
|
458
|
-
ctw, cth
|
|
459
|
-
);
|
|
460
|
-
if (tempC.left < 0) {
|
|
461
|
-
tempC.moveX(tempC.halfWidth);
|
|
462
|
-
} else if (tempC.right > this.tilesWidth - 1) {
|
|
463
|
-
tempC.moveX(this.tilesWidth - 1 - tempC.halfWidth);
|
|
464
|
-
}
|
|
465
|
-
if (tempC.top < 0) {
|
|
466
|
-
tempC.moveY(tempC.halfHeight);
|
|
467
|
-
} else if (tempC.bottom > this.tilesHeight - 1) {
|
|
468
|
-
tempC.moveY(this.tilesHeight - 1 - tempC.halfHeight);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
this.tilesSpriteCache.texture = this.cacheTexture;
|
|
472
|
-
this.cacheTexture = this.cacheTexture.alternate;
|
|
473
|
-
this.tilesSprite.texture = this.cacheTexture;
|
|
474
|
-
|
|
475
|
-
this.populateTiles(tempC, cache);
|
|
476
|
-
this.renderCache(tempC, this.cacheTexture, this.mapContainer, this.mapContainerWrapper, this.tilesSpriteCache);
|
|
477
|
-
cache.set(tempC);
|
|
478
|
-
|
|
479
|
-
cachePixels.setAll(
|
|
480
|
-
(cache.x + 0.5) * this.tileWidth + this.left,
|
|
481
|
-
(cache.y + 0.5) * this.tileHeight + this.top,
|
|
482
|
-
(cache.width + 1) * this.tileWidth,
|
|
483
|
-
(cache.height + 1) * this.tileHeight
|
|
484
|
-
);
|
|
485
|
-
|
|
486
|
-
this.tilesSprite.x = vp.left - this.laxCam.left + cache.left * this.tileWidth + this.left;
|
|
487
|
-
this.tilesSprite.y = vp.top - this.laxCam.top + cache.top * this.tileHeight + this.top;
|
|
488
|
-
}
|
|
459
|
+
this.refreshAllCaches();
|
|
460
|
+
this.updateCache = false;
|
|
489
461
|
}
|
|
490
462
|
},
|
|
491
463
|
|
|
@@ -535,8 +507,7 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
535
507
|
'handle-render': function () {
|
|
536
508
|
if (this.updateCache) {
|
|
537
509
|
this.updateCache = false;
|
|
538
|
-
this.
|
|
539
|
-
this.renderCache(this.cache, this.cacheTexture, this.mapContainer, this.mapContainerWrapper);
|
|
510
|
+
this.refreshAllCaches();
|
|
540
511
|
}
|
|
541
512
|
}
|
|
542
513
|
});
|
|
@@ -596,21 +567,8 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
596
567
|
},
|
|
597
568
|
'handle-render': function () {
|
|
598
569
|
if (this.updateCache) {
|
|
599
|
-
const
|
|
600
|
-
{cache, cacheGrid, cacheTilesHeight, cacheTilesWidth, tilesHeight, tilesWidth} = this,
|
|
601
|
-
tsh = tilesHeight - 1,
|
|
602
|
-
tsw = tilesWidth - 1;
|
|
603
|
-
|
|
604
570
|
this.updateCache = false;
|
|
605
|
-
|
|
606
|
-
for (let x = 0; x < cacheGrid.length; x++) {
|
|
607
|
-
for (let y = 0; y < cacheGrid[x].length; y++) {
|
|
608
|
-
cache.setBounds(x * cacheTilesWidth, y * cacheTilesHeight, Math.min((x + 1) * cacheTilesWidth, tsw), Math.min((y + 1) * cacheTilesHeight, tsh));
|
|
609
|
-
|
|
610
|
-
this.populateTiles(cache, null);
|
|
611
|
-
this.renderCacheWithExtrusion(cache, cacheGrid[x][y].texture, this.mapContainer, this.mapContainerWrapper);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
571
|
+
this.refreshAllCaches();
|
|
614
572
|
}
|
|
615
573
|
}
|
|
616
574
|
});
|
|
@@ -663,24 +621,7 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
663
621
|
this.updateBufferRegion(laxCam);
|
|
664
622
|
}
|
|
665
623
|
|
|
666
|
-
|
|
667
|
-
ctw = this.cacheTilesWidth - 1,
|
|
668
|
-
cth = this.cacheTilesHeight - 1,
|
|
669
|
-
ctw2 = ctw / 2,
|
|
670
|
-
cth2 = cth / 2;
|
|
671
|
-
|
|
672
|
-
//only attempt to draw children that are relevant
|
|
673
|
-
tempC.setAll(Math.round((laxCam.x - this.left) / this.tileWidth - ctw2) + ctw2, Math.round((laxCam.y - this.top) / this.tileHeight - cth2) + cth2, ctw, cth);
|
|
674
|
-
if (tempC.left < 0) {
|
|
675
|
-
tempC.moveX(tempC.halfWidth);
|
|
676
|
-
} else if (tempC.right > this.tilesWidth - 1) {
|
|
677
|
-
tempC.moveX(this.tilesWidth - 1 - tempC.halfWidth);
|
|
678
|
-
}
|
|
679
|
-
if (tempC.top < 0) {
|
|
680
|
-
tempC.moveY(tempC.halfHeight);
|
|
681
|
-
} else if (tempC.bottom > this.tilesHeight - 1) {
|
|
682
|
-
tempC.moveY(this.tilesHeight - 1 - tempC.halfHeight);
|
|
683
|
-
}
|
|
624
|
+
this.alignCacheToCamera(tempC, vp);
|
|
684
625
|
|
|
685
626
|
this.tilesSpriteCache.texture = this.cacheTexture;
|
|
686
627
|
this.cacheTexture = this.cacheTexture.alternate;
|
|
@@ -698,17 +639,9 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
698
639
|
this.tilesSprite.y = vp.top - laxCam.top + cache.top * this.tileHeight + this.top;
|
|
699
640
|
},
|
|
700
641
|
'handle-render': function () {
|
|
701
|
-
if (this.updateCache
|
|
642
|
+
if (this.updateCache) {
|
|
702
643
|
this.updateCache = false;
|
|
703
|
-
this.
|
|
704
|
-
this.renderCacheClear(this.cache, this.cacheTexture, this.mapContainer, this.mapContainerWrapper);
|
|
705
|
-
this.tilesSpriteCache.texture = this.cacheTexture;
|
|
706
|
-
this.cachePixels.setAll(
|
|
707
|
-
(this.cache.x + 0.5) * this.tileWidth + this.left,
|
|
708
|
-
(this.cache.y + 0.5) * this.tileHeight + this.top,
|
|
709
|
-
(this.cache.width + 1) * this.tileWidth,
|
|
710
|
-
(this.cache.height + 1) * this.tileHeight
|
|
711
|
-
);
|
|
644
|
+
this.refreshAllCaches();
|
|
712
645
|
}
|
|
713
646
|
}
|
|
714
647
|
});
|
|
@@ -746,24 +679,7 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
746
679
|
this.updateBufferRegion(laxCam);
|
|
747
680
|
}
|
|
748
681
|
|
|
749
|
-
|
|
750
|
-
ctw = this.cacheTilesWidth - 1,
|
|
751
|
-
cth = this.cacheTilesHeight - 1,
|
|
752
|
-
ctw2 = ctw / 2,
|
|
753
|
-
cth2 = cth / 2;
|
|
754
|
-
|
|
755
|
-
//only attempt to draw children that are relevant
|
|
756
|
-
tempC.setAll(Math.round((laxCam.x - this.left) / this.tileWidth - ctw2) + ctw2, Math.round((laxCam.y - this.top) / this.tileHeight - cth2) + cth2, ctw, cth);
|
|
757
|
-
if (tempC.left < 0) {
|
|
758
|
-
tempC.moveX(tempC.halfWidth);
|
|
759
|
-
} else if (tempC.right > this.tilesWidth - 1) {
|
|
760
|
-
tempC.moveX(this.tilesWidth - 1 - tempC.halfWidth);
|
|
761
|
-
}
|
|
762
|
-
if (tempC.top < 0) {
|
|
763
|
-
tempC.moveY(tempC.halfHeight);
|
|
764
|
-
} else if (tempC.bottom > this.tilesHeight - 1) {
|
|
765
|
-
tempC.moveY(this.tilesHeight - 1 - tempC.halfHeight);
|
|
766
|
-
}
|
|
682
|
+
this.alignCacheToCamera(tempC, vp);
|
|
767
683
|
|
|
768
684
|
this.populateTiles(tempC, null);
|
|
769
685
|
cache.set(tempC);
|
|
@@ -873,6 +789,10 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
873
789
|
* its world travel, laxCam is at the start of the layer's travel, and
|
|
874
790
|
* likewise at the end.
|
|
875
791
|
*
|
|
792
|
+
* Tiled `parallaxx` / `parallaxy` factors are then applied relative to the
|
|
793
|
+
* map's parallax origin so the layer's effective render position is:
|
|
794
|
+
* `layerPos - (camera - parallaxOrigin) * (1 - parallaxFactor)`.
|
|
795
|
+
*
|
|
876
796
|
* IMPORTANT: laxCam is resized to the *actual viewport dimensions* (not
|
|
877
797
|
* viewport + refreshBuffer). Its purpose is solely to compute the parallax
|
|
878
798
|
* offset for sprite positioning (vp.left - laxCam.left). Inflating it with
|
|
@@ -885,7 +805,8 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
885
805
|
worldPosX = worldWidth - camera.width,
|
|
886
806
|
worldHeight = this.worldHeight / this.scaleY,
|
|
887
807
|
worldPosY = worldHeight - camera.height,
|
|
888
|
-
laxCam = this.laxCam
|
|
808
|
+
laxCam = this.laxCam,
|
|
809
|
+
{parallaxOriginX, parallaxOriginY, parallaxX, parallaxY} = this;
|
|
889
810
|
|
|
890
811
|
if ((worldWidth === this.layerWidth) || !worldPosX) {
|
|
891
812
|
laxCam.moveX(camera.x);
|
|
@@ -899,6 +820,14 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
899
820
|
laxCam.moveY((camera.top - this.top) * (this.layerHeight - camera.height) / worldPosY + camera.halfHeight + this.top);
|
|
900
821
|
}
|
|
901
822
|
|
|
823
|
+
if (parallaxX !== 1) {
|
|
824
|
+
laxCam.moveX(laxCam.x + (camera.x - parallaxOriginX) * (1 - parallaxX));
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if (parallaxY !== 1) {
|
|
828
|
+
laxCam.moveY(laxCam.y + (camera.y - parallaxOriginY) * (1 - parallaxY));
|
|
829
|
+
}
|
|
830
|
+
|
|
902
831
|
// FIX: resize laxCam to the actual viewport size only — never camera + refreshBuffer.
|
|
903
832
|
if (camera.width !== laxCam.width || camera.height !== laxCam.height) {
|
|
904
833
|
laxCam.resize(camera.width, camera.height);
|
|
@@ -1030,7 +959,151 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
1030
959
|
this.mapContainer.mask = new Graphics().rect(0, 0, this.cacheClipWidth, this.cacheClipHeight).fill(0x000000);
|
|
1031
960
|
},
|
|
1032
961
|
|
|
962
|
+
/**
|
|
963
|
+
* Computes tile bounds for the panning cache centered on the current camera.
|
|
964
|
+
*
|
|
965
|
+
* @param {platypus.AABB} bounds - Receives the computed tile bounds.
|
|
966
|
+
* @param {platypus.AABB} viewport - The camera viewport.
|
|
967
|
+
*/
|
|
968
|
+
alignCacheToCamera: function (bounds, viewport) {
|
|
969
|
+
const
|
|
970
|
+
ctw = this.cacheTilesWidth - 1,
|
|
971
|
+
cth = this.cacheTilesHeight - 1,
|
|
972
|
+
ctw2 = ctw / 2,
|
|
973
|
+
cth2 = cth / 2;
|
|
974
|
+
|
|
975
|
+
this.convertCamera(viewport);
|
|
976
|
+
|
|
977
|
+
bounds.setAll(
|
|
978
|
+
Math.round((this.laxCam.x - this.left) / this.tileWidth - ctw2) + ctw2,
|
|
979
|
+
Math.round((this.laxCam.y - this.top) / this.tileHeight - cth2) + cth2,
|
|
980
|
+
ctw, cth
|
|
981
|
+
);
|
|
982
|
+
|
|
983
|
+
if (bounds.left < 0) {
|
|
984
|
+
bounds.moveX(bounds.halfWidth);
|
|
985
|
+
} else if (bounds.right > this.tilesWidth - 1) {
|
|
986
|
+
bounds.moveX(this.tilesWidth - 1 - bounds.halfWidth);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
if (bounds.top < 0) {
|
|
990
|
+
bounds.moveY(bounds.halfHeight);
|
|
991
|
+
} else if (bounds.bottom > this.tilesHeight - 1) {
|
|
992
|
+
bounds.moveY(this.tilesHeight - 1 - bounds.halfHeight);
|
|
993
|
+
}
|
|
994
|
+
},
|
|
995
|
+
|
|
996
|
+
/**
|
|
997
|
+
* Re-renders every texture in a multi-texture full-map cache grid.
|
|
998
|
+
*/
|
|
999
|
+
refreshAllCacheGrid: function () {
|
|
1000
|
+
const
|
|
1001
|
+
{cache, cacheGrid, cacheTilesHeight, cacheTilesWidth, tilesHeight, tilesWidth} = this,
|
|
1002
|
+
tsh = tilesHeight - 1,
|
|
1003
|
+
tsw = tilesWidth - 1;
|
|
1004
|
+
|
|
1005
|
+
for (let x = 0; x < cacheGrid.length; x++) {
|
|
1006
|
+
for (let y = 0; y < cacheGrid[x].length; y++) {
|
|
1007
|
+
cache.setBounds(
|
|
1008
|
+
x * cacheTilesWidth,
|
|
1009
|
+
y * cacheTilesHeight,
|
|
1010
|
+
Math.min((x + 1) * cacheTilesWidth, tsw),
|
|
1011
|
+
Math.min((y + 1) * cacheTilesHeight, tsh)
|
|
1012
|
+
);
|
|
1013
|
+
|
|
1014
|
+
this.populate(cache, null);
|
|
1015
|
+
this.renderCacheWithExtrusion(cache, cacheGrid[x][y].texture, this.mapContainer, this.mapContainerWrapper);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
},
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Re-renders the current panning-cache window in place.
|
|
1022
|
+
* Uses the alternate render texture while drawing so we never render
|
|
1023
|
+
* into the texture that is currently displayed on screen.
|
|
1024
|
+
*
|
|
1025
|
+
* @param {platypus.AABB} [viewport] - Optional camera viewport.
|
|
1026
|
+
*/
|
|
1027
|
+
refreshPanningCache: function (viewport) {
|
|
1028
|
+
const
|
|
1029
|
+
{cache, cachePixels, laxCam, left, top, tilesSprite} = this,
|
|
1030
|
+
vp = viewport ?? this.owner.parent.worldCamera?.viewport;
|
|
1031
|
+
|
|
1032
|
+
if (!vp) {
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
if (cache.empty) {
|
|
1037
|
+
this.alignCacheToCamera(cache, vp);
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
if (cache.empty) {
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
this.detachCacheCopy();
|
|
1045
|
+
|
|
1046
|
+
this.tilesSpriteCache.texture = this.cacheTexture;
|
|
1047
|
+
this.cacheTexture = this.cacheTexture.alternate;
|
|
1048
|
+
tilesSprite.texture = this.cacheTexture;
|
|
1049
|
+
|
|
1050
|
+
this.populate(cache, null);
|
|
1051
|
+
this.renderCacheClear(cache, this.cacheTexture, this.mapContainer, this.mapContainerWrapper);
|
|
1052
|
+
|
|
1053
|
+
this.tilesSpriteCache.texture = this.cacheTexture;
|
|
1054
|
+
cachePixels.setAll(
|
|
1055
|
+
(cache.x + 0.5) * this.tileWidth + left,
|
|
1056
|
+
(cache.y + 0.5) * this.tileHeight + top,
|
|
1057
|
+
(cache.width + 1) * this.tileWidth,
|
|
1058
|
+
(cache.height + 1) * this.tileHeight
|
|
1059
|
+
);
|
|
1060
|
+
|
|
1061
|
+
this.convertCamera(vp);
|
|
1062
|
+
tilesSprite.x = vp.left - laxCam.left + cache.left * this.tileWidth + left;
|
|
1063
|
+
tilesSprite.y = vp.top - laxCam.top + cache.top * this.tileHeight + top;
|
|
1064
|
+
},
|
|
1065
|
+
|
|
1066
|
+
detachCacheCopy: function () {
|
|
1067
|
+
const
|
|
1068
|
+
{mapContainer, tilesSpriteCache} = this;
|
|
1069
|
+
|
|
1070
|
+
if (tilesSpriteCache?.parent === mapContainer) {
|
|
1071
|
+
mapContainer.removeChild(tilesSpriteCache);
|
|
1072
|
+
}
|
|
1073
|
+
},
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Re-renders all cached tile textures for the active caching strategy.
|
|
1077
|
+
*
|
|
1078
|
+
* @param {platypus.AABB} [viewport] - Optional camera viewport for panning caches.
|
|
1079
|
+
*/
|
|
1080
|
+
refreshAllCaches: function (viewport) {
|
|
1081
|
+
if (!this.tileCache) {
|
|
1082
|
+
this.cachePixels.empty = true;
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
if (this.cacheGrid) {
|
|
1087
|
+
this.refreshAllCacheGrid();
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
if (this.cacheAll && this.cacheTexture) {
|
|
1092
|
+
this.populate(this.cache, null);
|
|
1093
|
+
this.render(this.cache, this.cacheTexture, this.mapContainer, this.mapContainerWrapper);
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
if (this.cacheTexture) {
|
|
1098
|
+
this.refreshPanningCache(viewport);
|
|
1099
|
+
}
|
|
1100
|
+
},
|
|
1101
|
+
|
|
1033
1102
|
populateTiles: function (bounds, oldBounds) {
|
|
1103
|
+
// When oldBounds is provided, only tiles outside the previous window are
|
|
1104
|
+
// drawn. That is correct for camera scrolling (reuse pixels from the old
|
|
1105
|
+
// cache texture) but must not be used for in-place tile edits — pass null
|
|
1106
|
+
// to redraw the entire bounds.
|
|
1034
1107
|
const
|
|
1035
1108
|
tiles = arrayCache.setUp();
|
|
1036
1109
|
|
|
@@ -1145,6 +1218,11 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
1145
1218
|
container: wrapper,
|
|
1146
1219
|
target: renderTexture
|
|
1147
1220
|
});
|
|
1221
|
+
|
|
1222
|
+
if (oldCache?.parent === src) {
|
|
1223
|
+
src.removeChild(oldCache);
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1148
1226
|
renderTexture.requiresUpdate = true;
|
|
1149
1227
|
},
|
|
1150
1228
|
|
|
@@ -1152,6 +1230,8 @@ export default createComponentClass(/** @lends platypus.components.RenderTiles.p
|
|
|
1152
1230
|
const
|
|
1153
1231
|
{renderer} = this;
|
|
1154
1232
|
|
|
1233
|
+
this.detachCacheCopy();
|
|
1234
|
+
|
|
1155
1235
|
src.x = -bounds.left * this.tileWidth;
|
|
1156
1236
|
src.y = -bounds.top * this.tileHeight;
|
|
1157
1237
|
renderer.render({
|
|
@@ -699,7 +699,7 @@ export default createComponentClass(/** @lends platypus.components.TiledLoader.p
|
|
|
699
699
|
},
|
|
700
700
|
|
|
701
701
|
methods: {
|
|
702
|
-
createLayer: function (entityKind, rawLayer, offsetX, offsetY, tileWidth, tileHeight, tilesets, tileSetTileData, images, combineRenderLayer, progress, entityLinker) {
|
|
702
|
+
createLayer: function (entityKind, rawLayer, offsetX, offsetY, tileWidth, tileHeight, tilesets, tileSetTileData, images, combineRenderLayer, progress, entityLinker, parallaxOriginX, parallaxOriginY) {
|
|
703
703
|
const
|
|
704
704
|
//This builds in parallaxing support by allowing the addition of width and height properties into Tiled layers so they pan at a separate rate than other layers.
|
|
705
705
|
checkParallax = ({data, height, properties, width}) => {
|
|
@@ -730,6 +730,8 @@ export default createComponentClass(/** @lends platypus.components.TiledLoader.p
|
|
|
730
730
|
},
|
|
731
731
|
|
|
732
732
|
layer = decodeLayer(rawLayer),
|
|
733
|
+
parallaxX = layer.parallaxx ?? 1,
|
|
734
|
+
parallaxY = layer.parallaxy ?? 1,
|
|
733
735
|
{
|
|
734
736
|
offsetx: layerOffsetX = 0,
|
|
735
737
|
offsety: layerOffsetY = 0,
|
|
@@ -835,6 +837,10 @@ export default createComponentClass(/** @lends platypus.components.TiledLoader.p
|
|
|
835
837
|
layerDefinitionProperties.left = layerDefinitionProperties.x || mapOffsetX;
|
|
836
838
|
layerDefinitionProperties.top = layerDefinitionProperties.y || mapOffsetY;
|
|
837
839
|
layerDefinitionProperties.z = layerDefinitionProperties.z || this.layerZ;
|
|
840
|
+
layerDefinitionProperties.parallaxX = parallaxX;
|
|
841
|
+
layerDefinitionProperties.parallaxY = parallaxY;
|
|
842
|
+
layerDefinitionProperties.parallaxOriginX = parallaxOriginX;
|
|
843
|
+
layerDefinitionProperties.parallaxOriginY = parallaxOriginY;
|
|
838
844
|
|
|
839
845
|
if (tilesets.length) {
|
|
840
846
|
let imageIndex = 0;
|
|
@@ -910,7 +916,7 @@ export default createComponentClass(/** @lends platypus.components.TiledLoader.p
|
|
|
910
916
|
}
|
|
911
917
|
}
|
|
912
918
|
|
|
913
|
-
if ((!this.separateTiles) && (combineRenderLayer?.tileHeight === tHeight) && (combineRenderLayer?.tileWidth === tWidth) && (combineRenderLayer?.columns === width) && (combineRenderLayer?.rows === height)) {
|
|
919
|
+
if ((!this.separateTiles) && (combineRenderLayer?.parallaxX ?? 1) === parallaxX && (combineRenderLayer?.parallaxY ?? 1) === parallaxY && (combineRenderLayer?.tileHeight === tHeight) && (combineRenderLayer?.tileWidth === tWidth) && (combineRenderLayer?.columns === width) && (combineRenderLayer?.rows === height)) {
|
|
914
920
|
combineRenderLayer.triggerEvent('add-tiles', renderTiles);
|
|
915
921
|
combineRenderLayer.triggerEvent('add-collision-tiles', collisionTiles);
|
|
916
922
|
|
|
@@ -998,7 +1004,9 @@ export default createComponentClass(/** @lends platypus.components.TiledLoader.p
|
|
|
998
1004
|
height = level.height * tileHeight,
|
|
999
1005
|
width = level.width * tileWidth,
|
|
1000
1006
|
x = offsetMap ? getPowerOfTen(width) : 0,
|
|
1001
|
-
y = offsetMap ? getPowerOfTen(height) : 0
|
|
1007
|
+
y = offsetMap ? getPowerOfTen(height) : 0,
|
|
1008
|
+
parallaxOriginX = (level.parallaxoriginx ?? 0) + x,
|
|
1009
|
+
parallaxOriginY = (level.parallaxoriginy ?? 0) + y;
|
|
1002
1010
|
let layer = null;
|
|
1003
1011
|
|
|
1004
1012
|
createTilesetObjectGroupReference(tileSetTileData, tilesets);
|
|
@@ -1130,7 +1138,7 @@ export default createComponentClass(/** @lends platypus.components.TiledLoader.p
|
|
|
1130
1138
|
switch (layerDefinition.type) {
|
|
1131
1139
|
case 'imagelayer':
|
|
1132
1140
|
layer = this.convertImageLayer(layerDefinition);
|
|
1133
|
-
layer = this.createLayer(getProperty(layer.properties, 'entity') || 'image-layer', layer, x, y, layer.tilewidth, layer.tileheight, [layer.tileset], null, images, layer, progress, entityLinker);
|
|
1141
|
+
layer = this.createLayer(getProperty(layer.properties, 'entity') || 'image-layer', layer, x, y, layer.tilewidth, layer.tileheight, [layer.tileset], null, images, layer, progress, entityLinker, parallaxOriginX, parallaxOriginY);
|
|
1134
1142
|
break;
|
|
1135
1143
|
case 'objectgroup':
|
|
1136
1144
|
this.setUpEntities(layerDefinition.objects.map((object) => getObjectCentered(object)), layerDefinition, x, y, tilesets, progress, entityLinker);
|
|
@@ -1138,7 +1146,7 @@ export default createComponentClass(/** @lends platypus.components.TiledLoader.p
|
|
|
1138
1146
|
this.updateLoadingProgress(progress);
|
|
1139
1147
|
break;
|
|
1140
1148
|
case 'tilelayer':
|
|
1141
|
-
layer = this.setupLayer(layerDefinition, layer, x, y, tileWidth, tileHeight, tilesets, tileSetTileData, images, progress, entityLinker);
|
|
1149
|
+
layer = this.setupLayer(layerDefinition, layer, x, y, tileWidth, tileHeight, tilesets, tileSetTileData, images, progress, entityLinker, parallaxOriginX, parallaxOriginY);
|
|
1142
1150
|
break;
|
|
1143
1151
|
default:
|
|
1144
1152
|
platypus.debug.warn('Component TiledLoader: Platypus does not support Tiled layers of type "' + layerDefinition.type + '". This layer will not be loaded.');
|
|
@@ -1374,7 +1382,7 @@ export default createComponentClass(/** @lends platypus.components.TiledLoader.p
|
|
|
1374
1382
|
};
|
|
1375
1383
|
}()),
|
|
1376
1384
|
|
|
1377
|
-
setupLayer: function (layer, combineRenderLayer, mapOffsetX, mapOffsetY, tileWidth, tileHeight, tilesets, tileSetTileData, images, progress, entityLinker) {
|
|
1385
|
+
setupLayer: function (layer, combineRenderLayer, mapOffsetX, mapOffsetY, tileWidth, tileHeight, tilesets, tileSetTileData, images, progress, entityLinker, parallaxOriginX, parallaxOriginY) {
|
|
1378
1386
|
const
|
|
1379
1387
|
entity = getProperty(layer.properties, 'entity') ?? 'render-layer', // default
|
|
1380
1388
|
entityDefinition = platypus.game.settings.entities[entity] ?? standardEntityLayers[entity];
|
|
@@ -1393,9 +1401,9 @@ export default createComponentClass(/** @lends platypus.components.TiledLoader.p
|
|
|
1393
1401
|
}
|
|
1394
1402
|
|
|
1395
1403
|
if (canCombine) {
|
|
1396
|
-
return this.createLayer(entity, layer, mapOffsetX, mapOffsetY, tileWidth, tileHeight, tilesets, tileSetTileData, images, combineRenderLayer, progress, entityLinker);
|
|
1404
|
+
return this.createLayer(entity, layer, mapOffsetX, mapOffsetY, tileWidth, tileHeight, tilesets, tileSetTileData, images, combineRenderLayer, progress, entityLinker, parallaxOriginX, parallaxOriginY);
|
|
1397
1405
|
} else {
|
|
1398
|
-
this.createLayer(entity, layer, mapOffsetX, mapOffsetY, tileWidth, tileHeight, tilesets, tileSetTileData, images, combineRenderLayer, progress, entityLinker);
|
|
1406
|
+
this.createLayer(entity, layer, mapOffsetX, mapOffsetY, tileWidth, tileHeight, tilesets, tileSetTileData, images, combineRenderLayer, progress, entityLinker, parallaxOriginX, parallaxOriginY);
|
|
1399
1407
|
return null;
|
|
1400
1408
|
}
|
|
1401
1409
|
},
|