PHASE 16: Performance Monitor - FPS tracker with visual graph, memory usage, sprite count (F3 toggle)
This commit is contained in:
@@ -70,6 +70,7 @@
|
||||
<script src="src/utils/SpatialGrid.js"></script>
|
||||
<script src="src/utils/Pathfinding.js"></script>
|
||||
<script src="src/utils/Compression.js"></script>
|
||||
<script src="src/utils/PerformanceMonitor.js"></script>
|
||||
|
||||
<!-- Data -->
|
||||
<script src="src/data/CraftingRecipes.js"></script>
|
||||
|
||||
203
src/utils/PerformanceMonitor.js
Normal file
203
src/utils/PerformanceMonitor.js
Normal file
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* PERFORMANCE MONITOR
|
||||
* Tracks FPS, memory usage, and performance metrics
|
||||
*/
|
||||
|
||||
class PerformanceMonitor {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
this.enabled = true; // Toggle with F3
|
||||
|
||||
// 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;
|
||||
}
|
||||
Reference in New Issue
Block a user