/** * Enhanced map canvas for RTS mode with terrain, units, and buildings */ export class RTSMapCanvas { constructor(canvasId = 'rts-game-map') { this.canvas = document.getElementById(canvasId); if (!this.canvas) { this.canvas = document.createElement('canvas'); this.canvas.id = canvasId; } this.ctx = this.canvas.getContext('2d'); this.zoom = 1; this.offsetX = 0; this.offsetY = 0; this.selectedUnit = null; this.selectedBuilding = null; this.initializeCanvas(); this.setupEventListeners(); } initializeCanvas() { this.canvas.width = 800; this.canvas.height = 600; this.drawTerrain(); this.drawGrid(); } setupEventListeners() { this.canvas.addEventListener('click', (e) => this.handleClick(e)); this.canvas.addEventListener('mousemove', (e) => this.handleMouseMove(e)); } drawTerrain() { const ctx = this.ctx; // Clear canvas ctx.fillStyle = '#1a2332'; ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); // Draw terrain features this.drawForests(); this.drawMountains(); this.drawRivers(); this.drawSettlement(); } drawGrid() { const ctx = this.ctx; ctx.strokeStyle = '#334155'; ctx.lineWidth = 0.5; ctx.globalAlpha = 0.3; const gridSize = 40; // Vertical lines for (let x = 0; x <= this.canvas.width; x += gridSize) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, this.canvas.height); ctx.stroke(); } // Horizontal lines for (let y = 0; y <= this.canvas.height; y += gridSize) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(this.canvas.width, y); ctx.stroke(); } ctx.globalAlpha = 1; } drawForests() { const ctx = this.ctx; ctx.fillStyle = '#22c55e'; // Forest patches const forests = [ { x: 100, y: 100, radius: 60 }, { x: 600, y: 150, radius: 80 }, { x: 200, y: 400, radius: 50 }, { x: 650, y: 450, radius: 70 } ]; forests.forEach(forest => { ctx.beginPath(); ctx.arc(forest.x, forest.y, forest.radius, 0, Math.PI * 2); ctx.fill(); // Add tree symbols for (let i = 0; i < 8; i++) { const angle = (i / 8) * Math.PI * 2; const treeX = forest.x + Math.cos(angle) * (forest.radius * 0.7); const treeY = forest.y + Math.sin(angle) * (forest.radius * 0.7); ctx.fillStyle = '#16a34a'; ctx.fillRect(treeX - 2, treeY - 2, 4, 4); } ctx.fillStyle = '#22c55e'; }); } drawMountains() { const ctx = this.ctx; ctx.fillStyle = '#64748b'; const mountains = [ { x: 300, y: 80, width: 100, height: 80 }, { x: 500, y: 300, width: 120, height: 100 } ]; mountains.forEach(mountain => { ctx.beginPath(); ctx.moveTo(mountain.x, mountain.y + mountain.height); ctx.lineTo(mountain.x + mountain.width / 2, mountain.y); ctx.lineTo(mountain.x + mountain.width, mountain.y + mountain.height); ctx.closePath(); ctx.fill(); }); } drawRivers() { const ctx = this.ctx; ctx.strokeStyle = '#3b82f6'; ctx.lineWidth = 8; ctx.beginPath(); ctx.moveTo(0, 200); ctx.quadraticCurveTo(200, 180, 400, 220); ctx.quadraticCurveTo(600, 260, 800, 240); ctx.stroke(); } drawSettlement() { const ctx = this.ctx; const centerX = 400; const centerY = 350; // Town hall (main building) ctx.fillStyle = '#8b5cf6'; ctx.fillRect(centerX - 20, centerY - 20, 40, 40); // Surrounding buildings const buildings = [ { x: centerX - 60, y: centerY - 10, type: 'barracks', color: '#ef4444' }, { x: centerX + 40, y: centerY - 10, type: 'storage', color: '#f59e0b' }, { x: centerX - 10, y: centerY - 60, type: 'farm', color: '#22c55e' }, { x: centerX - 10, y: centerY + 40, type: 'market', color: '#3b82f6' } ]; buildings.forEach(building => { ctx.fillStyle = building.color; ctx.fillRect(building.x - 15, building.y - 15, 30, 30); }); // Draw units around settlement this.drawUnits(); } drawUnits() { const ctx = this.ctx; const centerX = 400; const centerY = 350; const units = [ { x: centerX - 80, y: centerY + 20, type: 'warrior' }, { x: centerX - 70, y: centerY + 35, type: 'warrior' }, { x: centerX + 60, y: centerY + 25, type: 'archer' }, { x: centerX + 20, y: centerY - 80, type: 'cavalry' } ]; units.forEach(unit => { if (unit.type === 'warrior') { ctx.fillStyle = '#dc2626'; ctx.beginPath(); ctx.arc(unit.x, unit.y, 6, 0, Math.PI * 2); ctx.fill(); } else if (unit.type === 'archer') { ctx.fillStyle = '#059669'; ctx.fillRect(unit.x - 5, unit.y - 5, 10, 10); } else if (unit.type === 'cavalry') { ctx.fillStyle = '#7c3aed'; ctx.beginPath(); ctx.moveTo(unit.x, unit.y - 8); ctx.lineTo(unit.x - 6, unit.y + 4); ctx.lineTo(unit.x + 6, unit.y + 4); ctx.closePath(); ctx.fill(); } }); } handleClick(e) { const rect = this.canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; console.log(`Map clicked at: ${x}, ${y}`); // Check if clicked on a unit or building // This is a simplified example - in a real game you'd have proper hit detection this.showMapInfo(x, y); } handleMouseMove(e) { const rect = this.canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; // Update cursor based on what's under it this.canvas.style.cursor = 'default'; // Check for interactive elements if (this.isNearSettlement(x, y)) { this.canvas.style.cursor = 'pointer'; } } isNearSettlement(x, y) { const centerX = 400; const centerY = 350; const distance = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2); return distance < 100; } showMapInfo(x, y) { const overlay = document.getElementById('rts-map-overlay'); if (overlay) { if (this.isNearSettlement(x, y)) { overlay.innerHTML = `