Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add buffer bounds in TileMap #3389

Open
nionis opened this issue Mar 30, 2025 · 6 comments · May be fixed by #3406
Open

add buffer bounds in TileMap #3389

nionis opened this issue Mar 30, 2025 · 6 comments · May be fixed by #3406
Labels
bug This issue describes undesirable, incorrect, or unexpected behavior

Comments

@nionis
Copy link

nionis commented Mar 30, 2025

Context

Tiles can be clipped/culled while they are still visible on the screen.
This is reproducible when using tiles that are large (>100px).

public getOnScreenTiles(): readonly Tile[] {
let worldBounds = this._engine.screen.getWorldBounds();
const maybeParallax = this.get(ParallaxComponent);
if (maybeParallax && this.isInitialized) {
let pos = this.pos;
const oneMinusFactor = Vector.One.sub(maybeParallax.parallaxFactor);
const parallaxOffset = this._engine.currentScene.camera.pos.scale(oneMinusFactor);
pos = pos.sub(parallaxOffset);
// adjust world bounds by parallax factor
worldBounds = worldBounds.translate(pos);
}
const bounds = this.transform.coordPlane === CoordPlane.Screen ? this._engine.screen.getScreenBounds() : worldBounds;
const topLeft = this._getTileCoordinates(bounds.topLeft);
const topRight = this._getTileCoordinates(bounds.topRight);
const bottomRight = this._getTileCoordinates(bounds.bottomRight);
const bottomLeft = this._getTileCoordinates(bounds.bottomLeft);
const tileStartX = Math.min(clamp(topLeft.x, 0, this.columns - 1), clamp(topRight.x, 0, this.columns - 1));
const tileStartY = Math.min(clamp(topLeft.y, 0, this.rows - 1), clamp(topRight.y, 0, this.rows - 1));
const tileEndX = Math.max(clamp(bottomRight.x, 0, this.columns - 1), clamp(bottomLeft.x, 0, this.columns - 1));
const tileEndY = Math.max(clamp(bottomRight.y, 0, this.rows - 1), clamp(bottomLeft.y, 0, this.rows - 1));
const tiles: Tile[] = [];
for (let x = tileStartX; x <= tileEndX; x++) {
for (let y = tileStartY; y <= tileEndY; y++) {
tiles.push(this.getTile(x, y)!);
}
}
return tiles;
}

Example:
Image

Sloppy workaround:

diff --git a/node_modules/excalibur/build/esm/excalibur.development.js b/node_modules/excalibur/build/esm/excalibur.development.js
index 389aa28..7fee118 100644
--- a/node_modules/excalibur/build/esm/excalibur.development.js
+++ b/node_modules/excalibur/build/esm/excalibur.development.js
@@ -38001,6 +38001,7 @@ class TileMap extends _EntityComponentSystem_Entity__WEBPACK_IMPORTED_MODULE_0__
      * Useful if you need to perform specific logic on onscreen tiles
      */
     getOnScreenTiles() {
+        return this.tiles;
         let worldBounds = this._engine.screen.getWorldBounds();
         const maybeParallax = this.get(_Graphics__WEBPACK_IMPORTED_MODULE_15__.ParallaxComponent);
         if (maybeParallax && this.isInitialized) {

Fixed:

Image

Proposal

Find a way to take that into account or add some buffering.

@eonarheim
Copy link
Member

@nionis Good find, this looks like a bug! I wonder why this is happening with large tiles in theory the math should have been correct

@eonarheim eonarheim added the bug This issue describes undesirable, incorrect, or unexpected behavior label Apr 3, 2025
@eonarheim
Copy link
Member

@nionis Would you be able to share some more details, I think something else might be happening to cause this. I've tweaked my integration test to have 320px tiles and I'm not able to get the bug. Perhaps engine configuration or camera orientation?

https://github.com/excaliburjs/Excalibur/tree/main/sandbox/tests/tilemap

var tm = new ex.TileMap({
  pos: ex.vec(-300, -300),
  tileWidth: 16 * 20,
  tileHeight: 16 * 20,
  columns: 40,
  rows: 40
});
var tileSprite = ss.sprites[0];
tileSprite.destSize.width = 320;
tileSprite.destSize.height = 320;
tilemap-bug.mp4

@eonarheim
Copy link
Member

I noticed today that including parallax on the tilemap produces incorrect culling

@nionis
Copy link
Author

nionis commented Apr 3, 2025

@eonarheim does tiledplugin enable parallax for whatever reason? - meanwhile I will try to reproduce it and get back to you

FYI: the map was imported via tiledplugin, display mode FillScreen, nothing else in my engine config

@eonarheim
Copy link
Member

The plugin will add parallax if the layer has the parallaxx/parallaxy properties set.

I've pushed up a maybe fix for this (certainly it was a bug for culling w/ parallax enabled)

@nionis
Copy link
Author

nionis commented Apr 4, 2025

I can confirm this fixed my issue!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue describes undesirable, incorrect, or unexpected behavior
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants