/** * TwinBondUISystem.js * ==================== * KRVAVA Ε½ETEV - Twin Bond Heartbeat UI * * Features: * - Visual heartbeat indicator on screen * - Speeds up when near Ana's clues * - Purple glow effect * - Distance-based intensity * - Twin bond strength indicator * * @author NovaFarma Team * @date 2025-12-25 */ export default class TwinBondUISystem { constructor(scene) { this.scene = scene; // UI elements this.heartContainer = null; this.heartIcon = null; this.glowEffect = null; this.bondStrengthBar = null; // State this.baseHeartRate = 60; // bpm this.currentHeartRate = 60; this.bondStrength = 0; // 0-100 this.nearestClueDistance = Infinity; // Animation this.heartbeatTween = null; this.lastBeat = 0; console.log('πŸ’œ TwinBondUISystem initialized'); this.createUI(); this.startHeartbeat(); } /** * Create UI elements */ createUI() { const ui = this.scene.scene.get('UIScene') || this.scene; // Container (top-left corner) this.heartContainer = ui.add.container(50, 50); this.heartContainer.setDepth(1000); // Above everything this.heartContainer.setScrollFactor(0); // Fixed to camera // Purple glow effect (behind heart) this.glowEffect = ui.add.circle(0, 0, 25, 0x9370DB, 0); this.heartContainer.add(this.glowEffect); // Heart icon (emoji-style) this.heartIcon = ui.add.text(0, 0, 'πŸ’œ', { fontSize: '32px', fontFamily: 'Arial' }); this.heartIcon.setOrigin(0.5); this.heartContainer.add(this.heartIcon); // Bond strength bar (below heart) const barWidth = 50; const barHeight = 5; // Background bar const barBg = ui.add.rectangle(0, 30, barWidth, barHeight, 0x333333); this.heartContainer.add(barBg); // Strength bar this.bondStrengthBar = ui.add.rectangle( -barWidth / 2, 30, 0, // Start at 0 width barHeight, 0x9370DB ); this.bondStrengthBar.setOrigin(0, 0.5); this.heartContainer.add(this.bondStrengthBar); // Bond strength text this.bondStrengthText = ui.add.text(0, 45, '0%', { fontSize: '10px', fontFamily: 'Arial', color: '#9370DB' }); this.bondStrengthText.setOrigin(0.5); this.heartContainer.add(this.bondStrengthText); console.log('βœ… Twin Bond UI created'); } /** * Start heartbeat animation */ startHeartbeat() { const beatInterval = () => { const bpm = this.currentHeartRate; const msPerBeat = 60000 / bpm; // Convert BPM to ms // Heart pump animation if (this.heartIcon) { this.scene.tweens.add({ targets: [this.heartIcon], scale: { from: 1, to: 1.3 }, duration: 100, yoyo: true, ease: 'Quad.Out' }); // Glow pulse this.scene.tweens.add({ targets: [this.glowEffect], alpha: { from: 0, to: 0.6 }, scale: { from: 1, to: 1.5 }, duration: 150, yoyo: true, ease: 'Quad.Out' }); } // Schedule next beat this.heartbeatTimer = setTimeout(() => beatInterval(), msPerBeat); }; // Start beating beatInterval(); } /** * Update system (called every frame) */ update(time, delta) { if (!this.scene.player) return; // Calculate distance to nearest Ana clue this.calculateNearestClue(); // Update heart rate based on distance this.updateHeartRate(); // Update bond strength display this.updateBondStrengthDisplay(); } /** * Calculate distance to nearest Ana's clue */ calculateNearestClue() { if (!this.scene.anaClueSystem) { this.nearestClueDistance = Infinity; return; } const playerX = this.scene.player.sprite.x; const playerY = this.scene.player.sprite.y; let minDistance = Infinity; // Check all clues this.scene.anaClueSystem.clueLocations.forEach((position, clueId) => { // Skip already discovered clues if (this.scene.anaClueSystem.discovered.has(clueId)) return; const dx = position.x - playerX; const dy = position.y - playerY; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < minDistance) { minDistance = distance; } }); this.nearestClueDistance = minDistance; } /** * Update heart rate based on proximity to clues */ updateHeartRate() { const distance = this.nearestClueDistance; // Distance thresholds (in pixels) const veryClose = 200; // 4-5 blocks const close = 480; // 10 blocks const medium = 960; // 20 blocks let targetHeartRate = this.baseHeartRate; if (distance < veryClose) { // VERY CLOSE - Rapid heartbeat! targetHeartRate = 120; // 2x normal this.bondStrength = 100; } else if (distance < close) { // CLOSE - Fast heartbeat targetHeartRate = 90; this.bondStrength = 75; } else if (distance < medium) { // MEDIUM - Slightly elevated targetHeartRate = 75; this.bondStrength = 50; } else { // FAR - Normal heartbeat targetHeartRate = 60; this.bondStrength = Math.max(0, this.bondStrength - 1); // Slowly decrease } // Smooth transition this.currentHeartRate += (targetHeartRate - this.currentHeartRate) * 0.1; // Clamp this.currentHeartRate = Phaser.Math.Clamp(this.currentHeartRate, 30, 150); } /** * Update bond strength visual display */ updateBondStrengthDisplay() { if (!this.bondStrengthBar) return; // Update bar width const maxWidth = 50; const targetWidth = (this.bondStrength / 100) * maxWidth; this.bondStrengthBar.width = targetWidth; // Update text if (this.bondStrengthText) { this.bondStrengthText.setText(`${Math.floor(this.bondStrength)}%`); } // Color gradient based on strength if (this.bondStrength > 75) { this.bondStrengthBar.setFillStyle(0xFF69B4); // Hot pink - very strong } else if (this.bondStrength > 50) { this.bondStrengthBar.setFillStyle(0x9370DB); // Medium purple } else if (this.bondStrength > 25) { this.bondStrengthBar.setFillStyle(0x6A5ACD); // Slate blue } else { this.bondStrengthBar.setFillStyle(0x483D8B); // Dark slate blue } // Pulsing glow when strong bond if (this.bondStrength > 75 && this.glowEffect) { this.glowEffect.setAlpha(0.3 + Math.sin(Date.now() / 200) * 0.2); } } /** * Trigger special bond moment (e.g., flashback) */ triggerBondMoment(intensity = 'medium') { console.log(`πŸ’œ Twin Bond Moment! Intensity: ${intensity}`); // Screen flash this.scene.cameras.main.flash(500, 147, 112, 219, false); // Purple flash // Heart explosion effect if (this.heartIcon) { this.scene.tweens.add({ targets: [this.heartIcon], scale: { from: 1, to: 2 }, alpha: { from: 1, to: 0 }, duration: 800, ease: 'Quad.Out', onComplete: () => { this.heartIcon.setScale(1); this.heartIcon.setAlpha(1); } }); } // Glow burst if (this.glowEffect) { this.scene.tweens.add({ targets: [this.glowEffect], scale: { from: 1, to: 5 }, alpha: { from: 0.8, to: 0 }, duration: 1000, ease: 'Quad.Out', onComplete: () => { this.glowEffect.setScale(1); this.glowEffect.setAlpha(0); } }); } // Temporary heart rate spike this.currentHeartRate = 150; setTimeout(() => { this.currentHeartRate = this.baseHeartRate; }, 3000); // Bond strength boost this.bondStrength = 100; // Show notification this.scene.events.emit('show-notification', { title: 'Twin Bond Activated!', text: 'πŸ’œ You feel Ana\'s presence intensify!', icon: 'πŸ’œ', color: '#9370DB' }); } /** * Get current heart rate (for debugging) */ getCurrentHeartRate() { return Math.floor(this.currentHeartRate); } /** * Get bond strength (for other systems) */ getBondStrength() { return this.bondStrength; } /** * Cleanup */ destroy() { if (this.heartbeatTimer) { clearTimeout(this.heartbeatTimer); } if (this.heartContainer) { this.heartContainer.destroy(); } } }