class LyricsSystem { constructor() { this.lyrics = []; this.currentLyricIndex = -1; this.showLyrics = true; // Mostrar letras por defecto this.font = null; this.songDuration = 189; // 3:09 en segundos this.isGameOver = false; this.gameOverScreen = false; this.fadeOpacity = 1.0; this.fadeDirection = 1; // 1 para aparecer, -1 para desaparecer // Offset de tiempo para ajustar sincronización (en segundos) // Valor positivo = letras aparecen ANTES // Valor negativo = letras aparecen DESPUÉS this.timeOffset = 0.25; // Configuración de texto (scaled for 800x600 canvas) this.maxLineWidth = 700; // Ancho máximo de línea en píxeles (scaled) this.lineHeight = 45; // Altura entre líneas (scaled) // Cargar la fuente personalizada this.loadCustomFont(); // Parsear las letras desde el archivo this.parseLyrics(); } loadCustomFont() { this.font = new FontFace('CustomFont', 'url(assets/font.ttf)'); this.font.load().then(() => { document.fonts.add(this.font); }).catch(err => { console.warn('No se pudo cargar la fuente personalizada:', err); }); } parseLyrics() { // Letras en romaji usando los tiempos exactos del archivo const lyricsData = [ { time: 2.8, text: "mogumogu" }, { time: 6.4, text: "shinra banshou no akusenkutou mo mayoneizu kaketara daitai oishiku naru?" }, { time: 13.3, text: "kimi ga naite mo onaka wa suku yo shouka dekinakatta \"gomen gomen\"" }, { time: 19.8, text: "sui mo amai mo katte ni tabete gomeiwaku okakeshite imasu" }, { time: 26.7, text: "pakuchii na okite hen na aji no juusu kokoro wo mu ni shite nomikomimasu" }, { time: 33.3, text: "aa konton jouhou kata no resutoran de usoppachi no menyuu ni ocha koboshite" }, { time: 39.8, text: "kimi to mogumogu (mogumogu) mogumogu (mogumogu)" }, { time: 43, text: "juugeki-sen no mannaka de mogumogu (ugya~)" }, { time: 46, text: "chimi mouryou harapeko no mure manpuku ni naru mirai wo negatteiru yo" }, { time: 53, text: "mogumogu (mogumogu) mogumogu (mogumogu) sekai ga owaru mae ni" }, { time: 59, text: "mogumogu yamii maji kami yamuyamu ari no manma" }, { time: 66, text: "mogumogu yamii Magic Coming konoyo wo ajiwaun da umauma" }, { time: 67, text: "sorry i got lazy lmfao" }, // { time: 43.2, text: "riron busou no mirufiiyu sando (sando)" }, // { time: 44.9, text: "tokumei kibou no ourora sousu (sousu)" }, // { time: 48.3, text: "oozappa na ajitsuke oome ni mite yo oishiku nattara \"ok ok.\"" }, // { time: 51.1, text: "ii mon warui mon ippai tabete yogoreta kuchimoto nuguimasu" }, // { time: 55.2, text: "onigiri piza keiki gouka na furu kousu wana wo utagai ki wo tsukemasu" }, // { time: 58.6, text: "aa mousou ryuugen higo no baikingu de dokuiri to zeppin ryouri yoriwakete" }, // { time: 61.2, text: "kimi to mogumogu (mogumogu) mogumogu (mogumogu)" }, // { time: 64.5, text: "desugeimu no kyoushitsu de mogumogu (ugya~)" }, // { time: 67.9, text: "chimi mouryou harapeko no mure naka no ii kimi to ikinokoretara ii na" }, // { time: 162, text: "mogumogu (mogumogu) mogumogu (mogumogu) suu nen-go mo kono basho de" }, // { time: 74.6, text: "mogumogu yamii maji kami kon'ya no bangohan wa" }, // { time: 78, text: "mogumogu yamii Magic Coming tsugi wa omae no ban da" }, // { time: 81.4, text: "mogumogu yamii maji kami yamuyamu ari no manma" }, // { time: 84.8, text: "mogumogu yamii Magic Coming konoyo wo ajiwaun da umauma" }, { time: 162, text: "mogumogu mogumogu mogumogu mogumogu mogumogu mogumogu mogumogu yamii" }, { time: 168, text: "mogumogu mogumogu mogumogu mogumogu mogumogu mogumogu mogumogu yamii" }, { time: 175, text: "mogumogu mogumogu mogumogu mogumogu mogumogu mogumogu mogumogu yamii" }, { time: 181, text: "mogumogu mogumogu mogumogu mogumogu"}, { time: 187, text: "yamii yamii" } ]; this.lyrics = lyricsData; } update(currentTime) { // Aplicar offset de tiempo const adjustedTime = currentTime + this.timeOffset; // Verificar si la canción ha terminado if (adjustedTime >= this.songDuration && !this.isGameOver) { this.isGameOver = true; this.gameOverScreen = true; return; } // Actualizar letra actual basada en el tiempo ajustado this.updateCurrentLyric(adjustedTime); } updateCurrentLyric(currentTime) { let newIndex = -1; for (let i = 0; i < this.lyrics.length; i++) { if (currentTime >= this.lyrics[i].time) { newIndex = i; } else { break; } } if (newIndex !== this.currentLyricIndex) { this.currentLyricIndex = newIndex; } } draw(ctx, canvas) { if (!this.showLyrics && this.fadeOpacity <= 0) return; // Actualizar opacidad para transición suave if (this.showLyrics && this.fadeOpacity < 1.0) { this.fadeOpacity += 0.05; } else if (!this.showLyrics && this.fadeOpacity > 0) { this.fadeOpacity -= 0.05; } // Dibujar letra actual if (this.currentLyricIndex >= 0 && this.currentLyricIndex < this.lyrics.length) { const currentLyric = this.lyrics[this.currentLyricIndex]; // Configurar fuente (scaled) ctx.font = '35px CustomFont, Arial, sans-serif'; ctx.fillStyle = `rgba(255, 255, 255, ${this.fadeOpacity})`; ctx.strokeStyle = `rgba(0, 0, 0, ${this.fadeOpacity})`; ctx.lineWidth = 3; ctx.textAlign = 'center'; // Dividir texto en líneas const lines = this.wrapText(currentLyric.text, ctx, this.maxLineWidth); // Calcular posición Y inicial (scaled for 800x600) const totalHeight = lines.length * this.lineHeight; const startY = canvas.height - 450 - (totalHeight - this.lineHeight); // Agregar sombra ctx.shadowColor = `rgba(0, 0, 0, ${this.fadeOpacity * 0.8})`; ctx.shadowBlur = 4; ctx.shadowOffsetX = 2; ctx.shadowOffsetY = 2; // Dibujar cada línea lines.forEach((line, index) => { const x = canvas.width / 2; const y = startY + (index * this.lineHeight); ctx.strokeText(line, x, y); ctx.fillText(line, x, y); }); // Resetear sombra ctx.shadowColor = 'transparent'; ctx.shadowBlur = 0; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; } } toggleLyrics() { this.showLyrics = !this.showLyrics; this.fadeDirection = this.showLyrics ? 1 : -1; } // Método para ajustar offset de tiempo // seconds > 0: letras aparecen ANTES (más temprano) // seconds < 0: letras aparecen DESPUÉS (más tarde) adjustTimeOffset(seconds) { this.timeOffset += seconds; console.log(`Offset de tiempo ajustado a: ${this.timeOffset} segundos`); console.log(`Positivo = letras ANTES, Negativo = letras DESPUÉS`); } // Método para establecer offset de tiempo específico setTimeOffset(seconds) { this.timeOffset = seconds; console.log(`Offset de tiempo establecido a: ${this.timeOffset} segundos`); } // Método para dividir texto en líneas wrapText(text, ctx, maxWidth) { const words = text.split(' '); const lines = []; let currentLine = words[0]; for (let i = 1; i < words.length; i++) { const word = words[i]; const width = ctx.measureText(currentLine + ' ' + word).width; if (width < maxWidth) { currentLine += ' ' + word; } else { lines.push(currentLine); currentLine = word; } } lines.push(currentLine); return lines; } // Método para desarrollo: simular fin de canción simulateGameOver() { this.isGameOver = true; this.gameOverScreen = true; } // Método para reiniciar el juego reset() { this.currentLyricIndex = -1; this.isGameOver = false; this.gameOverScreen = false; this.showLyrics = true; this.fadeOpacity = 1.0; this.timeOffset = 0; // Resetear offset } }