/** * PERFORMANCE MONITOR * Tracks FPS, memory usage, and performance metrics */ class PerformanceMonitor { constructor(scene) { this.scene = scene; this.enabled = false; // Toggle with F3 (DISABLED by default) // FPS tracking this.fps = 60; this.fpsHistory = []; this.maxHistoryLength = 60; // 1 second at 60fps // Memory tracking (if available) this.memoryUsage = 0; // Performance stats this.stats = { avgFPS: 60, minFPS: 60, maxFPS: 60, frameTime: 16.67, // ms drawCalls: 0, activeSprites: 0 }; // Create UI this.createUI(); // Keyboard toggle (F3) if (scene.input && scene.input.keyboard) { scene.input.keyboard.on('keydown-F3', () => { this.toggle(); }); } } createUI() { if (!this.scene.add) return; // Background panel this.panel = this.scene.add.rectangle(10, 10, 200, 120, 0x000000, 0.7); this.panel.setOrigin(0, 0); this.panel.setScrollFactor(0); this.panel.setDepth(100000); // Text display this.text = this.scene.add.text(15, 15, '', { fontSize: '12px', fontFamily: 'Courier New', color: '#00ff00', stroke: '#000000', strokeThickness: 2 }); this.text.setOrigin(0, 0); this.text.setScrollFactor(0); this.text.setDepth(100001); // FPS graph (mini) this.graph = this.scene.add.graphics(); this.graph.setScrollFactor(0); this.graph.setDepth(100001); this.updateVisibility(); } toggle() { this.enabled = !this.enabled; this.updateVisibility(); console.log(`📊 Performance Monitor: ${this.enabled ? 'ON' : 'OFF'}`); } updateVisibility() { if (this.panel) this.panel.setVisible(this.enabled); if (this.text) this.text.setVisible(this.enabled); if (this.graph) this.graph.setVisible(this.enabled); } update(delta) { if (!this.enabled) return; // Calculate FPS this.fps = 1000 / delta; this.fpsHistory.push(this.fps); if (this.fpsHistory.length > this.maxHistoryLength) { this.fpsHistory.shift(); } // Calculate stats this.stats.avgFPS = this.fpsHistory.reduce((a, b) => a + b, 0) / this.fpsHistory.length; this.stats.minFPS = Math.min(...this.fpsHistory); this.stats.maxFPS = Math.max(...this.fpsHistory); this.stats.frameTime = delta; // Count active sprites this.stats.activeSprites = this.countActiveSprites(); // Memory (if available) if (performance.memory) { this.memoryUsage = (performance.memory.usedJSHeapSize / 1048576).toFixed(2); // MB } // Update UI every 5 frames (reduce overhead) if (this.scene.game.loop.frame % 5 === 0) { this.updateUI(); } } countActiveSprites() { if (!this.scene.children) return 0; return this.scene.children.list.filter(child => child.active && child.visible ).length; } updateUI() { if (!this.text) return; // Build text let lines = [ `FPS: ${this.fps.toFixed(1)}`, `Avg: ${this.stats.avgFPS.toFixed(1)}`, `Min: ${this.stats.minFPS.toFixed(1)} / Max: ${this.stats.maxFPS.toFixed(1)}`, `Frame: ${this.stats.frameTime.toFixed(2)}ms`, `Sprites: ${this.stats.activeSprites}` ]; if (this.memoryUsage > 0) { lines.push(`Memory: ${this.memoryUsage} MB`); } this.text.setText(lines.join('\n')); // Update graph this.drawGraph(); } drawGraph() { if (!this.graph) return; this.graph.clear(); const graphX = 15; const graphY = 100; const graphWidth = 180; const graphHeight = 20; const maxFPS = 60; // Draw background this.graph.fillStyle(0x222222, 0.5); this.graph.fillRect(graphX, graphY, graphWidth, graphHeight); // Draw FPS bars this.graph.fillStyle(0x00ff00, 0.8); const barWidth = graphWidth / this.maxHistoryLength; this.fpsHistory.forEach((fps, i) => { const barHeight = (fps / maxFPS) * graphHeight; const x = graphX + (i * barWidth); const y = graphY + graphHeight - barHeight; // Color based on FPS if (fps < 30) { this.graph.fillStyle(0xff0000, 0.8); // Red } else if (fps < 50) { this.graph.fillStyle(0xffaa00, 0.8); // Orange } else { this.graph.fillStyle(0x00ff00, 0.8); // Green } this.graph.fillRect(x, y, barWidth, barHeight); }); // Draw 60 FPS line this.graph.lineStyle(1, 0xffffff, 0.5); this.graph.beginPath(); this.graph.moveTo(graphX, graphY); this.graph.lineTo(graphX + graphWidth, graphY); this.graph.strokePath(); } // Get current stats for external use getStats() { return { ...this.stats, currentFPS: this.fps, memoryMB: this.memoryUsage }; } destroy() { if (this.panel) this.panel.destroy(); if (this.text) this.text.destroy(); if (this.graph) this.graph.destroy(); } } // Export if (typeof module !== 'undefined' && module.exports) { module.exports = PerformanceMonitor; }