Issue #5: Mouse handling — zoom-to-mouse + middle-click pan #10

Merged
tekki merged 21 commits from feature/mouse-handling into master 2026-03-21 14:06:45 +00:00
Collaborator

Closes #5

Was sich geändert hat

CameraSystem.ts

  • Zoom-to-Mouse: Nach cam.setZoom() wird der Scroll korrigiert, sodass der Weltpunkt unter dem Cursor fixiert bleibt
  • Formel: scrollX += (mouseX - screenW/2) * (1/zoomBefore - 1/zoomAfter)
  • getCenterWorld() korrigiert: war scrollX + width/(2·zoom), korrekt ist scrollX + width/2 (Phaser zoomt vom Screenzentrumm, nicht von der oberen linken Ecke)
  • JSDoc auf allen Methoden ergänzt
  • Middle-click pan unverändert beibehalten

src/test/ — Test-Infrastruktur (bleibt im Repo)

  • test.html + src/test/main.ts: eigener Vite-Entry, komplett getrennt vom Spiel
  • ZoomTestScene: Phaser-Default-Zoom zum Beobachten des Ankerpunkt-Verhaltens
  • ZoomMouseScene: Zoom-to-Mouse zum direkten Vergleich; Tab wechselt zwischen beiden
  • Vite-Middleware (/api/log): schreibt JSON-Logs nach game-test.log für Offline-Analyse

Hintergrund

Der korrekte Zoom-Ankerpunkt von Phaser war nicht dokumentiert und ließ sich nur empirisch über die Test-Szenen ermitteln. Die Ergebnisse sind in Issue #5 kommentiert.

Test

  • Scrollrad an verschiedenen Screenpositionen: Weltpunkt unter Cursor bleibt fixiert
  • Scrollrad in Screenmitte: verhält sich wie vorher (Zoom zur Mitte)
  • Mittelklick halten + ziehen: Camera-Pan
  • WASD/Pfeiltasten: unverändert
  • Zoom an Weltgrenzen: korrekt geclampt
Closes #5 ## Was sich geändert hat ### `CameraSystem.ts` - **Zoom-to-Mouse**: Nach `cam.setZoom()` wird der Scroll korrigiert, sodass der Weltpunkt unter dem Cursor fixiert bleibt - **Formel**: `scrollX += (mouseX - screenW/2) * (1/zoomBefore - 1/zoomAfter)` - **`getCenterWorld()`** korrigiert: war `scrollX + width/(2·zoom)`, korrekt ist `scrollX + width/2` (Phaser zoomt vom Screenzentrumm, nicht von der oberen linken Ecke) - **JSDoc** auf allen Methoden ergänzt - Middle-click pan unverändert beibehalten ### `src/test/` — Test-Infrastruktur (bleibt im Repo) - `test.html` + `src/test/main.ts`: eigener Vite-Entry, komplett getrennt vom Spiel - `ZoomTestScene`: Phaser-Default-Zoom zum Beobachten des Ankerpunkt-Verhaltens - `ZoomMouseScene`: Zoom-to-Mouse zum direkten Vergleich; Tab wechselt zwischen beiden - Vite-Middleware (`/api/log`): schreibt JSON-Logs nach `game-test.log` für Offline-Analyse ### Hintergrund Der korrekte Zoom-Ankerpunkt von Phaser war nicht dokumentiert und ließ sich nur empirisch über die Test-Szenen ermitteln. Die Ergebnisse sind in Issue #5 kommentiert. ## Test - Scrollrad an verschiedenen Screenpositionen: Weltpunkt unter Cursor bleibt fixiert - Scrollrad in Screenmitte: verhält sich wie vorher (Zoom zur Mitte) - Mittelklick halten + ziehen: Camera-Pan - WASD/Pfeiltasten: unverändert - Zoom an Weltgrenzen: korrekt geclampt
claude added 2 commits 2026-03-20 19:23:32 +00:00
- Scroll wheel now zooms toward the mouse cursor instead of screen center
- Middle mouse button held: pan camera by dragging
- Both actions respect current zoom level
claude added 1 commit 2026-03-20 19:29:57 +00:00
claude added 1 commit 2026-03-20 19:39:16 +00:00
claude added 1 commit 2026-03-20 20:15:16 +00:00
claude added 1 commit 2026-03-20 20:21:52 +00:00
claude added 1 commit 2026-03-20 20:34:35 +00:00
claude added 1 commit 2026-03-20 20:37:12 +00:00
claude added 1 commit 2026-03-20 20:39:55 +00:00
claude added 1 commit 2026-03-20 20:45:21 +00:00
claude added 1 commit 2026-03-20 20:57:48 +00:00
claude added 1 commit 2026-03-20 21:06:15 +00:00
claude added 1 commit 2026-03-20 21:09:17 +00:00
claude added 6 commits 2026-03-21 12:00:28 +00:00
Separate test environment at /test.html (own Vite entry, own Phaser
instance). ZoomTestScene renders a 50×50 tile grid with crosshair
markers and a live HUD overlay showing zoom, scroll, viewport in px
and tiles, mouse world/screen/tile coords, and renderer info.
Zoom uses plain cam.setZoom() — no mouse tracking — to observe
Phaser's default center-anchor behavior.
Vite dev server gets a /api/log middleware (POST appends to
game-test.log, DELETE clears it). ZoomTestScene writes a zoom event
with before/after state on every scroll, plus a full snapshot every
2 seconds. Log entries are newline-delimited JSON.
Text overlay now uses a dedicated HUD camera (zoom=1, fixed scroll)
so it's never scaled by the world zoom. World objects and HUD objects
are separated via camera ignore lists. Added red screen-center
crosshair to HUD layer as a precise alignment reference.
Implements scroll correction after cam.setZoom() so the world point
under the mouse stays fixed. Formula accounts for Phaser's
center-based zoom: scrollX += (mouseX - cw/2) * (1/zBefore - 1/zAfter).
Tab switches between the two test scenes in both directions.
Also fixes centerWorld formula in ZoomTestScene overlay and logs.
Replaces plain cam.setZoom() with zoom-to-mouse: after each zoom step
the scroll is corrected by (mouseOffset from center) * (1/zBefore - 1/zAfter),
keeping the world point under the cursor fixed. Also fixes getCenterWorld()
which previously divided by zoom incorrectly. Added JSDoc to all methods.
claude added 1 commit 2026-03-21 12:01:41 +00:00
claude changed title from Issue #5: Mouse handling — zoom to cursor + middle-click pan to Issue #5: Mouse handling — zoom-to-mouse + middle-click pan 2026-03-21 12:04:51 +00:00
claude added 2 commits 2026-03-21 12:36:24 +00:00
tekki approved these changes 2026-03-21 14:04:32 +00:00
tekki merged commit 4c41dc9205 into master 2026-03-21 14:06:45 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: tekki/nissefolk#10
No description provided.