Add server/static/map.js
This commit is contained in:
152
server/static/map.js
Normal file
152
server/static/map.js
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
export class MapView {
|
||||||
|
constructor(scene) {
|
||||||
|
this.scene = scene;
|
||||||
|
this.config = {
|
||||||
|
width: 4000,
|
||||||
|
height: 3000,
|
||||||
|
zoom: 1.2,
|
||||||
|
moveSpeed: 200
|
||||||
|
};
|
||||||
|
this.target = null;
|
||||||
|
this.nodes = [];
|
||||||
|
this.nodeSprites = new Map();
|
||||||
|
this.otherSprites = new Map(); // id -> { img,label }
|
||||||
|
}
|
||||||
|
|
||||||
|
create(me, world, nodes) {
|
||||||
|
const W = world?.width || this.config.width;
|
||||||
|
const H = world?.height || this.config.height;
|
||||||
|
this.config.width = W;
|
||||||
|
this.config.height = H;
|
||||||
|
|
||||||
|
// background
|
||||||
|
this.scene.add.rectangle(W / 2, H / 2, W, H, 0x020617).setDepth(-100);
|
||||||
|
|
||||||
|
// player
|
||||||
|
this.player = this.scene.add.image(me.x, me.y, 'player').setDepth(10);
|
||||||
|
this.nameText = this.scene
|
||||||
|
.add.text(me.x, me.y - 22, me.name || 'You', {
|
||||||
|
fontSize: '12px',
|
||||||
|
color: '#e5e7eb'
|
||||||
|
})
|
||||||
|
.setOrigin(0.5);
|
||||||
|
|
||||||
|
// camera
|
||||||
|
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);
|
||||||
|
|
||||||
|
// nodes
|
||||||
|
this.replaceNodes(nodes || []);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTarget(x, y) {
|
||||||
|
this.target = { x, y };
|
||||||
|
}
|
||||||
|
|
||||||
|
setZoom(z) {
|
||||||
|
this.config.zoom = z;
|
||||||
|
this.scene.cameras.main.setZoom(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
replaceNodes(list) {
|
||||||
|
// remove existing
|
||||||
|
for (const sprite of this.nodeSprites.values()) {
|
||||||
|
sprite.destroy();
|
||||||
|
}
|
||||||
|
this.nodeSprites.clear();
|
||||||
|
this.nodes = list.slice();
|
||||||
|
|
||||||
|
for (const n of this.nodes) {
|
||||||
|
const key = this.getTextureKeyForNode(n.type);
|
||||||
|
const spr = this.scene.add.image(n.x, n.y, key).setDepth(1);
|
||||||
|
spr.setAlpha(n.alive ? 1 : 0.2);
|
||||||
|
this.nodeSprites.set(n.id, spr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNode(u) {
|
||||||
|
const n = this.nodes.find(n => n.id === u.id);
|
||||||
|
if (n) n.alive = u.alive;
|
||||||
|
const spr = this.nodeSprites.get(u.id);
|
||||||
|
if (spr) spr.setAlpha(u.alive ? 1 : 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTextureKeyForNode(type) {
|
||||||
|
if (type === 'wood') return 'wood';
|
||||||
|
if (type === 'stone') return 'stone';
|
||||||
|
if (type === 'ore') return 'ore';
|
||||||
|
if (type === 'fiber') return 'fiber';
|
||||||
|
return 'wood';
|
||||||
|
}
|
||||||
|
|
||||||
|
getClosestNodeIdInRange(range) {
|
||||||
|
if (!this.player) return null;
|
||||||
|
let bestId = null;
|
||||||
|
let bestDist = Infinity;
|
||||||
|
for (const n of this.nodes) {
|
||||||
|
if (!n.alive) continue;
|
||||||
|
const d = Phaser.Math.Distance.Between(
|
||||||
|
this.player.x,
|
||||||
|
this.player.y,
|
||||||
|
n.x,
|
||||||
|
n.y
|
||||||
|
);
|
||||||
|
if (d <= range && d < bestDist) {
|
||||||
|
bestDist = d;
|
||||||
|
bestId = n.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateOtherPlayers(players) {
|
||||||
|
const seen = new Set();
|
||||||
|
for (const p of players) {
|
||||||
|
seen.add(p.id);
|
||||||
|
if (!this.otherSprites.has(p.id)) {
|
||||||
|
const img = this.scene.add.image(p.x, p.y, 'other').setDepth(5);
|
||||||
|
const label = this.scene
|
||||||
|
.add.text(p.x, p.y - 22, p.name || 'Player', {
|
||||||
|
fontSize: '12px',
|
||||||
|
color: '#9ca3af'
|
||||||
|
})
|
||||||
|
.setOrigin(0.5);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove missing
|
||||||
|
for (const [id, rec] of this.otherSprites) {
|
||||||
|
if (!seen.has(id)) {
|
||||||
|
rec.img.destroy();
|
||||||
|
rec.label.destroy();
|
||||||
|
this.otherSprites.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(delta) {
|
||||||
|
if (!this.target || !this.player) return;
|
||||||
|
const dt = delta / 1000;
|
||||||
|
const dx = this.target.x - this.player.x;
|
||||||
|
const dy = this.target.y - this.player.y;
|
||||||
|
const dist = Math.hypot(dx, dy);
|
||||||
|
const step = this.config.moveSpeed * dt;
|
||||||
|
if (dist <= step) {
|
||||||
|
this.player.setPosition(this.target.x, this.target.y);
|
||||||
|
this.nameText.setPosition(this.player.x, this.player.y - 22);
|
||||||
|
this.target = null;
|
||||||
|
} else {
|
||||||
|
this.player.setPosition(
|
||||||
|
this.player.x + (dx / dist) * step,
|
||||||
|
this.player.y + (dy / dist) * step
|
||||||
|
);
|
||||||
|
this.nameText.setPosition(this.player.x, this.player.y - 22);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user