diff --git a/server/static/map.js b/server/static/map.js index c342d01..5e5194e 100644 --- a/server/static/map.js +++ b/server/static/map.js @@ -1,12 +1,19 @@ +// server/static/map.js + export class MapView { constructor(scene) { this.scene = scene; + + // Tile config: adjust tileSize here if you want bigger/smaller tiles. + this.tileSize = 32; + this.config = { - width: 4000, - height: 3000, + width: 16000, // will be overridden by world.width from server + height: 12000, // " zoom: 1.2, moveSpeed: 200 }; + this.target = null; this.nodes = []; this.nodeSprites = new Map(); @@ -19,29 +26,73 @@ export class MapView { this.config.width = W; this.config.height = H; - // background - this.scene.add.rectangle(W / 2, H / 2, W, H, 0x020617).setDepth(-100); + // Draw tiled background/grid using a Graphics object + const g = this.scene.add.graphics(); + const bgColor = 0x020617; // dark background + const gridColor = 0x111827; // grid line color + const gridAlpha = 0.4; - // player sprite - this.player = this.scene.add.image(me.x, me.y, 'player').setDepth(10); + // Fill background + g.fillStyle(bgColor, 1); + g.fillRect(0, 0, W, H); + + // Grid lines + g.lineStyle(1, gridColor, gridAlpha); + for (let x = 0; x <= W; x += this.tileSize) { + g.beginPath(); + g.moveTo(x, 0); + g.lineTo(x, H); + g.strokePath(); + } + for (let y = 0; y <= H; y += this.tileSize) { + g.beginPath(); + g.moveTo(0, y); + g.lineTo(W, y); + g.strokePath(); + } + g.setDepth(-100); // stay behind everything + + // Player sprite + const startPos = this.snapToTile(me.x, me.y); + this.player = this.scene.add.image(startPos.x, startPos.y, 'player').setDepth(10); this.nameText = this.scene - .add.text(me.x, me.y - 22, me.username || me.name || 'You', { + .add.text(startPos.x, startPos.y - 22, me.username || me.name || 'You', { fontSize: '12px', color: '#e5e7eb' }) .setOrigin(0.5); - // camera follow + // Camera follow & bounds const cam = this.scene.cameras.main; cam.setBounds(0, 0, W, H); cam.startFollow(this.player, true, 0.15, 0.15); cam.setZoom(this.config.zoom); + // Initialize nodes this.replaceNodes(nodes || []); } + // Snap any x,y world coordinate to the center of the containing tile + snapToTile(x, y) { + const size = this.tileSize; + let tx = Math.floor(x / size); + let ty = Math.floor(y / size); + + // clamp to world bounds in tiles + const maxTx = Math.floor((this.config.width - 1) / size); + const maxTy = Math.floor((this.config.height - 1) / size); + tx = Math.max(0, Math.min(maxTx, tx)); + ty = Math.max(0, Math.min(maxTy, ty)); + + return { + x: tx * size + size / 2, + y: ty * size + size / 2 + }; + } + setTarget(x, y) { - this.target = { x, y }; + // When clicking, snap the target to a tile center + this.target = this.snapToTile(x, y); } setZoom(z) { @@ -50,17 +101,24 @@ export class MapView { } replaceNodes(list) { + // Clear old sprites for (const sprite of this.nodeSprites.values()) { sprite.destroy(); } this.nodeSprites.clear(); this.nodes = list.slice(); + // Recreate sprites, snapping them to tiles visually (without changing server state) for (const n of this.nodes) { + const snapped = this.snapToTile(n.x, n.y); const key = this.getTextureKeyForNode(n.type); - const spr = this.scene.add.image(n.x, n.y, key).setDepth(1); + const spr = this.scene.add.image(snapped.x, snapped.y, key).setDepth(1); spr.setAlpha(n.alive ? 1 : 0.2); this.nodeSprites.set(n.id, spr); + + // Also update stored coords so distance checks use snapped positions + n.x = snapped.x; + n.y = snapped.y; } } @@ -72,10 +130,10 @@ export class MapView { } getTextureKeyForNode(type) { - if (type === 'wood') return 'wood'; - if (type === 'stone') return 'stone'; - if (type === 'ore') return 'ore'; - if (type === 'fiber') return 'fiber'; + if (type === 'wood') return 'wood'; + if (type === 'stone') return 'stone'; + if (type === 'ore') return 'ore'; + if (type === 'fiber') return 'fiber'; return 'wood'; } @@ -103,10 +161,11 @@ export class MapView { const seen = new Set(); for (const p of players) { seen.add(p.id); + const snapped = this.snapToTile(p.x, p.y); if (!this.otherSprites.has(p.id)) { - const img = this.scene.add.image(p.x, p.y, 'other').setDepth(5); + const img = this.scene.add.image(snapped.x, snapped.y, 'other').setDepth(5); const label = this.scene - .add.text(p.x, p.y - 22, p.name || 'Player', { + .add.text(snapped.x, snapped.y - 22, p.name || 'Player', { fontSize: '12px', color: '#9ca3af' }) @@ -114,10 +173,11 @@ export class MapView { this.otherSprites.set(p.id, { img, label }); } else { const rec = this.otherSprites.get(p.id); - rec.img.setPosition(p.x, p.y); - rec.label.setPosition(p.x, p.y - 22); + rec.img.setPosition(snapped.x, snapped.y); + rec.label.setPosition(snapped.x, snapped.y - 22); } } + // Remove any that disappeared for (const [id, rec] of this.otherSprites) { if (!seen.has(id)) { rec.img.destroy();