User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1530
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1521
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1521
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1521
User prompt
Si la lista de misiones supera el alto de la pantalla, el contenedor principal debe permitir scroll vertical (deslizar hacia abajo). Asegúrate de que el contenedor tenga una propiedad tipo overflow-y: scroll 3. Experiencia visual: Agrega una pequeña barra de desplazamiento discreta o una animación que indique que se puede deslizar si hay más misiones. Mantén las misiones bien espaciadas para que no se superpongan entre sí. Al abrir la pestaña, la vista siempre debe comenzar desde la primera misión activa visible (parte superior). 4. Compatibilidad móvil: Asegúrate de que el deslizamiento sea fluido tanto con scroll de mouse como con swipe en pantalla táctil.
User prompt
Asegurar que la variable global nutripoints_total siempre comience en 0 la primera vez que se instala el juego y luego se incremente automáticamente cada vez que el jugador abra la aplicación (bono de inicio de sesión). 1. Inicialización y persistencia 1. Al cargar el juego (antes de cualquier menú): Verifica en localStorage (o almacenamiento equivalente) si existe la clave nutripoints_total. Si no existe (es la primera vez que se instala o se limpió la caché): nutripoints_total = 0 guardarEnStorage("nutripoints_total", 0) Si existe, carga su valor en la variable global nutripoints_total. 2. Crear una función global sumarNutriPoints(cantidad) Suma la cantidad indicada a la variable nutripoints_total. Actualiza inmediatamente el contador visual en la UI. Guarda el nuevo total en localStorage. --- 2. Bono de inicio de sesión (acumulativo) 1. Crea la clave ultima_fecha_inicio en localStorage. 2. Al iniciar el juego: Obtén la fecha actual (YYYY-MM-DD). Si ultima_fecha_inicio no coincide con la fecha actual → Llama a sumarNutriPoints(1) (o la cantidad de puntos que definas como bono de login). Guarda la nueva fecha en ultima_fecha_inicio. Opcional: muestra un mensaje no intrusivo “🎉 Has ganado 1 Nutripoint por iniciar hoy”. --- 3. Actualización de UI En el menú principal y en la Tienda muestra el contador de Nutripoints con el valor de nutripoints_total. Cada vez que nutripoints_total cambie (por login, misiones, etc.), refresca de inmediato el texto/ícono. --- 4. Prevención de duplicados El bono de inicio de sesión solo debe otorgarse una vez al día. Si el jugador cierra y abre varias veces el juego el mismo día, el valor de ultima_fecha_inicio evita que se sume de nuevo. --- ✅ Checklist para la IA [ ] Verificar clave nutripoints_total al arrancar; crearla en 0 si no existe. [ ] Implementar sumarNutriPoints() con persistencia y actualización UI. [ ] Sistema de bono diario que añada puntos solo una vez cada 24 h. [ ] Contador visual sincronizado en todo momento. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Agrega un boton de pausa que sea visible durante la partida, al darle click que se detenga el juego y de la opción de volver al menu principal, reanudar el juego o reiniciarlo
User prompt
las respuestas tambien que se mantengan dentro del marco y que no lo sobrepasen. Tambien,aumenta el tamaño de todas las preguntas y sus cuadros para que se vea mejor ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Requisitos del diseño y funcionalidad para el boton de preguntas: Formato de lista expandible (acordeón): ‐ Cada pregunta debe mostrarse como un botón o encabezado plegable. ‐ Al hacer clic o tocar sobre la pregunta, debe desplegarse suavemente la respuesta debajo, empujando el contenido inferior hacia abajo. ‐ Solo una pregunta puede estar abierta a la vez (opcional: permitir varias si se ve bien). Organización vertical ordenada: ‐ Todas las preguntas deben estar alineadas verticalmente con márgenes entre sí para que no se sobrepongan. ‐ Al expandirse una pregunta, la respuesta debe ocupar su propio espacio sin chocar ni montarse sobre las demás. ‐ Asegúrate de que el diseño sea responsive y se adapte bien a diferentes resoluciones o tamaños de pantalla. Estética y legibilidad: ‐ Usa una fuente clara como Poppins o Nunito. ‐ Tamaño recomendado: preguntas (20–24px), respuestas (18–20px). ‐ Colores suaves para el fondo (ej. blanco/beige claro) y destacados para los títulos (azul oscuro o verde saludable). ‐ Las tarjetas de preguntas deben tener borde suave y sombreado leve. Extras funcionales opcionales: ‐ Incluye una pequeña animación (fade o slide) al expandir la respuesta. ‐ Agrega un ícono (⊕ / ⊖) que indique si la pregunta está desplegada o no. ‐ Permite scroll si hay muchas preguntas (scroll vertical dentro del panel). 📦 Todo el apartado debe ser contenido en un solo contenedor bien espaciado, con padding interno y separación clara entre cada bloque de pregunta + respuesta. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que en la pantalla inicial aparezca la cantidad de nutripoints que tiene el jugador y cuando una misión sea completada, que sea remplazada por otra ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Misiones activas: El jugador tendrá 3 misiones activas al día (guardadas en localStorage) con metas distintas como: ‐ Atrapar X alimentos saludables ‐ Evitar X alimentos no saludables ‐ Completar partidas sin perder energía Barra de progreso funcional por misión: ‐ Cada misión debe tener una barra que refleje el progreso exacto (avanceActual / metaTotal). ‐ Las barras deben actualizarse automáticamente conforme se registran acciones del jugador durante las partidas. Eventos que actualizan progreso: Cuando ocurra una acción en el juego (ej: atrapar una manzana), se debe emitir un evento como "fruta_atrapada" o "gaseosa_evaded". El sistema de misiones debe escuchar esos eventos y actualizar el progreso correspondiente solo si esa misión está activa. Recompensa automática: ‐ Si una misión alcanza el avanceActual >= metaTotal, debe considerarse completada. ‐ Al completarla, debe aparecer un mensaje no intrusivo (“🎉 Misión cumplida +2 NP”), sin pausar el juego. ‐ El sistema debe sumar +2 Nutripoints al contador global (nutripoints_total) y guardar el nuevo total en localStorage. Persistencia: Todos los progresos de misión, el estado completado y los Nutripoints ganados deben mantenerse guardados en localStorage, incluso tras cerrar el juego. Evitar repeticiones o errores: Una vez una misión esté completada, no debe volver a otorgar puntos si se sigue avanzando más allá de su meta. Extras opcionales si es posible: ‐ Agrega una animación suave cuando la barra sube. ‐ Permite ver el progreso también desde la pantalla de pausa. 🎯 Resumen de variables clave para la IA: js Copiar Editar misiones_activas = [ { id: "saludables_10", descripcion: "Atrapa 10 alimentos saludables", avance: 3, meta: 10, completada: false }, { id: "evitar_gaseosa_60s", descripcion: "Evita gaseosas por 60 segundos", avance: 42, meta: 60, completada: false }, ... ] nutripoints_total = 6 ↪💡 Consider importing and using the following plugins: @upit/storage.v1, @upit/tween.v1
User prompt
podrías agrandar el tamaño de las misiones y su barra de progreso por favor
User prompt
aumenta al doble el tamaño de las misiones
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'storage.activeMissions = storageData;' Line Number: 187 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'storage.activeMissions = self.activeMissions;' Line Number: 160 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'stringify')' in or related to this line: 'storage.activeMissions = JSON.stringify(self.activeMissions);' Line Number: 223 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'storage.activeMissions = self.activeMissions.slice();' Line Number: 159 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'storage.activeMissions = self.activeMissions;' Line Number: 159 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'storage.activeMissions = missionManager.activeMissions;' Line Number: 156
User prompt
2. Barra de progreso de cada misión Parámetro Detalle a implementar Componente Barra horizontal + texto “X / Y”. Lógica ‐ Cada misión debe definir metaTotal (p. ej. 10 frutas) y avanceActual. ‐ Actualizar en tiempo real durante la partida (escucha de eventos). Estilos Fondo gris claro (40 % opacidad). Progreso verde #4CAF50. Altura 12–16 px. Borde redondeado. Animación Cada incremento → tween suave 200 ms. Ejemplos de progreso por misión Misión metaTotal incremento Atrapa 10 frutas saludables 10 +1 por cada fruta Evita gaseosas 60 seg 60 s +1 s cada frame que no atrape gaseosa Completa 3 partidas seguidas sin fallar 3 +1 al finalizar cada partida exitosa 3. Actualización en tiempo real desde la partida 1. En GameScene emite eventos cuando ocurre una acción relevante: emit("fruta_atrapada") emit("gaseosa_atrapada") emit("partida_ganada_sin_fallar") 2. Un MissionManager escucha esos eventos y actualiza avanceActual. 3. Cuando avanceActual >= metaTotal: Marca la misión “completada”. Suma +2 Nutripoints. Dispara el aviso visual (punto 4). 4. Aviso “¡Misión cumplida!” durante la partida Propiedad Detalle Formato Banner pequeño semitransparente en la parte superior (o esquina) para no tapar al jugador. Texto “🎉 Misión cumplida: [nombre corta] +2 NP” Duración 3 segundos visibles. Animación Fade‐in 250 ms → visible 2500 ms → Fade‐out 250 ms. Sonido SFX positivo breve (campanita). No pausa el juego El loop principal y la física continúan; banner está en una capa UI separada. 5. Almacenamiento y persistencia Guardar en localStorage: misiones_activas: array con id, metaTotal, avanceActual, completada (bool). fecha_misiones: YYYY‐MM‐DD. nutripoints_total. Al cargar el juego, el MissionManager reconstruye barras con su progreso. 6. Flujo completo resumido Inicio del día → generar 3 misiones y mostrar barras vacías. Durante la partida → al atrapar/evitar, emitir evento → MissionManager actualiza barra en memoria. UI in‐game (opcional) → pequeño icono “misión” con número de misiones pendientes; si lo tocas en pausa muestra barras live. Al completar meta → banner “Misión cumplida” + sumatoria de Nutripoints; no detiene gameplay. Regresas a MisionesScene → la tarjeta aparece con ✓, barra llena y texto “Completada ✔️”. ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
elimina los botones de volver de la parte superior
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'costo')' in or related to this line: 'if (playerNutripoints >= item.costo && ownedItems.indexOf(item.id) === -1) {' Line Number: 1748
User prompt
el boton de volver de cada sección que se encuentre en la parte inferior de cada sub página
User prompt
Elimina el texto amarillo que dice: Nutripoints y agranda el que dice Nutripoints pero de color verde ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ELimina el texto que dice: Nutripoints y donde dice: TOTAL, cambialo por Nutripoints:
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var FAQScreen = Container.expand(function () { var self = Container.call(this); // Create background var bg = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); bg.tint = 0xF8F9FA; self.addChild(bg); // Create scrollable container for FAQ content var scrollContainer = new Container(); self.addChild(scrollContainer); // Title var titleText = new Text2('PREGUNTAS FRECUENTES', { size: 80, fill: 0x2C3E50, font: "Impact" }); titleText.anchor.set(0.5, 0); titleText.x = 2048 / 2; titleText.y = 150; scrollContainer.addChild(titleText); self.faqContainer = new Container(); self.faqContainer.x = 0; self.faqContainer.y = 300; scrollContainer.addChild(self.faqContainer); // FAQ state tracking self.openFAQIndex = -1; // Track which FAQ is currently open self.faqItems = []; // Store FAQ item references // Create FAQ items self.createFAQItems = function () { self.faqContainer.removeChildren(); self.faqItems = []; var currentY = 0; var itemSpacing = 20; for (var i = 0; i < faqData.length; i++) { var faq = faqData[i]; var isOpen = self.openFAQIndex === i; // Question container with shadow effect var questionContainer = new Container(); questionContainer.y = currentY; self.faqContainer.addChild(questionContainer); // Question background with rounded appearance var questionBg = LK.getAsset('restartButton', { width: 1800, height: 120, anchorX: 0.5, anchorY: 0 }); questionBg.tint = isOpen ? 0x3498DB : 0x34495E; questionBg.x = 2048 / 2; questionBg.y = 0; questionContainer.addChild(questionBg); // Expand/collapse icon var iconText = new Text2(isOpen ? '⊖' : '⊕', { size: 60, fill: 0xFFFFFF, font: "Impact" }); iconText.anchor.set(0, 0.5); iconText.x = 250; iconText.y = 60; questionContainer.addChild(iconText); // Question text var questionText = new Text2(faq.question, { size: 48, fill: 0xFFFFFF, font: "Impact" }); questionText.anchor.set(0, 0.5); questionText.x = 350; questionText.y = 60; questionContainer.addChild(questionText); // Answer container (initially hidden if not open) var answerContainer = new Container(); answerContainer.y = 130; answerContainer.alpha = isOpen ? 1 : 0; answerContainer.visible = isOpen; questionContainer.addChild(answerContainer); // Answer background var answerBg = LK.getAsset('restartButton', { width: 1700, height: isOpen ? 180 : 0, anchorX: 0.5, anchorY: 0 }); answerBg.tint = 0xECF0F1; answerBg.x = 2048 / 2; answerBg.y = 0; answerContainer.addChild(answerBg); // Answer text var answerText = new Text2(faq.answer, { size: 42, fill: 0x2C3E50, font: "Impact" }); answerText.anchor.set(0.5, 0); answerText.x = 2048 / 2; answerText.y = 20; answerContainer.addChild(answerText); // Store references var faqItem = { index: i, questionContainer: questionContainer, questionBg: questionBg, iconText: iconText, answerContainer: answerContainer, answerBg: answerBg, isOpen: isOpen }; self.faqItems.push(faqItem); // Add click handlers with closure (function (itemIndex) { questionBg.down = function () { self.toggleFAQ(itemIndex); }; iconText.down = function () { self.toggleFAQ(itemIndex); }; questionText.down = function () { self.toggleFAQ(itemIndex); }; })(i); // Calculate next Y position currentY += 120 + itemSpacing; if (isOpen) { currentY += 180 + itemSpacing; } } }; // Toggle FAQ open/close self.toggleFAQ = function (index) { if (index === self.openFAQIndex) { // Close currently open FAQ self.closeFAQ(index); self.openFAQIndex = -1; } else { // Close currently open FAQ if any if (self.openFAQIndex >= 0) { self.closeFAQ(self.openFAQIndex); } // Open new FAQ self.openFAQ(index); self.openFAQIndex = index; } }; // Open FAQ with animation self.openFAQ = function (index) { var item = self.faqItems[index]; if (!item) return; // Update icon and background color item.iconText.setText('⊖'); tween(item.questionBg, { tint: 0x3498DB }, { duration: 200 }); // Show and animate answer container item.answerContainer.visible = true; item.answerContainer.alpha = 0; // Animate answer background height tween(item.answerBg, { height: 180 }, { duration: 300, easing: tween.easeOut }); // Fade in answer container tween(item.answerContainer, { alpha: 1 }, { duration: 250, onFinish: function onFinish() { // Recreate all items to adjust positions LK.setTimeout(function () { self.createFAQItems(); }, 50); } }); }; // Close FAQ with animation self.closeFAQ = function (index) { var item = self.faqItems[index]; if (!item) return; // Update icon and background color item.iconText.setText('⊕'); tween(item.questionBg, { tint: 0x34495E }, { duration: 200 }); // Fade out and hide answer container tween(item.answerContainer, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { item.answerContainer.visible = false; // Animate answer background height to 0 tween(item.answerBg, { height: 0 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { // Recreate all items to adjust positions LK.setTimeout(function () { self.createFAQItems(); }, 50); } }); } }); }; // Bottom back button var bottomBackButton = LK.getAsset('restartButton', { width: 400, height: 100, anchorX: 0.5, anchorY: 0.5 }); bottomBackButton.tint = 0xFF6B35; bottomBackButton.x = 2048 / 2; bottomBackButton.y = 2600; self.addChild(bottomBackButton); var bottomBackText = new Text2('← VOLVER', { size: 60, fill: 0xFFFFFF, font: "Impact" }); bottomBackText.anchor.set(0.5, 0.5); bottomBackText.x = 2048 / 2; bottomBackText.y = 2600; self.addChild(bottomBackText); bottomBackButton.down = function () { showStartScreen(); }; bottomBackText.down = function () { showStartScreen(); }; return self; }); var FallingItem = Container.expand(function (type, specificFood) { var self = Container.call(this); self.type = type; self.specificFood = specificFood; // Set different speeds based on type and add randomness if (type === 'anxiety') { self.speed = fallSpeed * 1.5; // Anxiety bombs fall faster } else if (type === 'water') { self.speed = fallSpeed * 0.8; // Water bottles fall slower } else { // Food items have variable speeds between 1.2x and 2.0x base speed (much faster) var speedMultiplier = 1.2 + Math.random() * 0.8; // Increase speed significantly during expert mode if (anxietyBombsActive) { speedMultiplier *= 2.2; // Make items fall 120% faster in expert mode } self.speed = fallSpeed * speedMultiplier; } var assetName = specificFood || 'waterBottle'; if (type === 'water') assetName = 'waterBottle';else if (type === 'anxiety') assetName = 'anxietyBomb'; var graphic = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { self.y += self.speed; }; return self; }); var MissionManager = Container.expand(function () { var self = Container.call(this); self.activeMissions = []; self.init = function () { self.loadActiveMissions(); }; self.loadActiveMissions = function () { var today = new Date().toDateString(); var savedDate = storage.missionsDate; if (savedDate !== today) { self.generateNewDailyMissions(); } else { var savedMissions = storage.activeMissions; if (savedMissions && savedMissions.length > 0) { self.activeMissions = []; for (var i = 0; i < savedMissions.length; i++) { self.activeMissions.push({ id: savedMissions['mission_' + i + '_id'], text: savedMissions['mission_' + i + '_text'], metaTotal: savedMissions['mission_' + i + '_metaTotal'], type: savedMissions['mission_' + i + '_type'], avanceActual: savedMissions['mission_' + i + '_avanceActual'] || 0, completada: savedMissions['mission_' + i + '_completada'] || false }); } } else { self.activeMissions = []; } missionManager.activeMissions = self.activeMissions; } }; self.generateNewDailyMissions = function () { var shuffled = allMissions.slice(); for (var i = shuffled.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = shuffled[i]; shuffled[i] = shuffled[j]; shuffled[j] = temp; } self.activeMissions = shuffled.slice(0, 3).map(function (mission) { return { id: mission.id, text: mission.text, metaTotal: mission.metaTotal, type: mission.type, avanceActual: 0, completada: false }; }); missionManager.activeMissions = self.activeMissions; var today = new Date().toDateString(); var storageData = {}; for (var i = 0; i < self.activeMissions.length; i++) { var mission = self.activeMissions[i]; storageData['mission_' + i + '_id'] = mission.id; storageData['mission_' + i + '_text'] = mission.text; storageData['mission_' + i + '_metaTotal'] = mission.metaTotal; storageData['mission_' + i + '_type'] = mission.type; storageData['mission_' + i + '_avanceActual'] = mission.avanceActual; storageData['mission_' + i + '_completada'] = mission.completada; } storageData.length = self.activeMissions.length; storage.activeMissions = storageData; storage.missionsDate = today; }; self.emitEvent = function (eventType, data) { for (var i = 0; i < self.activeMissions.length; i++) { var mission = self.activeMissions[i]; if (mission.completada) continue; var oldProgress = mission.avanceActual; switch (mission.type) { case "energia": if (eventType === "energia_updated" && data.energia >= mission.metaTotal) { mission.avanceActual = data.energia; } break; case "frutas": if (eventType === "fruta_atrapada") { mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal); } break; case "tiempo_sin_gaseosas": if (eventType === "frame_update" && data.gameTime >= 0) { var timeSinceLastSoda = data.gameTime - missionManager.lastGaseosaTime; mission.avanceActual = Math.min(timeSinceLastSoda, mission.metaTotal); } if (eventType === "gaseosa_atrapada") { missionManager.lastGaseosaTime = data.gameTime; mission.avanceActual = 0; } break; case "nutripoints_total": if (eventType === "nutripoints_updated") { mission.avanceActual = Math.min(data.total, mission.metaTotal); } break; case "agua": if (eventType === "agua_atrapada") { mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal); } break; case "partidas_consecutivas": if (eventType === "partida_ganada") { mission.avanceActual = Math.min(missionManager.consecutiveWins, mission.metaTotal); } break; case "partida_vidas": if (eventType === "partida_ganada" && data.vidasRestantes >= 3) { mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal); } break; case "falsos_ganar": if (eventType === "partida_ganada" && missionManager.falsosInCurrentGame >= 3) { mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal); } break; case "partidas_energia_25": if (eventType === "partida_ganada" && data.energia >= 25) { mission.avanceActual = Math.min(missionManager.consecutiveHighEnergyWins, mission.metaTotal); } break; case "tiempo_continuo": if (eventType === "frame_update") { var playTime = data.gameTime; mission.avanceActual = Math.min(playTime, mission.metaTotal); } break; } // Animate progress bar if progress changed if (oldProgress !== mission.avanceActual) { self.animateProgressBar(i, oldProgress, mission.avanceActual); } // Check if mission completed if (!mission.completada && mission.avanceActual >= mission.metaTotal) { mission.completada = true; totalNutripoints += 2; storage.totalNutripoints = totalNutripoints; self.showMissionCompleted(mission); // Replace completed mission with a new one after a short delay LK.setTimeout(function () { self.replaceCompletedMission(i); // Refresh missions display if currently viewing missions if (currentScreen === 'missions') { updateMissionsDisplay(); } }, 3000); // Wait 3 seconds before replacing } } missionManager.activeMissions = self.activeMissions; var storageData = {}; for (var i = 0; i < self.activeMissions.length; i++) { var mission = self.activeMissions[i]; storageData['mission_' + i + '_id'] = mission.id; storageData['mission_' + i + '_text'] = mission.text; storageData['mission_' + i + '_metaTotal'] = mission.metaTotal; storageData['mission_' + i + '_type'] = mission.type; storageData['mission_' + i + '_avanceActual'] = mission.avanceActual; storageData['mission_' + i + '_completada'] = mission.completada; } storageData.length = self.activeMissions.length; storage.activeMissions = storageData; }; self.animateProgressBar = function (missionIndex, oldProgress, newProgress) { // Find progress bar for this mission and animate it if (currentScreen === 'missions' && missionsScreen && missionsScreen.progressBars) { var progressBar = missionsScreen.progressBars[missionIndex]; if (progressBar) { var mission = self.activeMissions[missionIndex]; var newWidth = Math.min(newProgress / mission.metaTotal * 450, 450); tween(progressBar, { width: newWidth }, { duration: 300, easing: tween.easeOut }); } } }; self.replaceCompletedMission = function (missionIndex) { // Get available missions that are not currently active var availableMissions = []; for (var i = 0; i < allMissions.length; i++) { var isActive = false; for (var j = 0; j < self.activeMissions.length; j++) { if (self.activeMissions[j].id === allMissions[i].id) { isActive = true; break; } } if (!isActive) { availableMissions.push(allMissions[i]); } } // If we have available missions, replace the completed one if (availableMissions.length > 0) { var randomIndex = Math.floor(Math.random() * availableMissions.length); var newMission = availableMissions[randomIndex]; self.activeMissions[missionIndex] = { id: newMission.id, text: newMission.text, metaTotal: newMission.metaTotal, type: newMission.type, avanceActual: 0, completada: false }; // Save updated missions self.saveMissions(); } }; self.saveMissions = function () { var storageData = {}; for (var i = 0; i < self.activeMissions.length; i++) { var mission = self.activeMissions[i]; storageData['mission_' + i + '_id'] = mission.id; storageData['mission_' + i + '_text'] = mission.text; storageData['mission_' + i + '_metaTotal'] = mission.metaTotal; storageData['mission_' + i + '_type'] = mission.type; storageData['mission_' + i + '_avanceActual'] = mission.avanceActual; storageData['mission_' + i + '_completada'] = mission.completada; } storageData.length = self.activeMissions.length; storage.activeMissions = storageData; missionManager.activeMissions = self.activeMissions; }; self.showMissionCompleted = function (mission) { if (!gameActive) return; // Create mission completed banner var banner = LK.getAsset('restartButton', { width: 800, height: 120, anchorX: 0.5, anchorY: 0.5 }); banner.tint = 0x4CAF50; banner.alpha = 0; banner.x = 2048 / 2; banner.y = 200; game.addChild(banner); var bannerText = new Text2('¡Misión cumplida: ' + mission.text.substring(0, 20) + '... +2 NP!', { size: 35, fill: 0xFFFFFF, font: "Impact" }); bannerText.anchor.set(0.5, 0.5); bannerText.x = 2048 / 2; bannerText.y = 200; bannerText.alpha = 0; game.addChild(bannerText); // Play success sound LK.getSound('powerup').play(); // Animate banner tween(banner, { alpha: 0.9 }, { duration: 250, onFinish: function onFinish() { LK.setTimeout(function () { tween(banner, { alpha: 0 }, { duration: 250, onFinish: function onFinish() { banner.destroy(); } }); tween(bannerText, { alpha: 0 }, { duration: 250, onFinish: function onFinish() { bannerText.destroy(); } }); }, 2500); } }); tween(bannerText, { alpha: 1 }, { duration: 250 }); }; return self; }); var MissionsScreen = Container.expand(function () { var self = Container.call(this); // Create background var bg = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); bg.tint = 0x2C3E50; bg.alpha = 0.95; self.addChild(bg); // Title var titleText = new Text2('MISIONES DIARIAS', { size: 100, fill: 0xFFD700, font: "Impact" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 300; self.addChild(titleText); self.missionsContainer = new Container(); self.addChild(self.missionsContainer); // Bottom back button var bottomBackButton = LK.getAsset('restartButton', { width: 400, height: 100, anchorX: 0.5, anchorY: 0.5 }); bottomBackButton.tint = 0xFF6B35; bottomBackButton.x = 2048 / 2; bottomBackButton.y = 2600; self.addChild(bottomBackButton); var bottomBackText = new Text2('← VOLVER', { size: 60, fill: 0xFFFFFF, font: "Impact" }); bottomBackText.anchor.set(0.5, 0.5); bottomBackText.x = 2048 / 2; bottomBackText.y = 2600; self.addChild(bottomBackText); bottomBackButton.down = function () { showStartScreen(); }; bottomBackText.down = function () { showStartScreen(); }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerBody = self.attachAsset('player', { anchorX: 0.5, anchorY: 1.0 }); var basket = self.attachAsset('basket', { anchorX: 0.5, anchorY: 0.5, y: -110 }); self.speed = 8; self.targetX = self.x; self.update = function () { var dx = self.targetX - self.x; if (Math.abs(dx) > 5) { self.x += dx * 0.15; } else { self.x = self.targetX; } // Keep player within bounds if (self.x < 150) self.x = 150; if (self.x > 2048 - 150) self.x = 2048 - 150; }; self.moveTo = function (targetX) { self.targetX = targetX; }; return self; }); var StartScreen = Container.expand(function () { var self = Container.call(this); // Create background var bg = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); bg.tint = 0x5d6c16; self.addChild(bg); // Game title var titleText = new Text2('Caza-ingredientes', { size: 120, fill: 0xFFD700, font: "Impact" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 400; self.addChild(titleText); // Nutripoints display on start screen var nutripointsDisplay = new Text2('Nutripoints: ' + (storage.totalNutripoints || 0), { size: 75, fill: 0x32CD32, font: "Impact" }); nutripointsDisplay.anchor.set(0.5, 0.5); nutripointsDisplay.x = 2048 / 2; nutripointsDisplay.y = 500; self.addChild(nutripointsDisplay); var subtitleText = new Text2('Elige bien, vive mejor', { size: 80, fill: 0x32CD32, font: "Impact" }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 2048 / 2; subtitleText.y = 580; self.addChild(subtitleText); // Create buttons var buttonProps = [{ text: 'PLAY', y: 850, color: 0x32CD32 }, { text: 'MISIONES', y: 1050, color: 0xFF6B35 }, { text: 'TIENDA', y: 1250, color: 0x4ECDC4 }, { text: 'PREGUNTAS', y: 1450, color: 0x9B59B6 }]; self.buttons = []; for (var i = 0; i < buttonProps.length; i++) { var buttonBg = LK.getAsset('restartButton', { width: 600, height: 120, anchorX: 0.5, anchorY: 0.5 }); buttonBg.tint = buttonProps[i].color; buttonBg.x = 2048 / 2; buttonBg.y = buttonProps[i].y; self.addChild(buttonBg); var buttonText = new Text2(buttonProps[i].text, { size: 70, fill: 0xFFFFFF, font: "Impact" }); buttonText.anchor.set(0.5, 0.5); buttonText.x = 2048 / 2; buttonText.y = buttonProps[i].y; self.addChild(buttonText); buttonBg.buttonType = buttonProps[i].text; buttonText.buttonType = buttonProps[i].text; self.buttons.push({ bg: buttonBg, text: buttonText, type: buttonProps[i].text }); } // Button click handlers for (var j = 0; j < self.buttons.length; j++) { (function (button) { button.bg.down = function (x, y, obj) { handleStartScreenButton(button.type); }; button.text.down = function (x, y, obj) { handleStartScreenButton(button.type); }; })(self.buttons[j]); } return self; }); var StoreScreen = Container.expand(function () { var self = Container.call(this); // Create background var bg = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); bg.tint = 0x2C3E50; bg.alpha = 0.95; self.addChild(bg); // Title var titleText = new Text2('TIENDA', { size: 100, fill: 0xFFD700, font: "Impact" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 250; self.addChild(titleText); // Nutripoints display var nutripointsDisplay = new Text2('Nutripoints: ' + (storage.totalNutripoints || 0), { size: 60, fill: 0x32CD32, font: "Impact" }); nutripointsDisplay.anchor.set(0.5, 0.5); nutripointsDisplay.x = 2048 / 2; nutripointsDisplay.y = 350; self.addChild(nutripointsDisplay); self.storeContainer = new Container(); self.addChild(self.storeContainer); // Bottom back button var bottomBackButton = LK.getAsset('restartButton', { width: 400, height: 100, anchorX: 0.5, anchorY: 0.5 }); bottomBackButton.tint = 0xFF6B35; bottomBackButton.x = 2048 / 2; bottomBackButton.y = 2600; self.addChild(bottomBackButton); var bottomBackText = new Text2('← VOLVER', { size: 60, fill: 0xFFFFFF, font: "Impact" }); bottomBackText.anchor.set(0.5, 0.5); bottomBackText.x = 2048 / 2; bottomBackText.y = 2600; self.addChild(bottomBackText); bottomBackButton.down = function () { showStartScreen(); }; bottomBackText.down = function () { showStartScreen(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Game state management var currentScreen = 'start'; // 'start', 'game', 'missions', 'store', 'faq' var gameStarted = false; // Track if game has been started via PLAY button var startScreen; var missionsScreen; var storeScreen; var faqScreen; // Mission system var allMissions = [{ id: "energia_20", text: "Alcanza 20 de Energía en una sola partida.", metaTotal: 20, type: "energia" }, { id: "frutas_10", text: "Atrapa 10 frutas o verduras sanas en una partida.", metaTotal: 10, type: "frutas" }, { id: "evitar_gaseosas_60", text: "Evita TODAS las gaseosas durante 60 segundos.", metaTotal: 60, type: "tiempo_sin_gaseosas" }, { id: "nutripoints_6", text: "Consigue 6 Nutripoints en total.", metaTotal: 6, type: "nutripoints_total" }, { id: "agua_5", text: "Recoge 5 botellas de agua (power-ups) en una sesión.", metaTotal: 5, type: "agua" }, { id: "partidas_3_sin_perder", text: "Juega 3 partidas seguidas sin perder una vida.", metaTotal: 3, type: "partidas_consecutivas" }, { id: "partida_3_vidas", text: "Completa una partida con al menos 3 vidas restantes.", metaTotal: 1, type: "partida_vidas" }, { id: "falsos_3_ganar", text: "Atrapa 3 alimentos 'falsos sanos' y aún así gana.", metaTotal: 3, type: "falsos_ganar" }, { id: "energia_25_2_partidas", text: "Gana 2 partidas consecutivas con Energía ≥25.", metaTotal: 2, type: "partidas_energia_25" }, { id: "tiempo_5_min", text: "Juega durante 5 min. continuos sin colapsar.", metaTotal: 300, type: "tiempo_continuo" }]; // Store items var storeItems = [{ id: "skin_rojo", nombre: "Skin Roja", costo: 5, tipo: "skin" }, { id: "skin_verde", nombre: "Skin Verde", costo: 5, tipo: "skin" }, { id: "fondo_parque", nombre: "Fondo Parque", costo: 8, tipo: "fondo" }, { id: "fondo_playa", nombre: "Fondo Playa", costo: 10, tipo: "fondo" }]; // FAQ data var faqData = [{ question: "¿Cómo se juega \"Caza-ingredientes\"?", answer: "Mueve tu avatar a izquierda y derecha y atrapa solo los alimentos saludables para sumar Energía. Evita los ultraprocesados y trampas." }, { question: "¿Para qué sirve la barra de Energía?", answer: "Representa tu nivel de salud en el juego. Si llega a 0, pierdes. Si llegas a 30, ganas Nutripoints extra." }, { question: "¿Qué son los Nutripoints y cómo se consiguen?", answer: "Son puntos que obtienes al ganar con Energía completa o cumpliendo misiones. Sirven para comprar skins y fondos en la Tienda." }, { question: "¿Cómo funciona la Tienda?", answer: "En la Tienda puedes cambiar Nutripoints por apariencias nuevas para tu avatar o fondos temáticos para el juego." }, { question: "¿Cómo se completan las misiones?", answer: "Ve a MISIONES, revisa las tareas diarias y juega hasta lograr cada objetivo. Al cumplirlas, recibes Nutripoints automáticamente." }]; // Game elements // Fake healthy foods // Junk foods // Healthy foods // Game variables // Healthy Foods - Fruits // Healthy Foods - Vegetables // Healthy Foods - Proteins & Grains // Junk Foods // Fake Healthy Foods var player; var fallingItems = []; var energy = 15; var lives = 3; var fallSpeed = 350 / 60; // 350px/s converted to pixels per frame (much faster) var lastSpeedIncrease = 0; var lastWaterSpawn = 0; var gameStartTime = 0; var foodsCaught = 0; var anxietyBombsActive = false; var lastSpawnTime = 0; var lastAnxietySpawnTime = 0; var expertMessageShown = false; var gameActive = true; // Track if game is active var expertModeTimer = 0; // Timer to track when expert mode should activate (20 seconds) var expertModeStartTime = 1200; // 20 seconds * 60 fps = 1200 frames // Nutripoints system variables var totalNutripoints = storage.totalNutripoints || 0; var gameNutripoints = 0; // Points earned in current game // Mission tracking variables var missionManager = { activeMissions: [], gameStartTime: 0, lastGaseosaTime: 0, consecutiveWins: 0, falsosInCurrentGame: 0, consecutiveHighEnergyWins: 0, continuousPlayTime: 0 }; // Initialize mission progress from storage var missionProgress = storage.missionProgress || {}; // Food tracking variables var foodCounts = { 'apple': 0, 'banana': 0, 'hardEgg': 0, 'broccoli': 0, 'carrot': 0, 'wholeBread': 0, 'waterBottle': 0 }; // UI elements var livesText; var scoreText; var energyText; var energyBarBg; var energyBarFill; var nutripointsText; var totalNutripointsText; // Initialize UI function initializeUI() { // Energy text with larger size energyText = new Text2('Energía: 15/30', { size: 72, fill: 0xFFFFFF, font: "Impact" }); energyText.anchor.set(0, 0); LK.gui.topLeft.addChild(energyText); energyText.x = 150; energyText.y = 20; // Energy bar background energyBarBg = LK.getAsset('energyBarBg', { anchorX: 0, anchorY: 0 }); LK.gui.topLeft.addChild(energyBarBg); energyBarBg.x = 150; energyBarBg.y = 100; // Energy bar fill energyBarFill = LK.getAsset('energyBarFill', { anchorX: 0, anchorY: 0 }); LK.gui.topLeft.addChild(energyBarFill); energyBarFill.x = 150; energyBarFill.y = 100; // Lives text with larger size livesText = new Text2('Vidas: 3', { size: 84, fill: 0xFF0000, font: "Impact" }); livesText.anchor.set(1, 0); LK.gui.topRight.addChild(livesText); livesText.x = -20; livesText.y = 20; // Total Nutripoints display (made larger) totalNutripointsText = new Text2('Nutripoints: ' + totalNutripoints, { size: 72, fill: 0x32CD32, font: "Impact" }); totalNutripointsText.anchor.set(1, 0); LK.gui.topRight.addChild(totalNutripointsText); totalNutripointsText.x = -20; totalNutripointsText.y = 120; // Score text removed } // Update UI function updateUI() { if (energyText) energyText.setText('Energía: ' + energy + '/30'); if (livesText) livesText.setText('Vidas: ' + lives); if (totalNutripointsText) totalNutripointsText.setText('Nutripoints: ' + totalNutripoints); // Score text update removed // Update energy bar fill based on current energy (0-30 range) if (energyBarFill) { var energyPercentage = energy / 30; energyBarFill.width = 400 * energyPercentage; // Change energy bar color based on energy level if (energy >= 20) { energyBarFill.tint = 0x00ff00; // Green for high energy } else if (energy >= 10) { energyBarFill.tint = 0xffff00; // Yellow for medium energy } else { energyBarFill.tint = 0xff0000; // Red for low energy } } } // Flash effect function flashScreen(color) { LK.effects.flashScreen(color, 300); } // Food arrays for variety - exactly 10 sprite types + 2 fake healthy var healthyFoods = ['banana', 'apple', 'carrot', 'broccoli', 'wholeBread', 'hardEgg']; var junkFoods = ['soda', 'chips', 'candy', 'burger']; var fakeFoods = ['cerealBar', 'flavoredYogurt']; // Spawn falling item function spawnFallingItem() { var type = 'healthy'; var specificFood = null; var rand = Math.random(); if (foodsCaught > 0 && foodsCaught % 20 === 0 && lastWaterSpawn !== foodsCaught) { type = 'water'; lastWaterSpawn = foodsCaught; } else if (rand < 0.3) { type = 'junk'; specificFood = junkFoods[Math.floor(Math.random() * junkFoods.length)]; } else if (rand < 0.5) { type = 'fake'; specificFood = fakeFoods[Math.floor(Math.random() * fakeFoods.length)]; } else { type = 'healthy'; specificFood = healthyFoods[Math.floor(Math.random() * healthyFoods.length)]; } var item = new FallingItem(type, specificFood); item.x = Math.random() * (2048 - 350) + 175; item.y = -175; fallingItems.push(item); game.addChild(item); } // Spawn anxiety bomb function spawnAnxietyBomb() { var item = new FallingItem('anxiety', null); item.x = Math.random() * (2048 - 350) + 175; item.y = -175; fallingItems.push(item); game.addChild(item); } // Helper function for player visual feedback function playerFeedback(color, duration, scaleEffect) { if (scaleEffect) { tween(player, { scaleX: 1.2, scaleY: 1.2 }, { duration: duration, onFinish: function onFinish() { tween(player, { scaleX: 1.0, scaleY: 1.0 }, { duration: duration }); } }); } else { tween(player, { tint: color }, { duration: duration, onFinish: function onFinish() { tween(player, { tint: 0xFFFFFF }, { duration: duration }); } }); } } // Helper function for vibration feedback function vibrateDevice() { if (navigator && navigator.vibrate) { navigator.vibrate(100); } } // Handle item collision function handleItemCollision(item) { switch (item.type) { case 'healthy': energy = Math.min(30, energy + 1); // Score increment removed LK.getSound('ping').play(); flashScreen(0x32CD32); playerFeedback(0x32CD32, 100, false); foodsCaught++; // Track healthy food counts if (item.specificFood && foodCounts.hasOwnProperty(item.specificFood)) { foodCounts[item.specificFood]++; } // Emit mission event missionManagerInstance.emitEvent("fruta_atrapada", {}); missionManagerInstance.emitEvent("energia_updated", { energia: energy }); break; case 'junk': lives--; energy = Math.max(0, energy - 2); LK.getSound('buzz').play(); vibrateDevice(); flashScreen(0xFF4500); playerFeedback(0xFF4500, 100, false); // Emit mission event for soda specifically if (item.specificFood === 'soda') { var gameTime = (LK.ticks - gameStartTime) / 60; missionManagerInstance.emitEvent("gaseosa_atrapada", { gameTime: gameTime }); } missionManagerInstance.emitEvent("energia_updated", { energia: energy }); break; case 'fake': energy = Math.max(0, energy - 2); LK.getSound('buzz').play(); vibrateDevice(); flashScreen(0xFFD700); playerFeedback(0xFFD700, 100, false); missionManager.falsosInCurrentGame++; missionManagerInstance.emitEvent("energia_updated", { energia: energy }); break; case 'water': energy = Math.min(30, energy + 3); // Score increment removed LK.getSound('powerup').play(); flashScreen(0x00BFFF); playerFeedback(0x00BFFF, 150, true); // Track water bottle counts foodCounts['waterBottle']++; // Emit mission events missionManagerInstance.emitEvent("agua_atrapada", {}); missionManagerInstance.emitEvent("energia_updated", { energia: energy }); break; case 'anxiety': energy = Math.max(0, energy - 5); LK.getSound('explosion').play(); vibrateDevice(); flashScreen(0x8B008B); playerFeedback(0x8B008B, 300, false); missionManagerInstance.emitEvent("energia_updated", { energia: energy }); break; } // Update nutripoints mission missionManagerInstance.emitEvent("nutripoints_updated", { total: totalNutripoints }); } // Initialize game function initializeGame() { gameStartTime = LK.ticks; // Initialize mission tracking for this game missionManager.gameStartTime = gameStartTime; missionManager.falsosInCurrentGame = 0; // Create player player = new Player(); player.x = 2048 / 2; player.y = 2732 - 100; game.addChild(player); // Initialize UI initializeUI(); updateUI(); } // Game input handling game.down = function (x, y, obj) { if (!player) return; // Check if player exists var gamePos = game.toLocal({ x: x, y: y }); player.moveTo(gamePos.x); }; game.move = function (x, y, obj) { if (!player) return; // Check if player exists var gamePos = game.toLocal({ x: x, y: y }); player.moveTo(gamePos.x); }; // Main game update loop game.update = function () { // Don't update game logic if game hasn't started or is not active if (!gameStarted || !gameActive) { return; } var currentTime = LK.ticks; var gameTime = (currentTime - gameStartTime) / 60; // Convert to seconds // Increase speed every 15 seconds if (gameTime - lastSpeedIncrease >= 15) { fallSpeed += 20 / 60; // Increase by 20px/s (double the previous increment) lastSpeedIncrease = gameTime; } // Increment expert mode timer expertModeTimer++; // Activate anxiety bombs after 20 seconds (1200 frames) if (expertModeTimer >= expertModeStartTime && !anxietyBombsActive) { anxietyBombsActive = true; lastAnxietySpawnTime = currentTime; // Only show expert message when expert mode activates if (expertModeTimer >= expertModeStartTime && !expertMessageShown) { expertMessageShown = true; // Create full screen overlay for expert message var expertOverlay = LK.getAsset('basket', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); expertOverlay.tint = 0x000000; expertOverlay.alpha = 0.9; game.addChild(expertOverlay); // Show expert challenge message with attractive styling var expertText = new Text2('¡RETO EXPERTO!', { size: 150, fill: 0xFFD700, font: "Impact" }); expertText.anchor.set(0.5, 0.5); expertText.x = 2048 / 2; expertText.y = 2732 / 2 - 100; game.addChild(expertText); // Add subtitle text var subtitleText = new Text2('¡Los alimentos caen más rápido!', { size: 75, fill: 0xFF4500, font: "Impact" }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 2048 / 2; subtitleText.y = 2732 / 2 + 50; game.addChild(subtitleText); // Animate expert message with pulsing effect tween(expertText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(expertText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 500, easing: tween.easeInOut }); } }); // Animate and remove message after 4 seconds tween(expertOverlay, { alpha: 0 }, { duration: 4000, onFinish: function onFinish() { expertOverlay.destroy(); } }); tween(expertText, { alpha: 0 }, { duration: 4000, onFinish: function onFinish() { expertText.destroy(); } }); tween(subtitleText, { alpha: 0 }, { duration: 4000, onFinish: function onFinish() { subtitleText.destroy(); } }); } } // Spawn items every 1.5 seconds if (currentTime - lastSpawnTime >= 90) { // 1.5 * 60 = 90 frames // Spawn 2-3 items at once for more food variety var itemsToSpawn = 2 + Math.floor(Math.random() * 2); // 2 or 3 items for (var s = 0; s < itemsToSpawn; s++) { spawnFallingItem(); } lastSpawnTime = currentTime; } // Spawn anxiety bombs every 40 seconds after activation if (anxietyBombsActive && currentTime - lastAnxietySpawnTime >= 2400) { // 40 * 60 = 2400 frames spawnAnxietyBomb(); lastAnxietySpawnTime = currentTime; } // Update falling items for (var i = fallingItems.length - 1; i >= 0; i--) { var item = fallingItems[i]; // Check collision with player if (item.intersects(player)) { handleItemCollision(item); item.destroy(); fallingItems.splice(i, 1); continue; } // Remove items that fall off screen if (item.y > 2732 + 350) { item.destroy(); fallingItems.splice(i, 1); } } // Update UI updateUI(); // Emit frame update for missions if (gameActive && gameStarted) { var gameTime = (LK.ticks - gameStartTime) / 60; missionManagerInstance.emitEvent("frame_update", { gameTime: gameTime }); } // Check game over conditions if (energy >= 30) { // Store final stats for victory storage.finalEnergy = energy; storage.finalTime = Math.floor(gameTime); storage.gameEndReason = 'victoria'; // Track mission progress for winning with high energy missionManager.consecutiveWins++; if (energy >= 25) { missionManager.consecutiveHighEnergyWins++; } storage.consecutiveWins = missionManager.consecutiveWins; storage.consecutiveHighEnergyWins = missionManager.consecutiveHighEnergyWins; gameActive = false; // Stop game updates showVictoryMessage(); } else if (lives <= 0) { // Store final stats when lives reach 0 storage.finalEnergy = energy; storage.finalTime = Math.floor(gameTime); storage.gameEndReason = 'colapso'; // Reset consecutive wins on game over missionManager.consecutiveWins = 0; missionManager.consecutiveHighEnergyWins = 0; storage.consecutiveWins = 0; storage.consecutiveHighEnergyWins = 0; gameActive = false; // Stop game updates showGameOver(); } else if (energy <= 0) { // Store final stats storage.finalEnergy = energy; storage.finalTime = Math.floor(gameTime); storage.gameEndReason = 'fatiga'; // Reset consecutive wins on game over missionManager.consecutiveWins = 0; missionManager.consecutiveHighEnergyWins = 0; storage.consecutiveWins = 0; storage.consecutiveHighEnergyWins = 0; gameActive = false; // Stop game updates showCustomGameOver(); } }; // Get nutritional information for the most caught food function getNutritionalInfo() { var maxCount = 0; var mostCaughtFood = null; // Find the food with highest count for (var food in foodCounts) { if (foodCounts[food] > maxCount) { maxCount = foodCounts[food]; mostCaughtFood = food; } } if (!mostCaughtFood || maxCount === 0) { return { title: "¡Sigue practicando!", info: "Intenta atrapar más alimentos saludables la próxima vez." }; } var nutritionalData = { 'apple': { title: "Manzana (1 unidad mediana)", info: "✅ Rica en fibra (4g), mejora la digestión.\n✅ Aporta vitamina C (8% de la recomendación diaria).\n✅ Tiene antioxidantes que protegen las células.\n⚖️ Solo 95 kcal y 0 grasa." }, 'banana': { title: "Plátano (1 unidad mediana)", info: "✅ Rico en potasio (400–450 mg), ideal para los músculos.\n✅ Contiene vitamina B6, que ayuda al sistema nervioso.\n✅ Da energía rápida gracias a sus azúcares naturales." }, 'hardEgg': { title: "Huevo duro (1 unidad)", info: "✅ Aporta proteínas completas (6g por huevo).\n✅ Rico en colina, esencial para la memoria y el cerebro.\n✅ Contiene vitamina D y hierro.\n⚠️ Contiene algo de colesterol, pero no es dañino en jóvenes sanos." }, 'broccoli': { title: "Brócoli (1 taza cocida)", info: "✅ Altísimo en vitamina C y vitamina K.\n✅ Fuente de fibra y antioxidantes.\n✅ Tiene compuestos que ayudan a prevenir el cáncer." }, 'carrot': { title: "Zanahoria (1 mediana cruda)", info: "✅ Altísima en betacaroteno (vitamina A), buena para la vista.\n✅ Solo 25 kcal y con fibra.\n✅ Rica en antioxidantes, fortalece el sistema inmune." }, 'wholeBread': { title: "Pan integral (1 rebanada)", info: "✅ Buena fuente de fibra (2–3 g por porción).\n✅ Aporta carbohidratos complejos que dan energía duradera.\n✅ Tiene hierro y vitaminas del grupo B." }, 'waterBottle': { title: "Agua (1 vaso / 240ml)", info: "✅ Hidratación esencial para todo el cuerpo.\n✅ Regula la temperatura, transporta nutrientes y limpia toxinas.\n✅ 0 calorías, 0 azúcar, 100% necesaria." } }; return nutritionalData[mostCaughtFood] || { title: "¡Sigue practicando!", info: "Intenta atrapar más alimentos saludables la próxima vez." }; } // Show victory message when energy reaches 30 function showVictoryMessage() { var finalTime = storage.finalTime || Math.floor((LK.ticks - gameStartTime) / 60); // Emit mission events for winning the game missionManagerInstance.emitEvent("partida_ganada", { energia: energy, vidasRestantes: lives }); // Award Nutripoints only for reaching maximum energy if (energy >= 30) { gameNutripoints = 2; // Award 2 Nutripoints for completing with max energy totalNutripoints += gameNutripoints; storage.totalNutripoints = totalNutripoints; } // Create full screen overlay var overlay = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); overlay.tint = 0x000000; overlay.alpha = 0.9; game.addChild(overlay); // Victory title var titleText = new Text2('¡FELICITACIONES!', { size: 120, fill: 0xFFD700, font: "Impact" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 400; game.addChild(titleText); // Victory message var messageText = new Text2('¡Alcanzaste el nivel máximo de energía saludable!', { size: 70, fill: 0x32CD32, font: "Impact" }); messageText.anchor.set(0.5, 0.5); messageText.x = 2048 / 2; messageText.y = 600; game.addChild(messageText); // Additional message lines var message2Text = new Text2('Tu cuerpo y tu mente están listas para todo.', { size: 60, fill: 0x00BFFF, font: "Impact" }); message2Text.anchor.set(0.5, 0.5); message2Text.x = 2048 / 2; message2Text.y = 750; game.addChild(message2Text); var message3Text = new Text2('Elegiste bien, vivís mejor.', { size: 60, fill: 0xFF69B4, font: "Impact" }); message3Text.anchor.set(0.5, 0.5); message3Text.x = 2048 / 2; message3Text.y = 900; game.addChild(message3Text); // Score section removed // Time played section var timeText = new Text2('Tiempo jugado: ' + finalTime + ' segundos', { size: 60, fill: 0xFFFFFF, font: "Impact" }); timeText.anchor.set(0.5, 0.5); timeText.x = 2048 / 2; timeText.y = 1100; game.addChild(timeText); // Nutripoints message var gameNutripointsText = new Text2('¡Ganaste 2 Nutripoints por llegar al máximo de energía!', { size: 65, fill: 0x32CD32, font: "Impact" }); gameNutripointsText.anchor.set(0.5, 0.5); gameNutripointsText.x = 2048 / 2; gameNutripointsText.y = 1200; game.addChild(gameNutripointsText); var totalNutripointsText = new Text2('Total acumulado: ' + totalNutripoints + ' Nutripoints', { size: 55, fill: 0xFFD700, font: "Impact" }); totalNutripointsText.anchor.set(0.5, 0.5); totalNutripointsText.x = 2048 / 2; totalNutripointsText.y = 1300; game.addChild(totalNutripointsText); // Create animated restart button var restartButton = LK.getAsset('restartButton', { width: 700, height: 140, color: 0x32CD32, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); restartButton.x = 2048 / 2; restartButton.y = 1600; game.addChild(restartButton); var restartText = new Text2('Jugar de nuevo', { size: 80, fill: 0xFFFFFF, font: "Impact" }); restartText.anchor.set(0.5, 0.5); restartText.x = 2048 / 2; restartText.y = 1600; game.addChild(restartText); // Animate button with pulsing effect function animateVictoryRestartButton() { tween(restartButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: animateVictoryRestartButton }); } }); tween(restartText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut }); } }); } animateVictoryRestartButton(); // Add click handler for restart restartButton.down = function () { showStartScreen(); }; restartText.down = function () { showStartScreen(); }; } // Show game over message when lives reach 0 function showGameOver() { var finalTime = storage.finalTime || Math.floor((LK.ticks - gameStartTime) / 60); // No Nutripoints awarded when not reaching maximum energy // Create full screen overlay var overlay = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); overlay.tint = 0x000000; overlay.alpha = 0.9; game.addChild(overlay); // Game Over title var gameOverText = new Text2('GAME OVER', { size: 150, fill: 0xFF0000, font: "Impact" }); gameOverText.anchor.set(0.5, 0.5); gameOverText.x = 2048 / 2; gameOverText.y = 600; game.addChild(gameOverText); // Score section removed // Time played section var timeText = new Text2('Tiempo jugado: ' + finalTime + ' segundos', { size: 60, fill: 0xFFFFFF, font: "Impact" }); timeText.anchor.set(0.5, 0.5); timeText.x = 2048 / 2; timeText.y = 800; game.addChild(timeText); // Nutripoints encouragement message var nutripointsEncourageText = new Text2('¡Sigue eligiendo bien para ganar Nutripoints!', { size: 65, fill: 0xFFD700, font: "Impact" }); nutripointsEncourageText.anchor.set(0.5, 0.5); nutripointsEncourageText.x = 2048 / 2; nutripointsEncourageText.y = 900; game.addChild(nutripointsEncourageText); // Add nutritional information section var mostConsumedText = new Text2('Alimento que más consumiste en esta partida', { size: 70, fill: 0x32CD32, font: "Impact" }); mostConsumedText.anchor.set(0.5, 0.5); mostConsumedText.x = 2048 / 2; mostConsumedText.y = 1050; game.addChild(mostConsumedText); var nutritionalInfo = getNutritionalInfo(); var nutritionTitleText = new Text2(nutritionalInfo.title, { size: 80, fill: 0xFFD700, font: "Impact" }); nutritionTitleText.anchor.set(0.5, 0.5); nutritionTitleText.x = 2048 / 2; nutritionTitleText.y = 1200; game.addChild(nutritionTitleText); var nutritionInfoText = new Text2(nutritionalInfo.info, { size: 55, fill: 0xFFFFFF, font: "Impact" }); nutritionInfoText.anchor.set(0.5, 0); nutritionInfoText.x = 2048 / 2; nutritionInfoText.y = 1250; game.addChild(nutritionInfoText); // Create animated restart button var restartButton = LK.getAsset('restartButton', { width: 700, height: 140, color: 0x32CD32, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); restartButton.x = 2048 / 2; restartButton.y = 1650; game.addChild(restartButton); var restartText = new Text2('Jugar de nuevo', { size: 80, fill: 0xFFFFFF, font: "Impact" }); restartText.anchor.set(0.5, 0.5); restartText.x = 2048 / 2; restartText.y = 1650; game.addChild(restartText); // Animate button with pulsing effect function animateGameOverRestartButton() { tween(restartButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: animateGameOverRestartButton }); } }); tween(restartText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut }); } }); } animateGameOverRestartButton(); // Add click handler for restart restartButton.down = function () { showStartScreen(); }; restartText.down = function () { showStartScreen(); }; } // Show custom game over message for energy depletion function showCustomGameOver() { var finalEnergy = storage.finalEnergy || energy; var finalTime = storage.finalTime || Math.floor((LK.ticks - gameStartTime) / 60); var reason = storage.gameEndReason || 'fatiga'; var message = ''; if (finalEnergy >= 25) { message = '¡NutriMáster!'; } else if (finalEnergy >= 15) { message = '¡Buen cazador de nutrientes!'; } else { message = 'Sigue practicando, revisa tus elecciones'; } // No Nutripoints awarded when not reaching maximum energy // Create full screen overlay var overlay = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); overlay.tint = 0x000000; overlay.alpha = 0.9; game.addChild(overlay); // Title var titleText = new Text2('FATIGA, FALTA DE ENERGÍA', { size: 100, fill: 0xFFD700, font: "Impact" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 400; game.addChild(titleText); // Score section removed // Time played section var timeText = new Text2('Tiempo jugado: ' + finalTime + ' segundos', { size: 70, fill: 0x00BFFF, font: "Impact" }); timeText.anchor.set(0.5, 0.5); timeText.x = 2048 / 2; timeText.y = 700; game.addChild(timeText); // Nutripoints encouragement message var nutripointsEncourageText = new Text2('¡Sigue eligiendo bien para ganar Nutripoints!', { size: 65, fill: 0xFFD700, font: "Impact" }); nutripointsEncourageText.anchor.set(0.5, 0.5); nutripointsEncourageText.x = 2048 / 2; nutripointsEncourageText.y = 800; game.addChild(nutripointsEncourageText); // Message section with color based on performance var messageColor = 0xFFFFFF; if (finalEnergy >= 25) { messageColor = 0xFFD700; // Gold for NutriMaster } else if (finalEnergy >= 15) { messageColor = 0x32CD32; // Green for good hunter } else { messageColor = 0xFF4500; // Orange for keep practicing } var messageText = new Text2(message, { size: 80, fill: messageColor, font: "Impact" }); messageText.anchor.set(0.5, 0.5); messageText.x = 2048 / 2; messageText.y = 900; game.addChild(messageText); // Add nutritional information section var mostConsumedText = new Text2('Alimento que más consumiste en esta partida', { size: 70, fill: 0x32CD32, font: "Impact" }); mostConsumedText.anchor.set(0.5, 0.5); mostConsumedText.x = 2048 / 2; mostConsumedText.y = 1000; game.addChild(mostConsumedText); var nutritionalInfo = getNutritionalInfo(); var nutritionTitleText = new Text2(nutritionalInfo.title, { size: 80, fill: 0xFFD700, font: "Impact" }); nutritionTitleText.anchor.set(0.5, 0.5); nutritionTitleText.x = 2048 / 2; nutritionTitleText.y = 1150; game.addChild(nutritionTitleText); var nutritionInfoText = new Text2(nutritionalInfo.info, { size: 55, fill: 0xFFFFFF, font: "Impact" }); nutritionInfoText.anchor.set(0.5, 0); nutritionInfoText.x = 2048 / 2; nutritionInfoText.y = 1200; game.addChild(nutritionInfoText); // Create animated restart button var restartButton = LK.getAsset('restartButton', { width: 700, height: 140, color: 0x32CD32, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); restartButton.x = 2048 / 2; restartButton.y = 1600; game.addChild(restartButton); var restartText = new Text2('Jugar de nuevo', { size: 80, fill: 0xFFFFFF, font: "Impact" }); restartText.anchor.set(0.5, 0.5); restartText.x = 2048 / 2; restartText.y = 1600; game.addChild(restartText); // Animate button with pulsing effect function animateRestartButton() { tween(restartButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: animateRestartButton }); } }); tween(restartText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut }); } }); } animateRestartButton(); // Add click handler for restart restartButton.down = function () { showStartScreen(); }; restartText.down = function () { showStartScreen(); }; } // Start countdown and restart game function startCountdown() { // Clear all game objects for (var i = fallingItems.length - 1; i >= 0; i--) { fallingItems[i].destroy(); } fallingItems = []; game.removeChildren(); // Reset all game variables energy = 15; lives = 3; fallSpeed = 350 / 60; lastSpeedIncrease = 0; lastWaterSpawn = 0; gameStartTime = 0; foodsCaught = 0; anxietyBombsActive = false; lastSpawnTime = 0; lastAnxietySpawnTime = 0; expertMessageShown = false; gameActive = true; // Reactivate game gameStarted = true; // Ensure game logic runs during countdown and game expertModeTimer = 0; // Reset expert mode timer gameNutripoints = 0; // Reset current game Nutripoints // Score reset removed // Clear GUI elements to reset them properly LK.gui.topLeft.removeChildren(); LK.gui.topRight.removeChildren(); LK.gui.top.removeChildren(); // Reset UI variable references totalNutripointsText = null; // Reset food counts foodCounts = { 'apple': 0, 'banana': 0, 'hardEgg': 0, 'broccoli': 0, 'carrot': 0, 'wholeBread': 0, 'waterBottle': 0 }; // Show countdown var countdownNumbers = [3, 2, 1]; var currentCount = 0; function showCountdownNumber() { if (currentCount < countdownNumbers.length) { var countText = new Text2(countdownNumbers[currentCount].toString(), { size: 250, fill: 0xFFFF00, font: "Impact" }); countText.anchor.set(0.5, 0.5); countText.x = 2048 / 2; countText.y = 2732 / 2; game.addChild(countText); // Animate countdown number tween(countText, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 1000, onFinish: function onFinish() { countText.destroy(); currentCount++; if (currentCount < countdownNumbers.length) { showCountdownNumber(); } else { // Start new game initializeGame(); // Force UI update after initialization to show correct values updateUI(); } } }); } } showCountdownNumber(); } // Screen management functions function showStartScreen() { currentScreen = 'start'; gameStarted = false; // Reset game started state game.removeChildren(); LK.gui.topLeft.removeChildren(); LK.gui.topRight.removeChildren(); if (!startScreen) { startScreen = new StartScreen(); } game.addChild(startScreen); } function handleStartScreenButton(buttonType) { switch (buttonType) { case 'PLAY': // Find the PLAY button and animate it for (var i = 0; i < startScreen.buttons.length; i++) { if (startScreen.buttons[i].type === 'PLAY') { var playButton = startScreen.buttons[i]; // Set gameStarted immediately to enable game logic gameStarted = true; // Animate button press tween(playButton.bg, { scaleX: 0.95, scaleY: 0.95, tint: 0x228B22 }, { duration: 150, onFinish: function onFinish() { tween(playButton.bg, { scaleX: 1.0, scaleY: 1.0, tint: 0x32CD32 }, { duration: 150, onFinish: function onFinish() { // Start game immediately after animation startGame(); } }); } }); tween(playButton.text, { scaleX: 0.95, scaleY: 0.95 }, { duration: 150, onFinish: function onFinish() { tween(playButton.text, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150 }); } }); break; } } break; case 'MISIONES': showMissionsScreen(); break; case 'TIENDA': showStoreScreen(); break; case 'PREGUNTAS': showFAQScreen(); break; } } function startGame() { currentScreen = 'game'; game.removeChildren(); startCountdown(); } function showMissionsScreen() { currentScreen = 'missions'; game.removeChildren(); LK.gui.topLeft.removeChildren(); LK.gui.topRight.removeChildren(); if (!missionsScreen) { missionsScreen = new MissionsScreen(); } game.addChild(missionsScreen); updateMissionsDisplay(); } function showStoreScreen() { currentScreen = 'store'; game.removeChildren(); LK.gui.topLeft.removeChildren(); LK.gui.topRight.removeChildren(); if (!storeScreen) { storeScreen = new StoreScreen(); } game.addChild(storeScreen); updateStoreDisplay(); } function showFAQScreen() { currentScreen = 'faq'; game.removeChildren(); LK.gui.topLeft.removeChildren(); LK.gui.topRight.removeChildren(); if (!faqScreen) { faqScreen = new FAQScreen(); } game.addChild(faqScreen); updateFAQDisplay(); } // Mission system functions - handled by MissionManager class function updateMissionsDisplay() { if (!missionsScreen) return; missionsScreen.missionsContainer.removeChildren(); missionsScreen.progressBars = []; var activeMissions = missionManager.activeMissions; if (!activeMissions || activeMissions.length === 0) { missionManagerInstance.generateNewDailyMissions(); activeMissions = missionManager.activeMissions; } for (var i = 0; i < activeMissions.length; i++) { var mission = activeMissions[i]; var missionBg = LK.getAsset('restartButton', { width: 1800, height: 280, anchorX: 0.5, anchorY: 0.5 }); missionBg.tint = mission.completada ? 0x27AE60 : 0x34495E; missionBg.x = 2048 / 2; missionBg.y = 500 + i * 320; missionsScreen.missionsContainer.addChild(missionBg); var missionText = new Text2((mission.completada ? '✔️ ' : '') + mission.text, { size: 55, fill: 0xFFFFFF, font: "Impact" }); missionText.anchor.set(0.5, 0.5); missionText.x = 2048 / 2; missionText.y = 480 + i * 320; missionsScreen.missionsContainer.addChild(missionText); // Progress bar background var progressBg = LK.getAsset('energyBarBg', { width: 450, height: 25, anchorX: 0.5, anchorY: 0.5 }); progressBg.tint = 0x666666; progressBg.alpha = 0.4; progressBg.x = 2048 / 2 - 225; progressBg.y = 550 + i * 320; missionsScreen.missionsContainer.addChild(progressBg); // Progress bar fill var progressWidth = mission.avanceActual / mission.metaTotal * 450; var progressFill = LK.getAsset('energyBarFill', { width: progressWidth, height: 25, anchorX: 0, anchorY: 0.5 }); progressFill.tint = 0x4CAF50; progressFill.x = 2048 / 2 - 225; progressFill.y = 550 + i * 320; missionsScreen.missionsContainer.addChild(progressFill); missionsScreen.progressBars.push(progressFill); // Progress text var progressText = new Text2(mission.avanceActual + ' / ' + mission.metaTotal, { size: 45, fill: 0xFFFFFF, font: "Impact" }); progressText.anchor.set(0.5, 0.5); progressText.x = 2048 / 2 + 250; progressText.y = 550 + i * 320; missionsScreen.missionsContainer.addChild(progressText); if (mission.completada) { var rewardText = new Text2('Completada ✔️ +2 Nutripoints', { size: 45, fill: 0xFFD700, font: "Impact" }); rewardText.anchor.set(0.5, 0.5); rewardText.x = 2048 / 2; rewardText.y = 590 + i * 320; missionsScreen.missionsContainer.addChild(rewardText); } } } // Store system functions function updateStoreDisplay() { if (!storeScreen) return; storeScreen.storeContainer.removeChildren(); var playerNutripoints = storage.totalNutripoints || 0; var ownedItems = storage.ownedItems || []; for (var i = 0; i < storeItems.length; i++) { var item = storeItems[i]; var owned = ownedItems.indexOf(item.id) !== -1; var canAfford = playerNutripoints >= item.costo; var itemBg = LK.getAsset('restartButton', { width: 700, height: 150, anchorX: 0.5, anchorY: 0.5 }); itemBg.tint = owned ? 0x27AE60 : canAfford ? 0x3498DB : 0x95A5A6; itemBg.x = i % 2 * 800 + 500; itemBg.y = 500 + Math.floor(i / 2) * 200; storeScreen.storeContainer.addChild(itemBg); var nameText = new Text2(item.nombre, { size: 45, fill: 0xFFFFFF, font: "Impact" }); nameText.anchor.set(0.5, 0.5); nameText.x = itemBg.x; nameText.y = itemBg.y - 20; storeScreen.storeContainer.addChild(nameText); var costText = new Text2(owned ? 'COMPRADO' : item.costo + ' Nutripoints', { size: 35, fill: owned ? 0x2ECC71 : canAfford ? 0xFFD700 : 0xE74C3C, font: "Impact" }); costText.anchor.set(0.5, 0.5); costText.x = itemBg.x; costText.y = itemBg.y + 20; storeScreen.storeContainer.addChild(costText); if (!owned && canAfford) { itemBg.itemData = item; (function (itemData) { itemBg.down = function (x, y, obj) { purchaseItem(itemData); }; })(item); } } } function purchaseItem(item) { if (!item || typeof item.costo === 'undefined') { console.error('Invalid item data in purchaseItem'); return; } var playerNutripoints = storage.totalNutripoints || 0; var ownedItems = storage.ownedItems || []; if (playerNutripoints >= item.costo && ownedItems.indexOf(item.id) === -1) { storage.totalNutripoints = playerNutripoints - item.costo; ownedItems.push(item.id); storage.ownedItems = ownedItems; // Show purchase popup var popup = LK.getAsset('restartButton', { width: 800, height: 200, anchorX: 0.5, anchorY: 0.5 }); popup.tint = 0x27AE60; popup.x = 2048 / 2; popup.y = 2732 / 2; game.addChild(popup); var popupText = new Text2('¡Nuevo artículo desbloqueado!', { size: 60, fill: 0xFFFFFF, font: "Impact" }); popupText.anchor.set(0.5, 0.5); popupText.x = 2048 / 2; popupText.y = 2732 / 2; game.addChild(popupText); LK.getSound('powerup').play(); // Remove popup after 2 seconds LK.setTimeout(function () { popup.destroy(); popupText.destroy(); updateStoreDisplay(); }, 2000); } } // FAQ system functions function updateFAQDisplay() { if (!faqScreen) return; // Initialize FAQ items with accordion functionality faqScreen.createFAQItems(); } // Initialize mission manager var missionManagerInstance = new MissionManager(); missionManagerInstance.init(); // Initialize mission tracking variables properly missionManager.gameStartTime = 0; missionManager.lastGaseosaTime = -60; // Start with -60 to allow immediate tracking missionManager.consecutiveWins = storage.consecutiveWins || 0; missionManager.falsosInCurrentGame = 0; missionManager.consecutiveHighEnergyWins = storage.consecutiveHighEnergyWins || 0; missionManager.continuousPlayTime = storage.continuousPlayTime || 0; // Initialize storage for persistent data totalNutripoints = storage.totalNutripoints || 0; // Initialize the start screen as the first state showStartScreen(); ;
===================================================================
--- original.js
+++ change.js
@@ -17,20 +17,213 @@
anchorY: 0
});
bg.tint = 0xF8F9FA;
self.addChild(bg);
+ // Create scrollable container for FAQ content
+ var scrollContainer = new Container();
+ self.addChild(scrollContainer);
// Title
var titleText = new Text2('PREGUNTAS FRECUENTES', {
size: 80,
fill: 0x2C3E50,
font: "Impact"
});
- titleText.anchor.set(0.5, 0.5);
+ titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
- titleText.y = 250;
- self.addChild(titleText);
+ titleText.y = 150;
+ scrollContainer.addChild(titleText);
self.faqContainer = new Container();
- self.addChild(self.faqContainer);
+ self.faqContainer.x = 0;
+ self.faqContainer.y = 300;
+ scrollContainer.addChild(self.faqContainer);
+ // FAQ state tracking
+ self.openFAQIndex = -1; // Track which FAQ is currently open
+ self.faqItems = []; // Store FAQ item references
+ // Create FAQ items
+ self.createFAQItems = function () {
+ self.faqContainer.removeChildren();
+ self.faqItems = [];
+ var currentY = 0;
+ var itemSpacing = 20;
+ for (var i = 0; i < faqData.length; i++) {
+ var faq = faqData[i];
+ var isOpen = self.openFAQIndex === i;
+ // Question container with shadow effect
+ var questionContainer = new Container();
+ questionContainer.y = currentY;
+ self.faqContainer.addChild(questionContainer);
+ // Question background with rounded appearance
+ var questionBg = LK.getAsset('restartButton', {
+ width: 1800,
+ height: 120,
+ anchorX: 0.5,
+ anchorY: 0
+ });
+ questionBg.tint = isOpen ? 0x3498DB : 0x34495E;
+ questionBg.x = 2048 / 2;
+ questionBg.y = 0;
+ questionContainer.addChild(questionBg);
+ // Expand/collapse icon
+ var iconText = new Text2(isOpen ? '⊖' : '⊕', {
+ size: 60,
+ fill: 0xFFFFFF,
+ font: "Impact"
+ });
+ iconText.anchor.set(0, 0.5);
+ iconText.x = 250;
+ iconText.y = 60;
+ questionContainer.addChild(iconText);
+ // Question text
+ var questionText = new Text2(faq.question, {
+ size: 48,
+ fill: 0xFFFFFF,
+ font: "Impact"
+ });
+ questionText.anchor.set(0, 0.5);
+ questionText.x = 350;
+ questionText.y = 60;
+ questionContainer.addChild(questionText);
+ // Answer container (initially hidden if not open)
+ var answerContainer = new Container();
+ answerContainer.y = 130;
+ answerContainer.alpha = isOpen ? 1 : 0;
+ answerContainer.visible = isOpen;
+ questionContainer.addChild(answerContainer);
+ // Answer background
+ var answerBg = LK.getAsset('restartButton', {
+ width: 1700,
+ height: isOpen ? 180 : 0,
+ anchorX: 0.5,
+ anchorY: 0
+ });
+ answerBg.tint = 0xECF0F1;
+ answerBg.x = 2048 / 2;
+ answerBg.y = 0;
+ answerContainer.addChild(answerBg);
+ // Answer text
+ var answerText = new Text2(faq.answer, {
+ size: 42,
+ fill: 0x2C3E50,
+ font: "Impact"
+ });
+ answerText.anchor.set(0.5, 0);
+ answerText.x = 2048 / 2;
+ answerText.y = 20;
+ answerContainer.addChild(answerText);
+ // Store references
+ var faqItem = {
+ index: i,
+ questionContainer: questionContainer,
+ questionBg: questionBg,
+ iconText: iconText,
+ answerContainer: answerContainer,
+ answerBg: answerBg,
+ isOpen: isOpen
+ };
+ self.faqItems.push(faqItem);
+ // Add click handlers with closure
+ (function (itemIndex) {
+ questionBg.down = function () {
+ self.toggleFAQ(itemIndex);
+ };
+ iconText.down = function () {
+ self.toggleFAQ(itemIndex);
+ };
+ questionText.down = function () {
+ self.toggleFAQ(itemIndex);
+ };
+ })(i);
+ // Calculate next Y position
+ currentY += 120 + itemSpacing;
+ if (isOpen) {
+ currentY += 180 + itemSpacing;
+ }
+ }
+ };
+ // Toggle FAQ open/close
+ self.toggleFAQ = function (index) {
+ if (index === self.openFAQIndex) {
+ // Close currently open FAQ
+ self.closeFAQ(index);
+ self.openFAQIndex = -1;
+ } else {
+ // Close currently open FAQ if any
+ if (self.openFAQIndex >= 0) {
+ self.closeFAQ(self.openFAQIndex);
+ }
+ // Open new FAQ
+ self.openFAQ(index);
+ self.openFAQIndex = index;
+ }
+ };
+ // Open FAQ with animation
+ self.openFAQ = function (index) {
+ var item = self.faqItems[index];
+ if (!item) return;
+ // Update icon and background color
+ item.iconText.setText('⊖');
+ tween(item.questionBg, {
+ tint: 0x3498DB
+ }, {
+ duration: 200
+ });
+ // Show and animate answer container
+ item.answerContainer.visible = true;
+ item.answerContainer.alpha = 0;
+ // Animate answer background height
+ tween(item.answerBg, {
+ height: 180
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ // Fade in answer container
+ tween(item.answerContainer, {
+ alpha: 1
+ }, {
+ duration: 250,
+ onFinish: function onFinish() {
+ // Recreate all items to adjust positions
+ LK.setTimeout(function () {
+ self.createFAQItems();
+ }, 50);
+ }
+ });
+ };
+ // Close FAQ with animation
+ self.closeFAQ = function (index) {
+ var item = self.faqItems[index];
+ if (!item) return;
+ // Update icon and background color
+ item.iconText.setText('⊕');
+ tween(item.questionBg, {
+ tint: 0x34495E
+ }, {
+ duration: 200
+ });
+ // Fade out and hide answer container
+ tween(item.answerContainer, {
+ alpha: 0
+ }, {
+ duration: 200,
+ onFinish: function onFinish() {
+ item.answerContainer.visible = false;
+ // Animate answer background height to 0
+ tween(item.answerBg, {
+ height: 0
+ }, {
+ duration: 200,
+ easing: tween.easeIn,
+ onFinish: function onFinish() {
+ // Recreate all items to adjust positions
+ LK.setTimeout(function () {
+ self.createFAQItems();
+ }, 50);
+ }
+ });
+ }
+ });
+ };
// Bottom back button
var bottomBackButton = LK.getAsset('restartButton', {
width: 400,
height: 100,
@@ -2095,50 +2288,10 @@
}
// FAQ system functions
function updateFAQDisplay() {
if (!faqScreen) return;
- faqScreen.faqContainer.removeChildren();
- for (var i = 0; i < faqData.length; i++) {
- var faq = faqData[i];
- var questionBg = LK.getAsset('restartButton', {
- width: 1800,
- height: 100,
- anchorX: 0.5,
- anchorY: 0.5
- });
- questionBg.tint = 0x3498DB;
- questionBg.x = 2048 / 2;
- questionBg.y = 350 + i * 300;
- faqScreen.faqContainer.addChild(questionBg);
- var questionText = new Text2(faq.question, {
- size: 45,
- fill: 0xFFFFFF,
- font: "Impact"
- });
- questionText.anchor.set(0.5, 0.5);
- questionText.x = 2048 / 2;
- questionText.y = 350 + i * 300;
- faqScreen.faqContainer.addChild(questionText);
- var answerBg = LK.getAsset('restartButton', {
- width: 1800,
- height: 150,
- anchorX: 0.5,
- anchorY: 0.5
- });
- answerBg.tint = 0xECF0F1;
- answerBg.x = 2048 / 2;
- answerBg.y = 425 + i * 300;
- faqScreen.faqContainer.addChild(answerBg);
- var answerText = new Text2(faq.answer, {
- size: 35,
- fill: 0x2C3E50,
- font: "Impact"
- });
- answerText.anchor.set(0.5, 0.5);
- answerText.x = 2048 / 2;
- answerText.y = 425 + i * 300;
- faqScreen.faqContainer.addChild(answerText);
- }
+ // Initialize FAQ items with accordion functionality
+ faqScreen.createFAQItems();
}
// Initialize mission manager
var missionManagerInstance = new MissionManager();
missionManagerInstance.init();