🎉 initial commit
This commit is contained in:
105
src/systems/CameraSystem.ts
Normal file
105
src/systems/CameraSystem.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import Phaser from 'phaser'
|
||||
import { WORLD_TILES } from '../config'
|
||||
import { stateManager } from '../StateManager'
|
||||
import type { LocalAdapter } from '../NetworkAdapter'
|
||||
|
||||
const CAMERA_SPEED = 400 // px/s
|
||||
const MIN_ZOOM = 0.25
|
||||
const MAX_ZOOM = 2.0
|
||||
const ZOOM_STEP = 0.1
|
||||
|
||||
export class CameraSystem {
|
||||
private scene: Phaser.Scene
|
||||
private adapter: LocalAdapter
|
||||
private keys!: {
|
||||
up: Phaser.Input.Keyboard.Key
|
||||
down: Phaser.Input.Keyboard.Key
|
||||
left: Phaser.Input.Keyboard.Key
|
||||
right: Phaser.Input.Keyboard.Key
|
||||
w: Phaser.Input.Keyboard.Key
|
||||
s: Phaser.Input.Keyboard.Key
|
||||
a: Phaser.Input.Keyboard.Key
|
||||
d: Phaser.Input.Keyboard.Key
|
||||
}
|
||||
private saveTimer = 0
|
||||
private readonly SAVE_TICK = 2000
|
||||
|
||||
constructor(scene: Phaser.Scene, adapter: LocalAdapter) {
|
||||
this.scene = scene
|
||||
this.adapter = adapter
|
||||
}
|
||||
|
||||
create(): void {
|
||||
const state = stateManager.getState()
|
||||
const cam = this.scene.cameras.main
|
||||
|
||||
// Start at saved player position (reused as camera anchor)
|
||||
cam.scrollX = state.player.x - cam.width / 2
|
||||
cam.scrollY = state.player.y - cam.height / 2
|
||||
|
||||
const kb = this.scene.input.keyboard!
|
||||
this.keys = {
|
||||
up: kb.addKey(Phaser.Input.Keyboard.KeyCodes.UP),
|
||||
down: kb.addKey(Phaser.Input.Keyboard.KeyCodes.DOWN),
|
||||
left: kb.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT),
|
||||
right: kb.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT),
|
||||
w: kb.addKey(Phaser.Input.Keyboard.KeyCodes.W),
|
||||
s: kb.addKey(Phaser.Input.Keyboard.KeyCodes.S),
|
||||
a: kb.addKey(Phaser.Input.Keyboard.KeyCodes.A),
|
||||
d: kb.addKey(Phaser.Input.Keyboard.KeyCodes.D),
|
||||
}
|
||||
|
||||
// Scroll wheel zoom
|
||||
this.scene.input.on('wheel', (_ptr: Phaser.Input.Pointer, _objs: unknown, _dx: number, dy: number) => {
|
||||
const zoom = Phaser.Math.Clamp(cam.zoom - Math.sign(dy) * ZOOM_STEP, MIN_ZOOM, MAX_ZOOM)
|
||||
cam.setZoom(zoom)
|
||||
})
|
||||
}
|
||||
|
||||
update(delta: number): void {
|
||||
const cam = this.scene.cameras.main
|
||||
const speed = CAMERA_SPEED * (delta / 1000) / cam.zoom
|
||||
|
||||
const up = this.keys.up.isDown || this.keys.w.isDown
|
||||
const down = this.keys.down.isDown || this.keys.s.isDown
|
||||
const left = this.keys.left.isDown || this.keys.a.isDown
|
||||
const right = this.keys.right.isDown || this.keys.d.isDown
|
||||
|
||||
let dx = 0, dy = 0
|
||||
if (left) dx -= speed
|
||||
if (right) dx += speed
|
||||
if (up) dy -= speed
|
||||
if (down) dy += speed
|
||||
|
||||
if (dx !== 0 && dy !== 0) { dx *= 0.707; dy *= 0.707 }
|
||||
|
||||
const worldW = WORLD_TILES * 32 // TILE_SIZE hardcoded since WORLD_PX may not exist
|
||||
const worldH = WORLD_TILES * 32
|
||||
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)
|
||||
|
||||
// Periodically save camera center as "player position"
|
||||
this.saveTimer += delta
|
||||
if (this.saveTimer >= this.SAVE_TICK) {
|
||||
this.saveTimer = 0
|
||||
this.adapter.send({
|
||||
type: 'PLAYER_MOVE',
|
||||
x: cam.scrollX + cam.width / 2,
|
||||
y: cam.scrollY + cam.height / 2,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
getCenterWorld(): { x: number; y: number } {
|
||||
const cam = this.scene.cameras.main
|
||||
return {
|
||||
x: cam.scrollX + cam.width / (2 * cam.zoom),
|
||||
y: cam.scrollY + cam.height / (2 * cam.zoom),
|
||||
}
|
||||
}
|
||||
|
||||
getCenterTile(): { tileX: number; tileY: number } {
|
||||
const { x, y } = this.getCenterWorld()
|
||||
return { tileX: Math.floor(x / 32), tileY: Math.floor(y / 32) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user