User prompt
Cuando muestras las estrellas un sonido de victoria, ponlo como asset.
Code edit (6 edits merged)
Please save this source code
User prompt
Que solo sea un segundo y que el cuadro negro sea más grande en todas las direcciones, aunque sea más grande que la patnalla de juego. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Que al inicio del juego completo, el cuadro negro del fade se mantenga completamente negro por 2 segundo y solo despues de ese segundo se inicie el fade al menu principal. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
L logica del menu RESET para cuando se selecciona esta al eves, esta opaco y cuando se selecciona se hace normal, deberia estar normal y cuando se pasa el mouse se hace opaco ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Cuando inicio el juego la imagen de fondo llamada menu_background y la imagen Titulo tardan en cargar, hay manera que me ayudes a ajustarlas?
Code edit (6 edits merged)
Please save this source code
User prompt
No quiero que la variable Inicio sea Persistent data, que se local para que se borre cuando se carga de nuevo el juego completo.
User prompt
Necesito un delay para que inicie la cancion si es que es la segunda o mas de la segunda vez que se juega el juego, inicia una variable llamada INICIO, cuando se termine el juego por primera vez haz inicio = true. cuando Inicio = true exista este delay para iniciar la cancion del juego. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Asegurate de que la parte negra del fade in se muestre frente a todos los elemntos del juego.- ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Tambien eljueg inicial en el menu debe inciar con un fade in desde pantalla negra pero que dure más como tres segundos ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Tengo dos problemas, el primero es que mi escena ya no inicia desde un fade de pantalla negra y el segundo es que cuando se muestra la imagen de tutorial se ve en baja resolución
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Clase Cannon para mostrar el cañón y animar disparo var Cannon = Container.expand(function () { var self = Container.call(this); // Asset del cañón (ahora usa la imagen personalizada) self.cannonAsset = self.attachAsset('cannon', { anchorX: 0.5, anchorY: 1 }); // Efecto de fogonazo al disparar self.flash = null; // Estado self.isVisible = true; self.isShooting = false; // Posición base (centrado horizontal, abajo) self.baseX = 2048 / 2; // Coloca el cañón pegado a la parte baja del juego (anchorY:1, así que baseY es exactamente el borde inferior) self.baseY = 2732; self.x = self.baseX; self.y = self.baseY; // Mostrar cañón self.show = function () { self.visible = true; self.isVisible = true; // Animar subida si estaba oculto tween(self, { y: self.baseY }, { duration: 350, easing: tween.cubicOut }); }; // Animar disparo (pequeño retroceso y fogonazo) self.shoot = function () { if (self.isShooting) { return; } self.isShooting = true; // Retroceso rápido tween(self, { y: self.baseY - 60 }, { duration: 80, easing: tween.cubicOut, onFinish: function onFinish() { // Regresa a posición base tween(self, { y: self.baseY }, { duration: 120, easing: tween.cubicIn, onFinish: function onFinish() { self.isShooting = false; } }); } }); // Fogonazo visual if (!self.flash) { self.flash = self.attachAsset('cut_zone', { anchorX: 0.5, anchorY: 1, x: 0, y: -self.cannonAsset.height + 30, scaleX: 0.5, scaleY: 0.3, alpha: 0.0, color: 0xffffcc }); } self.flash.alpha = 0.7; self.flash.scaleX = 0.5; self.flash.scaleY = 0.3; tween(self.flash, { alpha: 0, scaleX: 1.2, scaleY: 0.7 }, { duration: 120, easing: tween.linear }); }; return self; }); // Clase para el objeto de cuenta regresiva "Go" var CountdownGo = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('Go', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.asset.width / 2; self.isActive = true; self.state = 'countdown'; self.destroyCountdown = function () { self.isActive = false; self.visible = false; self.destroy(); }; return self; }); // Clase para el objeto de cuenta regresiva "1" var CountdownOne = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('1', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.asset.width / 2; self.isActive = true; self.state = 'countdown'; self.destroyCountdown = function () { self.isActive = false; self.visible = false; self.destroy(); }; return self; }); // Clase para el objeto de cuenta regresiva "2" var CountdownTwo = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('2', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.asset.width / 2; self.isActive = true; self.state = 'countdown'; self.destroyCountdown = function () { self.isActive = false; self.visible = false; self.destroy(); }; return self; }); var Fruit = Container.expand(function () { var self = Container.call(this); // Selección aleatoria de tipo de fruta var fruitTypes = ['fruit_apple', 'fruit_lemon', 'fruit_orange', 'fruit_kiwi', 'fruit_plum']; self.fruitType = fruitTypes[Math.floor(Math.random() * fruitTypes.length)]; // Asset de la fruta self.fruitAsset = self.attachAsset(self.fruitType, { anchorX: 0.5, anchorY: 0.5 }); if (self.fruitAsset) { self.fruitAsset.scaleX = 1; // Empieza muy pequeño self.fruitAsset.scaleY = 1; } else if (self.children && self.children.length > 0) { var lastChild = self.children[self.children.length - 1]; lastChild.scaleX = 0.1; lastChild.scaleY = 0.1; self.fruitAsset = lastChild; } self.radius = self.fruitAsset.width * self.fruitAsset.scaleX / 2 + 60; // Estado self.isCut = false; self.isActive = true; // Agregamos la velocidad de crecimiento de escala (puedes ajustar) self.scaleGrowSpeed = 0.1; // escala por frame // Método para actualizar la fruta cada frame (debe llamarse en el ciclo principal) self.update = function () { if (!self.isCut && self.fruitAsset) { // Incrementar escala hasta 0.5 (máximo) if (self.fruitAsset.scaleX < 0.5) { self.fruitAsset.scaleX = Math.min(0.5, self.fruitAsset.scaleX + self.scaleGrowSpeed); self.fruitAsset.scaleY = self.fruitAsset.scaleX; // Actualizar radius para hitbox self.radius = self.fruitAsset.width * self.fruitAsset.scaleX / 2 + 60; } } }; self.cut = function () { if (self.isCut) { return; } self.isCut = true; self.isActive = false; self.visible = false; }; return self; }); // Clase para la fruta cortada (dos mitades) var FruitCut = Container.expand(function () { var self = Container.call(this); // Recibe tipo de fruta, posición base, rotación y escala self.init = function (fruitType, x, y, rotation, scale) { if (typeof rotation === "undefined") { rotation = 0; } if (typeof scale === "undefined") { scale = 1; } // Para las frutas, usar assets de mitades cortadas específicos por tipo de fruta var leftAssetId = 'fruit_apple_cut_left'; var rightAssetId = 'fruit_apple_cut_right'; if (fruitType === 'fruit_apple') { leftAssetId = 'fruit_apple_cut_left'; rightAssetId = 'fruit_apple_cut_right'; } else if (fruitType === 'fruit_lemon') { leftAssetId = 'fruit_lemon_cut_left'; rightAssetId = 'fruit_lemon_cut_right'; } else if (fruitType === 'fruit_orange') { leftAssetId = 'fruit_orange_cut_left'; rightAssetId = 'fruit_orange_cut_right'; } else if (fruitType === 'fruit_plum') { leftAssetId = 'fruit_plum_cut_left'; rightAssetId = 'fruit_plum_cut_right'; } else if (fruitType === 'fruit_kiwi') { leftAssetId = 'fruit_kiwi_cut_left'; rightAssetId = 'fruit_kiwi_cut_right'; } // Mitad izquierda reflejada horizontalmente (flipX: 1) self.left = self.attachAsset(leftAssetId, { anchorX: 1, anchorY: 0.5, scaleX: scale, scaleY: scale, x: 0, y: 0, flipX: 1 }); // Mitad derecha normal self.right = self.attachAsset(rightAssetId, { anchorX: 0, anchorY: 0.5, scaleX: scale, scaleY: scale, x: 0, y: 0 }); self.x = x; self.y = y; self.left.rotation = rotation; self.right.rotation = rotation; self.rotation = rotation; }; // Animación de separación self.animate = function (_onFinish) { // Reduce size to 80% immediately tween(self.left, { x: -80, rotation: self.left.rotation + 0.7, scaleX: self.left.scaleX * 0.8, scaleY: self.left.scaleY * 0.8 }, { duration: 500, easing: tween.cubicOut }); tween(self.right, { x: 80, rotation: self.right.rotation - 0.7, scaleX: self.right.scaleX * 0.8, scaleY: self.right.scaleY * 0.8 }, { duration: 500, easing: tween.cubicOut, onFinish: function onFinish() { // Fade out both halves after movement/scaling tween(self.left, { alpha: 0 }, { duration: 350, easing: tween.linear }); tween(self.right, { alpha: 0 }, { duration: 350, easing: tween.linear, onFinish: function onFinish() { if (_onFinish) { _onFinish(); } } }); } }); }; return self; }); // Base Scene class for scene management var Scene = Container.expand(function () { var self = Container.call(this); self.isActive = false; self.activate = function () { self.isActive = true; self.visible = true; // Make sure overlay is visible when scene is activated if (self.overlay) { self.overlay.visible = true; } }; self.deactivate = function () { self.isActive = false; self.visible = false; // Make sure to hide overlay to prevent black background if (self.overlay) { self.overlay.visible = false; } }; return self; }); // Menu Scene var MenuScene = Scene.expand(function () { var self = Scene.call(this); // Full screen background (added first so it's behind everything) var menuBg = self.attachAsset('menu_background', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); // Create decorative fruits container to ensure proper layering var fruitsContainer = new Container(); self.addChild(fruitsContainer); // Add Titulo asset at the top var titulo = self.attachAsset('Titulo', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1000 }); // Play button (will be added after fruits container) var playButton = self.attachAsset('button_play', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2000 }); // Button interaction playButton.interactive = true; playButton.down = function () { playButton.tint = 0xcccccc; }; playButton.up = function () { playButton.tint = 0xffffff; if (game.onPlayPressed) { game.onPlayPressed(); } }; // Decorative fruits var decorativeFruits = []; var fruitTypes = ['fruit_apple', 'fruit_lemon', 'fruit_orange', 'fruit_kiwi', 'fruit_plum']; var fruitScale = 1; // Normal size var fruitSpacing = 250; // Horizontal spacing between fruits var verticalSpacing = 200; // Vertical spacing between rows var baseY = 150; // Starting Y position for first row var fruitSpeed = 2; // Horizontal movement speed // Calculate how many rows we can fit var availableHeight = 2732 - 100; var numRows = Math.floor(availableHeight / verticalSpacing); // Decorative fruits var decorativeFruits = []; var fruitTypes = ['fruit_apple', 'fruit_lemon', 'fruit_orange', 'fruit_kiwi', 'fruit_plum']; var fruitScale = 1; // Normal size var fruitSpacing = 250; // Horizontal spacing between fruits var verticalSpacing = 200; // Vertical spacing between rows var baseY = 150; // Starting Y position for first row var fruitSpeed = 2; // Horizontal movement speed var resetX = -400; // X position where fruits reappear // Calculate how many rows we can fit var availableHeight = 2732 - 100; var numRows = Math.floor(availableHeight / verticalSpacing); // Create fruits and shadows for each row for (var row = 0; row < numRows; row++) { var y = baseY + row * verticalSpacing; var numFruits = Math.ceil((2048 + fruitSpacing * 2) / fruitSpacing); var rowOffset = row % 2 === 1 ? fruitSpacing / 2 : 0; var initialRotation = row % 2 === 1 ? Math.PI : 0; // 180° for odd rows for (var col = 0; col < numFruits; col++) { var fruitType = fruitTypes[(row + col) % fruitTypes.length]; var x = col * fruitSpacing - fruitSpacing + rowOffset; // Create shadow first (so it appears behind the fruit) var shadow = self.attachAsset(fruitType, { anchorX: 0.5, anchorY: 0.5, x: x + 15, y: y + 15, scaleX: fruitScale, scaleY: fruitScale, rotation: initialRotation, tint: 0x000000, alpha: 0.3 }); shadow.rotationSpeed = 0.02; shadow.isShadow = true; decorativeFruits.push(shadow); fruitsContainer.addChild(shadow); // Create actual fruit on top var fruit = self.attachAsset(fruitType, { anchorX: 0.5, anchorY: 0.5, x: x, y: y, scaleX: fruitScale, scaleY: fruitScale, rotation: initialRotation }); fruit.rotationSpeed = 0.02; fruit.isShadow = false; decorativeFruits.push(fruit); fruitsContainer.addChild(fruit); } } self.activate = function () { self.isActive = true; self.visible = true; // Create black overlay for fade-in effect var fadeOverlay = LK.getAsset('vertical_line', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732, color: 0x000000, alpha: 1 }); self.addChild(fadeOverlay); // Bring fade overlay to front to ensure it's above all other elements self.setChildIndex(fadeOverlay, self.children.length - 1); // Fade out the black overlay over 3 seconds tween(fadeOverlay, { alpha: 0 }, { duration: 3000, easing: tween.linear, onFinish: function onFinish() { fadeOverlay.destroy(); } }); // Play menu music when menu activates LK.playMusic('menu_music'); }; // Update function for menu scene self.updateMenu = function () { for (var i = 0; i < decorativeFruits.length; i++) { var fruit = decorativeFruits[i]; fruit.x += fruitSpeed; fruit.rotation += fruit.rotationSpeed; if (fruit.x > 2048 + fruitSpacing) { if (fruit.isShadow) { // Aparece un poco más a la izquierda para compensar desfase fruit.x = resetX; } else { fruit.x = resetX; } } } }; // Add tutorial reset button in bottom-right corner var tutorialResetButton = self.attachAsset('tutorial_reset_button', { anchorX: 0.5, anchorY: 0.5, x: 2048 - 80, // 80px from right edge y: 2732 - 80, // 80px from bottom edge scaleX: .6, scaleY: .6, alpha: 0.7 }); // Tutorial reset button interaction tutorialResetButton.interactive = true; tutorialResetButton.down = function () { tutorialResetButton.tint = 0xcccccc; }; tutorialResetButton.up = function () { tutorialResetButton.tint = 0xffffff; // Reset tutorial flag in storage storage.hasSeenIntro = false; // Visual feedback - flash the button LK.effects.flashObject(tutorialResetButton, 0x00ff00, 500); }; // Add hover effect self.move = function (x, y, obj) { // Convert coordinates to button's local space var globalPos = self.toGlobal({ x: x, y: y }); var localPos = playButton.toLocal(globalPos); var halfWidth = playButton.width / 2; var halfHeight = playButton.height / 2; if (localPos.x >= -halfWidth && localPos.x <= halfWidth && localPos.y >= -halfHeight && localPos.y <= halfHeight) { playButton.alpha = 0.8; // Make more opaque (less transparent) when hovering } else { playButton.alpha = 1; // Normal opacity (fully visible) } // Check hover for tutorial reset button var tutorialLocalPos = tutorialResetButton.toLocal(globalPos); var tutorialHalfWidth = tutorialResetButton.width * tutorialResetButton.scaleX / 2; var tutorialHalfHeight = tutorialResetButton.height * tutorialResetButton.scaleY / 2; if (tutorialLocalPos.x >= -tutorialHalfWidth && tutorialLocalPos.x <= tutorialHalfWidth && tutorialLocalPos.y >= -tutorialHalfHeight && tutorialLocalPos.y <= tutorialHalfHeight) { tutorialResetButton.alpha = 1.0; // More visible when hovering } else { tutorialResetButton.alpha = 0.7; // Normal transparency } }; return self; }); // IntroScene - displays tutorial image before game starts var IntroScene = Scene.expand(function () { var self = Scene.call(this); // Tutorial background image - use full resolution self.tutorialImage = self.attachAsset('tutorial', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 1.0, scaleY: 1.0 }); // Tap anywhere to continue text var continueText = new Text2('TAP TO CONTINUE', { size: 80, fill: 0x000000 }); continueText.anchor.set(0.5, 0.5); continueText.x = 1024; continueText.y = 2530; self.addChild(continueText); // Fade text in and out animation self.animateText = function () { tween(continueText, { alpha: 0.3 }, { duration: 800, easing: tween.linear, onFinish: function onFinish() { tween(continueText, { alpha: 1 }, { duration: 800, easing: tween.linear, onFinish: function onFinish() { if (self.isActive) { self.animateText(); } } }); } }); }; self.activate = function () { self.isActive = true; self.visible = true; self.animateText(); }; self.deactivate = function () { self.isActive = false; self.visible = false; }; // Handle tap to continue self.down = function (x, y, obj) { if (self.isActive && game.onIntroComplete) { game.onIntroComplete(); } }; // Start deactivated self.deactivate(); return self; }); // Game Scene - wraps all the existing game logic var GameScene = Scene.expand(function () { var self = Scene.call(this); // All game variables var bottomBg, topBg, greenLine, destructionLine, scoreTxt; var comboImage = null; var comboFadeTimeout = null; var comboFadeTween = null; var horizontalLine, cannon; var frutasGeneradas = 0; var frutasFalladas = 0; var fruits = []; var fallingFruits = []; var cutFruits = []; var frutasFalladasTimeout = null; var fruitSpeed = 25; var comboCounter = 0; var cutZoneAsset, cutZoneRadius; var canCut = true; var lastTouchTick = -100; // Round system variables var roundState, roundBullets, roundFruitsQueue, roundFruitsActive; var roundBulletsFired, roundDelayTicks, currentStage; var roundDelayBetweenRounds, roundNextBulletTick, roundStartTick; var countdownObjectsFired, goShotTick, stage2Scheduled, stage3Scheduled; var roundJustReset, showCountdownInMiddleDone; self.activate = function () { self.isActive = true; self.visible = true; // Start with black overlay for fade-in effect var fadeOverlay = LK.getAsset('vertical_line', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732, color: 0x000000, alpha: 1 }); self.addChild(fadeOverlay); // Bring fade overlay to front to ensure it's above all other elements self.setChildIndex(fadeOverlay, self.children.length - 1); // Fade out the black overlay tween(fadeOverlay, { alpha: 0 }, { duration: 800, easing: tween.linear, onFinish: function onFinish() { fadeOverlay.destroy(); } }); // Play background music when game starts if (Inicio) { // Add delay for subsequent plays LK.setTimeout(function () { LK.playMusic('bgmusic', { loop: false }); }, 300); // 2 second delay } else { // Play immediately for first time LK.playMusic('bgmusic', { loop: false }); } }; self.deactivate = function () { self.isActive = false; self.visible = false; }; // All game variables will be initialized here self.initGame = function () { // Fondo inferior café bottomBg = LK.getAsset('bottom_bg', { anchorX: 0, anchorY: 1, x: 0, y: 2732 }); self.addChild(bottomBg); // Fondo superior azul topBg = LK.getAsset('top_bg', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); self.addChild(topBg); // Línea verde casi transparente greenLine = LK.getAsset('greenLine', { anchorX: 0, anchorY: 0.5, x: 25, y: 500, alpha: 0.2 }); self.addChild(greenLine); // Línea roja de destrucción destructionLine = LK.getAsset('vertical_line', { anchorX: 0, anchorY: 0.5, x: 0, y: -100, width: 2048, height: 10, color: 0xff0000, shape: 'box' }); self.addChild(destructionLine); // Score text (invisible) scoreTxt = new Text2('', { size: 1, fill: "#222", alpha: 0 }); scoreTxt.visible = false; // Línea negra horizontal horizontalLine = LK.getAsset('vertical_line', { anchorX: 0, anchorY: 0.5, x: 0, y: 2732 / 2 + 540, width: 2048, height: 120, color: 0x000000, shape: 'box' }); // Instancia el cañón cannon = new Cannon(); self.addChild(horizontalLine); self.addChild(cannon); cannon.show(); // Initialize cut zone cutZoneAsset = LK.getAsset('cut_zone', { anchorX: 0.5, anchorY: 0.5 }); cutZoneRadius = cutZoneAsset.width / 2; cutZoneAsset.destroy(); // Reset all game variables frutasGeneradas = 0; frutasFalladas = 0; fruits = []; fallingFruits = []; cutFruits = []; fruitSpeed = 25; comboCounter = 0; canCut = true; lastTouchTick = -100; roundState = undefined; countdownObjectsFired = undefined; goShotTick = undefined; stage2Scheduled = undefined; stage3Scheduled = undefined; roundJustReset = undefined; showCountdownInMiddleDone = undefined; // Reset score LK.setScore(0); updateScore(0); // Set game start delay if coming from menu or restart self.gameStartDelay = LK.ticks; // 0.2 seconds delay (12 ticks at 60fps) }; // Helper functions function updateScore(val) { LK.setScore(val); scoreTxt.setText(val); } function tryCutFruit(x, y) { if (!canCut) { return; } canCut = false; lastTouchTick = LK.ticks; for (var i = 0; i < fallingFruits.length; i++) { var fruit = fallingFruits[i]; if (!fruit.isActive) { continue; } if (fruit.state === 'cuttable') { var dx = x - fruit.x; var dy = y - fruit.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist <= fruit.radius * fruit.scaleX) { fruit.cut(); if (fruit.cutZoneCircle) { fruit.cutZoneCircle.destroy(); fruit.cutZoneCircle = null; } LK.getSound('cut').play(); // Check if Y position is within combo zone (350-750) if (y >= 350 && y <= 750) { comboCounter++; if (comboCounter >= 13) { comboCounter = 1; // Reset to 1 after reaching 12 } } else { comboCounter = 0; } // Update combo image display if (comboFadeTimeout) { LK.clearTimeout(comboFadeTimeout); comboFadeTimeout = null; } if (comboImage) { // Cancel any ongoing tween on the previous combo image if (comboFadeTween) { comboFadeTween.stop(); comboFadeTween = null; } comboImage.destroy(); comboImage = null; } if (comboCounter > 0 && comboCounter <= 12) { comboImage = LK.getAsset('combo' + comboCounter, { anchorX: 1, anchorY: 0, alpha: 1, scaleX: 0.5, scaleY: 0.5 }); LK.gui.topRight.addChild(comboImage); comboImage.x = -20; // 20px from right edge comboImage.y = 20; // 20px from top // Scale up from 50% to 100% in 0.1 seconds tween(comboImage, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.cubicOut }); // After 0.3 seconds (0.1s grow + 0.2s show), start fade out comboFadeTimeout = LK.setTimeout(function () { if (comboImage) { comboFadeTween = tween(comboImage, { alpha: 0 }, { duration: 100, easing: tween.linear, onFinish: function onFinish() { if (comboImage) { comboImage.destroy(); comboImage = null; } comboFadeTween = null; } }); } comboFadeTimeout = null; }, 300); } // Animación de corte para todas las frutas var fruitCut = new FruitCut(); fruitCut.init(fruit.fruitType, fruit.x, fruit.y, fruit.rotation, fruit.scaleX); self.addChild(fruitCut); // Asegura que la línea negra esté sobre las frutas cortadas pero debajo del cañón if (horizontalLine && horizontalLine.parent) { horizontalLine.parent.removeChild(horizontalLine); self.addChild(horizontalLine); } // Asegura que el cañón siempre esté al frente if (cannon && cannon.parent) { cannon.parent.removeChild(cannon); self.addChild(cannon); } fruitCut.animate(function () { fruitCut.destroy(); }); cutFruits.push(fruitCut); frutasGeneradas++; updateScore(LK.getScore() + 1); return; } } } } self.down = function (x, y, obj) { if (self.isActive) { // Check if game start delay has passed if (self.gameStartDelay && LK.ticks < self.gameStartDelay) { return; } tryCutFruit(x, y); } }; self.updateGame = function () { if (!self.isActive) { return; } // Wait for game start delay before processing any game logic if (self.gameStartDelay && LK.ticks < self.gameStartDelay) { return; } // Permitir corte nuevamente tras 6 ticks (~100ms) if (!canCut && LK.ticks - lastTouchTick > 6) { canCut = true; } // --- SISTEMA DE BALAS POR RONDA (5 balas, 1s entre cada una, 7s delay antes de mostrar en pantalla superior) --- if (typeof roundState === "undefined") { // Estados posibles: 'waiting', 'spawning', 'waitingFruits' roundState = 'waiting'; roundBullets = 7; // 3 countdown objects + 4 fruits (stage 1) roundFruitsQueue = []; roundFruitsActive = []; roundBulletsFired = 0; roundDelayTicks = 0; currentStage = 1; // Track current stage (1 or 2) roundDelayBetweenRounds = 120; // 2 seconds between rounds } if (roundState === 'waiting') { // Limpiar arrays de frutas y mitades cortadas de la ronda anterior for (var i = fruits.length - 1; i >= 0; i--) { if (fruits[i]) { fruits[i].destroy(); } } fruits = []; for (var i = fallingFruits.length - 1; i >= 0; i--) { if (fallingFruits[i]) { fallingFruits[i].destroy(); } } fallingFruits = []; for (var i = cutFruits.length - 1; i >= 0; i--) { if (cutFruits[i]) { cutFruits[i].destroy(); } } cutFruits = []; // Limpiar arrays de control de ronda if (typeof roundFruitsQueue !== "undefined") { for (var i = roundFruitsQueue.length - 1; i >= 0; i--) { if (roundFruitsQueue[i] && roundFruitsQueue[i].destroy) { roundFruitsQueue[i].destroy(); } } } roundFruitsQueue = []; if (typeof roundFruitsActive !== "undefined") { for (var i = roundFruitsActive.length - 1; i >= 0; i--) { if (roundFruitsActive[i] && roundFruitsActive[i].destroy) { roundFruitsActive[i].destroy(); } } } roundFruitsActive = []; // Reset meta de ronda roundBulletsFired = 0; roundNextBulletTick = LK.ticks; roundDelayTicks = 0; // Set round bullets based on current stage if (currentStage === 1) { roundBullets = 7; // 3 countdown + 4 fruits // Schedule stage 2 to start 8 seconds after stage 1 begins if (typeof stage2Scheduled === "undefined" || !stage2Scheduled) { stage2Scheduled = true; LK.setTimeout(function () { // Start stage 2 currentStage = 2; roundState = 'waiting'; stage2Scheduled = false; // Schedule stage 3 to start 5 seconds after stage 2 begins if (typeof stage3Scheduled === "undefined" || !stage3Scheduled) { stage3Scheduled = true; LK.setTimeout(function () { currentStage = 3; roundState = 'waiting'; stage3Scheduled = false; }, 4000); // 5 seconds after stage 2 starts } }, 10300); // 8 seconds } } else if (currentStage === 2) { roundBullets = 4; // 3 fruits only, no countdown countdownObjectsFired = 4; // Skip countdown in stage 2 } else if (currentStage === 3) { // Reiniciar todas las variables para evitar errores en la generación de frutas frutasGeneradas = 0; frutasFalladas = 0; fruits = []; fallingFruits = []; cutFruits = []; roundFruitsQueue = []; roundFruitsActive = []; roundBullets = 4; // 4 frutas en la tercera etapa countdownObjectsFired = 4; // No countdown en la etapa 3 // Clear any existing combo display if (comboFadeTimeout) { LK.clearTimeout(comboFadeTimeout); comboFadeTimeout = null; } if (comboImage) { comboImage.destroy(); comboImage = null; } } // Esperar un frame antes de permitir el spawn para evitar generación múltiple if (typeof roundJustReset === "undefined" || !roundJustReset) { roundJustReset = true; return; } else { roundJustReset = false; roundState = 'spawning'; goShotTick = undefined; } } if (roundState === 'spawning') { // Espera inicial antes de cualquier disparo if (typeof roundStartTick === "undefined") { roundStartTick = LK.ticks; } var delay = 20; // ⏱️ Espera de 2 segundos (120 ticks) if (LK.ticks - roundStartTick < delay) { return; // ⏳ Aún esperando el inicio } // Disparar los objetos de cuenta regresiva "1", "2", "Go" en los primeros tres disparos if (typeof countdownObjectsFired === "undefined") { countdownObjectsFired = 0; } if (roundBulletsFired < roundBullets && LK.ticks >= roundNextBulletTick) { var margin = 180; var fruitX = margin + Math.random() * (2048 - 2 * margin); cannon.x = fruitX; cannon.show(); cannon.shoot(); // Dispara "1", "2", "Go" en los primeros tres disparos if (countdownObjectsFired === 0) { var obj1 = new Fruit(); obj1.fruitType = 'D1'; if (obj1.fruitAsset) { obj1.fruitAsset.destroy(); } obj1.fruitAsset = obj1.attachAsset('D1', { anchorX: 0.5, anchorY: 0.5 }); obj1.radius = obj1.fruitAsset.width / 2; obj1.x = fruitX; obj1.y = 2732 + obj1.radius - 120; obj1.startY = obj1.y; obj1.targetY = 2732 / 2 + 600; obj1.state = 'rising'; obj1.ticks = 0; obj1.scaleX = 0.1; obj1.scaleY = 0.1; obj1.roundMeta = { hasCrossed: false, crossedTick: null, showScheduled: false, showTimeout: null, destroyed: false }; fruits.push(obj1); roundFruitsQueue.push(obj1); self.addChild(obj1); // Mostrar "1" centrado y gigante con fade out var centerObj1 = new CountdownOne(); centerObj1.x = 2048 / 2; centerObj1.y = 2732 / 2.5; centerObj1.scaleX = centerObj1.scaleY = 1; // Gigante centerObj1.alpha = 1; self.addChild(centerObj1); // Fade out después de 0.5 segundos LK.setTimeout(function () { tween(centerObj1, { alpha: 0 }, { duration: 300, easing: tween.linear, onFinish: function onFinish() { centerObj1.destroy(); } }); }, 500); countdownObjectsFired++; } else if (countdownObjectsFired === 1) { var obj2 = new Fruit(); obj2.fruitType = 'D2'; if (obj2.fruitAsset) { obj2.fruitAsset.destroy(); } obj2.fruitAsset = obj2.attachAsset('D2', { anchorX: 0.5, anchorY: 0.5 }); obj2.radius = obj2.fruitAsset.width / 2; obj2.x = fruitX; obj2.y = 2732 + obj2.radius - 120; obj2.startY = obj2.y; obj2.targetY = 2732 / 2 + 600; obj2.state = 'rising'; obj2.ticks = 0; obj2.scaleX = 0.1; obj2.scaleY = 0.1; obj2.roundMeta = { hasCrossed: false, crossedTick: null, showScheduled: false, showTimeout: null, destroyed: false }; fruits.push(obj2); roundFruitsQueue.push(obj2); self.addChild(obj2); // Mostrar "2" centrado y gigante con fade out var centerObj2 = new CountdownTwo(); centerObj2.x = 2048 / 2; centerObj2.y = 2732 / 2.5; centerObj2.scaleX = centerObj2.scaleY = 1; // Gigante centerObj2.alpha = 1; self.addChild(centerObj2); // Fade out después de 0.5 segundos LK.setTimeout(function () { tween(centerObj2, { alpha: 0 }, { duration: 300, easing: tween.linear, onFinish: function onFinish() { centerObj2.destroy(); } }); }, 500); countdownObjectsFired++; } else if (countdownObjectsFired === 2) { var objGo = new Fruit(); objGo.fruitType = 'DGO'; if (objGo.fruitAsset) { objGo.fruitAsset.destroy(); } objGo.fruitAsset = objGo.attachAsset('DGO', { anchorX: 0.5, anchorY: 0.5 }); objGo.radius = objGo.fruitAsset.width / 2; objGo.x = fruitX; objGo.y = 2732 + objGo.radius - 120; objGo.startY = objGo.y; objGo.targetY = 2732 / 2 + 600; objGo.state = 'rising'; objGo.ticks = 0; objGo.scaleX = 0.1; objGo.scaleY = 0.1; objGo.roundMeta = { hasCrossed: false, crossedTick: null, showScheduled: false, showTimeout: null, destroyed: false }; fruits.push(objGo); roundFruitsQueue.push(objGo); self.addChild(objGo); // Mostrar "Go!" centrado y gigante con fade out var centerObjGo = new CountdownGo(); centerObjGo.x = 2048 / 2; centerObjGo.y = 2732 / 2.5; centerObjGo.scaleX = centerObjGo.scaleY = 1; // Gigante centerObjGo.alpha = 1; self.addChild(centerObjGo); // Fade out después de 0.5 segundos LK.setTimeout(function () { tween(centerObjGo, { alpha: 0 }, { duration: 300, easing: tween.linear, onFinish: function onFinish() { centerObjGo.destroy(); } }); }, 500); countdownObjectsFired++; // After Go!, wait 2 seconds before launching fruits if (typeof goShotTick === "undefined") { goShotTick = LK.ticks; // Schedule game end 18 seconds after Go! LK.setTimeout(function () { // Set Inicio to true when game ends for the first time if (!Inicio) { Inicio = true; } // Show stars based on fruits cut var starAsset; var starSound; if (LK.getScore() === 0) { starAsset = 'Estrellas0'; starSound = 'E1'; // Use E1 sound for 0 stars } else if (LK.getScore() <= 6) { starAsset = 'Estrellas1'; starSound = 'E1'; } else if (LK.getScore() <= 11) { starAsset = 'Estrellas2'; starSound = 'E2'; } else { starAsset = 'Estrellas3'; starSound = 'E3'; } // Create and display star var star = LK.getAsset(starAsset, { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0, scaleX: 0.5, scaleY: 0.5 }); self.addChild(star); // Play corresponding sound LK.getSound(starSound).play(); // Animate star appearance tween(star, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.cubicOut, onFinish: function onFinish() { // Keep star visible for a moment then show end scene LK.setTimeout(function () { // Stop music LK.stopMusic(); // Clean up combo display if (comboFadeTimeout) { LK.clearTimeout(comboFadeTimeout); comboFadeTimeout = null; } if (comboImage) { comboImage.destroy(); comboImage = null; } // Show end scene without deactivating game scene // This keeps the game visible in the background if (game.endScene) { game.endScene.activate(); game.currentScene = game.endScene; // Force end scene to be on top of everything game.endScene.bringToFront(); } }, 2000); } }); }, 18000); // 18 seconds } } else { // Wait 1.3 seconds (78 ticks) after Go! before launching fruits if (typeof goShotTick !== "undefined" && LK.ticks - goShotTick < 60) { return; } // Después de los tres primeros, dispara frutas normales var fruit = new Fruit(); fruit.x = fruitX; fruit.y = 2732 + fruit.radius - 300; fruit.startY = fruit.y; fruit.targetY = 2732 / 2 + 600; fruit.state = 'rising'; fruit.ticks = 0; fruit.roundMeta = { hasCrossed: false, crossedTick: null, showScheduled: false, showTimeout: null, destroyed: false }; fruits.push(fruit); roundFruitsQueue.push(fruit); self.addChild(fruit); } // Asegura que el cañón siempre esté al frente if (cannon && cannon.parent) { cannon.parent.removeChild(cannon); self.addChild(cannon); } roundBulletsFired++; // After Go!, wait 1.3 seconds before next bullet if (countdownObjectsFired === 3 && roundBulletsFired === 3) { roundNextBulletTick = LK.ticks + 60; // 1.3s wait after Go! } else if (roundBulletsFired < 3) { // Original timing for countdown objects (1, 2, Go!) roundNextBulletTick = LK.ticks + 30; // 0.5s between countdown objects } else { // Timing between fruits based on stage if (currentStage === 1) { roundNextBulletTick = LK.ticks + 60; // 1s entre frutas (stage 1) } else if (currentStage === 2) { roundNextBulletTick = LK.ticks + 30; // 0.5s entre frutas (stage 2) } else if (currentStage === 3) { roundNextBulletTick = LK.ticks + 30; } } } // When all bullets are fired, round is complete if (roundBulletsFired >= roundBullets) { roundState = 'complete'; } } if (roundState === 'complete') { // Round completed - do nothing, no more spawning } // Mover frutas que suben desde abajo hasta el centro for (var i = fruits.length - 1; i >= 0; i--) { var fruit = fruits[i]; // Only destroy objects that are NOT rising (i.e., not going up from bottom) // This ensures fruits launched from bottom can reach the top before being destroyed if (fruit.state !== 'rising' && fruit.y < -100) { // Destroy cut zone circle if exists if (fruit.cutZoneCircle) { fruit.cutZoneCircle.destroy(); fruit.cutZoneCircle = null; } // Mark as inactive fruit.isActive = false; // Mark as destroyed for round system if (fruit.roundMeta) { fruit.roundMeta.destroyed = true; } // Clear any scheduled timeouts if (fruit.roundMeta && fruit.roundMeta.showTimeout) { LK.clearTimeout(fruit.roundMeta.showTimeout); fruit.roundMeta.showTimeout = null; } // Remove from roundFruitsQueue if present if (typeof roundFruitsQueue !== "undefined") { for (var j = roundFruitsQueue.length - 1; j >= 0; j--) { if (roundFruitsQueue[j] === fruit) { roundFruitsQueue.splice(j, 1); break; } } } // Destroy the object completely fruit.destroy(); fruits.splice(i, 1); continue; // Skip rest of processing for this object } if (fruit.state === 'rising') { // Cambiar velocidad solo en etapa 2 var currentFruitSpeed = fruitSpeed; if (currentStage === 2) { currentFruitSpeed = 40; // velocidad más rápida en etapa 2 } fruit.y -= currentFruitSpeed; fruit.ticks++; // Escalado según altura (más arriba, más grande) var minScale = 1.0; var maxScale = 1.5; var y0 = 2732 + fruit.radius + 10; var y1 = 2732 / 2 + 420; var t = (fruit.y - y1) / (y0 - y1); if (t < 0) { t = 0; } if (t > 1) { t = 1; } var scale = minScale + (maxScale - minScale) * (1 - t); fruit.scaleX = fruit.scaleY = scale; // Rotación en la parte de abajo (solo mientras sube) if (typeof fruit.rotation === "undefined") { fruit.rotation = Math.random() * Math.PI * 2; } if (typeof fruit.rotationSpeed === "undefined") { fruit.rotationSpeed = (Math.random() - 0.5) * 0.08; } fruit.rotation += fruit.rotationSpeed; if (fruit.fruitAsset) { fruit.fruitAsset.rotation = fruit.rotation; } // Cuando cruza la altura objetivo (centro), programar aparición en pantalla superior tras un tiempo proporcional al número de frutas lanzadas if (!fruit.roundMeta.hasCrossed && fruit.y <= fruit.targetY) { fruit.roundMeta.hasCrossed = true; fruit.roundMeta.crossedTick = LK.ticks; fruit.visible = false; // Cambiar tiempo de espera solo en etapa 2 var appearDelayMs = 2700; // default 2.7s if (currentStage === 2) { appearDelayMs = 1100; // 1.5s en etapa 2 } if (currentStage === 3) { appearDelayMs = 1200; // 1.5s en etapa 2 } var isCountdownObject = fruit.fruitType === 'D1' || fruit.fruitType === 'D2' || fruit.fruitType === 'DGO'; if (!isCountdownObject) { fruit.roundMeta.showScheduled = true; fruit.roundMeta.showTimeout = LK.setTimeout(function (fruitRef, fruitsArr, iIdx) { return function () { if (fruitRef.roundMeta.destroyed) { return; } var fruitType = fruitRef.fruitType; var x = fruitRef.x; fruitRef.destroy(); for (var j = 0; j < fruitsArr.length; j++) { if (fruitsArr[j] === fruitRef) { fruitsArr.splice(j, 1); break; } } var fallingFruit = new Fruit(); if (typeof fruitType === "undefined" || !fruitType) { fruitType = fallingFruit.fruitType; } else { fallingFruit.fruitType = fruitType; } if (fallingFruit.fruitAsset) { fallingFruit.fruitAsset.destroy(); } fallingFruit.fruitAsset = fallingFruit.attachAsset(fallingFruit.fruitType, { anchorX: 0.5, anchorY: 0.5 }); fallingFruit.x = x; fallingFruit.y = 2732 / 2 + 420 + 100; fallingFruit.startY = fallingFruit.y; fallingFruit.lastY = 2732; // Initialize lastY to a safe value well below destruction line fallingFruit.state = 'cuttable'; fallingFruit.ticks = 0; fallingFruit.rotation = Math.random() * Math.PI * 2; fallingFruit.rotationSpeed = (Math.random() - 0.5) * 0.04; fallingFruit.roundMeta = { destroyed: false }; fallingFruits.push(fallingFruit); roundFruitsActive.push(fallingFruit); self.addChild(fallingFruit); if (horizontalLine && horizontalLine.parent) { horizontalLine.parent.removeChild(horizontalLine); self.addChild(horizontalLine); } if (cannon && cannon.parent) { cannon.parent.removeChild(cannon); self.addChild(cannon); } }; }(fruit, fruits, i), appearDelayMs); } } if (fruit.roundMeta.hasCrossed && fruit.roundMeta.showScheduled) { if (fruit.roundMeta.destroyed) { if (fruit.roundMeta.showTimeout) { LK.clearTimeout(fruit.roundMeta.showTimeout); fruit.roundMeta.showTimeout = null; } if (typeof roundFruitsQueue !== "undefined") { for (var j = roundFruitsQueue.length - 1; j >= 0; j--) { if (roundFruitsQueue[j] === fruit) { roundFruitsQueue.splice(j, 1); break; } } } fruits.splice(i, 1); } continue; } } } // Mover frutas que suben de nuevo y gestionar zona de corte visual // --- Asegura que la línea negra esté sobre los sprites de las frutas en cada frame --- if (horizontalLine && horizontalLine.parent) { horizontalLine.parent.removeChild(horizontalLine); self.addChild(horizontalLine); } // Asegura que la línea roja de destrucción esté visible encima de todo if (destructionLine && destructionLine.parent) { destructionLine.parent.removeChild(destructionLine); self.addChild(destructionLine); } // Volver a agregar la línea roja al final para que esté encima if (cannon && cannon.parent) { cannon.parent.removeChild(cannon); self.addChild(cannon); } if (destructionLine && destructionLine.parent) { destructionLine.parent.removeChild(destructionLine); self.addChild(destructionLine); } for (var i = fallingFruits.length - 1; i >= 0; i--) { var fruit = fallingFruits[i]; // Check if falling fruit passes above Y=800 for complete destruction // Only destroy fruits that are falling down (cuttable or flyingup states) if (fruit.y < -100 && (fruit.state === 'cuttable' || fruit.state === 'flyingup')) { // Destroy cut zone circle if exists if (fruit.cutZoneCircle) { fruit.cutZoneCircle.destroy(); fruit.cutZoneCircle = null; } // Mark as inactive fruit.isActive = false; // Mark as destroyed for round system if (fruit.roundMeta) { fruit.roundMeta.destroyed = true; } // Remove from roundFruitsActive if present if (typeof roundFruitsActive !== "undefined") { for (var j = roundFruitsActive.length - 1; j >= 0; j--) { if (roundFruitsActive[j] === fruit) { roundFruitsActive.splice(j, 1); break; } } } // Count as failed if not cut if (!fruit.isCut) { frutasFalladas++; frutasGeneradas++; comboCounter = 0; // Play fruit miss sound LK.getSound('fruit_miss').play(); // Clear any existing combo display if (comboFadeTimeout) { LK.clearTimeout(comboFadeTimeout); comboFadeTimeout = null; } if (comboImage) { comboImage.destroy(); comboImage = null; } } // Destroy the fruit completely fruit.destroy(); fallingFruits.splice(i, 1); continue; // Skip rest of processing for this fruit } if (!fruit.isActive) { continue; } // Escalado según altura (más arriba, más grande) var minScale = 1.0; var maxScale = 1.25 * 1.3 * 1.3; //{45} // 60% más grande en la parte superior var y0 = 2732 / 2 + 420; var y1 = 420; var t = (fruit.y - y1) / (y0 - y1); if (t < 0) { t = 0; } if (t > 1) { t = 1; } var scale = minScale + (maxScale - minScale) * (1 - t); fruit.scaleX = fruit.scaleY = scale; // Rotación suave if (typeof fruit.rotationSpeed !== "undefined") { fruit.rotation += fruit.rotationSpeed; if (fruit.fruitAsset) { fruit.fruitAsset.rotation = fruit.rotation; } } // Movimiento hacia arriba mientras sea cortable o volando hacia arriba if (fruit.state === 'cuttable' || fruit.state === 'flyingup') { var topFruitSpeed = fruitSpeed; if (currentStage === 2) { topFruitSpeed = 30; // velocidad más alta en la segunda etapa } // Double speed if fruit has passed cutting zone if (fruit.doubledSpeed) { topFruitSpeed = topFruitSpeed * 2; } fruit.y -= topFruitSpeed; } // --- Animación progresiva del círculo de corte --- // El círculo aparece desde el inicio de la subida (cuttable), crece y se difumina progresivamente if (fruit.state === 'cuttable') { // Si no existe el círculo, crearlo if (!fruit.cutZoneCircle) { fruit.cutZoneCircle = LK.getAsset('cut_zone', { anchorX: 0.5, anchorY: 0.5, x: fruit.x, y: fruit.y, alpha: 0.0, scaleX: 0.1, scaleY: 0.1 }); self.addChild(fruit.cutZoneCircle); // Asegura que la línea negra esté sobre el círculo de corte pero debajo del cañón if (horizontalLine && horizontalLine.parent) { horizontalLine.parent.removeChild(horizontalLine); self.addChild(horizontalLine); } // Asegura que el cañón siempre esté al frente if (cannon && cannon.parent) { cannon.parent.removeChild(cannon); self.addChild(cannon); } } // Progresión del círculo: desde que inicia la subida hasta que llega cerca de la parte superior var appearT = (y0 - fruit.y) / (y0 - y1); if (appearT < 0) { appearT = 0; } if (appearT > 1) { appearT = 1; } var maxScaleZone = 0.85; // Más pequeño, para que quede dentro de la fruta var minScaleZone = 0.15; var maxAlpha = 0.38; // Más difuminado var minAlpha = 0.08; var scaleZone = minScaleZone + (maxScaleZone - minScaleZone) * appearT; var alphaZone = minAlpha + (maxAlpha - minAlpha) * appearT; fruit.cutZoneCircle.scaleX = fruit.cutZoneCircle.scaleY = scaleZone; fruit.cutZoneCircle.alpha = alphaZone; fruit.cutZoneCircle.x = fruit.x; fruit.cutZoneCircle.y = fruit.y; // Si la fruta sale por arriba, eliminar círculo y pasar a flyingup if (fruit.y < y1) { // Si el círculo de corte existe y la fruta no fue cortada, contar como fallada if (fruit.cutZoneCircle) { fruit.cutZoneCircle.destroy(); fruit.cutZoneCircle = null; if (fruit.isActive && !fruit.isCut) { frutasFalladas++; frutasGeneradas++; comboCounter = 0; // Play fruit miss sound LK.getSound('fruit_miss').play(); // Clear any existing combo display if (comboFadeTimeout) { LK.clearTimeout(comboFadeTimeout); comboFadeTimeout = null; } if (comboImage) { comboImage.destroy(); comboImage = null; } } } fruit.state = 'flyingup'; // Double the speed when fruit can no longer be cut fruit.doubledSpeed = true; } } else { // Si no está en estado cortable y existe el círculo, destruirlo if (fruit.cutZoneCircle) { fruit.cutZoneCircle.destroy(); fruit.cutZoneCircle = null; } } // Si fue cortada, eliminar círculo visual inmediatamente pero mantener la fruta visible if (!fruit.isActive && fruit.cutZoneCircle) { fruit.cutZoneCircle.destroy(); fruit.cutZoneCircle = null; } // Si está cayendo, animar caída if (fruit.state === 'dropping') { fruit.dropSpeed += 2.5; // gravedad fruit.y += fruit.dropSpeed; // Escalado decreciente al caer fruit.scaleX = fruit.scaleY = Math.max(0.7, fruit.scaleX - 0.01); if (fruit.cutZoneCircle) { fruit.cutZoneCircle.x = fruit.x; fruit.cutZoneCircle.y = fruit.y; } // Si sale de pantalla, marcar como inactivo pero mantener visible if (fruit.y > 2732 + fruit.radius + 20) { if (fruit.cutZoneCircle) { fruit.cutZoneCircle.destroy(); fruit.cutZoneCircle = null; } fruit.isActive = false; } } // Si la fruta sigue subiendo después de la zona de corte y no fue cortada if (fruit.state === 'flyingup') { // Al entrar por primera vez en flyingup, inicia temporizador de espera if (typeof fruit.waitTicks === "undefined") { fruit.waitTicks = 0; } fruit.waitTicks++; // Mantener la fruta visible y estática durante 4 segundos (240 ticks) if (fruit.waitTicks < 240) { // Mantener posición (opcional: podrías hacer que siga subiendo lentamente) // fruit.y -= fruitSpeed * 0.1; } else { // Después de 7 segundos, hacer que suba y desaparezca // Continue moving at current speed (already doubled if applicable) // Escalado sigue creciendo un poco fruit.scaleX = fruit.scaleY = Math.min(maxScale, fruit.scaleX + 0.01); // Check if fruit passes destruction line at Y=800 for complete destruction if (fruit.y < -100) { // Destroy cut zone circle if exists if (fruit.cutZoneCircle) { fruit.cutZoneCircle.destroy(); fruit.cutZoneCircle = null; } // Mark as inactive fruit.isActive = false; // Mark as destroyed for round system if (fruit.roundMeta) { fruit.roundMeta.destroyed = true; } // Remove from roundFruitsActive if present if (typeof roundFruitsActive !== "undefined") { for (var j = roundFruitsActive.length - 1; j >= 0; j--) { if (roundFruitsActive[j] === fruit) { roundFruitsActive.splice(j, 1); break; } } } // Count as failed if not cut if (!fruit.isCut) { frutasFalladas++; frutasGeneradas++; comboCounter = 0; // Play fruit miss sound LK.getSound('fruit_miss').play(); // Clear any existing combo display if (comboFadeTimeout) { LK.clearTimeout(comboFadeTimeout); comboFadeTimeout = null; } if (comboImage) { comboImage.destroy(); comboImage = null; } } // Destroy the fruit completely fruit.destroy(); fallingFruits.splice(i, 1); continue; // Skip rest of processing for this fruit } // Si sale de pantalla por arriba, marcar como inactiva y eliminar círculo de corte si existe if (fruit.y < -fruit.radius - 20) { if (fruit.cutZoneCircle) { fruit.cutZoneCircle.destroy(); fruit.cutZoneCircle = null; } fruit.isActive = false; // Marcar como destruida para el sistema de ronda if (fruit.roundMeta) { fruit.roundMeta.destroyed = true; } // Eliminar de roundFruitsActive si está presente if (typeof roundFruitsActive !== "undefined") { for (var j = roundFruitsActive.length - 1; j >= 0; j--) { if (roundFruitsActive[j] === fruit) { roundFruitsActive.splice(j, 1); break; } } } // Aumentar frutasFalladas y frutasGeneradas solo si la fruta no fue cortada if (!fruit.isCut) { frutasFalladas++; frutasGeneradas++; comboCounter = 0; // Play fruit miss sound LK.getSound('fruit_miss').play(); // Clear any existing combo display if (comboFadeTimeout) { LK.clearTimeout(comboFadeTimeout); comboFadeTimeout = null; } if (comboImage) { comboImage.destroy(); comboImage = null; } } } } } // Si la fruta ya fue cortada o salió de pantalla, eliminar if (!fruit.isActive || fruit.y > 2732 + fruit.radius + 20 || fruit.y < -fruit.radius - 20) { if (fruit.cutZoneCircle) { fruit.cutZoneCircle.destroy(); fruit.cutZoneCircle = null; } // Marcar como destruida para el sistema de ronda if (fruit.roundMeta) { fruit.roundMeta.destroyed = true; } // Eliminar de roundFruitsActive si está presente if (typeof roundFruitsActive !== "undefined") { for (var j = roundFruitsActive.length - 1; j >= 0; j--) { if (roundFruitsActive[j] === fruit) { roundFruitsActive.splice(j, 1); break; } } } fruit.destroy(); fallingFruits.splice(i, 1); } } // Limpiar mitades cortadas que ya terminaron animación for (var i = cutFruits.length - 1; i >= 0; i--) { var fc = cutFruits[i]; if (!fc.left || !fc.right) { if (fc.destroy) { fc.destroy(); } cutFruits.splice(i, 1); } } // Variable para controlar el timeout (debe estar fuera de la función que chequea frutasFalladas) if (frutasFalladas >= 5 || frutasGeneradas >= 5 && frutasFalladas < 5) { // Mostrar los sprites 1, 2, Go en el centro con fade in/fade out rápido solo una vez, SOLO al inicio del juego if ((typeof showCountdownInMiddleDone === "undefined" || !showCountdownInMiddleDone) && LK.ticks < 120) { showCountdownInMiddleDone = true; var centerX = 2048 / 2; var centerY = 2732 / 2; var countdownSprites = [{ cls: CountdownOne, delay: 0 }, { cls: CountdownTwo, delay: 350 }, { cls: CountdownGo, delay: 700 }]; for (var idx = 0; idx < countdownSprites.length; idx++) { (function (idx) { var conf = countdownSprites[idx]; LK.setTimeout(function () { var obj = new conf.cls(); obj.x = centerX; obj.y = centerY; obj.alpha = 0; self.addChild(obj); // Fade in rápido tween(obj, { alpha: 1 }, { duration: 180, easing: tween.cubicOut, onFinish: function onFinish() { // Fade out rápido tween(obj, { alpha: 0 }, { duration: 180, delay: 180, easing: tween.cubicIn, onFinish: function onFinish() { obj.destroy(); } }); } }); }, conf.delay); })(idx); } } return; } }; return self; }); // EndScene - con método reset para botones y visibilidad var EndScene = Scene.expand(function () { var self = Scene.call(this); self.overlay = self.attachAsset('vertical_line', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, width: 2048, height: 2732, alpha: 0.1, tint: 0x000000 }); self.restartButton = self.attachAsset('button_restart', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1200 }); self.menuButton = self.attachAsset('button_menu', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1600 }); function setupButton(button, callback) { button.interactive = true; button.tint = 0xffffff; button.alpha = 1; button.down = function () { button.tint = 0xcccccc; }; button.up = function () { button.tint = 0xffffff; if (callback) { callback(); } }; } setupButton(self.restartButton, function () { if (game.onRestartPressed) { game.onRestartPressed(); } }); setupButton(self.menuButton, function () { if (game.onMenuPressed) { game.onMenuPressed(); } }); self.move = function (x, y, obj) { var globalPos = self.toGlobal({ x: x, y: y }); var lb = self.restartButton.toLocal(globalPos); var hw = self.restartButton.width / 2; var hh = self.restartButton.height / 2; self.restartButton.alpha = lb.x >= -hw && lb.x <= hw && lb.y >= -hh && lb.y <= hh ? 0.8 : 1; var lb2 = self.menuButton.toLocal(globalPos); var hw2 = self.menuButton.width / 2; var hh2 = self.menuButton.height / 2; self.menuButton.alpha = lb2.x >= -hw2 && lb2.x <= hw2 && lb2.y >= -hh2 && lb2.y <= hh2 ? 0.8 : 1; }; self.activate = function () { self.visible = true; self.restartButton.interactive = true; self.menuButton.interactive = true; self.restartButton.alpha = 1; self.menuButton.alpha = 1; self.restartButton.tint = 0xffffff; self.menuButton.tint = 0xffffff; // Always bring to front when activating self.bringToFront(); }; self.deactivate = function () { self.visible = false; self.restartButton.interactive = false; self.menuButton.interactive = false; }; // Subir esta escena a la cima del display list para que se vea encima de todo self.bringToFront = function () { if (self.parent) { self.parent.setChildIndex(self, self.parent.children.length - 1); } }; // Método para resetear los botones y visibilidad al mostrar la escena otra vez self.reset = function () { self.activate(); // Force multiple calls to ensure it's on top self.bringToFront(); LK.setTimeout(function () { self.bringToFront(); }, 10); }; // Empieza oculta self.deactivate(); return self; }); /**** * Initialize Game ****/ // -- Inicialización -- var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ var Inicio = false; // Track if this is the first game completion (local variable) // Preload critical menu assets to ensure they're ready var preloadedMenuBg = LK.getAsset('menu_background', {}); var preloadedTitulo = LK.getAsset('Titulo', {}); var menuScene = new MenuScene(); var introScene = new IntroScene(); var gameScene = new GameScene(); var endScene = new EndScene(); game.addChild(menuScene); game.addChild(introScene); game.addChild(gameScene); game.addChild(endScene); game.menuScene = menuScene; game.introScene = introScene; game.gameScene = gameScene; game.endScene = endScene; // Add a small delay before activating menu to ensure assets are loaded LK.setTimeout(function () { menuScene.activate(); }, 100); // Small delay to allow asset loading introScene.deactivate(); gameScene.deactivate(); endScene.deactivate(); var currentScene = menuScene; // -- Funciones de transición -- game.onPlayPressed = function () { // Stop menu music before transitioning LK.stopMusic(); menuScene.deactivate(); endScene.deactivate(); // Check if intro has been seen before if (storage.hasSeenIntro) { // Skip intro, go directly to game if (!gameScene.gameInitialized) { gameScene.initGame(); gameScene.gameInitialized = true; } gameScene.activate(); currentScene = gameScene; } else { // Show intro for first time introScene.activate(); currentScene = introScene; } }; game.onRestartPressed = function () { endScene.deactivate(); gameScene.deactivate(); introScene.deactivate(); game.removeChild(gameScene); gameScene = new GameScene(); game.addChild(gameScene); gameScene.initGame(); gameScene.gameInitialized = true; gameScene.activate(); currentScene = gameScene; LK.stopMusic(); }; game.onMenuPressed = function () { endScene.deactivate(); gameScene.deactivate(); introScene.deactivate(); LK.stopMusic(); menuScene.activate(); currentScene = menuScene; game.removeChild(gameScene); gameScene = new GameScene(); game.addChild(gameScene); gameScene.gameInitialized = false; }; game.onIntroComplete = function () { introScene.deactivate(); // Mark intro as seen in persistent storage storage.hasSeenIntro = true; if (!gameScene.gameInitialized) { gameScene.initGame(); gameScene.gameInitialized = true; } gameScene.activate(); currentScene = gameScene; }; // IMPORTANTE: cuando termines el juego llama esta función para mostrar los botones gameScene.onGameEnd = function () { gameScene.deactivate(); endScene.reset(); // <-- resetea y muestra el EndScene con botones activos y arriba currentScene = endScene; }; // -- Propagar movimiento -- game.move = function (x, y, obj) { if (currentScene && currentScene.move) { currentScene.move(x, y, obj); } }; game.update = function () { if (currentScene && currentScene.updateGame) { currentScene.updateGame(); } if (currentScene && currentScene.updateMenu) { currentScene.updateMenu(); } };
===================================================================
--- original.js
+++ change.js
@@ -629,9 +629,9 @@
LK.setTimeout(function () {
LK.playMusic('bgmusic', {
loop: false
});
- }, 20); // 2 second delay
+ }, 300); // 2 second delay
} else {
// Play immediately for first time
LK.playMusic('bgmusic', {
loop: false
@@ -1934,8 +1934,11 @@
/****
* Game Code
****/
var Inicio = false; // Track if this is the first game completion (local variable)
+// Preload critical menu assets to ensure they're ready
+var preloadedMenuBg = LK.getAsset('menu_background', {});
+var preloadedTitulo = LK.getAsset('Titulo', {});
var menuScene = new MenuScene();
var introScene = new IntroScene();
var gameScene = new GameScene();
var endScene = new EndScene();
@@ -1946,9 +1949,12 @@
game.menuScene = menuScene;
game.introScene = introScene;
game.gameScene = gameScene;
game.endScene = endScene;
-menuScene.activate();
+// Add a small delay before activating menu to ensure assets are loaded
+LK.setTimeout(function () {
+ menuScene.activate();
+}, 100); // Small delay to allow asset loading
introScene.deactivate();
gameScene.deactivate();
endScene.deactivate();
var currentScene = menuScene;
Kiwi Fruta con ojos lindos. In-Game asset. 2d. High contrast. No shadows. Cartoon.
Limon Circular Fruta con ojos lindos. In-Game asset. 2d. High contrast. No shadows. Cartoon.
Naranja Circular Fruta con ojos lindos. In-Game asset. 2d. High contrast. No shadows. Cartoon.
Manzana Fruta con ojos lindos. In-Game asset. 2d. High contrast. No shadows. Cartoon.
Ciruela Fruta con ojos lindos. In-Game asset. 2d. High contrast. No shadows. Cartoon.
Manzana Fruta cortada a la mitad. In-Game asset. 2d. High contrast. No shadows. Cartoon.
Kiwi Fruta cortado por la mitad. In-Game asset. 2d. High contrast. No shadows. Cartoon.
Limon Circular Cortado por la mitad. In-Game asset. 2d. High contrast. No shadows. Cartoon.
Naranja Circular Cortada por la mitad. In-Game asset. 2d. High contrast. No shadows. Cartoon.
Ciruela Fruta cortada por la mitad. In-Game asset. 2d. High contrast. No shadows. Cartoon.
Agrega una rueda en la parte trasera del cañon.
En lugar del numero 2 un numero 1
Letars GO! dentro del circulo.
Red cicle thiner but maintan the image size
En lugar del numero 1 un numero 2
Puedes hacer varias imagenes reemplazando el numero 2 por los numeros 3, 4, 5, 6, 7 y 8? Solo debe haber un numero en cada imagen.
En lugar del numero 3 un numero 4
En lugar del numero 4 un numero 5
En lugar del numero 5 un numero 6
En lugar del numero 6 un numero 7
En lugar del numero 1 un numero 8
En lugar del numero 1 un numero 9
En lugar del numero 9 un numero 10
En lugar del numero 1 un numero 11
Boton de juego que diga "START". In-Game asset. 2d. High contrast. No shadows
Boton de juego que diga "RESTART". In-Game asset. 2d. High contrast. No shadows
Boton de juego Azul que diga "MENU". In-Game asset. 2d. High contrast. No shadows
Un fondo colorido y brillante estilo caricatura. La escena es un bosque abierto alegre con colores pastel vibrantes, formas suaves y redondeadas, y un cielo azul claro con nubes esponjosas. El estilo es kawaii, juguetón y fantástico, con líneas suaves y una atmósfera feliz y amigable, perfecto para una introducción divertida y cute de un juego. In-Game asset. 2d. High contrast. No shadows
"Beat the Fruit" titulo para el juego, muestra las letras en grande blancas con un borde negro y sin fondo, con algunas frutitas felices junto a las letras. In-Game asset. 2d. High contrast. No shadows
Barra verde horizontal estilo caricatura.. In-Game asset. 2d. High contrast. No shadows