Skip to main content

Cached Surface Layer

Hs2dCachedSurfaceLayer is a custom world-space cache. It creates one world-sized surface, calls a paint callback until it succeeds, and then uses CachedWorldViewportRenderer to crop and scale the active camera viewport to the screen. Once painted, normal frames are viewport blits.

Use cached surfaces for expensive static world content that does not fit tile-layer semantics. They are the correct alternative to raw draw loops for static custom backgrounds, large boards, generated terrain, or pre-rendered world decoration.

When To Use

Use a cached surface when:

Good fitBetter alternative
Static custom world art that is expensive to draw repeatedly.Static tile for grid terrain.
Generated background or board painted once from many primitives.Cached chunk tile for large sparse tile maps.
Content may be unavailable on the first frame and can retry painting.Direct/surface parallax for moving background strips.

If content changes during gameplay, either rebuild the cached layer around explicit dirty events or add a purpose-built dirty region strategy. Do not repaint the whole surface every frame.

Construction Pattern

const terrainCache = world.addCachedSurfaceLayer({
id: 'terrain-cache',
worldWidth,
worldHeight,
surfaceClearColor: 0x00000000,
viewportClearColor: 0x000000ff,
alphaEnable: true,
paint: (surface, helpers) => {
const atlas = this.bitmapCache.getOrCreate(this.terrainAtlasUri);
if (!atlas) return false;

const rock = helpers.createRegion(atlas, 0, 0, 64, 64);
for (let i = 0; i < rocks.length; i++) {
surface.DrawObject(rocks[i].x, rocks[i].y, rock);
}

return true;
},
});

Returning false defers painting. The layer retries on later compose calls until the callback returns true.

Update, Render, And Compose Behavior

PhaseBehavior
AttachNo immediate painting is required.
PaintensurePainted creates the world surface, clears it, and calls paint(surface, helpers) until it returns true.
Update/renderNo normal update or render work.
ComposeCrops the world surface to the active camera viewport, redraws the viewport surface only when camera/scale/viewport/source dimensions changed, then draws that viewport surface to the screen.

The same layer also exposes drawViewport(...) for standalone render loops outside an Hs2dWorld.

Performance Notes

  • Keep world surface dimensions within target device memory limits.
  • Paint once or on explicit dirty events, never as a hidden frame-loop draw routine.
  • Use helpers.createRegion for source atlas regions.
  • Watch getViewportRedraws() to confirm static cameras are reusing the viewport surface.
  • Prefer tile-specific layers for tile maps because they expose tile stats and builder integration.

Code Sample

protected override buildWorld(): Hs2dWorld {
const world = Hs2dWorld.create({
x: this.cameraX,
y: this.cameraY,
viewportWidth: this.screenWidth,
viewportHeight: this.screenHeight,
worldWidth: this.worldWidth,
worldHeight: this.worldHeight,
});

world.addCachedSurfaceLayer({
id: 'static-decor',
worldWidth: this.worldWidth,
worldHeight: this.worldHeight,
surfaceClearColor: 0x00000000,
paint: (surface, helpers) => this.paintDecorSurface(surface, helpers),
});

return world;
}

Source References

SourceWhy it matters
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dCachedSurfaceLayer.tsCached surface options, paint retry, drawViewport, compose behavior, and custom layer neighbor type.
../games/hosanna-ui/src/hosanna-game/scene/CachedWorldViewportRenderer.tsViewport surface creation, camera crop, scale redraw checks, and viewport redraw counters.
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dWorld.tsaddCachedSurfaceLayer world API.
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dStaticTileLayer.tsSimilar whole-world cache approach for tile maps.
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dChunkedTileLayer.tsChunked cache alternative for large tile maps.
Talk to us