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
Showing only changes of commit 34220818b0 - Show all commits

View File

@@ -26,11 +26,6 @@ export class CameraSystem {
private middlePanActive = false
private lastPanX = 0
private lastPanY = 0
private mouseScreenX = 0
private mouseScreenY = 0
private mouseWorldX = 0
private mouseWorldY = 0
private debugCross?: Phaser.GameObjects.Graphics
constructor(scene: Phaser.Scene, adapter: LocalAdapter) {
this.scene = scene
@@ -57,28 +52,10 @@ export class CameraSystem {
d: kb.addKey(Phaser.Input.Keyboard.KeyCodes.D),
}
// Debug cross — redrawn every frame in world space, no transforms needed
this.debugCross = this.scene.add.graphics()
this.debugCross.setDepth(999)
// Track mouse world position on every move so we have a stable value for zoom
this.scene.input.on('pointermove', (ptr: Phaser.Input.Pointer) => {
this.mouseScreenX = ptr.x
this.mouseScreenY = ptr.y
this.mouseWorldX = cam.scrollX + ptr.x / cam.zoom
this.mouseWorldY = cam.scrollY + ptr.y / cam.zoom
})
// Scroll wheel zoom — zoom toward mouse pointer
// Scroll wheel zoom
this.scene.input.on('wheel', (_ptr: Phaser.Input.Pointer, _objs: unknown, _dx: number, dy: number) => {
const newZoom = Phaser.Math.Clamp(cam.zoom - Math.sign(dy) * ZOOM_STEP, MIN_ZOOM, MAX_ZOOM)
if (newZoom === cam.zoom) return
cam.setZoom(newZoom)
cam.scrollX = this.mouseWorldX - this.mouseScreenX / newZoom
cam.scrollY = this.mouseWorldY - this.mouseScreenY / newZoom
const centerX = cam.scrollX + cam.width / (2 * cam.zoom)
const centerY = cam.scrollY + cam.height / (2 * cam.zoom)
console.log(`[zoom] screen=(${this.mouseScreenX.toFixed(0)},${this.mouseScreenY.toFixed(0)}) world=(${this.mouseWorldX.toFixed(0)},${this.mouseWorldY.toFixed(0)}) center=(${centerX.toFixed(0)},${centerY.toFixed(0)}) zoom=${cam.zoom.toFixed(2)}`)
})
// Middle-click pan: start on button down
@@ -131,17 +108,6 @@ export class CameraSystem {
cam.scrollX = Phaser.Math.Clamp(cam.scrollX + dx, 0, worldW - cam.width / cam.zoom)
cam.scrollY = Phaser.Math.Clamp(cam.scrollY + dy, 0, worldH - cam.height / cam.zoom)
// Redraw debug cross every frame at viewport center in world space
if (this.debugCross) {
const cx = cam.scrollX + cam.width / (2 * cam.zoom)
const cy = cam.scrollY + cam.height / (2 * cam.zoom)
const arm = 12 / cam.zoom // 12 screen pixels at any zoom
this.debugCross.clear()
this.debugCross.lineStyle(2 / cam.zoom, 0xff0000, 1)
this.debugCross.lineBetween(cx - arm, cy, cx + arm, cy)
this.debugCross.lineBetween(cx, cy - arm, cx, cy + arm)
}
// Periodically save camera center as "player position"
this.saveTimer += delta
if (this.saveTimer >= this.SAVE_TICK) {