Skip to main content

Minimap And Core Utilities

Hosanna Game includes focused utilities for common game-loop problems. They are deliberately allocation-conscious and do not decide your game rules.

Minimap

Hs2dMiniMap projects a world rectangle into a screen-space map. It supports a full-world view or a scrollable world viewport, a baked terrain surface, styled live markers, blinking and edge clamping, heading markers, and a camera-view outline.

Create and prepare it during level setup:

const minimap = new Hs2dMiniMap({
x: 24,
y: 520,
width: 220,
height: 160,
worldWidth,
worldHeight,
backgroundColor: 0x0b1220ff,
borderColor: 0x334155ff,
borderWidth: 2,
});

const playerStyle = minimap.defineMarkerStyle({
color: 0xffffffff,
size: 8,
});
const objectiveStyle = minimap.defineMarkerStyle({
color: 0xfacc15ff,
size: 7,
blinkPeriodMs: 600,
});

At level-build time, optionally call beginBackgroundPaint(fillColor, alphaEnabled?) and paint static world rectangles with paintBackgroundRect(...). At runtime:

  1. call update(deltaMs) once;
  2. call draw(screen) for the frame and baked terrain;
  3. call drawMarker() or drawHeadingMarker() for live entities;
  4. optionally draw the camera viewport.

Do not repaint static terrain each frame. If surface allocation fails, draw() falls back to the configured flat background.

For a scrolling minimap, the baked surface covers the full world at the minimap viewport's projection scale, not just the visible map rectangle. Check the resulting surface dimensions against the target device's texture limits; omit the bake or use a game-specific segmented background when that surface would be too large.

The vertical shooter uses a deliberately non-uniform narrow radar strip. Hosanna Dungeon preserves the dungeon aspect ratio and draws several marker classes. Both are valid uses of the same projection API.

Deterministic Random Numbers

Hs2dLcg is a seeded Park–Miller generator:

const random = new Hs2dLcg(levelSeed);
const chance = random.nextFloat(); // [0, 1)
const x = random.nextRange(minX, maxX); // [minX, maxX)
const lane = random.nextInt(0, 4); // 0, 1, 2, or 3

Keep one explicit generator per deterministic simulation stream. Resetting to the same nonzero-normalized seed reproduces the sequence.

Logical Entity Pools

Hs2dEntityPool<T> allocates every logical slot in its constructor. It owns activation and deactivation, not entity behavior:

const projectiles = new Hs2dEntityPool({
id: 'projectiles',
capacity: 64,
create: (index) => ({ index, active: false, x: 0, y: 0 }),
onDeactivate: (projectile) => parkProjectileSprite(projectile.index),
});

Systems iterate the stable items array and skip inactive slots. When reuseOldestWhenFull is enabled, activate() reuses a slot; otherwise it returns undefined at capacity.

Despite the option name, the current implementation rotates through slots on full-pool reuse; it does not record and compare activation ages. The initial full-pool sequence behaves oldest-first because slots were activated in index order, but later deactivate/reactivate patterns can diverge. Depend on bounded reuse, not strict age ordering, unless the engine adds activation timestamps.

This is a logical pool. Use Hs2dSpritePool or a direct-sprite group for the corresponding render objects.

Shared Grid Flow Field

GridFlowField builds one breadth-first distance field toward a target tile so many agents can share the result. Prefer a retained row-major blockedCells mask on device:

const field = new GridFlowField({
width: columns,
height: rows,
blockedCells,
});

const isReady = field.rebuild(targetCellX, targetCellY, 96);

if (field.stepToward(enemyCellX, enemyCellY, scratchStep)) {
enemy.moveX = scratchStep.x;
enemy.moveY = scratchStep.y;
}

The optional rebuild budget spreads work over simulation steps. Call rebuild() again with the same target until it returns true; each call continues the unfinished breadth-first search. stepToward() writes into the caller's object and returns false for the target, unreachable cells, or cells not reached by an incomplete build. Call invalidate() after mutating the retained blocked mask.

Source References

SourceWhat it proves
../games/hosanna-ui/src/hosanna-game/core/Hs2dMiniMap.tsProjection, viewport scrolling, baked surface, styles, markers, heading, and camera outline.
../games/hosanna-ui/src/hosanna-game/core/Hs2dLcg.tsSeed normalization and deterministic number ranges.
../games/hosanna-ui/src/hosanna-game/core/Hs2dEntityPool.tsFixed logical slots, activation, callbacks, reuse, and stats.
../games/hosanna-ui/src/hosanna-game/tile-map/GridFlowField.tsRetained mask, budgeted BFS, invalidation, and allocation-free gradient steps.
../hosanna-ui-game-samples-public/src/hosanna-game-examples/native-shoot-em-up/VerticalShooterLevelScene.tsRadar-style minimap and deterministic gameplay random source.
Talk to us