import { gameState } from './gameState.js'; import { getSize, calculateCenterOfMass } from './utils.js'; import { WORLD_SIZE, COLORS, FOOD_SIZE } from './config.js'; let canvas, ctx, minimapCanvas, minimapCtx, scoreElement, leaderboardContent; export function initRenderer(canvasElements) { canvas = canvasElements.gameCanvas; ctx = canvas.getContext('2d'); minimapCanvas = canvasElements.minimapCanvas; minimapCtx = minimapCanvas.getContext('2d'); scoreElement = canvasElements.scoreElement; leaderboardContent = canvasElements.leaderboardContent; // Initial canvas setup resizeCanvas(); } export function resizeCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } function drawCircle(x, y, value, color, isFood) { const size = isFood ? value : getSize(value); ctx.beginPath(); ctx.arc(x, y, size, 0, Math.PI * 2); ctx.fillStyle = color; ctx.fill(); } function drawCellWithName(x, y, score, color, name) { const size = getSize(score); // Draw cell ctx.beginPath(); ctx.arc(x, y, size, 0, Math.PI * 2); ctx.fillStyle = color; ctx.fill(); // Draw name if (size > 20) { // Only draw name if cell is big enough ctx.save(); // Calculate font size based on cell size const fontSize = Math.max(12, Math.min(20, size / 2)); ctx.font = `bold ${fontSize}px Arial`; ctx.fillStyle = 'white'; ctx.strokeStyle = 'black'; ctx.lineWidth = 3; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; // Draw text stroke (outline) ctx.strokeText(name, x, y); // Draw text fill ctx.fillText(name, x, y); ctx.restore(); } } export function drawGame() { if (!ctx) return; ctx.clearRect(0, 0, canvas.width, canvas.height); // Update camera to follow player's center of mass const centerOfMass = calculateCenterOfMass(gameState.playerCells); gameState.camera.x = centerOfMass.x - canvas.width / 2; gameState.camera.y = centerOfMass.y - canvas.height / 2; // Draw food gameState.food.forEach(food => { const screenX = food.x - gameState.camera.x; const screenY = food.y - gameState.camera.y; if (screenX >= -FOOD_SIZE && screenX <= canvas.width + FOOD_SIZE && screenY >= -FOOD_SIZE && screenY <= canvas.height + FOOD_SIZE) { drawCircle(screenX, screenY, FOOD_SIZE, food.color, true); } }); // Draw AI players gameState.aiPlayers.forEach(ai => { const screenX = ai.x - gameState.camera.x; const screenY = ai.y - gameState.camera.y; const size = getSize(ai.score); if (screenX >= -size && screenX <= canvas.width + size && screenY >= -size && screenY <= canvas.height + size) { drawCellWithName(screenX, screenY, ai.score, ai.color, ai.name); } }); // Draw player cells gameState.playerCells.forEach(cell => { const screenX = cell.x - gameState.camera.x; const screenY = cell.y - gameState.camera.y; const size = getSize(cell.score); if (screenX >= -size && screenX <= canvas.width + size && screenY >= -size && screenY <= canvas.height + size) { drawCellWithName(screenX, screenY, cell.score, COLORS.PLAYER, gameState.playerName); } }); // Update score display scoreElement.textContent = `Score: ${Math.floor(gameState.playerCells.reduce((sum, cell) => sum + cell.score, 0))}`; } export function drawMinimap() { if (!minimapCtx) return; const MINIMAP_SIZE = 150; const scale = MINIMAP_SIZE / WORLD_SIZE; minimapCtx.fillStyle = 'rgba(0, 0, 0, 0.7)'; minimapCtx.fillRect(0, 0, MINIMAP_SIZE, MINIMAP_SIZE); const viewWidth = canvas.width * scale; const viewHeight = canvas.height * scale; const viewX = gameState.camera.x * scale; const viewY = gameState.camera.y * scale; minimapCtx.strokeStyle = 'rgba(255, 255, 255, 0.5)'; minimapCtx.strokeRect(viewX, viewY, viewWidth, viewHeight); // Draw AI players on minimap gameState.aiPlayers.forEach(ai => { minimapCtx.beginPath(); minimapCtx.arc( ai.x * scale, ai.y * scale, 2, 0, Math.PI * 2 ); minimapCtx.fillStyle = COLORS.MINIMAP.OTHER; minimapCtx.fill(); }); // Draw player cells on minimap gameState.playerCells.forEach(cell => { minimapCtx.beginPath(); minimapCtx.arc( cell.x * scale, cell.y * scale, 3, 0, Math.PI * 2 ); minimapCtx.fillStyle = COLORS.MINIMAP.PLAYER; minimapCtx.fill(); }); } export function updateLeaderboard() { if (!leaderboardContent) return; const playerTotalScore = gameState.playerCells.reduce((sum, cell) => sum + cell.score, 0); // Combine player score with AI scores const allPlayers = [ { name: gameState.playerName, score: playerTotalScore, isPlayer: true }, ...gameState.aiPlayers.map(ai => ({ name: ai.name, score: ai.score, isPlayer: false })) ]; allPlayers.sort((a, b) => b.score - a.score); leaderboardContent.innerHTML = allPlayers .slice(0, 5) .map((player, index) => `