← Back to home
Workshop series

Gameplay Physics Is Responsive Too

Adaptive Layout for a Poki HTML5 Game Section 7 of 11

11. Gameplay Physics Is Responsive Too

A common mistake in HTML5 games: UI is responsive, but gameplay logic still uses old bounds.

In Stickers Merge, physics bounds are recalculated when the screen changes.

LevelPhysicsBoundsResolver uses current virtual size and layout:

const virtualSize = this.screen.getVirtualSize();
const leftInset = this.screen.getOrientation() === 'land'
  ? this.resolveLandLeftInset(layout, virtualSize)
  : 0;

const localTopLeft = playfield.view.toLocal({ x: leftInset, y: 0 }, root.view);
const localTopRight = playfield.view.toLocal({ x: virtualSize.width, y: 0 }, root.view);
const localBottomLeft = playfield.view.toLocal({ x: leftInset, y: virtualSize.height }, root.view);

In landscape, bounds start after the left panel. In portrait, bounds start at zero because the panel is at the bottom.

On SCREEN_CHANGED, the FSM runs:

[SharedUiEvents.ScreenChanged]: {
  actions: ['RebuildLevelStickersOnResizeCommand'],
},

The command calls:

await this.getSceneService<LevelStickerResizeRebuildService>(
  GameServices.LevelStickerResizeRebuildService,
).rebuildFromCurrentScene({
  layout: this.layout,
  stickersLayer: this.getStickersLayer(),
});

The service:

  • cleans up active drag;
  • captures current sticker state;
  • recalculates physics bounds;
  • removes old physics bodies;
  • spawns stickers again in the new layout;
  • warms up the physics simulation;
  • marks stickers as settled.
const stickersSnapshot = this.captureSnapshot();
this.physics.setBounds(this.boundsResolver.resolveFromLayout(params.layout));
await this.mergeService.consumeManyByIds(stickersSnapshot.map((entry) => entry.id));

const respawnedRecords = await this.spawnFlowService.spawnBatch({
  layer: params.stickersLayer,
  physics: this.physics,
  registrar: this.registrar,
  entries: stickersSnapshot,
  mode: 'packed_visible',
});

Responsive gameplay means visual resize is not enough. Physics, spawn positions, collision bounds, and drag state must respond too.