fix(input): account for world offset in pointer events - #1605
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes pointer event hit detection when the root world is offset (e.g., due to flex-height / flex-width centering), ensuring pointer coordinates, bounds checks, and local pointer coordinates use the correct coordinate space for floating vs non-floating renderables.
Changes:
- Adjust pointer candidate retrieval and bounds checks to account for root world offset for non-floating renderables while preserving level-local logic for floating renderables.
- Add regression tests covering both vertical and horizontal world-offset scenarios.
- Ensure test cleanup resets world position between cases.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/melonjs/src/input/pointerevent.ts | Updates pointer event dispatch candidate retrieval and coordinate-space handling to correctly detect hits when the world has a root offset. |
| packages/melonjs/tests/input.spec.js | Adds regression coverage for pointerdown hit detection under flex-induced world offsets and resets world position during cleanup. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| currentPointer.pos.set(absoluteWorldX, absoluteWorldY); | ||
| const absoluteCandidates = _app.world.broadphase.retrieve( | ||
| currentPointer, | ||
| (a: any, b: any) => _app.world._sortReverseZ(a, b), | ||
| undefined, | ||
| ); |
Confirms the reported bug is real and that the fix holds, by reverting `pointerevent.ts` to master and watching these fail: without it the pointer handler is never called at all for a non-floating region in an offset world — not a coordinate drift, a total loss of input. 12 of the 15 new cases fail on master and pass with the fix. The three that pass either way are the regression guards: a floating region, a child of a floating container, and an unshifted world must all behave exactly as before. Covered beyond the original two cases: negative, fractional and both-axis offsets; that a pointer OUTSIDE a shifted region still misses (the fix runs a second broadphase query and merges, so the hazard is a widened net — asserted with a positive control so it cannot pass by never hitting); that `gameWorldX/Y` stay level-local; children of floating containers, since `isFloating` inherits from the ancestor and the fix branches on it; a nested container with its own position; a scrolled camera; z-order between two overlapping regions, since the merged candidate list gets re-sorted; pointermove; and an offset changed after registration. Also pins that no scale method introduces a world offset, at init or through a resize. That is the blast radius: `world.pos` is moved by GAME code to centre a level, never by the engine, so an ordinary game keeps taking the original path in every mode. The bug is therefore not specific to flex-height/flex-width — any non-zero world offset reaches it. Deliberately not asserted: that a click lands on a region under each scale method. Those call `renderer.resize()` against the parent element, which in a headless harness has no meaningful size (the canvas comes out at 800x1731), so such a test measures the harness rather than the engine. Verified separately that behaviour under every mode is identical before and after this change. Adds the CHANGELOG entry, and picks up the biome formatting `pnpm lint` wants on the spec file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
|
Reviewed this, and the bug is real. Thanks for tracking it down — this one is nastier than the title suggests. Confirmed
I checked the failure mode rather than assuming it, by reverting What I pushed to your branch
Beyond the two cases you had:
On regressions in other modesNo behaviour change: scale-method handling is identical before and after, and Which leads to the one thing I would flag about the framing: nothing in the engine ever sets Deliberately not asserted: a click landing on a region under each scale method. Those call Two things left
Also merged current master in, since 20.2.0 landed after you opened this. Full suite on the merged result: 6280 passed, 9 skipped, types and lint clean. |
Bare handle in a trailing `(thanks @user)`, matching every other credited entry in the file, rather than a linked handle inside the leading ref. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
Description
Fix pointer event hit detection when
flex-heightorflex-widthscaling introduces an offset on the root game world.Previously, pointer coordinates and non-floating renderable bounds could use different coordinate spaces. This caused registered pointer events, such as
pointerdown, to become offset from their visual renderables.This change:
flex-heightand horizontalflex-widthworld offsets.Type of change
Checklist
pnpm lintpasses)pnpm testpasses)pnpm build)Related issues
No related issue.