/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Hand = Container.expand(function () { var self = Container.call(this); var handGraphics = self.attachAsset('hand', { width: 120, height: 120, color: 0xFFDBB3, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); return self; }); var MenuButton = Container.expand(function (text, color) { var self = Container.call(this); // Create button background var buttonBg = LK.getAsset('background', { width: 800, height: 200, anchorX: 0.5, anchorY: 0.5, tint: color || 0x4A90E2 }); self.addChild(buttonBg); // Create button text var buttonText = new Text2(text, { size: 80, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); // Define the down method directly self.down = function (x, y, obj) { // Button press animation tween(self, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeIn }); } }); }; return self; }); // Game variables var Player = Container.expand(function () { var self = Container.call(this); var playerGraphicsNormal = self.attachAsset('player', { width: 450, height: 675, anchorX: 0.5, anchorY: 0.5 }); var playerGraphicsDiscovered = self.attachAsset('player_discovered', { width: 450, height: 675, anchorX: 0.5, anchorY: 0.5, visible: false }); var playerGraphicsSuccess = self.attachAsset('player_success', { width: 450, height: 675, anchorX: 0.5, anchorY: 0.5, visible: false }); var playerGraphicsTouchedDistracted = self.attachAsset('player_touched_distracted', { width: 450, height: 675, anchorX: 0.5, anchorY: 0.5, visible: false }); var playerGraphicsCaught = self.attachAsset('target_caught', { width: 450, height: 675, anchorX: 0.5, anchorY: 0.5, visible: false }); self.state = 'normal'; // 'normal', 'discovered', 'success' self.stateTimer = 0; self.setState = function (newState, duration) { self.state = newState; self.stateTimer = duration || 0; // Hide all graphics playerGraphicsNormal.visible = false; playerGraphicsDiscovered.visible = false; playerGraphicsSuccess.visible = false; playerGraphicsTouchedDistracted.visible = false; playerGraphicsCaught.visible = false; // Show appropriate graphic if (newState === 'discovered') { playerGraphicsDiscovered.visible = true; } else if (newState === 'success') { playerGraphicsSuccess.visible = true; } else if (newState === 'touched_distracted') { playerGraphicsTouchedDistracted.visible = true; } else if (newState === 'caught') { playerGraphicsCaught.visible = true; } else { playerGraphicsNormal.visible = true; } }; self.update = function () { if (self.stateTimer > 0) { self.stateTimer--; if (self.stateTimer <= 0) { self.setState('normal'); } } }; // Initialize to normal state self.setState('normal'); return self; }); var Target = Container.expand(function () { var self = Container.call(this); // Create both assets but only show one at a time var targetGraphicsAlert = self.attachAsset('target', { width: 450, height: 675, anchorX: 0.5, anchorY: 0.5 }); var targetGraphicsDistracted = self.attachAsset('target_distracted', { width: 450, height: 675, scaleX: 0.95, scaleY: 0.95, anchorX: 0.5, anchorY: 0.5, visible: false }); var targetGraphicsCaught = self.attachAsset('target_caught', { width: 450, height: 675, anchorX: 0.5, anchorY: 0.5, visible: false }); var targetGraphicsTouchedConcentrated = self.attachAsset('target_touched_concentrated', { width: 450, height: 675, anchorX: 0.5, anchorY: 0.5, visible: false }); var targetGraphicsTouchedDistracted = self.attachAsset('target_touched_distracted', { width: 450, height: 675, scaleX: 0.95, scaleY: 0.95, anchorX: 0.5, anchorY: 0.5, visible: false }); self.isDistracted = false; // false = alert state, true = distracted state self.state = 'alert'; // 'alert', 'distracted', 'caught' self.stateTimer = 0; self.maxStateTime = 180; // 3 seconds at 60fps self.graceTimer = 0; // Grace period timer after state change self.gracePeriod = 6; // 0.1 seconds at 60fps (6 frames) self.canDetect = true; // Whether detection is active self.tempStateTimer = 0; // Timer for temporary states like 'caught' self.setState = function (newState, duration) { self.state = newState; self.tempStateTimer = duration || 0; // Hide all graphics targetGraphicsAlert.visible = false; targetGraphicsDistracted.visible = false; targetGraphicsCaught.visible = false; targetGraphicsTouchedConcentrated.visible = false; targetGraphicsTouchedDistracted.visible = false; // Show appropriate graphic if (newState === 'distracted') { targetGraphicsDistracted.visible = true; self.isDistracted = true; } else if (newState === 'caught') { targetGraphicsCaught.visible = true; self.isDistracted = false; } else if (newState === 'touched_concentrated') { targetGraphicsTouchedConcentrated.visible = true; } else if (newState === 'touched_distracted') { targetGraphicsTouchedDistracted.visible = true; } else { targetGraphicsAlert.visible = true; self.isDistracted = false; } }; self.update = function () { // Handle temporary states like 'caught' if (self.tempStateTimer > 0) { self.tempStateTimer--; if (self.tempStateTimer <= 0) { // Return to normal cycle based on previous distracted state if (self.isDistracted) { self.setState('distracted'); } else { self.setState('alert'); } } return; } // Normal state cycling only when not in temporary state if (self.state === 'alert' || self.state === 'distracted') { self.stateTimer++; if (self.stateTimer >= self.maxStateTime) { if (self.isDistracted) { self.setState('alert'); self.graceTimer = self.gracePeriod; self.canDetect = false; } else { self.setState('distracted'); } self.stateTimer = 0; } } // Handle grace period countdown if (self.graceTimer > 0) { self.graceTimer--; if (self.graceTimer <= 0) { self.canDetect = true; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game variables var score = 0; var lives = 10; var gameTime = 3600; // 60 seconds at 60fps var gameActive = true; var touchCooldown = 0; // Prevent rapid tapping exploit var gameMode = 'menu'; // 'menu', 'carrera', 'arcade', 'confirmation' var difficulty = 1; // For carrera mode var menuContainer = null; var gameContainer = null; var confirmationContainer = null; var player = null; var target = null; var hand = null; var musicVolume = storage.musicVolume || 0.8; var selectedMode = ''; var isDragging = false; // Volume slider dragging state var instructionsShown = storage.instructionsShown || false; // Track if instructions have been shown var highScoreArcade = storage.highScoreArcade || 0; var highScoreCarrera = storage.highScoreCarrera || 0; // Create main menu function createMainMenu() { menuContainer = game.addChild(new Container()); // Add menu background var background = menuContainer.addChild(LK.getAsset('menu_background', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); // Volume control at bottom of screen var volumeText = new Text2('Volumen Música: ' + Math.round(musicVolume * 100) + '%', { size: 60, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3 }); volumeText.anchor.set(0.5, 0.5); volumeText.x = 1024; volumeText.y = 2500; menuContainer.addChild(volumeText); // Volume slider container at bottom var volumeSliderContainer = menuContainer.addChild(new Container()); volumeSliderContainer.x = 1024; volumeSliderContainer.y = 2600; // Slider background bar using new asset var sliderBg = LK.getAsset('slider_bar', { anchorX: 0.5, anchorY: 0.5 }); volumeSliderContainer.addChild(sliderBg); // Slider fill bar using new asset var sliderFill = LK.getAsset('slider_fill', { width: 800 * musicVolume, anchorX: 0, anchorY: 0.5 }); sliderFill.x = -400; volumeSliderContainer.addChild(sliderFill); // Slider handle using new asset var sliderHandle = LK.getAsset('slider_handle', { anchorX: 0.5, anchorY: 0.5 }); sliderHandle.x = -400 + 800 * musicVolume; volumeSliderContainer.addChild(sliderHandle); // Make slider interactive var isDragging = false; volumeSliderContainer.down = function (x, y, obj) { isDragging = true; updateSliderVolume(x, y); }; volumeSliderContainer.up = function (x, y, obj) { isDragging = false; }; volumeSliderContainer.move = function (x, y, obj) { if (isDragging) { var localPos = volumeSliderContainer.toLocal({ x: x, y: y }); updateSliderVolume(localPos.x, localPos.y); } }; function updateSliderVolume(localX, localY) { // Convert local position to volume (slider is 800px wide, centered) var normalizedX = (localX + 400) / 800; normalizedX = Math.max(0, Math.min(1, normalizedX)); var oldVolume = musicVolume; musicVolume = normalizedX; storage.musicVolume = musicVolume; // Update visual elements volumeText.setText('Volumen Música: ' + Math.round(musicVolume * 100) + '%'); sliderFill.width = 800 * musicVolume; sliderHandle.x = -400 + 800 * musicVolume; // Update music with fade - check which music is currently playing if (gameMode === 'menu' || gameMode === 'confirmation') { // Update MenuMusic when in menu LK.playMusic('MenuMusic', { fade: { start: oldVolume, end: musicVolume, duration: 100 } }); } else if (gameMode === 'carrera' || gameMode === 'arcade') { // Update Romantic music when in game LK.playMusic('Romantic', { fade: { start: oldVolume, end: musicVolume, duration: 100 } }); } } // Carrera mode button using custom asset - positioned at left bottom var carreraButton = menuContainer.addChild(LK.getAsset('carrera_button', { anchorX: 0.5, anchorY: 0.5 })); carreraButton.x = 600; carreraButton.y = 1900; // Moved up by 1.5 times button height (300px) carreraButton.down = function (x, y, obj) { showModeConfirmation('carrera'); }; // Arcade mode button using custom asset - positioned at right bottom var arcadeButton = menuContainer.addChild(LK.getAsset('arcade_button', { anchorX: 0.5, anchorY: 0.5 })); arcadeButton.x = 1448; arcadeButton.y = 1900; // Moved up by 1.5 times button height (300px) arcadeButton.down = function (x, y, obj) { showModeConfirmation('arcade'); }; } function showModeConfirmation(mode) { selectedMode = mode; gameMode = 'confirmation'; // Remove main menu if (menuContainer) { menuContainer.destroy(); menuContainer = null; } // Create confirmation container confirmationContainer = game.addChild(new Container()); // Add background var background = confirmationContainer.addChild(LK.getAsset('menu_background', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); // Mode title var modeTitle = new Text2(mode.toUpperCase(), { size: 150, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 6 }); modeTitle.anchor.set(0.5, 0.5); modeTitle.x = 1024; modeTitle.y = 600; confirmationContainer.addChild(modeTitle); // Mode description var description = ''; if (mode === 'carrera') { description = 'MODO CARRERA\n\n• Sin límite de tiempo\n• Dificultad creciente\n• Supervivencia infinita\n• ¡Alcanza la puntuación más alta!'; } else { description = 'MODO ARCADE\n\n• 60 segundos de juego\n• Dificultad constante\n• Modo clásico\n• ¡Consigue el máximo de toques!'; } // Create background for description text var descBackground = LK.getAsset('text_background', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); descBackground.x = 1024; descBackground.y = 1100; confirmationContainer.addChild(descBackground); var descText = new Text2(description, { size: 70, fill: 0xBDC3C7, stroke: 0x000000, strokeThickness: 2 }); descText.anchor.set(0.5, 0.5); descText.x = 1024; descText.y = 1100; confirmationContainer.addChild(descText); // Play button var playButton = confirmationContainer.addChild(new MenuButton('JUGAR', 0x27AE60)); playButton.x = 1024; playButton.y = 1600; playButton.down = function (x, y, obj) { LK.setTimeout(function () { startGame(selectedMode); }, 200); }; // Back button var backButton = confirmationContainer.addChild(new MenuButton('VOLVER', 0xE67E22)); backButton.x = 1024; backButton.y = 1800; backButton.down = function (x, y, obj) { LK.setTimeout(function () { returnToMainMenu(); }, 200); }; } function returnToMainMenu() { gameMode = 'menu'; // Clean up game event handlers game.move = null; game.up = null; // Remove confirmation screen if (confirmationContainer) { confirmationContainer.destroy(); confirmationContainer = null; } // Recreate main menu createMainMenu(); } function showPauseMenu() { // Create pause menu overlay var pauseOverlay = game.addChild(new Container()); // Semi-transparent background var overlay = LK.getAsset('pause_overlay_bg', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.7 }); pauseOverlay.addChild(overlay); // Pause menu background var pauseBg = LK.getAsset('pause_menu_bg', { anchorX: 0.5, anchorY: 0.5 }); pauseBg.x = 1024; pauseBg.y = 1366; pauseOverlay.addChild(pauseBg); // Return to menu option (left) var returnOption = LK.getAsset('menu_option_return', { anchorX: 0.5, anchorY: 0.5 }); returnOption.x = 1024 - 310; // Left position returnOption.y = 1366; pauseOverlay.addChild(returnOption); returnOption.down = function (x, y, obj) { pauseOverlay.destroy(); menuConfirmVisible = false; LK.setTimeout(function () { // Clean up game UI and reset text variables LK.gui.bottom.removeChildren(); LK.gui.top.removeChildren(); LK.gui.topRight.removeChildren(); scoreText = null; timeText = null; livesText = null; difficultyText = null; // Remove game container if (gameContainer) { gameContainer.destroy(); gameContainer = null; } // Return to main menu gameMode = 'menu'; createMainMenu(); // Play menu music when returning to menu LK.playMusic('MenuMusic', { volume: musicVolume }); }, 200); }; // Continue playing option (center) var continueOption = LK.getAsset('menu_option_continue', { anchorX: 0.5, anchorY: 0.5 }); continueOption.x = 1024; // Center position continueOption.y = 1366; pauseOverlay.addChild(continueOption); continueOption.down = function (x, y, obj) { pauseOverlay.destroy(); menuConfirmVisible = false; gameActive = true; // Resume game }; // Restart level option (right) var restartOption = LK.getAsset('menu_option_restart', { anchorX: 0.5, anchorY: 0.5 }); restartOption.x = 1024 + 310; // Right position restartOption.y = 1366; pauseOverlay.addChild(restartOption); restartOption.down = function (x, y, obj) { pauseOverlay.destroy(); menuConfirmVisible = false; LK.setTimeout(function () { // Clean up current game LK.gui.bottom.removeChildren(); LK.gui.top.removeChildren(); LK.gui.topRight.removeChildren(); scoreText = null; timeText = null; livesText = null; difficultyText = null; if (gameContainer) { gameContainer.destroy(); gameContainer = null; } // Restart the same game mode startGame(gameMode); }, 200); }; } function showStatistics(isNewRecord) { // Create statistics container var statsContainer = game.addChild(new Container()); // Calculate stars first to determine background var stars = 0; if (gameMode === 'carrera') { // Different scoring for endless mode if (score >= 50) { stars = 3; } else if (score >= 30) { stars = 2; } else if (score >= 15) { stars = 1; } } else { // Arcade mode star system based on touches if (score >= 50) { stars = 3; } else if (score >= 25) { stars = 2; } else if (score >= 10) { stars = 1; } else { stars = 0; } } // Add background based on game mode - use carrera background for carrera mode var backgroundAsset; if (gameMode === 'carrera') { backgroundAsset = 'carrera_background'; } else { backgroundAsset = 'star_' + stars + '_background'; } var background = statsContainer.addChild(LK.getAsset(backgroundAsset, { anchorX: 0, anchorY: 0, x: 0, y: 0 })); // Title text removed as requested // Text background removed as requested // Game mode and current score var modeText = gameMode === 'carrera' ? 'MODO CARRERA' : 'MODO ARCADE'; var currentHighScore = gameMode === 'carrera' ? highScoreCarrera : highScoreArcade; var recordText = isNewRecord ? '\n🎉 ¡NUEVO RÉCORD! 🎉' : ''; // Add statistics background with 50% opacity var statsBackground = LK.getAsset('statistics_background', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); statsBackground.x = 1024; statsBackground.y = 1800; statsContainer.addChild(statsBackground); var statsText = new Text2(modeText + '\n\nPuntuación: ' + score + '\nMejor puntuación: ' + currentHighScore + recordText, { size: 70, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 2 }); statsText.anchor.set(0.5, 0.5); statsText.x = 1024; statsText.y = 1800; statsContainer.addChild(statsText); // Play again button - moved down by 4 times button height (800px) var playAgainButton = statsContainer.addChild(new MenuButton('JUGAR DE NUEVO', 0x27AE60)); playAgainButton.x = 1024; playAgainButton.y = 2300; playAgainButton.down = function (x, y, obj) { LK.setTimeout(function () { statsContainer.destroy(); startGame(gameMode); }, 200); }; // Return to menu button - moved down by 4 times button height (800px) var menuButton = statsContainer.addChild(new MenuButton('MENÚ PRINCIPAL', 0xE67E22)); menuButton.x = 1024; menuButton.y = 2500; menuButton.down = function (x, y, obj) { LK.setTimeout(function () { statsContainer.destroy(); // Clean up game event handlers game.move = null; game.up = null; gameMode = 'menu'; createMainMenu(); LK.playMusic('MenuMusic', { volume: musicVolume }); }, 200); }; // Display stars for arcade mode if (gameMode === 'arcade') { var starsText = new Text2(+stars + '/3', { size: 80, fill: 0xFFD700, stroke: 0x000000, strokeThickness: 3 }); starsText.anchor.set(0.5, 0.5); starsText.x = 1024; starsText.y = 2000; statsContainer.addChild(starsText); // Display visual stars var starContainer = statsContainer.addChild(new Container()); starContainer.x = 1024; starContainer.y = 2100; for (var i = 0; i < 3; i++) { var star = new Text2('★', { size: 200, fill: i < stars ? 0xFFD700 : 0x666666, stroke: 0x000000, strokeThickness: 2 }); star.anchor.set(0.5, 0.5); star.x = (i - 1) * 120; starContainer.addChild(star); } } LK.setScore(stars * 1000 + score); // Stars worth 1000 points each if (stars > 0) { LK.getSound('victory').play(); } } var instructionGraphic = null; var instructionsCompleted = false; var menuConfirmVisible = false; function startGame(mode) { gameMode = mode; instructionsCompleted = false; // Remove menu if (menuContainer) { menuContainer.destroy(); menuContainer = null; } // Remove confirmation container if it exists if (confirmationContainer) { confirmationContainer.destroy(); confirmationContainer = null; } // Create game container gameContainer = game.addChild(new Container()); // Add background var background = gameContainer.addChild(LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); // Create characters player = gameContainer.addChild(new Player()); player.x = 550; // Left side moved more to the right player.y = 1619; // Moved up by 1/8 character height (84 pixels) // Add breathing animation to player addPlayerBreathingAnimation(player); // Add background element behind target var backgroundElement = gameContainer.addChild(LK.getAsset('background_element', { width: 750, height: 750, anchorX: 0.5, anchorY: 0.5 })); backgroundElement.x = 1498; // Same position as target backgroundElement.y = 1619; // Same position as target target = gameContainer.addChild(new Target()); target.x = 1498; // Right side moved more to the left target.y = 1619; // Moved up by 1/8 character height (84 pixels) // Create hand for mouse cursor hand = gameContainer.addChild(new Hand()); hand.x = 1024; hand.y = 1366; // Reset game variables based on mode score = 0; lives = 10; touchCooldown = 0; if (mode === 'carrera') { difficulty = 1; gameTime = -1; // No time limit } else { gameTime = 3600; // 60 seconds } createGameUI(); // Show instructions at the start of arcade or carrera mode instructionGraphic = LK.getAsset('instructions', { width: 600, height: 600, anchorX: 0.5, anchorY: 0, alpha: 0, scaleX: 0.5, scaleY: 0.5 }); instructionGraphic.y = 50; LK.gui.top.addChild(instructionGraphic); // Entrance animation tween(instructionGraphic, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { // Wait for 2 additional seconds before fading out LK.setTimeout(function () { // Fade out and enable game after extended duration tween(instructionGraphic, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { // Game becomes active after instructions fade out gameActive = true; instructionsCompleted = true; instructionGraphic = null; } }); }, 2000); } }); // Temporarily disable game until instructions are done gameActive = false; // Play game music LK.playMusic('Romantic', { volume: musicVolume }); } // Initialize with main menu createMainMenu(); // Add breathing animation for player when created function addPlayerBreathingAnimation(playerObj) { if (!playerObj) { return; } // Start breathing animation function breathe() { tween(playerObj, { scaleX: 1.05, scaleY: 1.05 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(playerObj, { scaleX: 1, scaleY: 1 }, { duration: 2000, easing: tween.easeInOut, onFinish: breathe }); } }); } breathe(); } var scoreText, timeText, livesContainer, livesText, difficultyText; function createGameUI() { // Clear any existing UI elements first to prevent overlapping LK.gui.bottom.removeChildren(); LK.gui.top.removeChildren(); LK.gui.topRight.removeChildren(); // Add back to menu button in top right with new visual asset var menuButton = LK.getAsset('menu_button_bg', { anchorX: 0.5, anchorY: 0.5 }); menuButton.x = -100; menuButton.y = 100; // Add menu text var menuText = new Text2('☰', { size: 60, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 2 }); menuText.anchor.set(0.5, 0.5); menuButton.addChild(menuText); menuButton.down = function (x, y, obj) { if (menuConfirmVisible) { return; } // Prevent multiple confirmations menuConfirmVisible = true; gameActive = false; // Pause game temporarily showPauseMenu(); }; LK.gui.topRight.addChild(menuButton); // Create UI elements scoreText = new Text2('Toques: 0', { size: 120, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); scoreText.anchor.set(0.5, 1); scoreText.y = -50; LK.gui.bottom.addChild(scoreText); if (gameMode === 'arcade') { timeText = new Text2('Tiempo: 60', { size: 80, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 8 }); timeText.anchor.set(0.5, 1); timeText.y = -300; LK.gui.bottom.addChild(timeText); } else { difficultyText = new Text2('Nivel: 1', { size: 80, fill: 0xFFD700, stroke: 0x000000, strokeThickness: 8 }); difficultyText.anchor.set(0.5, 1); difficultyText.y = -300; LK.gui.bottom.addChild(difficultyText); } // Create lives display livesContainer = new Container(); var heartGraphic = LK.getAsset('heart', { width: 60, height: 60, anchorX: 0.5, anchorY: 0.5 }); heartGraphic.x = -18.75; // Center the heart horizontally (adjusted for larger size) livesContainer.addChild(heartGraphic); livesText = new Text2('x10', { size: 75, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3 }); livesText.anchor.set(0, 0.5); livesText.x = 18.75; livesContainer.addChild(livesText); livesContainer.y = -250; LK.gui.bottom.addChild(livesContainer); } // Instructions are now handled in startGame function // Touch detection function checkTouch() { if (!gameActive) { return; } if (touchCooldown > 0) { return; } // Prevent rapid tapping if (hand.intersects(target)) { if (target.isDistracted) { // Successful touch - target is distracted score++; // Clear and update score text to prevent overlapping if (scoreText) { scoreText.setText('Toques: ' + score); } LK.getSound('poke_distracted').play(); touchCooldown = 30; // 0.5 second cooldown // Increase difficulty in carrera mode if (gameMode === 'carrera' && score % 10 === 0) { difficulty++; if (difficultyText) { difficultyText.setText('Nivel: ' + difficulty); } // Make target state changes faster target.maxStateTime = Math.max(60, 180 - difficulty * 10); } // Set target to touched_distracted state for 1 second target.setState('touched_distracted', 60); // Add tween animation for target surprise state tween(target, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(target, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } }); // Set player to touched_distracted state for 1 second player.setState('touched_distracted', 60); // Add tween animation for success state tween(player, { scaleX: 1.1, scaleY: 1.1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(player, { scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeIn }); } }); } else if (target.canDetect) { // Caught! Target is alert and can detect - lose lives lives--; // Ensure lives don't go below 0 if (lives < 0) { lives = 0; } if (livesText) { livesText.setText('x' + lives); } // End game immediately if lives reach 0 in carrera mode if (gameMode === 'carrera' && lives <= 0) { gameActive = false; LK.setTimeout(function () { endGame(); }, 100); return; } touchCooldown = 60; // 1 second cooldown when caught // Don't end game here - only end when all lives are lost in carrera mode // or when time runs out in arcade mode LK.getSound('poke_fail').play(); // Set target to touched_concentrated state for longer duration (2 seconds) target.setState('touched_concentrated', 120); // Set player to caught state when target is touched while concentrated player.setState('caught', 120); // Add longer tween animation for target surprise state when caught tween(target, { scaleX: 0.8, scaleY: 0.8 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { tween(target, { scaleX: 1, scaleY: 1 }, { duration: 400, easing: tween.easeIn }); } }); } } } // Game input handling game.down = function (x, y, obj) { if (gameMode === 'menu') { // Handle volume slider in menu return; } if (gameMode === 'confirmation' || !gameActive || !instructionsCompleted) { return; } // Move hand towards touch point if (hand) { hand.x = x; hand.y = y; } // Only check touch if the hand is actually near the target if (hand && target) { var distanceX = Math.abs(hand.x - target.x); var distanceY = Math.abs(hand.y - target.y); // Only check touch if within reasonable distance (target size is about 450x675) if (distanceX < 300 && distanceY < 400) { checkTouch(); } } }; var originalGameMove = function originalGameMove(x, y, obj) { if (gameMode === 'confirmation' || !gameActive) { return; } // Move hand with drag if (hand) { hand.x = x; hand.y = y; } }; var originalGameUp = function originalGameUp(x, y, obj) { // Handle volume slider release isDragging = false; }; // Game event handlers will be set conditionally based on game mode in the update function function endGame() { gameActive = false; instructionsCompleted = false; // Clean up UI elements to prevent overlapping LK.gui.bottom.removeChildren(); LK.gui.top.removeChildren(); LK.gui.topRight.removeChildren(); // Reset UI text variables scoreText = null; timeText = null; livesText = null; difficultyText = null; instructionGraphic = null; // Update high scores var isNewRecord = false; if (gameMode === 'carrera') { if (score > highScoreCarrera) { highScoreCarrera = score; storage.highScoreCarrera = highScoreCarrera; isNewRecord = true; } } else { if (score > highScoreArcade) { highScoreArcade = score; storage.highScoreArcade = highScoreArcade; isNewRecord = true; } } // Show statistics screen showStatistics(isNewRecord); } // Main game update game.update = function () { // Set up event handlers based on current game mode if (gameMode === 'menu' || gameMode === 'confirmation') { // Remove game event handlers when in menu/confirmation modes game.move = null; game.up = null; return; } // Set up game event handlers only when in active game modes if (gameMode === 'carrera' || gameMode === 'arcade') { if (!game.move) { game.move = originalGameMove; } if (!game.up) { game.up = originalGameUp; } } if (!gameActive) { return; } // Reset menu confirmation state when game is active menuConfirmVisible = false; // Update cooldown timer if (touchCooldown > 0) { touchCooldown--; } // Update game timer only in arcade mode if (gameMode === 'arcade' && gameTime > 0) { gameTime--; var seconds = Math.ceil(gameTime / 60); if (timeText) { timeText.setText('Tiempo: ' + seconds); } // End game when time runs out in arcade mode if (gameTime <= 0) { endGame(); return; } } // End game when lives reach 0 in arcade mode if (gameMode === 'arcade' && lives <= 0) { gameActive = false; LK.setTimeout(function () { endGame(); }, 100); return; } // End game in carrera mode only when all lives are lost (0 or below) if (gameMode === 'carrera' && lives <= 0) { endGame(); return; } // Update target character if (target) { target.update(); } // Update player character if (player) { player.update(); } }; // Start menu music LK.playMusic('MenuMusic', { volume: musicVolume });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Hand = Container.expand(function () {
var self = Container.call(this);
var handGraphics = self.attachAsset('hand', {
width: 120,
height: 120,
color: 0xFFDBB3,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var MenuButton = Container.expand(function (text, color) {
var self = Container.call(this);
// Create button background
var buttonBg = LK.getAsset('background', {
width: 800,
height: 200,
anchorX: 0.5,
anchorY: 0.5,
tint: color || 0x4A90E2
});
self.addChild(buttonBg);
// Create button text
var buttonText = new Text2(text, {
size: 80,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
// Define the down method directly
self.down = function (x, y, obj) {
// Button press animation
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeIn
});
}
});
};
return self;
});
// Game variables
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphicsNormal = self.attachAsset('player', {
width: 450,
height: 675,
anchorX: 0.5,
anchorY: 0.5
});
var playerGraphicsDiscovered = self.attachAsset('player_discovered', {
width: 450,
height: 675,
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var playerGraphicsSuccess = self.attachAsset('player_success', {
width: 450,
height: 675,
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var playerGraphicsTouchedDistracted = self.attachAsset('player_touched_distracted', {
width: 450,
height: 675,
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var playerGraphicsCaught = self.attachAsset('target_caught', {
width: 450,
height: 675,
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
self.state = 'normal'; // 'normal', 'discovered', 'success'
self.stateTimer = 0;
self.setState = function (newState, duration) {
self.state = newState;
self.stateTimer = duration || 0;
// Hide all graphics
playerGraphicsNormal.visible = false;
playerGraphicsDiscovered.visible = false;
playerGraphicsSuccess.visible = false;
playerGraphicsTouchedDistracted.visible = false;
playerGraphicsCaught.visible = false;
// Show appropriate graphic
if (newState === 'discovered') {
playerGraphicsDiscovered.visible = true;
} else if (newState === 'success') {
playerGraphicsSuccess.visible = true;
} else if (newState === 'touched_distracted') {
playerGraphicsTouchedDistracted.visible = true;
} else if (newState === 'caught') {
playerGraphicsCaught.visible = true;
} else {
playerGraphicsNormal.visible = true;
}
};
self.update = function () {
if (self.stateTimer > 0) {
self.stateTimer--;
if (self.stateTimer <= 0) {
self.setState('normal');
}
}
};
// Initialize to normal state
self.setState('normal');
return self;
});
var Target = Container.expand(function () {
var self = Container.call(this);
// Create both assets but only show one at a time
var targetGraphicsAlert = self.attachAsset('target', {
width: 450,
height: 675,
anchorX: 0.5,
anchorY: 0.5
});
var targetGraphicsDistracted = self.attachAsset('target_distracted', {
width: 450,
height: 675,
scaleX: 0.95,
scaleY: 0.95,
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var targetGraphicsCaught = self.attachAsset('target_caught', {
width: 450,
height: 675,
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var targetGraphicsTouchedConcentrated = self.attachAsset('target_touched_concentrated', {
width: 450,
height: 675,
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var targetGraphicsTouchedDistracted = self.attachAsset('target_touched_distracted', {
width: 450,
height: 675,
scaleX: 0.95,
scaleY: 0.95,
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
self.isDistracted = false; // false = alert state, true = distracted state
self.state = 'alert'; // 'alert', 'distracted', 'caught'
self.stateTimer = 0;
self.maxStateTime = 180; // 3 seconds at 60fps
self.graceTimer = 0; // Grace period timer after state change
self.gracePeriod = 6; // 0.1 seconds at 60fps (6 frames)
self.canDetect = true; // Whether detection is active
self.tempStateTimer = 0; // Timer for temporary states like 'caught'
self.setState = function (newState, duration) {
self.state = newState;
self.tempStateTimer = duration || 0;
// Hide all graphics
targetGraphicsAlert.visible = false;
targetGraphicsDistracted.visible = false;
targetGraphicsCaught.visible = false;
targetGraphicsTouchedConcentrated.visible = false;
targetGraphicsTouchedDistracted.visible = false;
// Show appropriate graphic
if (newState === 'distracted') {
targetGraphicsDistracted.visible = true;
self.isDistracted = true;
} else if (newState === 'caught') {
targetGraphicsCaught.visible = true;
self.isDistracted = false;
} else if (newState === 'touched_concentrated') {
targetGraphicsTouchedConcentrated.visible = true;
} else if (newState === 'touched_distracted') {
targetGraphicsTouchedDistracted.visible = true;
} else {
targetGraphicsAlert.visible = true;
self.isDistracted = false;
}
};
self.update = function () {
// Handle temporary states like 'caught'
if (self.tempStateTimer > 0) {
self.tempStateTimer--;
if (self.tempStateTimer <= 0) {
// Return to normal cycle based on previous distracted state
if (self.isDistracted) {
self.setState('distracted');
} else {
self.setState('alert');
}
}
return;
}
// Normal state cycling only when not in temporary state
if (self.state === 'alert' || self.state === 'distracted') {
self.stateTimer++;
if (self.stateTimer >= self.maxStateTime) {
if (self.isDistracted) {
self.setState('alert');
self.graceTimer = self.gracePeriod;
self.canDetect = false;
} else {
self.setState('distracted');
}
self.stateTimer = 0;
}
}
// Handle grace period countdown
if (self.graceTimer > 0) {
self.graceTimer--;
if (self.graceTimer <= 0) {
self.canDetect = true;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game variables
var score = 0;
var lives = 10;
var gameTime = 3600; // 60 seconds at 60fps
var gameActive = true;
var touchCooldown = 0; // Prevent rapid tapping exploit
var gameMode = 'menu'; // 'menu', 'carrera', 'arcade', 'confirmation'
var difficulty = 1; // For carrera mode
var menuContainer = null;
var gameContainer = null;
var confirmationContainer = null;
var player = null;
var target = null;
var hand = null;
var musicVolume = storage.musicVolume || 0.8;
var selectedMode = '';
var isDragging = false; // Volume slider dragging state
var instructionsShown = storage.instructionsShown || false; // Track if instructions have been shown
var highScoreArcade = storage.highScoreArcade || 0;
var highScoreCarrera = storage.highScoreCarrera || 0;
// Create main menu
function createMainMenu() {
menuContainer = game.addChild(new Container());
// Add menu background
var background = menuContainer.addChild(LK.getAsset('menu_background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Volume control at bottom of screen
var volumeText = new Text2('Volumen Música: ' + Math.round(musicVolume * 100) + '%', {
size: 60,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
volumeText.anchor.set(0.5, 0.5);
volumeText.x = 1024;
volumeText.y = 2500;
menuContainer.addChild(volumeText);
// Volume slider container at bottom
var volumeSliderContainer = menuContainer.addChild(new Container());
volumeSliderContainer.x = 1024;
volumeSliderContainer.y = 2600;
// Slider background bar using new asset
var sliderBg = LK.getAsset('slider_bar', {
anchorX: 0.5,
anchorY: 0.5
});
volumeSliderContainer.addChild(sliderBg);
// Slider fill bar using new asset
var sliderFill = LK.getAsset('slider_fill', {
width: 800 * musicVolume,
anchorX: 0,
anchorY: 0.5
});
sliderFill.x = -400;
volumeSliderContainer.addChild(sliderFill);
// Slider handle using new asset
var sliderHandle = LK.getAsset('slider_handle', {
anchorX: 0.5,
anchorY: 0.5
});
sliderHandle.x = -400 + 800 * musicVolume;
volumeSliderContainer.addChild(sliderHandle);
// Make slider interactive
var isDragging = false;
volumeSliderContainer.down = function (x, y, obj) {
isDragging = true;
updateSliderVolume(x, y);
};
volumeSliderContainer.up = function (x, y, obj) {
isDragging = false;
};
volumeSliderContainer.move = function (x, y, obj) {
if (isDragging) {
var localPos = volumeSliderContainer.toLocal({
x: x,
y: y
});
updateSliderVolume(localPos.x, localPos.y);
}
};
function updateSliderVolume(localX, localY) {
// Convert local position to volume (slider is 800px wide, centered)
var normalizedX = (localX + 400) / 800;
normalizedX = Math.max(0, Math.min(1, normalizedX));
var oldVolume = musicVolume;
musicVolume = normalizedX;
storage.musicVolume = musicVolume;
// Update visual elements
volumeText.setText('Volumen Música: ' + Math.round(musicVolume * 100) + '%');
sliderFill.width = 800 * musicVolume;
sliderHandle.x = -400 + 800 * musicVolume;
// Update music with fade - check which music is currently playing
if (gameMode === 'menu' || gameMode === 'confirmation') {
// Update MenuMusic when in menu
LK.playMusic('MenuMusic', {
fade: {
start: oldVolume,
end: musicVolume,
duration: 100
}
});
} else if (gameMode === 'carrera' || gameMode === 'arcade') {
// Update Romantic music when in game
LK.playMusic('Romantic', {
fade: {
start: oldVolume,
end: musicVolume,
duration: 100
}
});
}
}
// Carrera mode button using custom asset - positioned at left bottom
var carreraButton = menuContainer.addChild(LK.getAsset('carrera_button', {
anchorX: 0.5,
anchorY: 0.5
}));
carreraButton.x = 600;
carreraButton.y = 1900; // Moved up by 1.5 times button height (300px)
carreraButton.down = function (x, y, obj) {
showModeConfirmation('carrera');
};
// Arcade mode button using custom asset - positioned at right bottom
var arcadeButton = menuContainer.addChild(LK.getAsset('arcade_button', {
anchorX: 0.5,
anchorY: 0.5
}));
arcadeButton.x = 1448;
arcadeButton.y = 1900; // Moved up by 1.5 times button height (300px)
arcadeButton.down = function (x, y, obj) {
showModeConfirmation('arcade');
};
}
function showModeConfirmation(mode) {
selectedMode = mode;
gameMode = 'confirmation';
// Remove main menu
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
}
// Create confirmation container
confirmationContainer = game.addChild(new Container());
// Add background
var background = confirmationContainer.addChild(LK.getAsset('menu_background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Mode title
var modeTitle = new Text2(mode.toUpperCase(), {
size: 150,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 6
});
modeTitle.anchor.set(0.5, 0.5);
modeTitle.x = 1024;
modeTitle.y = 600;
confirmationContainer.addChild(modeTitle);
// Mode description
var description = '';
if (mode === 'carrera') {
description = 'MODO CARRERA\n\n• Sin límite de tiempo\n• Dificultad creciente\n• Supervivencia infinita\n• ¡Alcanza la puntuación más alta!';
} else {
description = 'MODO ARCADE\n\n• 60 segundos de juego\n• Dificultad constante\n• Modo clásico\n• ¡Consigue el máximo de toques!';
}
// Create background for description text
var descBackground = LK.getAsset('text_background', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
descBackground.x = 1024;
descBackground.y = 1100;
confirmationContainer.addChild(descBackground);
var descText = new Text2(description, {
size: 70,
fill: 0xBDC3C7,
stroke: 0x000000,
strokeThickness: 2
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 1100;
confirmationContainer.addChild(descText);
// Play button
var playButton = confirmationContainer.addChild(new MenuButton('JUGAR', 0x27AE60));
playButton.x = 1024;
playButton.y = 1600;
playButton.down = function (x, y, obj) {
LK.setTimeout(function () {
startGame(selectedMode);
}, 200);
};
// Back button
var backButton = confirmationContainer.addChild(new MenuButton('VOLVER', 0xE67E22));
backButton.x = 1024;
backButton.y = 1800;
backButton.down = function (x, y, obj) {
LK.setTimeout(function () {
returnToMainMenu();
}, 200);
};
}
function returnToMainMenu() {
gameMode = 'menu';
// Clean up game event handlers
game.move = null;
game.up = null;
// Remove confirmation screen
if (confirmationContainer) {
confirmationContainer.destroy();
confirmationContainer = null;
}
// Recreate main menu
createMainMenu();
}
function showPauseMenu() {
// Create pause menu overlay
var pauseOverlay = game.addChild(new Container());
// Semi-transparent background
var overlay = LK.getAsset('pause_overlay_bg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.7
});
pauseOverlay.addChild(overlay);
// Pause menu background
var pauseBg = LK.getAsset('pause_menu_bg', {
anchorX: 0.5,
anchorY: 0.5
});
pauseBg.x = 1024;
pauseBg.y = 1366;
pauseOverlay.addChild(pauseBg);
// Return to menu option (left)
var returnOption = LK.getAsset('menu_option_return', {
anchorX: 0.5,
anchorY: 0.5
});
returnOption.x = 1024 - 310; // Left position
returnOption.y = 1366;
pauseOverlay.addChild(returnOption);
returnOption.down = function (x, y, obj) {
pauseOverlay.destroy();
menuConfirmVisible = false;
LK.setTimeout(function () {
// Clean up game UI and reset text variables
LK.gui.bottom.removeChildren();
LK.gui.top.removeChildren();
LK.gui.topRight.removeChildren();
scoreText = null;
timeText = null;
livesText = null;
difficultyText = null;
// Remove game container
if (gameContainer) {
gameContainer.destroy();
gameContainer = null;
}
// Return to main menu
gameMode = 'menu';
createMainMenu();
// Play menu music when returning to menu
LK.playMusic('MenuMusic', {
volume: musicVolume
});
}, 200);
};
// Continue playing option (center)
var continueOption = LK.getAsset('menu_option_continue', {
anchorX: 0.5,
anchorY: 0.5
});
continueOption.x = 1024; // Center position
continueOption.y = 1366;
pauseOverlay.addChild(continueOption);
continueOption.down = function (x, y, obj) {
pauseOverlay.destroy();
menuConfirmVisible = false;
gameActive = true; // Resume game
};
// Restart level option (right)
var restartOption = LK.getAsset('menu_option_restart', {
anchorX: 0.5,
anchorY: 0.5
});
restartOption.x = 1024 + 310; // Right position
restartOption.y = 1366;
pauseOverlay.addChild(restartOption);
restartOption.down = function (x, y, obj) {
pauseOverlay.destroy();
menuConfirmVisible = false;
LK.setTimeout(function () {
// Clean up current game
LK.gui.bottom.removeChildren();
LK.gui.top.removeChildren();
LK.gui.topRight.removeChildren();
scoreText = null;
timeText = null;
livesText = null;
difficultyText = null;
if (gameContainer) {
gameContainer.destroy();
gameContainer = null;
}
// Restart the same game mode
startGame(gameMode);
}, 200);
};
}
function showStatistics(isNewRecord) {
// Create statistics container
var statsContainer = game.addChild(new Container());
// Calculate stars first to determine background
var stars = 0;
if (gameMode === 'carrera') {
// Different scoring for endless mode
if (score >= 50) {
stars = 3;
} else if (score >= 30) {
stars = 2;
} else if (score >= 15) {
stars = 1;
}
} else {
// Arcade mode star system based on touches
if (score >= 50) {
stars = 3;
} else if (score >= 25) {
stars = 2;
} else if (score >= 10) {
stars = 1;
} else {
stars = 0;
}
}
// Add background based on game mode - use carrera background for carrera mode
var backgroundAsset;
if (gameMode === 'carrera') {
backgroundAsset = 'carrera_background';
} else {
backgroundAsset = 'star_' + stars + '_background';
}
var background = statsContainer.addChild(LK.getAsset(backgroundAsset, {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Title text removed as requested
// Text background removed as requested
// Game mode and current score
var modeText = gameMode === 'carrera' ? 'MODO CARRERA' : 'MODO ARCADE';
var currentHighScore = gameMode === 'carrera' ? highScoreCarrera : highScoreArcade;
var recordText = isNewRecord ? '\n🎉 ¡NUEVO RÉCORD! 🎉' : '';
// Add statistics background with 50% opacity
var statsBackground = LK.getAsset('statistics_background', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
statsBackground.x = 1024;
statsBackground.y = 1800;
statsContainer.addChild(statsBackground);
var statsText = new Text2(modeText + '\n\nPuntuación: ' + score + '\nMejor puntuación: ' + currentHighScore + recordText, {
size: 70,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 2
});
statsText.anchor.set(0.5, 0.5);
statsText.x = 1024;
statsText.y = 1800;
statsContainer.addChild(statsText);
// Play again button - moved down by 4 times button height (800px)
var playAgainButton = statsContainer.addChild(new MenuButton('JUGAR DE NUEVO', 0x27AE60));
playAgainButton.x = 1024;
playAgainButton.y = 2300;
playAgainButton.down = function (x, y, obj) {
LK.setTimeout(function () {
statsContainer.destroy();
startGame(gameMode);
}, 200);
};
// Return to menu button - moved down by 4 times button height (800px)
var menuButton = statsContainer.addChild(new MenuButton('MENÚ PRINCIPAL', 0xE67E22));
menuButton.x = 1024;
menuButton.y = 2500;
menuButton.down = function (x, y, obj) {
LK.setTimeout(function () {
statsContainer.destroy();
// Clean up game event handlers
game.move = null;
game.up = null;
gameMode = 'menu';
createMainMenu();
LK.playMusic('MenuMusic', {
volume: musicVolume
});
}, 200);
};
// Display stars for arcade mode
if (gameMode === 'arcade') {
var starsText = new Text2(+stars + '/3', {
size: 80,
fill: 0xFFD700,
stroke: 0x000000,
strokeThickness: 3
});
starsText.anchor.set(0.5, 0.5);
starsText.x = 1024;
starsText.y = 2000;
statsContainer.addChild(starsText);
// Display visual stars
var starContainer = statsContainer.addChild(new Container());
starContainer.x = 1024;
starContainer.y = 2100;
for (var i = 0; i < 3; i++) {
var star = new Text2('★', {
size: 200,
fill: i < stars ? 0xFFD700 : 0x666666,
stroke: 0x000000,
strokeThickness: 2
});
star.anchor.set(0.5, 0.5);
star.x = (i - 1) * 120;
starContainer.addChild(star);
}
}
LK.setScore(stars * 1000 + score); // Stars worth 1000 points each
if (stars > 0) {
LK.getSound('victory').play();
}
}
var instructionGraphic = null;
var instructionsCompleted = false;
var menuConfirmVisible = false;
function startGame(mode) {
gameMode = mode;
instructionsCompleted = false;
// Remove menu
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
}
// Remove confirmation container if it exists
if (confirmationContainer) {
confirmationContainer.destroy();
confirmationContainer = null;
}
// Create game container
gameContainer = game.addChild(new Container());
// Add background
var background = gameContainer.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create characters
player = gameContainer.addChild(new Player());
player.x = 550; // Left side moved more to the right
player.y = 1619; // Moved up by 1/8 character height (84 pixels)
// Add breathing animation to player
addPlayerBreathingAnimation(player);
// Add background element behind target
var backgroundElement = gameContainer.addChild(LK.getAsset('background_element', {
width: 750,
height: 750,
anchorX: 0.5,
anchorY: 0.5
}));
backgroundElement.x = 1498; // Same position as target
backgroundElement.y = 1619; // Same position as target
target = gameContainer.addChild(new Target());
target.x = 1498; // Right side moved more to the left
target.y = 1619; // Moved up by 1/8 character height (84 pixels)
// Create hand for mouse cursor
hand = gameContainer.addChild(new Hand());
hand.x = 1024;
hand.y = 1366;
// Reset game variables based on mode
score = 0;
lives = 10;
touchCooldown = 0;
if (mode === 'carrera') {
difficulty = 1;
gameTime = -1; // No time limit
} else {
gameTime = 3600; // 60 seconds
}
createGameUI();
// Show instructions at the start of arcade or carrera mode
instructionGraphic = LK.getAsset('instructions', {
width: 600,
height: 600,
anchorX: 0.5,
anchorY: 0,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
});
instructionGraphic.y = 50;
LK.gui.top.addChild(instructionGraphic);
// Entrance animation
tween(instructionGraphic, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Wait for 2 additional seconds before fading out
LK.setTimeout(function () {
// Fade out and enable game after extended duration
tween(instructionGraphic, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
// Game becomes active after instructions fade out
gameActive = true;
instructionsCompleted = true;
instructionGraphic = null;
}
});
}, 2000);
}
});
// Temporarily disable game until instructions are done
gameActive = false;
// Play game music
LK.playMusic('Romantic', {
volume: musicVolume
});
}
// Initialize with main menu
createMainMenu();
// Add breathing animation for player when created
function addPlayerBreathingAnimation(playerObj) {
if (!playerObj) {
return;
}
// Start breathing animation
function breathe() {
tween(playerObj, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(playerObj, {
scaleX: 1,
scaleY: 1
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: breathe
});
}
});
}
breathe();
}
var scoreText, timeText, livesContainer, livesText, difficultyText;
function createGameUI() {
// Clear any existing UI elements first to prevent overlapping
LK.gui.bottom.removeChildren();
LK.gui.top.removeChildren();
LK.gui.topRight.removeChildren();
// Add back to menu button in top right with new visual asset
var menuButton = LK.getAsset('menu_button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
menuButton.x = -100;
menuButton.y = 100;
// Add menu text
var menuText = new Text2('☰', {
size: 60,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 2
});
menuText.anchor.set(0.5, 0.5);
menuButton.addChild(menuText);
menuButton.down = function (x, y, obj) {
if (menuConfirmVisible) {
return;
} // Prevent multiple confirmations
menuConfirmVisible = true;
gameActive = false; // Pause game temporarily
showPauseMenu();
};
LK.gui.topRight.addChild(menuButton);
// Create UI elements
scoreText = new Text2('Toques: 0', {
size: 120,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
scoreText.anchor.set(0.5, 1);
scoreText.y = -50;
LK.gui.bottom.addChild(scoreText);
if (gameMode === 'arcade') {
timeText = new Text2('Tiempo: 60', {
size: 80,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 8
});
timeText.anchor.set(0.5, 1);
timeText.y = -300;
LK.gui.bottom.addChild(timeText);
} else {
difficultyText = new Text2('Nivel: 1', {
size: 80,
fill: 0xFFD700,
stroke: 0x000000,
strokeThickness: 8
});
difficultyText.anchor.set(0.5, 1);
difficultyText.y = -300;
LK.gui.bottom.addChild(difficultyText);
}
// Create lives display
livesContainer = new Container();
var heartGraphic = LK.getAsset('heart', {
width: 60,
height: 60,
anchorX: 0.5,
anchorY: 0.5
});
heartGraphic.x = -18.75; // Center the heart horizontally (adjusted for larger size)
livesContainer.addChild(heartGraphic);
livesText = new Text2('x10', {
size: 75,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
livesText.anchor.set(0, 0.5);
livesText.x = 18.75;
livesContainer.addChild(livesText);
livesContainer.y = -250;
LK.gui.bottom.addChild(livesContainer);
}
// Instructions are now handled in startGame function
// Touch detection
function checkTouch() {
if (!gameActive) {
return;
}
if (touchCooldown > 0) {
return;
} // Prevent rapid tapping
if (hand.intersects(target)) {
if (target.isDistracted) {
// Successful touch - target is distracted
score++;
// Clear and update score text to prevent overlapping
if (scoreText) {
scoreText.setText('Toques: ' + score);
}
LK.getSound('poke_distracted').play();
touchCooldown = 30; // 0.5 second cooldown
// Increase difficulty in carrera mode
if (gameMode === 'carrera' && score % 10 === 0) {
difficulty++;
if (difficultyText) {
difficultyText.setText('Nivel: ' + difficulty);
}
// Make target state changes faster
target.maxStateTime = Math.max(60, 180 - difficulty * 10);
}
// Set target to touched_distracted state for 1 second
target.setState('touched_distracted', 60);
// Add tween animation for target surprise state
tween(target, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(target, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Set player to touched_distracted state for 1 second
player.setState('touched_distracted', 60);
// Add tween animation for success state
tween(player, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
}
});
} else if (target.canDetect) {
// Caught! Target is alert and can detect - lose lives
lives--;
// Ensure lives don't go below 0
if (lives < 0) {
lives = 0;
}
if (livesText) {
livesText.setText('x' + lives);
}
// End game immediately if lives reach 0 in carrera mode
if (gameMode === 'carrera' && lives <= 0) {
gameActive = false;
LK.setTimeout(function () {
endGame();
}, 100);
return;
}
touchCooldown = 60; // 1 second cooldown when caught
// Don't end game here - only end when all lives are lost in carrera mode
// or when time runs out in arcade mode
LK.getSound('poke_fail').play();
// Set target to touched_concentrated state for longer duration (2 seconds)
target.setState('touched_concentrated', 120);
// Set player to caught state when target is touched while concentrated
player.setState('caught', 120);
// Add longer tween animation for target surprise state when caught
tween(target, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(target, {
scaleX: 1,
scaleY: 1
}, {
duration: 400,
easing: tween.easeIn
});
}
});
}
}
}
// Game input handling
game.down = function (x, y, obj) {
if (gameMode === 'menu') {
// Handle volume slider in menu
return;
}
if (gameMode === 'confirmation' || !gameActive || !instructionsCompleted) {
return;
}
// Move hand towards touch point
if (hand) {
hand.x = x;
hand.y = y;
}
// Only check touch if the hand is actually near the target
if (hand && target) {
var distanceX = Math.abs(hand.x - target.x);
var distanceY = Math.abs(hand.y - target.y);
// Only check touch if within reasonable distance (target size is about 450x675)
if (distanceX < 300 && distanceY < 400) {
checkTouch();
}
}
};
var originalGameMove = function originalGameMove(x, y, obj) {
if (gameMode === 'confirmation' || !gameActive) {
return;
}
// Move hand with drag
if (hand) {
hand.x = x;
hand.y = y;
}
};
var originalGameUp = function originalGameUp(x, y, obj) {
// Handle volume slider release
isDragging = false;
};
// Game event handlers will be set conditionally based on game mode in the update function
function endGame() {
gameActive = false;
instructionsCompleted = false;
// Clean up UI elements to prevent overlapping
LK.gui.bottom.removeChildren();
LK.gui.top.removeChildren();
LK.gui.topRight.removeChildren();
// Reset UI text variables
scoreText = null;
timeText = null;
livesText = null;
difficultyText = null;
instructionGraphic = null;
// Update high scores
var isNewRecord = false;
if (gameMode === 'carrera') {
if (score > highScoreCarrera) {
highScoreCarrera = score;
storage.highScoreCarrera = highScoreCarrera;
isNewRecord = true;
}
} else {
if (score > highScoreArcade) {
highScoreArcade = score;
storage.highScoreArcade = highScoreArcade;
isNewRecord = true;
}
}
// Show statistics screen
showStatistics(isNewRecord);
}
// Main game update
game.update = function () {
// Set up event handlers based on current game mode
if (gameMode === 'menu' || gameMode === 'confirmation') {
// Remove game event handlers when in menu/confirmation modes
game.move = null;
game.up = null;
return;
}
// Set up game event handlers only when in active game modes
if (gameMode === 'carrera' || gameMode === 'arcade') {
if (!game.move) {
game.move = originalGameMove;
}
if (!game.up) {
game.up = originalGameUp;
}
}
if (!gameActive) {
return;
}
// Reset menu confirmation state when game is active
menuConfirmVisible = false;
// Update cooldown timer
if (touchCooldown > 0) {
touchCooldown--;
}
// Update game timer only in arcade mode
if (gameMode === 'arcade' && gameTime > 0) {
gameTime--;
var seconds = Math.ceil(gameTime / 60);
if (timeText) {
timeText.setText('Tiempo: ' + seconds);
}
// End game when time runs out in arcade mode
if (gameTime <= 0) {
endGame();
return;
}
}
// End game when lives reach 0 in arcade mode
if (gameMode === 'arcade' && lives <= 0) {
gameActive = false;
LK.setTimeout(function () {
endGame();
}, 100);
return;
}
// End game in carrera mode only when all lives are lost (0 or below)
if (gameMode === 'carrera' && lives <= 0) {
endGame();
return;
}
// Update target character
if (target) {
target.update();
}
// Update player character
if (player) {
player.update();
}
};
// Start menu music
LK.playMusic('MenuMusic', {
volume: musicVolume
});
Es una trabajadora de sams club, tierna bonita de lentes con gorra verde y mandil verde, playera polo blanca y pantalon negro. In-Game asset. High contrast. No shadows
Es una trabajador de sams club, adorable, cabello un poco de emo, un poco cacheton y orejas de gatito en forma de diadema por encima de su gorra con gorra verde y mandil verde, playera polo blanca y pantalon negro. In-Game asset. High contrast. No shadows
Debe decir “Piko piko” y ser estilo cute. In-Game asset. High contrast. No shadows
Que tenga un mantel azul con el logo de sams club, sean menos productos y la mesita sea mas alta, el mantel no llega hasta el suelo, si no hasta a la mitad de la altura y permite ver las patitas de la mesa
Los pasillos de sams club vistos desde dentro hacia el centro del establecimiento. 2d ANIMADO. In-Game asset. 2d. High contrast. No shadows
Una mano cerrada con el dedo indici estirado, debe ser cute. In-Game asset. 2d. High contrast. No shadows
Haz estemismo personaje pero de espaldas
Debe de decir sams clue en su playera, verse la gorra y no olvides trazar las lineas cuando lo hagas png sin fondo
Que se sonroje y se ria con ternura, agrega unos brillitos al rededor de su cabeza, como de sorpresa
Que levante el brazo derecho apuntando con el dedo y que diga en un globo de dialogo ́ ́Calmate Mensa''. CON UNA CARITA como burlandose un poco enojado. No olvides las lineas negras al volverlo png
Un corazon verde de sams club. In-Game asset. 2d. High contrast. No shadows
Un cuadro de dialogo. Este dira ''Picale las costillas al Demo'' TIENE QUE SER ADORABLE pero retro, de videojuego. In-Game asset. 2d. High contrast. No shadows
MODO ARCADE, boton de seleccion de modo de juego. In-Game asset. 2d. High contrast. No shadows
Redondeado de las orillas y al hacelro png no olvides ningunalinea
Ambos deberan ser trabajadores de sams club, gorra verde con el logo, la chica de la izqueirda debera usar lentes, polo blanca, mandil verde con el logo del trabajo. EL chico de la derecha, pelo negro un poco alrgo, gorra igual verde y el amndil. Igual el de la derecha usara playera de polo blanca. Y al ededor de la mano que esta tocando deberia decir PICO PICO, COMO SI FUERA UN EFECTO DE SONIDO AL TOCARLO
Recuadro de color negro con borde verde claro, que sea semi transparente en un 70% y que sea algo retro, apra menu de videojuego. In-Game asset. 2d. High contrast. No shadows
No olvides las orejas de gatito para el chico, que sean de color negro.
Un simbolo de reiniciar, sin letras, es como un circulo con una flecha. In-Game asset. 2d. High contrast. No shadows
Un simbolo de continuar sin letras, como un triangulo. In-Game asset. 2d. High contrast. No shadows
uN SIMBOLO verde de una casita, para el menu de volver al menu principal. sin letras. In-Game asset. 2d. High contrast. No shadows
SImbolo de menu de hamburguesa. In-Game asset. 2d. High contrast. No shadows
El fondo de un menu pqueño, este se dezpliga asi que deberia ser bonito, acorde a un menu rapido y de tipo retro. colores verde pastel o azul marino mate claro. con borde blanco, y que tenga una pestañita superior que diga menu como si fuera una carpeta. In-Game asset. 2d. High contrast. No shadows
El se debe de ver desde lejos, ELLA SE VEA ASI COMO esta, pero el otro debe estar triste mientras lo despiden y le dan sus cosas, ya no traera la gorra ni el mantel por que las estan entregando
Agrega las orejitas al chico vistas desde atras, y su camisa debe ser una plo blanca, por debajo de su mandil verde
Has que estos dos personajes se esten besando en un congelador de sams club, escondidos entre los productos. agrega corazoncitos y evita el tono sepia, debe ser alegre
Los gatitos estan separados, sus dueños estan debajo de las sabanas tapados, los corazones deben estar arriba de la silueta en la cama, y los textos de tuchi tuchi igual. eS UNA ESCENA ALGO MORBOSA pero no se ve nada, que la figura en las sabanas abarque gran parte de la cama