User prompt
rebaja a 1.1 segundos la paralizacion de la katana
User prompt
mira el espacio donde quiero que funcione esa funcion que sean 1.5 cm contando de arriba hacia abajo de la parte superior de la pantalla
User prompt
ya esta bien, pero que se active solo cuando hace movimientos muy muy rapido y que solo se active esta funcion si el usuario tiene la katana arriba en la parte superior e la pantalla y empieza hacer movmientos rapidos
User prompt
bien, ahora hace que si el jugador empieza hacer con la katana movimientos bruscos como de un lado a otro rapidamente a la katana le salga una barra de vida y que si se vacia la katan queda paralisada x 2.5 segundos ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ya, mira quiero que cada vez que el jugador corte una fruta la velocidad vaya subiendo y aumentando las frutas, PERO QUE SEA PROGRESIVAMENTE para que dure arto el juego
User prompt
agrega el contador, quitale el fondo y solo deja la parte de los numeros, y ponlo en 3D
User prompt
dale mas forma al contador y centralo a la pantalla en la parte de arriba, y agrega que si las frutas tocan el piso el jugador pierde
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'scoreTxt.style.fill = 0xF39C12; // Orange for starting scores' Line Number: 333
User prompt
hace que el contador sea en 3d y bonito con colores
Code edit (1 edits merged)
Please save this source code
User prompt
Fruit Ninja Katana
Initial prompt
Crea frutas que vengan de la parte superior de la pantalla y que haya una katana que se contrelo con el mouse y que la katana parta a la mitad las frutas, dale las imagenes a las frutas y pone todas las frutas que encuentren nesecario, y a la katana igual dale su forma de katana y efectos al cortar las frutas
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { scoreNames: [], scoreValues: [] }); /**** * Classes ****/ var AutoSword = Container.expand(function () { var self = Container.call(this); self.sliced = false; var swordGraphics = self.attachAsset('katana', { anchorX: 0.5, anchorY: 0.5 }); swordGraphics.tint = 0x00FF00; // Green tint for auto swords swordGraphics.alpha = 0.8; // Auto movement properties self.targetFruit = null; self.speed = 12; // Increased speed for faster fruit catching self.cooldownTimer = 0; self.maxCooldown = 60; // Reduced cooldown to 1 second at 60fps for faster slicing self.update = function () { if (self.cooldownTimer > 0) { self.cooldownTimer--; return; } // Find nearest unsliced fruit var nearestFruit = null; var nearestDistance = Infinity; for (var i = 0; i < fruits.length; i++) { var fruit = fruits[i]; if (!fruit.sliced) { var distance = Math.sqrt(Math.pow(fruit.x - self.x, 2) + Math.pow(fruit.y - self.y, 2)); if (distance < nearestDistance) { nearestDistance = distance; nearestFruit = fruit; } } } // Move towards nearest fruit if (nearestFruit) { self.targetFruit = nearestFruit; var dx = nearestFruit.x - self.x; var dy = nearestFruit.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 80) { // Move towards fruit self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Rotate towards target swordGraphics.rotation = Math.atan2(dy, dx); } else { // Close enough to slice if (!nearestFruit.sliced) { nearestFruit.slice(); self.cooldownTimer = self.maxCooldown; // No visual effect for auto-sword } } } else { // No fruits found, patrol randomly if (Math.random() < 0.02) { // 2% chance per frame to change direction self.x += (Math.random() - 0.5) * 100; self.y += (Math.random() - 0.5) * 100; // Keep within screen bounds self.x = Math.max(100, Math.min(1948, self.x)); self.y = Math.max(100, Math.min(2632, self.y)); } } }; return self; }); // Storage plugin removed as requested var Building = Container.expand(function (buildingX, buildingY, scale, height) { var self = Container.call(this); // Building base with varying heights var baseHeight = height || Math.random() * 200 + 250; var buildingBase = self.attachAsset('building_base', { anchorX: 0.5, anchorY: 1 }); buildingBase.scaleY = baseHeight / 300; buildingBase.y = 0; // Building roof var roof = self.attachAsset('building_roof', { anchorX: 0.5, anchorY: 1 }); roof.y = -baseHeight; // Add windows in a grid pattern var windowRows = Math.floor(baseHeight / 40); var windowCols = 4; for (var row = 0; row < windowRows; row++) { for (var col = 0; col < windowCols; col++) { var window = self.attachAsset('building_window', { anchorX: 0.5, anchorY: 0.5 }); window.x = (col - 1.5) * 25; window.y = -30 - row * 40; // Random window lighting if (Math.random() > 0.3) { window.alpha = Math.random() * 0.8 + 0.2; } else { window.alpha = 0.1; } } } // Set position and scale self.x = buildingX; self.y = buildingY; self.scaleX = scale || 1; self.scaleY = scale || 1; // Animation properties for subtle building sway self.swaySpeed = Math.random() * 0.005 + 0.002; self.swayAmount = Math.random() * 0.02 + 0.01; self.animationOffset = Math.random() * Math.PI * 2; self.update = function () { // Very subtle building sway var sway = Math.sin(LK.ticks * self.swaySpeed + self.animationOffset) * self.swayAmount; self.rotation = sway; }; return self; }); var Cloud = Container.expand(function (cloudX, cloudY, cloudScale) { var self = Container.call(this); // Create cloud with multiple overlapping circles var cloud1 = self.attachAsset('cloud', { anchorX: 0.5, anchorY: 0.5 }); var cloud2 = self.attachAsset('cloud', { anchorX: 0.5, anchorY: 0.5 }); cloud2.x = 40; cloud2.scaleX = 0.8; cloud2.scaleY = 0.8; var cloud3 = self.attachAsset('cloud', { anchorX: 0.5, anchorY: 0.5 }); cloud3.x = -30; cloud3.scaleX = 0.9; cloud3.scaleY = 0.9; self.x = cloudX; self.y = cloudY; self.scaleX = cloudScale || 1; self.scaleY = cloudScale || 1; // Floating animation self.floatSpeed = Math.random() * 0.01 + 0.005; self.floatAmount = Math.random() * 20 + 10; self.driftSpeed = Math.random() * 0.5 + 0.2; self.originalX = cloudX; self.update = function () { // Gentle floating motion self.y = cloudY + Math.sin(LK.ticks * self.floatSpeed) * self.floatAmount; // Slow horizontal drift self.x += self.driftSpeed; // Reset position when off screen if (self.x > 2200) { self.x = -200; } }; return self; }); var Fruit = Container.expand(function (fruitType) { var self = Container.call(this); self.fruitType = fruitType; self.sliced = false; self.fallSpeed = Math.random() * 3 + (baseFallSpeed + currentDifficultyLevel * 0.3); var fruitGraphics = self.attachAsset(fruitType, { anchorX: 0.5, anchorY: 0.5 }); // Simple straight fall self.velocityY = self.fallSpeed; self.gravity = 0.1; self.update = function () { if (!self.sliced) { self.y += self.velocityY; self.velocityY += self.gravity; } }; self.slice = function () { if (self.sliced) return; self.sliced = true; // Award points based on fruit type var basePoints = 0; switch (self.fruitType) { case 'apple': basePoints = 10; break; case 'orange': basePoints = 15; break; case 'watermelon': basePoints = 30; break; case 'pineapple': basePoints = 25; break; case 'banana': basePoints = 20; break; } var points = basePoints; LK.setScore(LK.getScore() + points); updateScoreDisplay(LK.getScore()); // Update difficulty progressively based on score var newScore = LK.getScore(); var newDifficultyLevel = Math.floor(newScore / 50); // Increase difficulty every 50 points if (newDifficultyLevel > currentDifficultyLevel) { currentDifficultyLevel = newDifficultyLevel; // Gradually decrease spawn rate (faster spawning) - minimum 20 frames spawnRate = Math.max(20, baseSpawnRate - currentDifficultyLevel * 8); } // Create slice effect self.createSliceEffect(); // Play slice sound LK.getSound('slice').play(); // Create floating score text var floatingScore = new Text2('+' + points, { size: 60, fill: 0xFFD700 }); floatingScore.anchor.set(0.5, 0.5); floatingScore.x = self.x; floatingScore.y = self.y; game.addChild(floatingScore); // Animate floating score tween(floatingScore, { y: floatingScore.y - 150, alpha: 0 }, { duration: 1000, onComplete: function onComplete() { floatingScore.destroy(); } }); // Animate fruit halves self.animateSlice(); }; self.createSliceEffect = function () { // Create particle explosion for (var i = 0; i < 8; i++) { var particle = new Particle(); particle.x = self.x; particle.y = self.y; particles.push(particle); game.addChild(particle); } }; self.animateSlice = function () { // Split fruit into two halves var leftHalf = self.attachAsset(self.fruitType, { anchorX: 0.5, anchorY: 0.5, x: -20 }); var rightHalf = self.attachAsset(self.fruitType, { anchorX: 0.5, anchorY: 0.5, x: 20 }); // Hide original fruit fruitGraphics.alpha = 0; // Animate halves falling tween(leftHalf, { x: leftHalf.x - 100, y: leftHalf.y + 200, rotation: -1 }, { duration: 1000 }); tween(rightHalf, { x: rightHalf.x + 100, y: rightHalf.y + 200, rotation: 1 }, { duration: 1000 }); tween(leftHalf, { alpha: 0 }, { duration: 800 }); tween(rightHalf, { alpha: 0 }, { duration: 800 }); }; return self; }); var GrassClump = Container.expand(function (grassX, grassY) { var self = Container.call(this); // Create multiple grass blades for (var i = 0; i < 5; i++) { var blade = self.attachAsset('grass_blade', { anchorX: 0.5, anchorY: 1 }); blade.x = (i - 2) * 8; blade.scaleY = Math.random() * 0.5 + 0.7; blade.rotation = (Math.random() - 0.5) * 0.3; // Vary grass color slightly var greenVariation = Math.random() * 0.2 + 0.9; blade.tint = 0x7CFC00 * greenVariation; } self.x = grassX; self.y = grassY; // Wind animation self.windSpeed = Math.random() * 0.03 + 0.02; self.windOffset = Math.random() * Math.PI * 2; self.update = function () { var wind = Math.sin(LK.ticks * self.windSpeed + self.windOffset) * 0.15; self.rotation = wind; }; return self; }); var Katana = Container.expand(function () { var self = Container.call(this); self.trailPoints = []; self.maxTrailLength = 10; var katanaGraphics = self.attachAsset('katana', { anchorX: 0.5, anchorY: 0.5 }); self.updatePosition = function (x, y) { // Add current position to trail self.trailPoints.push({ x: self.x, y: self.y }); if (self.trailPoints.length > self.maxTrailLength) { self.trailPoints.shift(); } // Calculate angle based on movement if (self.trailPoints.length > 1) { var lastPoint = self.trailPoints[self.trailPoints.length - 2]; var angle = Math.atan2(y - lastPoint.y, x - lastPoint.x); katanaGraphics.rotation = angle; } self.x = x; self.y = y; }; self.checkFruitCollisions = function () { for (var i = fruits.length - 1; i >= 0; i--) { var fruit = fruits[i]; if (!fruit.sliced && self.intersects(fruit)) { fruit.slice(); } } }; return self; }); var Particle = Container.expand(function () { var self = Container.call(this); var particleGraphics = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = (Math.random() - 0.5) * 10; self.velocityY = (Math.random() - 0.5) * 10; self.life = 60; // 1 second at 60fps // Random color for juice effect var colors = [0xFF6B6B, 0xFFE66D, 0x4ECDC4, 0x45B7D1, 0x96CEB4]; particleGraphics.tint = colors[Math.floor(Math.random() * colors.length)]; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.velocityY += 0.2; // gravity self.life--; particleGraphics.alpha = self.life / 60; if (self.life <= 0) { self.destroy(); for (var i = particles.length - 1; i >= 0; i--) { if (particles[i] === self) { particles.splice(i, 1); break; } } } }; return self; }); var ShootingStar = Container.expand(function (startX, startY) { var self = Container.call(this); // Create main shooting star body var starBody = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); starBody.tint = 0xFFFFFF; starBody.scaleX = 1.5; starBody.scaleY = 1.5; // Create glowing trail particles self.trailParticles = []; for (var t = 0; t < 8; t++) { var trailParticle = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); trailParticle.tint = 0xFFD700; // Golden trail trailParticle.scaleX = 0.8 - t * 0.1; trailParticle.scaleY = 0.8 - t * 0.1; trailParticle.alpha = 0.8 - t * 0.1; self.trailParticles.push(trailParticle); } // Set position and movement properties self.x = startX; self.y = startY; self.velocityX = Math.random() * 3 + 2; // Moving right and down self.velocityY = Math.random() * 4 + 3; self.life = 300; // 5 seconds at 60fps self.maxLife = 300; // Trail position tracking self.trailPositions = []; self.update = function () { // Store current position for trail self.trailPositions.push({ x: self.x, y: self.y }); if (self.trailPositions.length > self.trailParticles.length) { self.trailPositions.shift(); } // Update position self.x += self.velocityX; self.y += self.velocityY; self.life--; // Update trail particles for (var t = 0; t < self.trailParticles.length; t++) { if (self.trailPositions[self.trailPositions.length - 1 - t]) { var trailPos = self.trailPositions[self.trailPositions.length - 1 - t]; self.trailParticles[t].x = trailPos.x - self.x; self.trailParticles[t].y = trailPos.y - self.y; } } // Fade out as life decreases var fadePercent = self.life / self.maxLife; starBody.alpha = fadePercent; for (var t = 0; t < self.trailParticles.length; t++) { self.trailParticles[t].alpha = (0.8 - t * 0.1) * fadePercent; } // Twinkle effect starBody.scaleX = 1.5 + Math.sin(LK.ticks * 0.2) * 0.3; starBody.scaleY = 1.5 + Math.sin(LK.ticks * 0.2) * 0.3; }; return self; }); var Tree = Container.expand(function (treeX, treeY, scale) { var self = Container.call(this); // Tree trunk var trunk = self.attachAsset('tree_trunk', { anchorX: 0.5, anchorY: 1 }); trunk.y = 0; // Multiple foliage layers for depth var foliageDark = self.attachAsset('tree_foliage_dark', { anchorX: 0.5, anchorY: 1 }); foliageDark.y = -200; foliageDark.x = 10; var foliageMain = self.attachAsset('tree_foliage', { anchorX: 0.5, anchorY: 1 }); foliageMain.y = -180; var foliageLight = self.attachAsset('tree_foliage_light', { anchorX: 0.5, anchorY: 1 }); foliageLight.y = -160; foliageLight.x = -15; // Set position and scale self.x = treeX; self.y = treeY; self.scaleX = scale || 1; self.scaleY = scale || 1; // Animation properties self.swaySpeed = Math.random() * 0.02 + 0.01; self.swayAmount = Math.random() * 0.1 + 0.05; self.animationOffset = Math.random() * Math.PI * 2; self.update = function () { // Gentle swaying animation var sway = Math.sin(LK.ticks * self.swaySpeed + self.animationOffset) * self.swayAmount; foliageMain.rotation = sway; foliageLight.rotation = sway * 0.8; foliageDark.rotation = sway * 1.2; trunk.rotation = sway * 0.3; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Create animated forest background // Generate unique player ID if not exists // Initialize weapons object properly function _typeof2(o) { "@babel/helpers - typeof"; return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof2(o); } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } // Player ID initialization removed var backgroundContainer = new Container(); game.addChild(backgroundContainer); // Create sky gradient effect with sunset to night colors var skyLayers = []; var sunsetColors = [0xFF4500, // Deep orange at horizon 0xFF6347, // Tomato red-orange 0xDC143C, // Crimson red 0x9932CC, // Dark orchid purple 0x483D8B, // Dark slate blue 0x2F4F4F, // Dark slate gray 0x191970, // Midnight blue 0x000000 // Pure black night ]; for (var s = 0; s < 8; s++) { var skyLayer = LK.getAsset('shape', { anchorX: 0, anchorY: 0, scaleX: 20.48, scaleY: 3.4 }); skyLayer.y = s * 340; // Use sunset to night gradient colors skyLayer.tint = sunsetColors[s]; skyLayer.alpha = 0.8; backgroundContainer.addChild(skyLayer); skyLayers.push(skyLayer); } ; // Play ambient music for game atmosphere LK.playMusic('am', { loop: true }); // Create sun with sunset colors var sun = backgroundContainer.addChild(LK.getAsset('sun', { anchorX: 0.5, anchorY: 0.5 })); sun.x = 1600; sun.y = 400; // Lower position for sunset effect sun.tint = 0xFF6347; // Deep sunset tomato color sun.scaleX = 1.3; sun.scaleY = 1.3; // Create layered mountains with anime-style atmospheric perspective and snow caps var mountains = []; var snowCaps = []; // Far distant snow-capped mountains (very light blue/purple with white peaks) for (var m1 = 0; m1 < 8; m1++) { var farMountain = backgroundContainer.addChild(LK.getAsset('mountain', { anchorX: 0.5, anchorY: 1 })); farMountain.x = m1 * 350 + 100; farMountain.y = 1800; farMountain.scaleY = Math.random() * 0.3 + 0.4; farMountain.scaleX = Math.random() * 0.4 + 0.8; farMountain.tint = 0x9BB5D6; // Light blue-purple farMountain.alpha = 0.4; mountains.push(farMountain); // Add snow cap to tall mountains if (farMountain.scaleY > 0.6) { var farSnowCap = backgroundContainer.addChild(LK.getAsset('snow_cap', { anchorX: 0.5, anchorY: 1 })); farSnowCap.x = farMountain.x; farSnowCap.y = farMountain.y - farMountain.scaleY * 200 * 0.7; farSnowCap.scaleX = farMountain.scaleX * 0.9; farSnowCap.scaleY = 0.3; farSnowCap.alpha = 0.6; farSnowCap.tint = 0xf0f8ff; snowCaps.push(farSnowCap); } ; } ; // Mid-distance snow-capped mountains (blue-gray with prominent snow) for (var m2 = 0; m2 < 6; m2++) { var midMountain = backgroundContainer.addChild(LK.getAsset('mountain', { anchorX: 0.5, anchorY: 1 })); midMountain.x = m2 * 400 + 150; midMountain.y = 2000; midMountain.scaleY = Math.random() * 0.4 + 0.6; midMountain.scaleX = Math.random() * 0.3 + 0.9; midMountain.tint = 0x7A8FA3; // Blue-gray midMountain.alpha = 0.6; mountains.push(midMountain); // Add snow cap var midSnowCap = backgroundContainer.addChild(LK.getAsset('snow_cap', { anchorX: 0.5, anchorY: 1 })); midSnowCap.x = midMountain.x; midSnowCap.y = midMountain.y - midMountain.scaleY * 200 * 0.6; midSnowCap.scaleX = midMountain.scaleX * 0.95; midSnowCap.scaleY = 0.4; midSnowCap.alpha = 0.8; snowCaps.push(midSnowCap); } // Close mountains (green-brown) for (var m3 = 0; m3 < 4; m3++) { var closeMountain = backgroundContainer.addChild(LK.getAsset('mountain', { anchorX: 0.5, anchorY: 1 })); closeMountain.x = m3 * 500 + 200; closeMountain.y = 2200; closeMountain.scaleY = Math.random() * 0.5 + 0.8; closeMountain.scaleX = Math.random() * 0.3 + 1.1; closeMountain.tint = 0x556B2F; closeMountain.alpha = 0.8; mountains.push(closeMountain); } // Add distant city buildings behind mountains var distantBuildings = []; for (var db = 0; db < 12; db++) { var building = backgroundContainer.addChild(new Building(db * 180 + Math.random() * 50 + 50, 1900, Math.random() * 0.4 + 0.3, Math.random() * 150 + 200)); building.alpha = 0.3; building.tint = 0x708090; distantBuildings.push(building); } // Add mid-distance city buildings var midBuildings = []; for (var mb = 0; mb < 8; mb++) { var midBuilding = backgroundContainer.addChild(new Building(mb * 250 + Math.random() * 80 + 100, 2100, Math.random() * 0.3 + 0.5, Math.random() * 200 + 300)); midBuilding.alpha = 0.5; midBuilding.tint = 0x556B6F; midBuildings.push(midBuilding); } // Create atmospheric mist layers var mistLayers = []; for (var mist = 0; mist < 5; mist++) { var mistLayer = backgroundContainer.addChild(LK.getAsset('cloud', { anchorX: 0.5, anchorY: 0.5 })); mistLayer.x = Math.random() * 2400 - 200; mistLayer.y = 1600 + mist * 150; mistLayer.scaleX = Math.random() * 3 + 2; mistLayer.scaleY = Math.random() * 0.8 + 0.4; mistLayer.tint = 0xF0F8FF; mistLayer.alpha = 0.3; mistLayers.push(mistLayer); } // Create clouds var clouds = []; for (var c = 0; c < 8; c++) { var cloud = backgroundContainer.addChild(new Cloud(Math.random() * 2400 - 200, Math.random() * 600 + 200, Math.random() * 0.8 + 0.6)); clouds.push(cloud); } // Create rolling hills for terrain depth var hills = []; for (var h = 0; h < 12; h++) { var hill = backgroundContainer.addChild(LK.getAsset('mountain', { anchorX: 0.5, anchorY: 1 })); hill.x = h * 200 + Math.random() * 100; hill.y = 2300 + Math.random() * 100; hill.scaleY = Math.random() * 0.3 + 0.2; hill.scaleX = Math.random() * 0.5 + 1.5; hill.tint = 0x6B8E23; // Olive green hill.alpha = 0.6; hills.push(hill); } // Create background trees (larger, further back) var backgroundTrees = []; for (var bt = 0; bt < 15; bt++) { var bgTree = backgroundContainer.addChild(new Tree(Math.random() * 2400 - 200, 2200, Math.random() * 0.8 + 1.2)); bgTree.alpha = 0.7; bgTree.tint = 0x556B2F; backgroundTrees.push(bgTree); } // Create middle ground trees var middleTrees = []; for (var mt = 0; mt < 20; mt++) { var midTree = backgroundContainer.addChild(new Tree(Math.random() * 2600 - 300, 2400, Math.random() * 0.6 + 0.8)); midTree.alpha = 0.85; middleTrees.push(midTree); } // Create foreground trees var foregroundTrees = []; for (var ft = 0; ft < 12; ft++) { var fgTree = backgroundContainer.addChild(new Tree(Math.random() * 2800 - 400, 2600, Math.random() * 0.4 + 0.6)); foregroundTrees.push(fgTree); } // Create grass clumps across the ground var grassClumps = []; for (var g = 0; g < 50; g++) { var grass = backgroundContainer.addChild(new GrassClump(Math.random() * 2400, 2650 + Math.random() * 80)); grassClumps.push(grass); } // Create cherry blossom petals floating in the air var blossomPetals = []; for (var bp = 0; bp < 25; bp++) { var petal = backgroundContainer.addChild(LK.getAsset('flower', { anchorX: 0.5, anchorY: 0.5 })); petal.x = Math.random() * 2048; petal.y = Math.random() * 2000; petal.scaleX = Math.random() * 0.3 + 0.2; petal.scaleY = Math.random() * 0.3 + 0.2; petal.tint = 0xFFB6C1; // Light pink petal.alpha = Math.random() * 0.6 + 0.4; petal.rotation = Math.random() * Math.PI * 2; blossomPetals.push(petal); } // Create colorful flowers scattered around var flowers = []; var flowerColors = [0xFF69B4, 0xFF6347, 0x9370DB, 0x00CED1, 0xFFD700, 0xFF4500]; for (var f = 0; f < 30; f++) { var flower = backgroundContainer.addChild(LK.getAsset('flower', { anchorX: 0.5, anchorY: 0.5 })); flower.x = Math.random() * 2048; flower.y = 2600 + Math.random() * 100; flower.tint = flowerColors[Math.floor(Math.random() * flowerColors.length)]; flowers.push(flower); } // Create shooting stars array var shootingStars = []; var shootingStarSpawnTimer = 0; var shootingStarSpawnRate = 180; // Spawn every 3 seconds (180 frames at 60fps) var fruits = []; var particles = []; var fruitTypes = ['apple', 'orange', 'watermelon', 'pineapple', 'banana']; var spawnTimer = 0; var spawnRate = 90; // frames between spawns var baseSpawnRate = 90; // original spawn rate var baseFallSpeed = 2; // base fall speed for fruits var currentDifficultyLevel = 0; // Katana health system variables var katanaHealth = 100; var maxKatanaHealth = 100; var katanaParalyzed = false; var paralyzeTimer = 0; var lastKatanaX = 0; var lastKatanaY = 0; var movementSamples = []; var maxMovementSamples = 10; // Power-up system variables var powerUpActive = false; var extraKatanas = []; var powerUpActivated = false; var powerUpTimer = 0; var powerUpMaxTimer = 1050; // 17.5 seconds at 60fps // Auto-sword system variables var autoSwords = []; var autoSwordActivated = false; var autoSwordTimer = 0; var autoSwordCooldown = 120; // 2 seconds at 60fps between auto slices // Create katana var katana = game.addChild(new Katana()); katana.x = 1024; katana.y = 1366; katana.visible = false; // Hide katana on start screen // Game state management var gameState = 'start'; // 'start', 'playing' var startScreenVisible = true; // Create new score display positioned at bottom right var scoreContainer = new Container(); LK.gui.bottomRight.addChild(scoreContainer); // Create SCORE label shadow var scoreLabelShadow = new Text2('SCORE', { size: 40, fill: 0x000000 }); scoreLabelShadow.anchor.set(1, 1); scoreLabelShadow.x = 2; scoreLabelShadow.y = -118; scoreLabelShadow.alpha = 0.5; scoreContainer.addChild(scoreLabelShadow); // Create SCORE label text var scoreLabel = new Text2('SCORE', { size: 40, fill: 0xFFFFFF }); scoreLabel.anchor.set(1, 1); scoreLabel.x = 0; scoreLabel.y = -120; scoreContainer.addChild(scoreLabel); // Create shadow for depth var scoreShadow = new Text2('0', { size: 80, fill: 0x000000 }); scoreShadow.anchor.set(1, 1); scoreShadow.x = 2; scoreShadow.y = 2; scoreShadow.alpha = 0.5; scoreContainer.addChild(scoreShadow); // Create main score text var scoreTxt = new Text2('0', { size: 80, fill: 0xFFD700 }); scoreTxt.anchor.set(1, 1); scoreContainer.addChild(scoreTxt); // Position container at bottom right with some padding scoreContainer.x = -20; // 20px from right edge scoreContainer.y = -20; // 20px from bottom edge // Hide game UI on start screen scoreContainer.visible = false; // Create katana health bar var healthBarContainer = new Container(); LK.gui.bottom.addChild(healthBarContainer); // Health bar background var healthBarBg = LK.getAsset('shape', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 0.3 }); healthBarBg.tint = 0x333333; healthBarContainer.addChild(healthBarBg); // Health bar fill var healthBarFill = LK.getAsset('shape', { anchorX: 0, anchorY: 0.5, scaleX: 3, scaleY: 0.25 }); healthBarFill.tint = 0x27AE60; healthBarFill.x = -150; // Start from left edge of background healthBarContainer.addChild(healthBarFill); // Health bar border var healthBarBorder = LK.getAsset('shape', { anchorX: 0.5, anchorY: 0.5, scaleX: 3.1, scaleY: 0.35 }); healthBarBorder.tint = 0xFFFFFF; healthBarBorder.alpha = 0.8; healthBarContainer.addChild(healthBarBorder); // Position health bar at bottom center healthBarContainer.x = 1024; healthBarContainer.y = 2600; healthBarContainer.alpha = 0; // Initially hidden healthBarContainer.visible = false; // Hide on start screen // Create katana power-up progress bar var powerBarContainer = new Container(); LK.gui.topRight.addChild(powerBarContainer); // Power bar background var powerBarBg = LK.getAsset('shape', { anchorX: 1, anchorY: 0, scaleX: 2.5, scaleY: 0.4 }); powerBarBg.tint = 0x333333; powerBarContainer.addChild(powerBarBg); // Power bar fill var powerBarFill = LK.getAsset('shape', { anchorX: 0, anchorY: 0, scaleX: 0, scaleY: 0.35 }); powerBarFill.tint = 0xFFD700; // Gold color for ninja power powerBarFill.x = -250; // Start from left edge of background powerBarContainer.addChild(powerBarFill); // Power bar label with 3D effect var powerBarLabelShadow = new Text2('KATANA-NINJA', { size: 30, fill: 0x000000 }); powerBarLabelShadow.anchor.set(1, 0); powerBarLabelShadow.x = 2; powerBarLabelShadow.y = -33; powerBarLabelShadow.alpha = 0.6; powerBarContainer.addChild(powerBarLabelShadow); var powerBarLabel = new Text2('KATANA-NINJA', { size: 30, fill: 0xFFD700 }); powerBarLabel.anchor.set(1, 0); powerBarLabel.x = 0; powerBarLabel.y = -35; powerBarContainer.addChild(powerBarLabel); // Position power bar at top right with padding powerBarContainer.x = -20; // 20px from right edge powerBarContainer.y = 120; // Below the platform menu area powerBarContainer.visible = false; // Hide on start screen // Create Apoyo support bar for auto-sword system var apoyoBarContainer = new Container(); LK.gui.topRight.addChild(apoyoBarContainer); // Apoyo bar background var apoyoBarBg = LK.getAsset('shape', { anchorX: 1, anchorY: 0, scaleX: 2.5, scaleY: 0.4 }); apoyoBarBg.tint = 0x333333; apoyoBarContainer.addChild(apoyoBarBg); // Apoyo bar fill var apoyoBarFill = LK.getAsset('shape', { anchorX: 0, anchorY: 0, scaleX: 0, scaleY: 0.35 }); apoyoBarFill.tint = 0x00FF00; // Green color for support apoyoBarFill.x = -250; // Start from left edge of background apoyoBarContainer.addChild(apoyoBarFill); // Apoyo bar label with 3D effect var apoyoBarLabelShadow = new Text2('APOYO', { size: 30, fill: 0x000000 }); apoyoBarLabelShadow.anchor.set(1, 0); apoyoBarLabelShadow.x = 2; apoyoBarLabelShadow.y = -33; apoyoBarLabelShadow.alpha = 0.6; apoyoBarContainer.addChild(apoyoBarLabelShadow); var apoyoBarLabel = new Text2('APOYO', { size: 30, fill: 0x00FF00 }); apoyoBarLabel.anchor.set(1, 0); apoyoBarLabel.x = 0; apoyoBarLabel.y = -35; apoyoBarContainer.addChild(apoyoBarLabel); // Position apoyo bar lower and separate from katana bar apoyoBarContainer.x = -20; // 20px from right edge apoyoBarContainer.y = 220; // Lower position, more separated from katana bar apoyoBarContainer.visible = false; // Hide on start screen // Create new exit button positioned at bottom center var exitButtonContainer = new Container(); LK.gui.bottom.addChild(exitButtonContainer); // Create exit button background var exitBtnBg = LK.getAsset('shape', { anchorX: 0.5, anchorY: 1, scaleX: 2, scaleY: 1.2 }); exitBtnBg.tint = 0xE74C3C; exitBtnBg.alpha = 0.9; exitButtonContainer.addChild(exitBtnBg); // Create exit button text var exitBtnText = new Text2('SALIR', { size: 40, fill: 0xFFFFFF }); exitBtnText.anchor.set(0.5, 0.5); exitBtnText.x = 0; exitBtnText.y = -30; exitButtonContainer.addChild(exitBtnText); // Position exit button at bottom center with padding exitButtonContainer.x = 0; exitButtonContainer.y = -120; // 120px from bottom edge exitButtonContainer.visible = false; // Hide on start screen // Exit button interaction exitButtonContainer.down = function (x, y, obj) { // Make all fruits disintegrate with animation for (var i = fruits.length - 1; i >= 0; i--) { var fruit = fruits[i]; // Animate fruit disintegration tween(fruit, { alpha: 0, scaleX: 0.1, scaleY: 0.1, rotation: Math.PI * 2 }, { duration: 500, onFinish: function onFinish() { // Destroy fruit after animation if (fruit && fruit.destroy) { fruit.destroy(); } } }); } // Clear fruits array fruits = []; // Return to start screen gameState = 'start'; startScreenVisible = true; // Hide game UI elements scoreContainer.visible = false; healthBarContainer.visible = false; powerBarContainer.visible = false; apoyoBarContainer.visible = false; exitButtonContainer.visible = false; // Show start screen startScreenContainer.visible = true; startScreenContainer.alpha = 1; startScreenContainer.scaleX = 1; startScreenContainer.scaleY = 1; // Hide katana on start screen katana.visible = false; }; // Create start screen container var startScreenContainer = new Container(); game.addChild(startScreenContainer); // Create start screen dark overlay var startOverlay = LK.getAsset('shape', { anchorX: 0.5, anchorY: 0.5, scaleX: 25, scaleY: 35 }); startOverlay.tint = 0x000000; startOverlay.alpha = 0.6; startOverlay.x = 1024; startOverlay.y = 1366; startScreenContainer.addChild(startOverlay); // Create main title with 3D effect // Create multiple shadow layers for depth var titleShadow3 = new Text2('FRUIT NINJA', { size: 120, fill: 0x000000 }); titleShadow3.anchor.set(0.5, 0.5); titleShadow3.x = 1024 + 8; titleShadow3.y = 800 + 8; titleShadow3.alpha = 0.3; startScreenContainer.addChild(titleShadow3); var titleShadow2 = new Text2('FRUIT NINJA', { size: 120, fill: 0x8B0000 }); titleShadow2.anchor.set(0.5, 0.5); titleShadow2.x = 1024 + 4; titleShadow2.y = 800 + 4; titleShadow2.alpha = 0.5; startScreenContainer.addChild(titleShadow2); var titleShadow1 = new Text2('FRUIT NINJA', { size: 120, fill: 0xCD5C5C }); titleShadow1.anchor.set(0.5, 0.5); titleShadow1.x = 1024 + 2; titleShadow1.y = 800 + 2; titleShadow1.alpha = 0.7; startScreenContainer.addChild(titleShadow1); var gameTitle = new Text2('FRUIT NINJA', { size: 120, fill: 0xFF6B6B }); gameTitle.anchor.set(0.5, 0.5); gameTitle.x = 1024; gameTitle.y = 800; startScreenContainer.addChild(gameTitle); // Add pulsing glow effect tween(gameTitle, { scaleX: 1.05, scaleY: 1.05 }, { duration: 2000, onComplete: function onComplete() { tween(gameTitle, { scaleX: 1.0, scaleY: 1.0 }, { duration: 2000 }); } }); // Create subtitle with 3D effect var subtitleShadow2 = new Text2('KATANA MASTER', { size: 60, fill: 0x000000 }); subtitleShadow2.anchor.set(0.5, 0.5); subtitleShadow2.x = 1024 + 6; subtitleShadow2.y = 950 + 6; subtitleShadow2.alpha = 0.4; startScreenContainer.addChild(subtitleShadow2); var subtitleShadow1 = new Text2('KATANA MASTER', { size: 60, fill: 0xB8860B }); subtitleShadow1.anchor.set(0.5, 0.5); subtitleShadow1.x = 1024 + 3; subtitleShadow1.y = 950 + 3; subtitleShadow1.alpha = 0.6; startScreenContainer.addChild(subtitleShadow1); var gameSubtitle = new Text2('KATANA MASTER', { size: 60, fill: 0xFFD700 }); gameSubtitle.anchor.set(0.5, 0.5); gameSubtitle.x = 1024; gameSubtitle.y = 950; startScreenContainer.addChild(gameSubtitle); // Add subtle rotation animation tween(gameSubtitle, { rotation: 0.05 }, { duration: 3000, onComplete: function onComplete() { tween(gameSubtitle, { rotation: -0.05 }, { duration: 3000, onComplete: function onComplete() { tween(gameSubtitle, { rotation: 0 }, { duration: 3000 }); } }); } }); // Create play button var playBtn = LK.getAsset('shape', { anchorX: 0.5, anchorY: 0.5, scaleX: 6, scaleY: 2 }); playBtn.tint = 0x27AE60; playBtn.x = 1024; playBtn.y = 1200; startScreenContainer.addChild(playBtn); var playText = new Text2('JUGAR', { size: 70, fill: 0xFFFFFF }); playText.anchor.set(0.5, 0.5); playText.x = 1024; playText.y = 1200; startScreenContainer.addChild(playText); // Create shop button var shopBtn = LK.getAsset('shape', { anchorX: 0.5, anchorY: 0.5, scaleX: 4, scaleY: 1.5 }); shopBtn.tint = 0x8E44AD; shopBtn.x = 1024; shopBtn.y = 1450; startScreenContainer.addChild(shopBtn); var shopText = new Text2('Tienda\nPROXIMAMENTE', { size: 40, fill: 0xFFFFFF }); shopText.anchor.set(0.5, 0.5); shopText.x = 1024; shopText.y = 1450; startScreenContainer.addChild(shopText); // Create leaderboard table with 3D title var leaderboardTitleShadow = new Text2('TOP JUGADORES', { size: 60, fill: 0x000000 }); leaderboardTitleShadow.anchor.set(0.5, 0.5); leaderboardTitleShadow.x = 1024 + 3; leaderboardTitleShadow.y = 1650 + 3; leaderboardTitleShadow.alpha = 0.5; startScreenContainer.addChild(leaderboardTitleShadow); var leaderboardTitle = new Text2('TOP JUGADORES', { size: 60, fill: 0xFF6B6B }); leaderboardTitle.anchor.set(0.5, 0.5); leaderboardTitle.x = 1024; leaderboardTitle.y = 1650; startScreenContainer.addChild(leaderboardTitle); // Create leaderboard entries var leaderboardEntries = []; for (var l = 0; l < 3; l++) { var entryText = new Text2('', { size: 48, fill: 0xFFFFFF }); entryText.anchor.set(0.5, 0.5); entryText.x = 1024; entryText.y = 1740 + l * 60; startScreenContainer.addChild(entryText); leaderboardEntries.push(entryText); } // Initialize leaderboard display function updateLeaderboard() { var scoreNames = storage.scoreNames || []; var scoreValues = storage.scoreValues || []; // Create combined array for sorting var combinedScores = []; for (var i = 0; i < scoreNames.length; i++) { combinedScores.push({ name: scoreNames[i], score: scoreValues[i] }); } // Sort scores in descending order combinedScores.sort(function (a, b) { return b.score - a.score; }); // Display top 3 scores for (var i = 0; i < 3; i++) { if (i < combinedScores.length) { leaderboardEntries[i].setText('#' + (i + 1) + ': ' + combinedScores[i].name + ' - ' + combinedScores[i].score + ' puntos'); } else { leaderboardEntries[i].setText('#' + (i + 1) + ': --- puntos'); } } } // Function to save player score function savePlayerScore(score) { // Generate consistent player ID based on some unique factor // For now, we'll use a simple player ID system var playerId = storage.currentPlayerId || 1; if (!storage.currentPlayerId) { storage.currentPlayerId = playerId; } var playerName = 'Jugador' + playerId; // Store as separate arrays instead of objects to comply with storage limitations var scoreNames = storage.scoreNames || []; var scoreValues = storage.scoreValues || []; // Check if this player already has a score var existingPlayerIndex = -1; for (var i = 0; i < scoreNames.length; i++) { if (scoreNames[i] === playerName) { existingPlayerIndex = i; break; } } // If player exists, only update if new score is higher if (existingPlayerIndex >= 0) { if (score > scoreValues[existingPlayerIndex]) { scoreValues[existingPlayerIndex] = score; } } else { // New player, add to arrays scoreNames.push(playerName); scoreValues.push(score); } storage.scoreNames = scoreNames; storage.scoreValues = scoreValues; updateLeaderboard(); } // Initialize leaderboard on game start updateLeaderboard(); // Create instructions var instructionText = new Text2('Desliza para cortar frutas\nEvita que toquen el suelo', { size: 35, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = 1950; startScreenContainer.addChild(instructionText); // Leaderboard functionality removed // Play button interaction playBtn.down = function (x, y, obj) { // Reset all game variables to start fresh LK.setScore(0); fruits = []; particles = []; spawnTimer = 0; spawnRate = 90; baseSpawnRate = 90; baseFallSpeed = 2; currentDifficultyLevel = 0; katanaHealth = 100; maxKatanaHealth = 100; katanaParalyzed = false; paralyzeTimer = 0; lastKatanaX = 0; lastKatanaY = 0; movementSamples = []; powerUpActive = false; powerUpActivated = false; powerUpTimer = 0; powerUpMaxTimer = 1050; // Clear any existing extra katanas for (var k = 0; k < extraKatanas.length; k++) { extraKatanas[k].destroy(); } extraKatanas = []; // Clear any existing auto swords for (var s = 0; s < autoSwords.length; s++) { autoSwords[s].destroy(); } autoSwords = []; autoSwordActivated = false; autoSwordTimer = 0; // Reset katana appearance and position katana.destroy(); katana = game.addChild(new Katana()); katana.tint = 0xFFFFFF; katana.x = 1024; katana.y = 1366; katana.visible = true; // Show katana when game starts // Reset power bar powerBarFill.scaleX = 0; powerBarFill.tint = 0xFFD700; powerBarLabel.setText('KATANA-NINJA'); // Reset apoyo bar apoyoBarFill.scaleX = 0; apoyoBarFill.tint = 0x90EE90; apoyoBarLabel.setText('APOYO'); // Reset health bar healthBarFill.scaleX = 3; healthBarFill.tint = 0x27AE60; healthBarContainer.alpha = 0; // Update score display updateScoreDisplay(0); // Start the game gameState = 'playing'; startScreenVisible = false; // Show game UI elements scoreContainer.visible = true; healthBarContainer.visible = true; powerBarContainer.visible = true; apoyoBarContainer.visible = true; exitButtonContainer.visible = true; // Animate start screen out tween(startScreenContainer, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 500, onComplete: function onComplete() { startScreenContainer.visible = false; } }); }; // Database functions removed as requested // Play button hover effect playBtn.move = function (x, y, obj) { playBtn.alpha = 0.8; }; // Exit button hover effect exitButtonContainer.move = function (x, y, obj) { exitBtnBg.alpha = 0.7; }; // Function to update all score texts and add animation function updateScoreDisplay(newScore) { var scoreText = newScore.toString(); scoreTxt.setText(scoreText); scoreShadow.setText(scoreText); // Add pulsing animation tween(scoreContainer, { scaleX: 1.2, scaleY: 1.2 }, { duration: 150, onComplete: function onComplete() { tween(scoreContainer, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150 }); } }); // Update katana-ninja bar progress (3 katanas activate at 1000 score) var powerProgress = Math.min(newScore / 1000, 1.0); // Progress from 0 to 1 var powerBarWidth = 2.5 * powerProgress; // Scale to match background width tween(powerBarFill, { scaleX: powerBarWidth }, { duration: 200 }); // Change power bar color as it fills up if (powerProgress >= 1.0) { powerBarFill.tint = 0x00FF00; // Green when ready powerBarLabel.setText('READY!'); } else if (powerProgress >= 0.7) { powerBarFill.tint = 0xFFD700; // Gold when close } else { powerBarFill.tint = 0xFF6B35; // Orange when building up } // Update Apoyo bar progress (auto-sword activates at 389 score) var apoyoProgress = Math.min(newScore / 389, 1.0); // Progress from 0 to 1 var apoyoBarWidth = 2.5 * apoyoProgress; // Scale to match background width tween(apoyoBarFill, { scaleX: apoyoBarWidth }, { duration: 200 }); // Change apoyo bar color and label as it fills up if (apoyoProgress >= 1.0) { apoyoBarFill.tint = 0x00FF00; // Green when active apoyoBarLabel.setText('ACTIVO'); } else if (apoyoProgress >= 0.7) { apoyoBarFill.tint = 0x32CD32; // Light green when close apoyoBarLabel.setText('APOYO'); } else { apoyoBarFill.tint = 0x90EE90; // Very light green when building up apoyoBarLabel.setText('APOYO'); } // Check for power-up activation at different score thresholds if (newScore >= 8990 && powerUpActivated !== 6) { deactivatePowerUp(); activatePowerUp(6); // 6 katanas at 8990 score powerUpActivated = 6; } else if (newScore >= 5999 && powerUpActivated !== 5) { deactivatePowerUp(); activatePowerUp(5); // 5 katanas at 5999 score powerUpActivated = 5; } else if (newScore >= 3500 && powerUpActivated !== 4) { deactivatePowerUp(); activatePowerUp(4); // 4 katanas at 3500 score powerUpActivated = 4; } else if (newScore >= 1000 && powerUpActivated !== 3) { activatePowerUp(3); // 3 katanas at 1000 score powerUpActivated = 3; } // Check for auto-sword activation at 389 score and every 2500 score after if (newScore >= 389 && !autoSwordActivated) { activateAutoSword(1); // First auto sword at 389 autoSwordActivated = 389; } else if (newScore >= 389) { var currentAutoSwords = Math.floor((newScore - 389) / 2500) + 1; var expectedAutoSwords = Math.floor((autoSwordActivated - 389) / 2500) + 1; if (currentAutoSwords > expectedAutoSwords) { activateAutoSword(currentAutoSwords - expectedAutoSwords); // Add additional auto swords autoSwordActivated = newScore; } } // Enhanced color change effect based on score if (newScore >= 500) { scoreTxt.fill = 0xFFD700; // Gold for power-up scores } else if (newScore >= 200) { scoreTxt.fill = 0x9B59B6; // Purple for medium scores } else if (newScore >= 100) { scoreTxt.fill = 0x3498DB; // Blue for decent scores } else { scoreTxt.fill = 0xFFD700; // Gold for starting scores } } // Power-up activation function function activatePowerUp(numKatanas) { powerUpActive = true; // Set power duration (17.5 seconds = 1050 frames at 60fps) powerUpTimer = 1050; powerUpMaxTimer = 1050; // Create visual explosion effect LK.effects.flashScreen(0xFFD700, 2000); // Golden flash // Create additional katanas with better spacing var extraKatanasToCreate = numKatanas - 1; // Subtract 1 because main katana already exists for (var k = 0; k < extraKatanasToCreate; k++) { var extraKatana = game.addChild(new Katana()); extraKatana.x = katana.x; extraKatana.y = katana.y; extraKatana.katanaIndex = k; // Assign index for positioning extraKatanas.push(extraKatana); // Add golden tint to extra katanas extraKatana.tint = 0xFFD700; // Add glowing effect to extra katanas tween(extraKatana, { alpha: 0.7 }, { duration: 500, onComplete: function onComplete() { tween(extraKatana, { alpha: 1 }, { duration: 500 }); } }); } // Add golden glow effect to main katana katana.tint = 0xFFD700; tween(katana, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onComplete: function onComplete() { tween(katana, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300 }); } }); } // Auto-sword activation function function activateAutoSword(numSwords) { for (var s = 0; s < numSwords; s++) { var autoSword = game.addChild(new AutoSword()); autoSword.x = Math.random() * 1500 + 250; // Random position within screen bounds autoSword.y = Math.random() * 1500 + 250; autoSwords.push(autoSword); // Add spawn animation tween(autoSword, { scaleX: 1, scaleY: 1, alpha: 0.8 }, { duration: 500 }); } // No visual effects for auto-sword activation } // Track mouse movement var isSlicing = false; var lastMouseX = 0; var lastMouseY = 0; game.move = function (x, y, obj) { if (!katanaParalyzed) { katana.updatePosition(x, y); // Update extra katanas with better spacing for multiple katanas if (powerUpActive) { for (var k = 0; k < extraKatanas.length; k++) { var spacing = 250; // Increased spacing for better separation var offsetX = 0; var offsetY = 0; // Position katanas symmetrically around center var totalKatanas = extraKatanas.length + 1; // Include main katana var startOffset = -(totalKatanas - 1) * spacing / 2; offsetX = startOffset + (k + 1) * spacing; // k+1 because main katana is at center (index 0) extraKatanas[k].updatePosition(x + offsetX, y + offsetY); } } if (isSlicing) { katana.checkFruitCollisions(); // Check collisions for extra katanas too if (powerUpActive) { for (var k = 0; k < extraKatanas.length; k++) { extraKatanas[k].checkFruitCollisions(); } } } } // Track movement for katana health system var distance = Math.sqrt(Math.pow(x - lastKatanaX, 2) + Math.pow(y - lastKatanaY, 2)); movementSamples.push(distance); if (movementSamples.length > maxMovementSamples) { movementSamples.shift(); } // Calculate average movement in recent samples var totalMovement = 0; for (var i = 0; i < movementSamples.length; i++) { totalMovement += movementSamples[i]; } var avgMovement = totalMovement / movementSamples.length; // Only activate health system if katana is in upper 1.5cm (approximately 109 pixels) from top var isInUpperScreen = y < 109; // 1.5cm from top of screen (at 72 DPI: 1.5cm ≈ 109 pixels) // If movement is very rapid (increased threshold: 50+ pixels per frame on average) AND in upper screen if (avgMovement > 50 && movementSamples.length >= maxMovementSamples && isInUpperScreen) { katanaHealth -= 3; // Drain health faster for rapid movements // Show health bar when taking damage if (healthBarContainer.alpha < 1) { tween(healthBarContainer, { alpha: 1 }, { duration: 200 }); } // Update health bar fill var healthPercent = Math.max(0, katanaHealth / maxKatanaHealth); tween(healthBarFill, { scaleX: 3 * healthPercent }, { duration: 100 }); // Change color based on health level if (healthPercent < 0.3) { healthBarFill.tint = 0xE74C3C; // Red } else if (healthPercent < 0.6) { healthBarFill.tint = 0xF39C12; // Orange } else { healthBarFill.tint = 0x27AE60; // Green } // Check if health is depleted if (katanaHealth <= 0) { katanaHealth = 0; katanaParalyzed = true; paralyzeTimer = 66; // 1.1 seconds at 60fps // Flash katana red to indicate paralysis LK.effects.flashObject(katana, 0xFF0000, 1100); } } lastKatanaX = x; lastKatanaY = y; lastMouseX = x; lastMouseY = y; }; game.down = function (x, y, obj) { isSlicing = true; katana.updatePosition(x, y); // Update extra katanas position on touch down if (powerUpActive) { for (var k = 0; k < extraKatanas.length; k++) { var spacing = 250; // Consistent spacing with move handler var offsetX = 0; var offsetY = 0; // Position katanas symmetrically around center var totalKatanas = extraKatanas.length + 1; // Include main katana var startOffset = -(totalKatanas - 1) * spacing / 2; offsetX = startOffset + (k + 1) * spacing; // k+1 because main katana is at center extraKatanas[k].updatePosition(x + offsetX, y + offsetY); } } }; game.up = function (x, y, obj) { isSlicing = false; }; game.update = function () { // Handle start screen state - only show background animation if (gameState === 'start') { // Only animate background elements on start screen // Animate cherry blossom petals falling and swirling for (var bp = 0; bp < blossomPetals.length; bp++) { var petal = blossomPetals[bp]; petal.y += Math.sin(LK.ticks * 0.01 + bp) * 0.5 + 0.3; petal.x += Math.sin(LK.ticks * 0.008 + bp) * 0.8; petal.rotation += 0.02; // Reset petal position when it goes off screen if (petal.y > 2800) { petal.y = -50; petal.x = Math.random() * 2048; } if (petal.x > 2100) { petal.x = -50; } } return; // Don't update game logic on start screen } // Animate background elements // Animate cherry blossom petals falling and swirling for (var bp = 0; bp < blossomPetals.length; bp++) { var petal = blossomPetals[bp]; petal.y += Math.sin(LK.ticks * 0.01 + bp) * 0.5 + 0.3; petal.x += Math.sin(LK.ticks * 0.008 + bp) * 0.8; petal.rotation += 0.02; // Reset petal position when it goes off screen if (petal.y > 2800) { petal.y = -50; petal.x = Math.random() * 2048; } if (petal.x > 2100) { petal.x = -50; } } // Animate mist layers with slow drift for (var mist = 0; mist < mistLayers.length; mist++) { var mistLayer = mistLayers[mist]; mistLayer.x += Math.sin(LK.ticks * 0.002 + mist) * 0.2 + 0.1; mistLayer.alpha = 0.3 + Math.sin(LK.ticks * 0.005 + mist) * 0.1; // Reset position when off screen if (mistLayer.x > 2400) { mistLayer.x = -400; } } // Animate flowers with gentle bobbing for (var f = 0; f < flowers.length; f++) { var flower = flowers[f]; flower.rotation = Math.sin(LK.ticks * 0.02 + f) * 0.2; flower.scaleX = 1 + Math.sin(LK.ticks * 0.015 + f) * 0.1; flower.scaleY = 1 + Math.sin(LK.ticks * 0.015 + f) * 0.1; } // Add subtle parallax effect to background layers for (var bt = 0; bt < backgroundTrees.length; bt++) { var bgTree = backgroundTrees[bt]; bgTree.x += Math.sin(LK.ticks * 0.001 + bt) * 0.1; } // Animate hills with very subtle movement for (var h = 0; h < hills.length; h++) { var hill = hills[h]; hill.alpha = 0.6 + Math.sin(LK.ticks * 0.003 + h) * 0.1; } // Gentle sky color animation transitioning between sunset and night if (LK.ticks % 120 === 0) { var timePhase = Math.sin(LK.ticks * 0.0005) * 0.5 + 0.5; // Oscillates between 0 and 1 var sunsetNightColors = [[0xFF4500, 0x191970], // Horizon: deep orange to midnight blue [0xFF6347, 0x2F4F4F], // Tomato to dark slate gray [0xDC143C, 0x483D8B], // Crimson to dark slate blue [0x9932CC, 0x191970], // Dark orchid to midnight blue [0x483D8B, 0x000000], // Dark slate blue to black [0x2F4F4F, 0x000000], // Dark slate gray to black [0x191970, 0x000000], // Midnight blue to black [0x000000, 0x000000] // Pure black to pure black ]; for (var s = 0; s < skyLayers.length; s++) { var skyLayer = skyLayers[s]; var sunsetColor = sunsetNightColors[s][0]; var nightColor = sunsetNightColors[s][1]; // Interpolate between sunset and night colors var r1 = sunsetColor >> 16 & 0xFF; var g1 = sunsetColor >> 8 & 0xFF; var b1 = sunsetColor & 0xFF; var r2 = nightColor >> 16 & 0xFF; var g2 = nightColor >> 8 & 0xFF; var b2 = nightColor & 0xFF; // Blend with adjacent layers for smoother transitions var blendFactor = 0.3; // Amount of blending with neighbors var r = Math.floor(r1 + (r2 - r1) * timePhase); var g = Math.floor(g1 + (g2 - g1) * timePhase); var b = Math.floor(b1 + (b2 - b1) * timePhase); // Blend with previous layer if it exists if (s > 0) { var prevColor = sunsetNightColors[s - 1]; var prevSunset = prevColor[0]; var prevNight = prevColor[1]; var prevR1 = prevSunset >> 16 & 0xFF; var prevG1 = prevSunset >> 8 & 0xFF; var prevB1 = prevSunset & 0xFF; var prevR2 = prevNight >> 16 & 0xFF; var prevG2 = prevNight >> 8 & 0xFF; var prevB2 = prevNight & 0xFF; var prevR = Math.floor(prevR1 + (prevR2 - prevR1) * timePhase); var prevG = Math.floor(prevG1 + (prevG2 - prevG1) * timePhase); var prevB = Math.floor(prevB1 + (prevB2 - prevB1) * timePhase); // Blend current color with previous layer r = Math.floor(r * (1 - blendFactor) + prevR * blendFactor); g = Math.floor(g * (1 - blendFactor) + prevG * blendFactor); b = Math.floor(b * (1 - blendFactor) + prevB * blendFactor); } // Blend with next layer if it exists if (s < skyLayers.length - 1) { var nextColor = sunsetNightColors[s + 1]; var nextSunset = nextColor[0]; var nextNight = nextColor[1]; var nextR1 = nextSunset >> 16 & 0xFF; var nextG1 = nextSunset >> 8 & 0xFF; var nextB1 = nextSunset & 0xFF; var nextR2 = nextNight >> 16 & 0xFF; var nextG2 = nextNight >> 8 & 0xFF; var nextB2 = nextNight & 0xFF; var nextR = Math.floor(nextR1 + (nextR2 - nextR1) * timePhase); var nextG = Math.floor(nextG1 + (nextG2 - nextG1) * timePhase); var nextB = Math.floor(nextB1 + (nextB2 - nextB1) * timePhase); // Blend current color with next layer r = Math.floor(r * (1 - blendFactor * 0.5) + nextR * (blendFactor * 0.5)); g = Math.floor(g * (1 - blendFactor * 0.5) + nextG * (blendFactor * 0.5)); b = Math.floor(b * (1 - blendFactor * 0.5) + nextB * (blendFactor * 0.5)); } // Apply smooth transition with tween for even smoother color changes var targetColor = r << 16 | g << 8 | b; tween(skyLayer, { tint: targetColor }, { duration: 120, easing: tween.easeOut }); } } // Animate snow caps with subtle shimmer for (var sc = 0; sc < snowCaps.length; sc++) { var snowCap = snowCaps[sc]; snowCap.alpha = snowCap.alpha + Math.sin(LK.ticks * 0.01 + sc) * 0.05; } // Spawn shooting stars periodically shootingStarSpawnTimer++; if (shootingStarSpawnTimer >= shootingStarSpawnRate) { shootingStarSpawnTimer = 0; // Random chance to spawn (not every time) if (Math.random() < 0.7) { var shootingStar = new ShootingStar(Math.random() * 500 - 200, // Start from left side of screen Math.random() * 800 + 100 // Random height in upper portion ); shootingStars.push(shootingStar); backgroundContainer.addChild(shootingStar); } } // Update shooting stars and remove expired ones for (var ss = shootingStars.length - 1; ss >= 0; ss--) { var star = shootingStars[ss]; star.update(); // Remove stars that are off screen or expired if (star.life <= 0 || star.x > 2400 || star.y > 2800) { star.destroy(); shootingStars.splice(ss, 1); } } // Update distant and mid buildings for (var db = 0; db < distantBuildings.length; db++) { distantBuildings[db].update(); } for (var mb = 0; mb < midBuildings.length; mb++) { midBuildings[mb].update(); } // Spawn fruits spawnTimer++; if (spawnTimer >= spawnRate) { spawnTimer = 0; var fruitType = fruitTypes[Math.floor(Math.random() * fruitTypes.length)]; // Create fruit with simple falling behavior var fruit = new Fruit(fruitType); // Spawn fruit at random horizontal position across entire screen width fruit.x = Math.random() * 2048; fruit.y = -100; // Start above screen fruits.push(fruit); game.addChild(fruit); // Spawn rate is now controlled by difficulty level in slice function } // Update fruits and remove off-screen ones for (var i = fruits.length - 1; i >= 0; i--) { var fruit = fruits[i]; // Explicitly call fruit update to ensure falling continues after pause fruit.update(); // Check if fruit touched the ground (game over condition) - only if still playing if (fruit.y > 2732 && !fruit.sliced && gameState === 'playing') { // Save current score to database savePlayerScore(LK.getScore()); // Game over - fruit touched the ground LK.showGameOver(); return; // Stop game execution } // Remove fruits that fall off screen if (fruit.y > 2800) { fruit.destroy(); fruits.splice(i, 1); } } // Update particles for (var j = particles.length - 1; j >= 0; j--) { var particle = particles[j]; if (particle.life <= 0) { particles.splice(j, 1); } } // Update power-up timer and bar if (powerUpActive) { powerUpTimer--; // Update power bar to show countdown var powerProgress = powerUpTimer / powerUpMaxTimer; var powerBarWidth = 2.5 * powerProgress; tween(powerBarFill, { scaleX: powerBarWidth }, { duration: 100 }); // Change power bar color during countdown if (powerProgress <= 0.3) { powerBarFill.tint = 0xFF0000; // Red when almost finished powerBarLabel.setText('ENDING!'); } else if (powerProgress <= 0.6) { powerBarFill.tint = 0xFF6B35; // Orange when halfway powerBarLabel.setText('ACTIVE'); } else { powerBarFill.tint = 0x00FF00; // Green when active powerBarLabel.setText('ACTIVE'); } // Keep power active permanently - no deactivation when timer reaches 0 if (powerUpTimer <= 0) { // Power remains active permanently } } // Track mouse movement if (katanaParalyzed) { paralyzeTimer--; if (paralyzeTimer <= 0) { katanaParalyzed = false; katanaHealth = maxKatanaHealth; // Restore full health // Update health bar to full tween(healthBarFill, { scaleX: 3 }, { duration: 300 }); healthBarFill.tint = 0x27AE60; // Green // Hide health bar after recovery tween(healthBarContainer, { alpha: 0 }, { duration: 1000 }); } } else { // Gradually regenerate health when not making rapid movements if (katanaHealth < maxKatanaHealth) { katanaHealth += 0.5; // Slow regeneration if (katanaHealth > maxKatanaHealth) { katanaHealth = maxKatanaHealth; } // Update health bar fill var healthPercent = katanaHealth / maxKatanaHealth; healthBarFill.scaleX = 3 * healthPercent; // Update color if (healthPercent < 0.3) { healthBarFill.tint = 0xE74C3C; // Red } else if (healthPercent < 0.6) { healthBarFill.tint = 0xF39C12; // Orange } else { healthBarFill.tint = 0x27AE60; // Green } // Hide health bar when fully recovered and not being used if (katanaHealth >= maxKatanaHealth && healthBarContainer.alpha > 0) { tween(healthBarContainer, { alpha: 0 }, { duration: 2000 }); } } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
scoreNames: [],
scoreValues: []
});
/****
* Classes
****/
var AutoSword = Container.expand(function () {
var self = Container.call(this);
self.sliced = false;
var swordGraphics = self.attachAsset('katana', {
anchorX: 0.5,
anchorY: 0.5
});
swordGraphics.tint = 0x00FF00; // Green tint for auto swords
swordGraphics.alpha = 0.8;
// Auto movement properties
self.targetFruit = null;
self.speed = 12; // Increased speed for faster fruit catching
self.cooldownTimer = 0;
self.maxCooldown = 60; // Reduced cooldown to 1 second at 60fps for faster slicing
self.update = function () {
if (self.cooldownTimer > 0) {
self.cooldownTimer--;
return;
}
// Find nearest unsliced fruit
var nearestFruit = null;
var nearestDistance = Infinity;
for (var i = 0; i < fruits.length; i++) {
var fruit = fruits[i];
if (!fruit.sliced) {
var distance = Math.sqrt(Math.pow(fruit.x - self.x, 2) + Math.pow(fruit.y - self.y, 2));
if (distance < nearestDistance) {
nearestDistance = distance;
nearestFruit = fruit;
}
}
}
// Move towards nearest fruit
if (nearestFruit) {
self.targetFruit = nearestFruit;
var dx = nearestFruit.x - self.x;
var dy = nearestFruit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 80) {
// Move towards fruit
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
// Rotate towards target
swordGraphics.rotation = Math.atan2(dy, dx);
} else {
// Close enough to slice
if (!nearestFruit.sliced) {
nearestFruit.slice();
self.cooldownTimer = self.maxCooldown;
// No visual effect for auto-sword
}
}
} else {
// No fruits found, patrol randomly
if (Math.random() < 0.02) {
// 2% chance per frame to change direction
self.x += (Math.random() - 0.5) * 100;
self.y += (Math.random() - 0.5) * 100;
// Keep within screen bounds
self.x = Math.max(100, Math.min(1948, self.x));
self.y = Math.max(100, Math.min(2632, self.y));
}
}
};
return self;
});
// Storage plugin removed as requested
var Building = Container.expand(function (buildingX, buildingY, scale, height) {
var self = Container.call(this);
// Building base with varying heights
var baseHeight = height || Math.random() * 200 + 250;
var buildingBase = self.attachAsset('building_base', {
anchorX: 0.5,
anchorY: 1
});
buildingBase.scaleY = baseHeight / 300;
buildingBase.y = 0;
// Building roof
var roof = self.attachAsset('building_roof', {
anchorX: 0.5,
anchorY: 1
});
roof.y = -baseHeight;
// Add windows in a grid pattern
var windowRows = Math.floor(baseHeight / 40);
var windowCols = 4;
for (var row = 0; row < windowRows; row++) {
for (var col = 0; col < windowCols; col++) {
var window = self.attachAsset('building_window', {
anchorX: 0.5,
anchorY: 0.5
});
window.x = (col - 1.5) * 25;
window.y = -30 - row * 40;
// Random window lighting
if (Math.random() > 0.3) {
window.alpha = Math.random() * 0.8 + 0.2;
} else {
window.alpha = 0.1;
}
}
}
// Set position and scale
self.x = buildingX;
self.y = buildingY;
self.scaleX = scale || 1;
self.scaleY = scale || 1;
// Animation properties for subtle building sway
self.swaySpeed = Math.random() * 0.005 + 0.002;
self.swayAmount = Math.random() * 0.02 + 0.01;
self.animationOffset = Math.random() * Math.PI * 2;
self.update = function () {
// Very subtle building sway
var sway = Math.sin(LK.ticks * self.swaySpeed + self.animationOffset) * self.swayAmount;
self.rotation = sway;
};
return self;
});
var Cloud = Container.expand(function (cloudX, cloudY, cloudScale) {
var self = Container.call(this);
// Create cloud with multiple overlapping circles
var cloud1 = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
var cloud2 = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
cloud2.x = 40;
cloud2.scaleX = 0.8;
cloud2.scaleY = 0.8;
var cloud3 = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
cloud3.x = -30;
cloud3.scaleX = 0.9;
cloud3.scaleY = 0.9;
self.x = cloudX;
self.y = cloudY;
self.scaleX = cloudScale || 1;
self.scaleY = cloudScale || 1;
// Floating animation
self.floatSpeed = Math.random() * 0.01 + 0.005;
self.floatAmount = Math.random() * 20 + 10;
self.driftSpeed = Math.random() * 0.5 + 0.2;
self.originalX = cloudX;
self.update = function () {
// Gentle floating motion
self.y = cloudY + Math.sin(LK.ticks * self.floatSpeed) * self.floatAmount;
// Slow horizontal drift
self.x += self.driftSpeed;
// Reset position when off screen
if (self.x > 2200) {
self.x = -200;
}
};
return self;
});
var Fruit = Container.expand(function (fruitType) {
var self = Container.call(this);
self.fruitType = fruitType;
self.sliced = false;
self.fallSpeed = Math.random() * 3 + (baseFallSpeed + currentDifficultyLevel * 0.3);
var fruitGraphics = self.attachAsset(fruitType, {
anchorX: 0.5,
anchorY: 0.5
});
// Simple straight fall
self.velocityY = self.fallSpeed;
self.gravity = 0.1;
self.update = function () {
if (!self.sliced) {
self.y += self.velocityY;
self.velocityY += self.gravity;
}
};
self.slice = function () {
if (self.sliced) return;
self.sliced = true;
// Award points based on fruit type
var basePoints = 0;
switch (self.fruitType) {
case 'apple':
basePoints = 10;
break;
case 'orange':
basePoints = 15;
break;
case 'watermelon':
basePoints = 30;
break;
case 'pineapple':
basePoints = 25;
break;
case 'banana':
basePoints = 20;
break;
}
var points = basePoints;
LK.setScore(LK.getScore() + points);
updateScoreDisplay(LK.getScore());
// Update difficulty progressively based on score
var newScore = LK.getScore();
var newDifficultyLevel = Math.floor(newScore / 50); // Increase difficulty every 50 points
if (newDifficultyLevel > currentDifficultyLevel) {
currentDifficultyLevel = newDifficultyLevel;
// Gradually decrease spawn rate (faster spawning) - minimum 20 frames
spawnRate = Math.max(20, baseSpawnRate - currentDifficultyLevel * 8);
}
// Create slice effect
self.createSliceEffect();
// Play slice sound
LK.getSound('slice').play();
// Create floating score text
var floatingScore = new Text2('+' + points, {
size: 60,
fill: 0xFFD700
});
floatingScore.anchor.set(0.5, 0.5);
floatingScore.x = self.x;
floatingScore.y = self.y;
game.addChild(floatingScore);
// Animate floating score
tween(floatingScore, {
y: floatingScore.y - 150,
alpha: 0
}, {
duration: 1000,
onComplete: function onComplete() {
floatingScore.destroy();
}
});
// Animate fruit halves
self.animateSlice();
};
self.createSliceEffect = function () {
// Create particle explosion
for (var i = 0; i < 8; i++) {
var particle = new Particle();
particle.x = self.x;
particle.y = self.y;
particles.push(particle);
game.addChild(particle);
}
};
self.animateSlice = function () {
// Split fruit into two halves
var leftHalf = self.attachAsset(self.fruitType, {
anchorX: 0.5,
anchorY: 0.5,
x: -20
});
var rightHalf = self.attachAsset(self.fruitType, {
anchorX: 0.5,
anchorY: 0.5,
x: 20
});
// Hide original fruit
fruitGraphics.alpha = 0;
// Animate halves falling
tween(leftHalf, {
x: leftHalf.x - 100,
y: leftHalf.y + 200,
rotation: -1
}, {
duration: 1000
});
tween(rightHalf, {
x: rightHalf.x + 100,
y: rightHalf.y + 200,
rotation: 1
}, {
duration: 1000
});
tween(leftHalf, {
alpha: 0
}, {
duration: 800
});
tween(rightHalf, {
alpha: 0
}, {
duration: 800
});
};
return self;
});
var GrassClump = Container.expand(function (grassX, grassY) {
var self = Container.call(this);
// Create multiple grass blades
for (var i = 0; i < 5; i++) {
var blade = self.attachAsset('grass_blade', {
anchorX: 0.5,
anchorY: 1
});
blade.x = (i - 2) * 8;
blade.scaleY = Math.random() * 0.5 + 0.7;
blade.rotation = (Math.random() - 0.5) * 0.3;
// Vary grass color slightly
var greenVariation = Math.random() * 0.2 + 0.9;
blade.tint = 0x7CFC00 * greenVariation;
}
self.x = grassX;
self.y = grassY;
// Wind animation
self.windSpeed = Math.random() * 0.03 + 0.02;
self.windOffset = Math.random() * Math.PI * 2;
self.update = function () {
var wind = Math.sin(LK.ticks * self.windSpeed + self.windOffset) * 0.15;
self.rotation = wind;
};
return self;
});
var Katana = Container.expand(function () {
var self = Container.call(this);
self.trailPoints = [];
self.maxTrailLength = 10;
var katanaGraphics = self.attachAsset('katana', {
anchorX: 0.5,
anchorY: 0.5
});
self.updatePosition = function (x, y) {
// Add current position to trail
self.trailPoints.push({
x: self.x,
y: self.y
});
if (self.trailPoints.length > self.maxTrailLength) {
self.trailPoints.shift();
}
// Calculate angle based on movement
if (self.trailPoints.length > 1) {
var lastPoint = self.trailPoints[self.trailPoints.length - 2];
var angle = Math.atan2(y - lastPoint.y, x - lastPoint.x);
katanaGraphics.rotation = angle;
}
self.x = x;
self.y = y;
};
self.checkFruitCollisions = function () {
for (var i = fruits.length - 1; i >= 0; i--) {
var fruit = fruits[i];
if (!fruit.sliced && self.intersects(fruit)) {
fruit.slice();
}
}
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = (Math.random() - 0.5) * 10;
self.velocityY = (Math.random() - 0.5) * 10;
self.life = 60; // 1 second at 60fps
// Random color for juice effect
var colors = [0xFF6B6B, 0xFFE66D, 0x4ECDC4, 0x45B7D1, 0x96CEB4];
particleGraphics.tint = colors[Math.floor(Math.random() * colors.length)];
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityY += 0.2; // gravity
self.life--;
particleGraphics.alpha = self.life / 60;
if (self.life <= 0) {
self.destroy();
for (var i = particles.length - 1; i >= 0; i--) {
if (particles[i] === self) {
particles.splice(i, 1);
break;
}
}
}
};
return self;
});
var ShootingStar = Container.expand(function (startX, startY) {
var self = Container.call(this);
// Create main shooting star body
var starBody = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
starBody.tint = 0xFFFFFF;
starBody.scaleX = 1.5;
starBody.scaleY = 1.5;
// Create glowing trail particles
self.trailParticles = [];
for (var t = 0; t < 8; t++) {
var trailParticle = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
trailParticle.tint = 0xFFD700; // Golden trail
trailParticle.scaleX = 0.8 - t * 0.1;
trailParticle.scaleY = 0.8 - t * 0.1;
trailParticle.alpha = 0.8 - t * 0.1;
self.trailParticles.push(trailParticle);
}
// Set position and movement properties
self.x = startX;
self.y = startY;
self.velocityX = Math.random() * 3 + 2; // Moving right and down
self.velocityY = Math.random() * 4 + 3;
self.life = 300; // 5 seconds at 60fps
self.maxLife = 300;
// Trail position tracking
self.trailPositions = [];
self.update = function () {
// Store current position for trail
self.trailPositions.push({
x: self.x,
y: self.y
});
if (self.trailPositions.length > self.trailParticles.length) {
self.trailPositions.shift();
}
// Update position
self.x += self.velocityX;
self.y += self.velocityY;
self.life--;
// Update trail particles
for (var t = 0; t < self.trailParticles.length; t++) {
if (self.trailPositions[self.trailPositions.length - 1 - t]) {
var trailPos = self.trailPositions[self.trailPositions.length - 1 - t];
self.trailParticles[t].x = trailPos.x - self.x;
self.trailParticles[t].y = trailPos.y - self.y;
}
}
// Fade out as life decreases
var fadePercent = self.life / self.maxLife;
starBody.alpha = fadePercent;
for (var t = 0; t < self.trailParticles.length; t++) {
self.trailParticles[t].alpha = (0.8 - t * 0.1) * fadePercent;
}
// Twinkle effect
starBody.scaleX = 1.5 + Math.sin(LK.ticks * 0.2) * 0.3;
starBody.scaleY = 1.5 + Math.sin(LK.ticks * 0.2) * 0.3;
};
return self;
});
var Tree = Container.expand(function (treeX, treeY, scale) {
var self = Container.call(this);
// Tree trunk
var trunk = self.attachAsset('tree_trunk', {
anchorX: 0.5,
anchorY: 1
});
trunk.y = 0;
// Multiple foliage layers for depth
var foliageDark = self.attachAsset('tree_foliage_dark', {
anchorX: 0.5,
anchorY: 1
});
foliageDark.y = -200;
foliageDark.x = 10;
var foliageMain = self.attachAsset('tree_foliage', {
anchorX: 0.5,
anchorY: 1
});
foliageMain.y = -180;
var foliageLight = self.attachAsset('tree_foliage_light', {
anchorX: 0.5,
anchorY: 1
});
foliageLight.y = -160;
foliageLight.x = -15;
// Set position and scale
self.x = treeX;
self.y = treeY;
self.scaleX = scale || 1;
self.scaleY = scale || 1;
// Animation properties
self.swaySpeed = Math.random() * 0.02 + 0.01;
self.swayAmount = Math.random() * 0.1 + 0.05;
self.animationOffset = Math.random() * Math.PI * 2;
self.update = function () {
// Gentle swaying animation
var sway = Math.sin(LK.ticks * self.swaySpeed + self.animationOffset) * self.swayAmount;
foliageMain.rotation = sway;
foliageLight.rotation = sway * 0.8;
foliageDark.rotation = sway * 1.2;
trunk.rotation = sway * 0.3;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Create animated forest background
// Generate unique player ID if not exists
// Initialize weapons object properly
function _typeof2(o) {
"@babel/helpers - typeof";
return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof2(o);
}
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
// Player ID initialization removed
var backgroundContainer = new Container();
game.addChild(backgroundContainer);
// Create sky gradient effect with sunset to night colors
var skyLayers = [];
var sunsetColors = [0xFF4500,
// Deep orange at horizon
0xFF6347,
// Tomato red-orange
0xDC143C,
// Crimson red
0x9932CC,
// Dark orchid purple
0x483D8B,
// Dark slate blue
0x2F4F4F,
// Dark slate gray
0x191970,
// Midnight blue
0x000000 // Pure black night
];
for (var s = 0; s < 8; s++) {
var skyLayer = LK.getAsset('shape', {
anchorX: 0,
anchorY: 0,
scaleX: 20.48,
scaleY: 3.4
});
skyLayer.y = s * 340;
// Use sunset to night gradient colors
skyLayer.tint = sunsetColors[s];
skyLayer.alpha = 0.8;
backgroundContainer.addChild(skyLayer);
skyLayers.push(skyLayer);
}
;
// Play ambient music for game atmosphere
LK.playMusic('am', {
loop: true
});
// Create sun with sunset colors
var sun = backgroundContainer.addChild(LK.getAsset('sun', {
anchorX: 0.5,
anchorY: 0.5
}));
sun.x = 1600;
sun.y = 400; // Lower position for sunset effect
sun.tint = 0xFF6347; // Deep sunset tomato color
sun.scaleX = 1.3;
sun.scaleY = 1.3;
// Create layered mountains with anime-style atmospheric perspective and snow caps
var mountains = [];
var snowCaps = [];
// Far distant snow-capped mountains (very light blue/purple with white peaks)
for (var m1 = 0; m1 < 8; m1++) {
var farMountain = backgroundContainer.addChild(LK.getAsset('mountain', {
anchorX: 0.5,
anchorY: 1
}));
farMountain.x = m1 * 350 + 100;
farMountain.y = 1800;
farMountain.scaleY = Math.random() * 0.3 + 0.4;
farMountain.scaleX = Math.random() * 0.4 + 0.8;
farMountain.tint = 0x9BB5D6; // Light blue-purple
farMountain.alpha = 0.4;
mountains.push(farMountain);
// Add snow cap to tall mountains
if (farMountain.scaleY > 0.6) {
var farSnowCap = backgroundContainer.addChild(LK.getAsset('snow_cap', {
anchorX: 0.5,
anchorY: 1
}));
farSnowCap.x = farMountain.x;
farSnowCap.y = farMountain.y - farMountain.scaleY * 200 * 0.7;
farSnowCap.scaleX = farMountain.scaleX * 0.9;
farSnowCap.scaleY = 0.3;
farSnowCap.alpha = 0.6;
farSnowCap.tint = 0xf0f8ff;
snowCaps.push(farSnowCap);
}
;
}
;
// Mid-distance snow-capped mountains (blue-gray with prominent snow)
for (var m2 = 0; m2 < 6; m2++) {
var midMountain = backgroundContainer.addChild(LK.getAsset('mountain', {
anchorX: 0.5,
anchorY: 1
}));
midMountain.x = m2 * 400 + 150;
midMountain.y = 2000;
midMountain.scaleY = Math.random() * 0.4 + 0.6;
midMountain.scaleX = Math.random() * 0.3 + 0.9;
midMountain.tint = 0x7A8FA3; // Blue-gray
midMountain.alpha = 0.6;
mountains.push(midMountain);
// Add snow cap
var midSnowCap = backgroundContainer.addChild(LK.getAsset('snow_cap', {
anchorX: 0.5,
anchorY: 1
}));
midSnowCap.x = midMountain.x;
midSnowCap.y = midMountain.y - midMountain.scaleY * 200 * 0.6;
midSnowCap.scaleX = midMountain.scaleX * 0.95;
midSnowCap.scaleY = 0.4;
midSnowCap.alpha = 0.8;
snowCaps.push(midSnowCap);
}
// Close mountains (green-brown)
for (var m3 = 0; m3 < 4; m3++) {
var closeMountain = backgroundContainer.addChild(LK.getAsset('mountain', {
anchorX: 0.5,
anchorY: 1
}));
closeMountain.x = m3 * 500 + 200;
closeMountain.y = 2200;
closeMountain.scaleY = Math.random() * 0.5 + 0.8;
closeMountain.scaleX = Math.random() * 0.3 + 1.1;
closeMountain.tint = 0x556B2F;
closeMountain.alpha = 0.8;
mountains.push(closeMountain);
}
// Add distant city buildings behind mountains
var distantBuildings = [];
for (var db = 0; db < 12; db++) {
var building = backgroundContainer.addChild(new Building(db * 180 + Math.random() * 50 + 50, 1900, Math.random() * 0.4 + 0.3, Math.random() * 150 + 200));
building.alpha = 0.3;
building.tint = 0x708090;
distantBuildings.push(building);
}
// Add mid-distance city buildings
var midBuildings = [];
for (var mb = 0; mb < 8; mb++) {
var midBuilding = backgroundContainer.addChild(new Building(mb * 250 + Math.random() * 80 + 100, 2100, Math.random() * 0.3 + 0.5, Math.random() * 200 + 300));
midBuilding.alpha = 0.5;
midBuilding.tint = 0x556B6F;
midBuildings.push(midBuilding);
}
// Create atmospheric mist layers
var mistLayers = [];
for (var mist = 0; mist < 5; mist++) {
var mistLayer = backgroundContainer.addChild(LK.getAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
}));
mistLayer.x = Math.random() * 2400 - 200;
mistLayer.y = 1600 + mist * 150;
mistLayer.scaleX = Math.random() * 3 + 2;
mistLayer.scaleY = Math.random() * 0.8 + 0.4;
mistLayer.tint = 0xF0F8FF;
mistLayer.alpha = 0.3;
mistLayers.push(mistLayer);
}
// Create clouds
var clouds = [];
for (var c = 0; c < 8; c++) {
var cloud = backgroundContainer.addChild(new Cloud(Math.random() * 2400 - 200, Math.random() * 600 + 200, Math.random() * 0.8 + 0.6));
clouds.push(cloud);
}
// Create rolling hills for terrain depth
var hills = [];
for (var h = 0; h < 12; h++) {
var hill = backgroundContainer.addChild(LK.getAsset('mountain', {
anchorX: 0.5,
anchorY: 1
}));
hill.x = h * 200 + Math.random() * 100;
hill.y = 2300 + Math.random() * 100;
hill.scaleY = Math.random() * 0.3 + 0.2;
hill.scaleX = Math.random() * 0.5 + 1.5;
hill.tint = 0x6B8E23; // Olive green
hill.alpha = 0.6;
hills.push(hill);
}
// Create background trees (larger, further back)
var backgroundTrees = [];
for (var bt = 0; bt < 15; bt++) {
var bgTree = backgroundContainer.addChild(new Tree(Math.random() * 2400 - 200, 2200, Math.random() * 0.8 + 1.2));
bgTree.alpha = 0.7;
bgTree.tint = 0x556B2F;
backgroundTrees.push(bgTree);
}
// Create middle ground trees
var middleTrees = [];
for (var mt = 0; mt < 20; mt++) {
var midTree = backgroundContainer.addChild(new Tree(Math.random() * 2600 - 300, 2400, Math.random() * 0.6 + 0.8));
midTree.alpha = 0.85;
middleTrees.push(midTree);
}
// Create foreground trees
var foregroundTrees = [];
for (var ft = 0; ft < 12; ft++) {
var fgTree = backgroundContainer.addChild(new Tree(Math.random() * 2800 - 400, 2600, Math.random() * 0.4 + 0.6));
foregroundTrees.push(fgTree);
}
// Create grass clumps across the ground
var grassClumps = [];
for (var g = 0; g < 50; g++) {
var grass = backgroundContainer.addChild(new GrassClump(Math.random() * 2400, 2650 + Math.random() * 80));
grassClumps.push(grass);
}
// Create cherry blossom petals floating in the air
var blossomPetals = [];
for (var bp = 0; bp < 25; bp++) {
var petal = backgroundContainer.addChild(LK.getAsset('flower', {
anchorX: 0.5,
anchorY: 0.5
}));
petal.x = Math.random() * 2048;
petal.y = Math.random() * 2000;
petal.scaleX = Math.random() * 0.3 + 0.2;
petal.scaleY = Math.random() * 0.3 + 0.2;
petal.tint = 0xFFB6C1; // Light pink
petal.alpha = Math.random() * 0.6 + 0.4;
petal.rotation = Math.random() * Math.PI * 2;
blossomPetals.push(petal);
}
// Create colorful flowers scattered around
var flowers = [];
var flowerColors = [0xFF69B4, 0xFF6347, 0x9370DB, 0x00CED1, 0xFFD700, 0xFF4500];
for (var f = 0; f < 30; f++) {
var flower = backgroundContainer.addChild(LK.getAsset('flower', {
anchorX: 0.5,
anchorY: 0.5
}));
flower.x = Math.random() * 2048;
flower.y = 2600 + Math.random() * 100;
flower.tint = flowerColors[Math.floor(Math.random() * flowerColors.length)];
flowers.push(flower);
}
// Create shooting stars array
var shootingStars = [];
var shootingStarSpawnTimer = 0;
var shootingStarSpawnRate = 180; // Spawn every 3 seconds (180 frames at 60fps)
var fruits = [];
var particles = [];
var fruitTypes = ['apple', 'orange', 'watermelon', 'pineapple', 'banana'];
var spawnTimer = 0;
var spawnRate = 90; // frames between spawns
var baseSpawnRate = 90; // original spawn rate
var baseFallSpeed = 2; // base fall speed for fruits
var currentDifficultyLevel = 0;
// Katana health system variables
var katanaHealth = 100;
var maxKatanaHealth = 100;
var katanaParalyzed = false;
var paralyzeTimer = 0;
var lastKatanaX = 0;
var lastKatanaY = 0;
var movementSamples = [];
var maxMovementSamples = 10;
// Power-up system variables
var powerUpActive = false;
var extraKatanas = [];
var powerUpActivated = false;
var powerUpTimer = 0;
var powerUpMaxTimer = 1050; // 17.5 seconds at 60fps
// Auto-sword system variables
var autoSwords = [];
var autoSwordActivated = false;
var autoSwordTimer = 0;
var autoSwordCooldown = 120; // 2 seconds at 60fps between auto slices
// Create katana
var katana = game.addChild(new Katana());
katana.x = 1024;
katana.y = 1366;
katana.visible = false; // Hide katana on start screen
// Game state management
var gameState = 'start'; // 'start', 'playing'
var startScreenVisible = true;
// Create new score display positioned at bottom right
var scoreContainer = new Container();
LK.gui.bottomRight.addChild(scoreContainer);
// Create SCORE label shadow
var scoreLabelShadow = new Text2('SCORE', {
size: 40,
fill: 0x000000
});
scoreLabelShadow.anchor.set(1, 1);
scoreLabelShadow.x = 2;
scoreLabelShadow.y = -118;
scoreLabelShadow.alpha = 0.5;
scoreContainer.addChild(scoreLabelShadow);
// Create SCORE label text
var scoreLabel = new Text2('SCORE', {
size: 40,
fill: 0xFFFFFF
});
scoreLabel.anchor.set(1, 1);
scoreLabel.x = 0;
scoreLabel.y = -120;
scoreContainer.addChild(scoreLabel);
// Create shadow for depth
var scoreShadow = new Text2('0', {
size: 80,
fill: 0x000000
});
scoreShadow.anchor.set(1, 1);
scoreShadow.x = 2;
scoreShadow.y = 2;
scoreShadow.alpha = 0.5;
scoreContainer.addChild(scoreShadow);
// Create main score text
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFD700
});
scoreTxt.anchor.set(1, 1);
scoreContainer.addChild(scoreTxt);
// Position container at bottom right with some padding
scoreContainer.x = -20; // 20px from right edge
scoreContainer.y = -20; // 20px from bottom edge
// Hide game UI on start screen
scoreContainer.visible = false;
// Create katana health bar
var healthBarContainer = new Container();
LK.gui.bottom.addChild(healthBarContainer);
// Health bar background
var healthBarBg = LK.getAsset('shape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 0.3
});
healthBarBg.tint = 0x333333;
healthBarContainer.addChild(healthBarBg);
// Health bar fill
var healthBarFill = LK.getAsset('shape', {
anchorX: 0,
anchorY: 0.5,
scaleX: 3,
scaleY: 0.25
});
healthBarFill.tint = 0x27AE60;
healthBarFill.x = -150; // Start from left edge of background
healthBarContainer.addChild(healthBarFill);
// Health bar border
var healthBarBorder = LK.getAsset('shape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.1,
scaleY: 0.35
});
healthBarBorder.tint = 0xFFFFFF;
healthBarBorder.alpha = 0.8;
healthBarContainer.addChild(healthBarBorder);
// Position health bar at bottom center
healthBarContainer.x = 1024;
healthBarContainer.y = 2600;
healthBarContainer.alpha = 0; // Initially hidden
healthBarContainer.visible = false; // Hide on start screen
// Create katana power-up progress bar
var powerBarContainer = new Container();
LK.gui.topRight.addChild(powerBarContainer);
// Power bar background
var powerBarBg = LK.getAsset('shape', {
anchorX: 1,
anchorY: 0,
scaleX: 2.5,
scaleY: 0.4
});
powerBarBg.tint = 0x333333;
powerBarContainer.addChild(powerBarBg);
// Power bar fill
var powerBarFill = LK.getAsset('shape', {
anchorX: 0,
anchorY: 0,
scaleX: 0,
scaleY: 0.35
});
powerBarFill.tint = 0xFFD700; // Gold color for ninja power
powerBarFill.x = -250; // Start from left edge of background
powerBarContainer.addChild(powerBarFill);
// Power bar label with 3D effect
var powerBarLabelShadow = new Text2('KATANA-NINJA', {
size: 30,
fill: 0x000000
});
powerBarLabelShadow.anchor.set(1, 0);
powerBarLabelShadow.x = 2;
powerBarLabelShadow.y = -33;
powerBarLabelShadow.alpha = 0.6;
powerBarContainer.addChild(powerBarLabelShadow);
var powerBarLabel = new Text2('KATANA-NINJA', {
size: 30,
fill: 0xFFD700
});
powerBarLabel.anchor.set(1, 0);
powerBarLabel.x = 0;
powerBarLabel.y = -35;
powerBarContainer.addChild(powerBarLabel);
// Position power bar at top right with padding
powerBarContainer.x = -20; // 20px from right edge
powerBarContainer.y = 120; // Below the platform menu area
powerBarContainer.visible = false; // Hide on start screen
// Create Apoyo support bar for auto-sword system
var apoyoBarContainer = new Container();
LK.gui.topRight.addChild(apoyoBarContainer);
// Apoyo bar background
var apoyoBarBg = LK.getAsset('shape', {
anchorX: 1,
anchorY: 0,
scaleX: 2.5,
scaleY: 0.4
});
apoyoBarBg.tint = 0x333333;
apoyoBarContainer.addChild(apoyoBarBg);
// Apoyo bar fill
var apoyoBarFill = LK.getAsset('shape', {
anchorX: 0,
anchorY: 0,
scaleX: 0,
scaleY: 0.35
});
apoyoBarFill.tint = 0x00FF00; // Green color for support
apoyoBarFill.x = -250; // Start from left edge of background
apoyoBarContainer.addChild(apoyoBarFill);
// Apoyo bar label with 3D effect
var apoyoBarLabelShadow = new Text2('APOYO', {
size: 30,
fill: 0x000000
});
apoyoBarLabelShadow.anchor.set(1, 0);
apoyoBarLabelShadow.x = 2;
apoyoBarLabelShadow.y = -33;
apoyoBarLabelShadow.alpha = 0.6;
apoyoBarContainer.addChild(apoyoBarLabelShadow);
var apoyoBarLabel = new Text2('APOYO', {
size: 30,
fill: 0x00FF00
});
apoyoBarLabel.anchor.set(1, 0);
apoyoBarLabel.x = 0;
apoyoBarLabel.y = -35;
apoyoBarContainer.addChild(apoyoBarLabel);
// Position apoyo bar lower and separate from katana bar
apoyoBarContainer.x = -20; // 20px from right edge
apoyoBarContainer.y = 220; // Lower position, more separated from katana bar
apoyoBarContainer.visible = false; // Hide on start screen
// Create new exit button positioned at bottom center
var exitButtonContainer = new Container();
LK.gui.bottom.addChild(exitButtonContainer);
// Create exit button background
var exitBtnBg = LK.getAsset('shape', {
anchorX: 0.5,
anchorY: 1,
scaleX: 2,
scaleY: 1.2
});
exitBtnBg.tint = 0xE74C3C;
exitBtnBg.alpha = 0.9;
exitButtonContainer.addChild(exitBtnBg);
// Create exit button text
var exitBtnText = new Text2('SALIR', {
size: 40,
fill: 0xFFFFFF
});
exitBtnText.anchor.set(0.5, 0.5);
exitBtnText.x = 0;
exitBtnText.y = -30;
exitButtonContainer.addChild(exitBtnText);
// Position exit button at bottom center with padding
exitButtonContainer.x = 0;
exitButtonContainer.y = -120; // 120px from bottom edge
exitButtonContainer.visible = false; // Hide on start screen
// Exit button interaction
exitButtonContainer.down = function (x, y, obj) {
// Make all fruits disintegrate with animation
for (var i = fruits.length - 1; i >= 0; i--) {
var fruit = fruits[i];
// Animate fruit disintegration
tween(fruit, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1,
rotation: Math.PI * 2
}, {
duration: 500,
onFinish: function onFinish() {
// Destroy fruit after animation
if (fruit && fruit.destroy) {
fruit.destroy();
}
}
});
}
// Clear fruits array
fruits = [];
// Return to start screen
gameState = 'start';
startScreenVisible = true;
// Hide game UI elements
scoreContainer.visible = false;
healthBarContainer.visible = false;
powerBarContainer.visible = false;
apoyoBarContainer.visible = false;
exitButtonContainer.visible = false;
// Show start screen
startScreenContainer.visible = true;
startScreenContainer.alpha = 1;
startScreenContainer.scaleX = 1;
startScreenContainer.scaleY = 1;
// Hide katana on start screen
katana.visible = false;
};
// Create start screen container
var startScreenContainer = new Container();
game.addChild(startScreenContainer);
// Create start screen dark overlay
var startOverlay = LK.getAsset('shape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 25,
scaleY: 35
});
startOverlay.tint = 0x000000;
startOverlay.alpha = 0.6;
startOverlay.x = 1024;
startOverlay.y = 1366;
startScreenContainer.addChild(startOverlay);
// Create main title with 3D effect
// Create multiple shadow layers for depth
var titleShadow3 = new Text2('FRUIT NINJA', {
size: 120,
fill: 0x000000
});
titleShadow3.anchor.set(0.5, 0.5);
titleShadow3.x = 1024 + 8;
titleShadow3.y = 800 + 8;
titleShadow3.alpha = 0.3;
startScreenContainer.addChild(titleShadow3);
var titleShadow2 = new Text2('FRUIT NINJA', {
size: 120,
fill: 0x8B0000
});
titleShadow2.anchor.set(0.5, 0.5);
titleShadow2.x = 1024 + 4;
titleShadow2.y = 800 + 4;
titleShadow2.alpha = 0.5;
startScreenContainer.addChild(titleShadow2);
var titleShadow1 = new Text2('FRUIT NINJA', {
size: 120,
fill: 0xCD5C5C
});
titleShadow1.anchor.set(0.5, 0.5);
titleShadow1.x = 1024 + 2;
titleShadow1.y = 800 + 2;
titleShadow1.alpha = 0.7;
startScreenContainer.addChild(titleShadow1);
var gameTitle = new Text2('FRUIT NINJA', {
size: 120,
fill: 0xFF6B6B
});
gameTitle.anchor.set(0.5, 0.5);
gameTitle.x = 1024;
gameTitle.y = 800;
startScreenContainer.addChild(gameTitle);
// Add pulsing glow effect
tween(gameTitle, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 2000,
onComplete: function onComplete() {
tween(gameTitle, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 2000
});
}
});
// Create subtitle with 3D effect
var subtitleShadow2 = new Text2('KATANA MASTER', {
size: 60,
fill: 0x000000
});
subtitleShadow2.anchor.set(0.5, 0.5);
subtitleShadow2.x = 1024 + 6;
subtitleShadow2.y = 950 + 6;
subtitleShadow2.alpha = 0.4;
startScreenContainer.addChild(subtitleShadow2);
var subtitleShadow1 = new Text2('KATANA MASTER', {
size: 60,
fill: 0xB8860B
});
subtitleShadow1.anchor.set(0.5, 0.5);
subtitleShadow1.x = 1024 + 3;
subtitleShadow1.y = 950 + 3;
subtitleShadow1.alpha = 0.6;
startScreenContainer.addChild(subtitleShadow1);
var gameSubtitle = new Text2('KATANA MASTER', {
size: 60,
fill: 0xFFD700
});
gameSubtitle.anchor.set(0.5, 0.5);
gameSubtitle.x = 1024;
gameSubtitle.y = 950;
startScreenContainer.addChild(gameSubtitle);
// Add subtle rotation animation
tween(gameSubtitle, {
rotation: 0.05
}, {
duration: 3000,
onComplete: function onComplete() {
tween(gameSubtitle, {
rotation: -0.05
}, {
duration: 3000,
onComplete: function onComplete() {
tween(gameSubtitle, {
rotation: 0
}, {
duration: 3000
});
}
});
}
});
// Create play button
var playBtn = LK.getAsset('shape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 2
});
playBtn.tint = 0x27AE60;
playBtn.x = 1024;
playBtn.y = 1200;
startScreenContainer.addChild(playBtn);
var playText = new Text2('JUGAR', {
size: 70,
fill: 0xFFFFFF
});
playText.anchor.set(0.5, 0.5);
playText.x = 1024;
playText.y = 1200;
startScreenContainer.addChild(playText);
// Create shop button
var shopBtn = LK.getAsset('shape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 1.5
});
shopBtn.tint = 0x8E44AD;
shopBtn.x = 1024;
shopBtn.y = 1450;
startScreenContainer.addChild(shopBtn);
var shopText = new Text2('Tienda\nPROXIMAMENTE', {
size: 40,
fill: 0xFFFFFF
});
shopText.anchor.set(0.5, 0.5);
shopText.x = 1024;
shopText.y = 1450;
startScreenContainer.addChild(shopText);
// Create leaderboard table with 3D title
var leaderboardTitleShadow = new Text2('TOP JUGADORES', {
size: 60,
fill: 0x000000
});
leaderboardTitleShadow.anchor.set(0.5, 0.5);
leaderboardTitleShadow.x = 1024 + 3;
leaderboardTitleShadow.y = 1650 + 3;
leaderboardTitleShadow.alpha = 0.5;
startScreenContainer.addChild(leaderboardTitleShadow);
var leaderboardTitle = new Text2('TOP JUGADORES', {
size: 60,
fill: 0xFF6B6B
});
leaderboardTitle.anchor.set(0.5, 0.5);
leaderboardTitle.x = 1024;
leaderboardTitle.y = 1650;
startScreenContainer.addChild(leaderboardTitle);
// Create leaderboard entries
var leaderboardEntries = [];
for (var l = 0; l < 3; l++) {
var entryText = new Text2('', {
size: 48,
fill: 0xFFFFFF
});
entryText.anchor.set(0.5, 0.5);
entryText.x = 1024;
entryText.y = 1740 + l * 60;
startScreenContainer.addChild(entryText);
leaderboardEntries.push(entryText);
}
// Initialize leaderboard display
function updateLeaderboard() {
var scoreNames = storage.scoreNames || [];
var scoreValues = storage.scoreValues || [];
// Create combined array for sorting
var combinedScores = [];
for (var i = 0; i < scoreNames.length; i++) {
combinedScores.push({
name: scoreNames[i],
score: scoreValues[i]
});
}
// Sort scores in descending order
combinedScores.sort(function (a, b) {
return b.score - a.score;
});
// Display top 3 scores
for (var i = 0; i < 3; i++) {
if (i < combinedScores.length) {
leaderboardEntries[i].setText('#' + (i + 1) + ': ' + combinedScores[i].name + ' - ' + combinedScores[i].score + ' puntos');
} else {
leaderboardEntries[i].setText('#' + (i + 1) + ': --- puntos');
}
}
}
// Function to save player score
function savePlayerScore(score) {
// Generate consistent player ID based on some unique factor
// For now, we'll use a simple player ID system
var playerId = storage.currentPlayerId || 1;
if (!storage.currentPlayerId) {
storage.currentPlayerId = playerId;
}
var playerName = 'Jugador' + playerId;
// Store as separate arrays instead of objects to comply with storage limitations
var scoreNames = storage.scoreNames || [];
var scoreValues = storage.scoreValues || [];
// Check if this player already has a score
var existingPlayerIndex = -1;
for (var i = 0; i < scoreNames.length; i++) {
if (scoreNames[i] === playerName) {
existingPlayerIndex = i;
break;
}
}
// If player exists, only update if new score is higher
if (existingPlayerIndex >= 0) {
if (score > scoreValues[existingPlayerIndex]) {
scoreValues[existingPlayerIndex] = score;
}
} else {
// New player, add to arrays
scoreNames.push(playerName);
scoreValues.push(score);
}
storage.scoreNames = scoreNames;
storage.scoreValues = scoreValues;
updateLeaderboard();
}
// Initialize leaderboard on game start
updateLeaderboard();
// Create instructions
var instructionText = new Text2('Desliza para cortar frutas\nEvita que toquen el suelo', {
size: 35,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 1950;
startScreenContainer.addChild(instructionText);
// Leaderboard functionality removed
// Play button interaction
playBtn.down = function (x, y, obj) {
// Reset all game variables to start fresh
LK.setScore(0);
fruits = [];
particles = [];
spawnTimer = 0;
spawnRate = 90;
baseSpawnRate = 90;
baseFallSpeed = 2;
currentDifficultyLevel = 0;
katanaHealth = 100;
maxKatanaHealth = 100;
katanaParalyzed = false;
paralyzeTimer = 0;
lastKatanaX = 0;
lastKatanaY = 0;
movementSamples = [];
powerUpActive = false;
powerUpActivated = false;
powerUpTimer = 0;
powerUpMaxTimer = 1050;
// Clear any existing extra katanas
for (var k = 0; k < extraKatanas.length; k++) {
extraKatanas[k].destroy();
}
extraKatanas = [];
// Clear any existing auto swords
for (var s = 0; s < autoSwords.length; s++) {
autoSwords[s].destroy();
}
autoSwords = [];
autoSwordActivated = false;
autoSwordTimer = 0;
// Reset katana appearance and position
katana.destroy();
katana = game.addChild(new Katana());
katana.tint = 0xFFFFFF;
katana.x = 1024;
katana.y = 1366;
katana.visible = true; // Show katana when game starts
// Reset power bar
powerBarFill.scaleX = 0;
powerBarFill.tint = 0xFFD700;
powerBarLabel.setText('KATANA-NINJA');
// Reset apoyo bar
apoyoBarFill.scaleX = 0;
apoyoBarFill.tint = 0x90EE90;
apoyoBarLabel.setText('APOYO');
// Reset health bar
healthBarFill.scaleX = 3;
healthBarFill.tint = 0x27AE60;
healthBarContainer.alpha = 0;
// Update score display
updateScoreDisplay(0);
// Start the game
gameState = 'playing';
startScreenVisible = false;
// Show game UI elements
scoreContainer.visible = true;
healthBarContainer.visible = true;
powerBarContainer.visible = true;
apoyoBarContainer.visible = true;
exitButtonContainer.visible = true;
// Animate start screen out
tween(startScreenContainer, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
onComplete: function onComplete() {
startScreenContainer.visible = false;
}
});
};
// Database functions removed as requested
// Play button hover effect
playBtn.move = function (x, y, obj) {
playBtn.alpha = 0.8;
};
// Exit button hover effect
exitButtonContainer.move = function (x, y, obj) {
exitBtnBg.alpha = 0.7;
};
// Function to update all score texts and add animation
function updateScoreDisplay(newScore) {
var scoreText = newScore.toString();
scoreTxt.setText(scoreText);
scoreShadow.setText(scoreText);
// Add pulsing animation
tween(scoreContainer, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
onComplete: function onComplete() {
tween(scoreContainer, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150
});
}
});
// Update katana-ninja bar progress (3 katanas activate at 1000 score)
var powerProgress = Math.min(newScore / 1000, 1.0); // Progress from 0 to 1
var powerBarWidth = 2.5 * powerProgress; // Scale to match background width
tween(powerBarFill, {
scaleX: powerBarWidth
}, {
duration: 200
});
// Change power bar color as it fills up
if (powerProgress >= 1.0) {
powerBarFill.tint = 0x00FF00; // Green when ready
powerBarLabel.setText('READY!');
} else if (powerProgress >= 0.7) {
powerBarFill.tint = 0xFFD700; // Gold when close
} else {
powerBarFill.tint = 0xFF6B35; // Orange when building up
}
// Update Apoyo bar progress (auto-sword activates at 389 score)
var apoyoProgress = Math.min(newScore / 389, 1.0); // Progress from 0 to 1
var apoyoBarWidth = 2.5 * apoyoProgress; // Scale to match background width
tween(apoyoBarFill, {
scaleX: apoyoBarWidth
}, {
duration: 200
});
// Change apoyo bar color and label as it fills up
if (apoyoProgress >= 1.0) {
apoyoBarFill.tint = 0x00FF00; // Green when active
apoyoBarLabel.setText('ACTIVO');
} else if (apoyoProgress >= 0.7) {
apoyoBarFill.tint = 0x32CD32; // Light green when close
apoyoBarLabel.setText('APOYO');
} else {
apoyoBarFill.tint = 0x90EE90; // Very light green when building up
apoyoBarLabel.setText('APOYO');
}
// Check for power-up activation at different score thresholds
if (newScore >= 8990 && powerUpActivated !== 6) {
deactivatePowerUp();
activatePowerUp(6); // 6 katanas at 8990 score
powerUpActivated = 6;
} else if (newScore >= 5999 && powerUpActivated !== 5) {
deactivatePowerUp();
activatePowerUp(5); // 5 katanas at 5999 score
powerUpActivated = 5;
} else if (newScore >= 3500 && powerUpActivated !== 4) {
deactivatePowerUp();
activatePowerUp(4); // 4 katanas at 3500 score
powerUpActivated = 4;
} else if (newScore >= 1000 && powerUpActivated !== 3) {
activatePowerUp(3); // 3 katanas at 1000 score
powerUpActivated = 3;
}
// Check for auto-sword activation at 389 score and every 2500 score after
if (newScore >= 389 && !autoSwordActivated) {
activateAutoSword(1); // First auto sword at 389
autoSwordActivated = 389;
} else if (newScore >= 389) {
var currentAutoSwords = Math.floor((newScore - 389) / 2500) + 1;
var expectedAutoSwords = Math.floor((autoSwordActivated - 389) / 2500) + 1;
if (currentAutoSwords > expectedAutoSwords) {
activateAutoSword(currentAutoSwords - expectedAutoSwords); // Add additional auto swords
autoSwordActivated = newScore;
}
}
// Enhanced color change effect based on score
if (newScore >= 500) {
scoreTxt.fill = 0xFFD700; // Gold for power-up scores
} else if (newScore >= 200) {
scoreTxt.fill = 0x9B59B6; // Purple for medium scores
} else if (newScore >= 100) {
scoreTxt.fill = 0x3498DB; // Blue for decent scores
} else {
scoreTxt.fill = 0xFFD700; // Gold for starting scores
}
}
// Power-up activation function
function activatePowerUp(numKatanas) {
powerUpActive = true;
// Set power duration (17.5 seconds = 1050 frames at 60fps)
powerUpTimer = 1050;
powerUpMaxTimer = 1050;
// Create visual explosion effect
LK.effects.flashScreen(0xFFD700, 2000); // Golden flash
// Create additional katanas with better spacing
var extraKatanasToCreate = numKatanas - 1; // Subtract 1 because main katana already exists
for (var k = 0; k < extraKatanasToCreate; k++) {
var extraKatana = game.addChild(new Katana());
extraKatana.x = katana.x;
extraKatana.y = katana.y;
extraKatana.katanaIndex = k; // Assign index for positioning
extraKatanas.push(extraKatana);
// Add golden tint to extra katanas
extraKatana.tint = 0xFFD700;
// Add glowing effect to extra katanas
tween(extraKatana, {
alpha: 0.7
}, {
duration: 500,
onComplete: function onComplete() {
tween(extraKatana, {
alpha: 1
}, {
duration: 500
});
}
});
}
// Add golden glow effect to main katana
katana.tint = 0xFFD700;
tween(katana, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
onComplete: function onComplete() {
tween(katana, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300
});
}
});
}
// Auto-sword activation function
function activateAutoSword(numSwords) {
for (var s = 0; s < numSwords; s++) {
var autoSword = game.addChild(new AutoSword());
autoSword.x = Math.random() * 1500 + 250; // Random position within screen bounds
autoSword.y = Math.random() * 1500 + 250;
autoSwords.push(autoSword);
// Add spawn animation
tween(autoSword, {
scaleX: 1,
scaleY: 1,
alpha: 0.8
}, {
duration: 500
});
}
// No visual effects for auto-sword activation
}
// Track mouse movement
var isSlicing = false;
var lastMouseX = 0;
var lastMouseY = 0;
game.move = function (x, y, obj) {
if (!katanaParalyzed) {
katana.updatePosition(x, y);
// Update extra katanas with better spacing for multiple katanas
if (powerUpActive) {
for (var k = 0; k < extraKatanas.length; k++) {
var spacing = 250; // Increased spacing for better separation
var offsetX = 0;
var offsetY = 0;
// Position katanas symmetrically around center
var totalKatanas = extraKatanas.length + 1; // Include main katana
var startOffset = -(totalKatanas - 1) * spacing / 2;
offsetX = startOffset + (k + 1) * spacing; // k+1 because main katana is at center (index 0)
extraKatanas[k].updatePosition(x + offsetX, y + offsetY);
}
}
if (isSlicing) {
katana.checkFruitCollisions();
// Check collisions for extra katanas too
if (powerUpActive) {
for (var k = 0; k < extraKatanas.length; k++) {
extraKatanas[k].checkFruitCollisions();
}
}
}
}
// Track movement for katana health system
var distance = Math.sqrt(Math.pow(x - lastKatanaX, 2) + Math.pow(y - lastKatanaY, 2));
movementSamples.push(distance);
if (movementSamples.length > maxMovementSamples) {
movementSamples.shift();
}
// Calculate average movement in recent samples
var totalMovement = 0;
for (var i = 0; i < movementSamples.length; i++) {
totalMovement += movementSamples[i];
}
var avgMovement = totalMovement / movementSamples.length;
// Only activate health system if katana is in upper 1.5cm (approximately 109 pixels) from top
var isInUpperScreen = y < 109; // 1.5cm from top of screen (at 72 DPI: 1.5cm ≈ 109 pixels)
// If movement is very rapid (increased threshold: 50+ pixels per frame on average) AND in upper screen
if (avgMovement > 50 && movementSamples.length >= maxMovementSamples && isInUpperScreen) {
katanaHealth -= 3; // Drain health faster for rapid movements
// Show health bar when taking damage
if (healthBarContainer.alpha < 1) {
tween(healthBarContainer, {
alpha: 1
}, {
duration: 200
});
}
// Update health bar fill
var healthPercent = Math.max(0, katanaHealth / maxKatanaHealth);
tween(healthBarFill, {
scaleX: 3 * healthPercent
}, {
duration: 100
});
// Change color based on health level
if (healthPercent < 0.3) {
healthBarFill.tint = 0xE74C3C; // Red
} else if (healthPercent < 0.6) {
healthBarFill.tint = 0xF39C12; // Orange
} else {
healthBarFill.tint = 0x27AE60; // Green
}
// Check if health is depleted
if (katanaHealth <= 0) {
katanaHealth = 0;
katanaParalyzed = true;
paralyzeTimer = 66; // 1.1 seconds at 60fps
// Flash katana red to indicate paralysis
LK.effects.flashObject(katana, 0xFF0000, 1100);
}
}
lastKatanaX = x;
lastKatanaY = y;
lastMouseX = x;
lastMouseY = y;
};
game.down = function (x, y, obj) {
isSlicing = true;
katana.updatePosition(x, y);
// Update extra katanas position on touch down
if (powerUpActive) {
for (var k = 0; k < extraKatanas.length; k++) {
var spacing = 250; // Consistent spacing with move handler
var offsetX = 0;
var offsetY = 0;
// Position katanas symmetrically around center
var totalKatanas = extraKatanas.length + 1; // Include main katana
var startOffset = -(totalKatanas - 1) * spacing / 2;
offsetX = startOffset + (k + 1) * spacing; // k+1 because main katana is at center
extraKatanas[k].updatePosition(x + offsetX, y + offsetY);
}
}
};
game.up = function (x, y, obj) {
isSlicing = false;
};
game.update = function () {
// Handle start screen state - only show background animation
if (gameState === 'start') {
// Only animate background elements on start screen
// Animate cherry blossom petals falling and swirling
for (var bp = 0; bp < blossomPetals.length; bp++) {
var petal = blossomPetals[bp];
petal.y += Math.sin(LK.ticks * 0.01 + bp) * 0.5 + 0.3;
petal.x += Math.sin(LK.ticks * 0.008 + bp) * 0.8;
petal.rotation += 0.02;
// Reset petal position when it goes off screen
if (petal.y > 2800) {
petal.y = -50;
petal.x = Math.random() * 2048;
}
if (petal.x > 2100) {
petal.x = -50;
}
}
return; // Don't update game logic on start screen
}
// Animate background elements
// Animate cherry blossom petals falling and swirling
for (var bp = 0; bp < blossomPetals.length; bp++) {
var petal = blossomPetals[bp];
petal.y += Math.sin(LK.ticks * 0.01 + bp) * 0.5 + 0.3;
petal.x += Math.sin(LK.ticks * 0.008 + bp) * 0.8;
petal.rotation += 0.02;
// Reset petal position when it goes off screen
if (petal.y > 2800) {
petal.y = -50;
petal.x = Math.random() * 2048;
}
if (petal.x > 2100) {
petal.x = -50;
}
}
// Animate mist layers with slow drift
for (var mist = 0; mist < mistLayers.length; mist++) {
var mistLayer = mistLayers[mist];
mistLayer.x += Math.sin(LK.ticks * 0.002 + mist) * 0.2 + 0.1;
mistLayer.alpha = 0.3 + Math.sin(LK.ticks * 0.005 + mist) * 0.1;
// Reset position when off screen
if (mistLayer.x > 2400) {
mistLayer.x = -400;
}
}
// Animate flowers with gentle bobbing
for (var f = 0; f < flowers.length; f++) {
var flower = flowers[f];
flower.rotation = Math.sin(LK.ticks * 0.02 + f) * 0.2;
flower.scaleX = 1 + Math.sin(LK.ticks * 0.015 + f) * 0.1;
flower.scaleY = 1 + Math.sin(LK.ticks * 0.015 + f) * 0.1;
}
// Add subtle parallax effect to background layers
for (var bt = 0; bt < backgroundTrees.length; bt++) {
var bgTree = backgroundTrees[bt];
bgTree.x += Math.sin(LK.ticks * 0.001 + bt) * 0.1;
}
// Animate hills with very subtle movement
for (var h = 0; h < hills.length; h++) {
var hill = hills[h];
hill.alpha = 0.6 + Math.sin(LK.ticks * 0.003 + h) * 0.1;
}
// Gentle sky color animation transitioning between sunset and night
if (LK.ticks % 120 === 0) {
var timePhase = Math.sin(LK.ticks * 0.0005) * 0.5 + 0.5; // Oscillates between 0 and 1
var sunsetNightColors = [[0xFF4500, 0x191970],
// Horizon: deep orange to midnight blue
[0xFF6347, 0x2F4F4F],
// Tomato to dark slate gray
[0xDC143C, 0x483D8B],
// Crimson to dark slate blue
[0x9932CC, 0x191970],
// Dark orchid to midnight blue
[0x483D8B, 0x000000],
// Dark slate blue to black
[0x2F4F4F, 0x000000],
// Dark slate gray to black
[0x191970, 0x000000],
// Midnight blue to black
[0x000000, 0x000000] // Pure black to pure black
];
for (var s = 0; s < skyLayers.length; s++) {
var skyLayer = skyLayers[s];
var sunsetColor = sunsetNightColors[s][0];
var nightColor = sunsetNightColors[s][1];
// Interpolate between sunset and night colors
var r1 = sunsetColor >> 16 & 0xFF;
var g1 = sunsetColor >> 8 & 0xFF;
var b1 = sunsetColor & 0xFF;
var r2 = nightColor >> 16 & 0xFF;
var g2 = nightColor >> 8 & 0xFF;
var b2 = nightColor & 0xFF;
// Blend with adjacent layers for smoother transitions
var blendFactor = 0.3; // Amount of blending with neighbors
var r = Math.floor(r1 + (r2 - r1) * timePhase);
var g = Math.floor(g1 + (g2 - g1) * timePhase);
var b = Math.floor(b1 + (b2 - b1) * timePhase);
// Blend with previous layer if it exists
if (s > 0) {
var prevColor = sunsetNightColors[s - 1];
var prevSunset = prevColor[0];
var prevNight = prevColor[1];
var prevR1 = prevSunset >> 16 & 0xFF;
var prevG1 = prevSunset >> 8 & 0xFF;
var prevB1 = prevSunset & 0xFF;
var prevR2 = prevNight >> 16 & 0xFF;
var prevG2 = prevNight >> 8 & 0xFF;
var prevB2 = prevNight & 0xFF;
var prevR = Math.floor(prevR1 + (prevR2 - prevR1) * timePhase);
var prevG = Math.floor(prevG1 + (prevG2 - prevG1) * timePhase);
var prevB = Math.floor(prevB1 + (prevB2 - prevB1) * timePhase);
// Blend current color with previous layer
r = Math.floor(r * (1 - blendFactor) + prevR * blendFactor);
g = Math.floor(g * (1 - blendFactor) + prevG * blendFactor);
b = Math.floor(b * (1 - blendFactor) + prevB * blendFactor);
}
// Blend with next layer if it exists
if (s < skyLayers.length - 1) {
var nextColor = sunsetNightColors[s + 1];
var nextSunset = nextColor[0];
var nextNight = nextColor[1];
var nextR1 = nextSunset >> 16 & 0xFF;
var nextG1 = nextSunset >> 8 & 0xFF;
var nextB1 = nextSunset & 0xFF;
var nextR2 = nextNight >> 16 & 0xFF;
var nextG2 = nextNight >> 8 & 0xFF;
var nextB2 = nextNight & 0xFF;
var nextR = Math.floor(nextR1 + (nextR2 - nextR1) * timePhase);
var nextG = Math.floor(nextG1 + (nextG2 - nextG1) * timePhase);
var nextB = Math.floor(nextB1 + (nextB2 - nextB1) * timePhase);
// Blend current color with next layer
r = Math.floor(r * (1 - blendFactor * 0.5) + nextR * (blendFactor * 0.5));
g = Math.floor(g * (1 - blendFactor * 0.5) + nextG * (blendFactor * 0.5));
b = Math.floor(b * (1 - blendFactor * 0.5) + nextB * (blendFactor * 0.5));
}
// Apply smooth transition with tween for even smoother color changes
var targetColor = r << 16 | g << 8 | b;
tween(skyLayer, {
tint: targetColor
}, {
duration: 120,
easing: tween.easeOut
});
}
}
// Animate snow caps with subtle shimmer
for (var sc = 0; sc < snowCaps.length; sc++) {
var snowCap = snowCaps[sc];
snowCap.alpha = snowCap.alpha + Math.sin(LK.ticks * 0.01 + sc) * 0.05;
}
// Spawn shooting stars periodically
shootingStarSpawnTimer++;
if (shootingStarSpawnTimer >= shootingStarSpawnRate) {
shootingStarSpawnTimer = 0;
// Random chance to spawn (not every time)
if (Math.random() < 0.7) {
var shootingStar = new ShootingStar(Math.random() * 500 - 200,
// Start from left side of screen
Math.random() * 800 + 100 // Random height in upper portion
);
shootingStars.push(shootingStar);
backgroundContainer.addChild(shootingStar);
}
}
// Update shooting stars and remove expired ones
for (var ss = shootingStars.length - 1; ss >= 0; ss--) {
var star = shootingStars[ss];
star.update();
// Remove stars that are off screen or expired
if (star.life <= 0 || star.x > 2400 || star.y > 2800) {
star.destroy();
shootingStars.splice(ss, 1);
}
}
// Update distant and mid buildings
for (var db = 0; db < distantBuildings.length; db++) {
distantBuildings[db].update();
}
for (var mb = 0; mb < midBuildings.length; mb++) {
midBuildings[mb].update();
}
// Spawn fruits
spawnTimer++;
if (spawnTimer >= spawnRate) {
spawnTimer = 0;
var fruitType = fruitTypes[Math.floor(Math.random() * fruitTypes.length)];
// Create fruit with simple falling behavior
var fruit = new Fruit(fruitType);
// Spawn fruit at random horizontal position across entire screen width
fruit.x = Math.random() * 2048;
fruit.y = -100; // Start above screen
fruits.push(fruit);
game.addChild(fruit);
// Spawn rate is now controlled by difficulty level in slice function
}
// Update fruits and remove off-screen ones
for (var i = fruits.length - 1; i >= 0; i--) {
var fruit = fruits[i];
// Explicitly call fruit update to ensure falling continues after pause
fruit.update();
// Check if fruit touched the ground (game over condition) - only if still playing
if (fruit.y > 2732 && !fruit.sliced && gameState === 'playing') {
// Save current score to database
savePlayerScore(LK.getScore());
// Game over - fruit touched the ground
LK.showGameOver();
return; // Stop game execution
}
// Remove fruits that fall off screen
if (fruit.y > 2800) {
fruit.destroy();
fruits.splice(i, 1);
}
}
// Update particles
for (var j = particles.length - 1; j >= 0; j--) {
var particle = particles[j];
if (particle.life <= 0) {
particles.splice(j, 1);
}
}
// Update power-up timer and bar
if (powerUpActive) {
powerUpTimer--;
// Update power bar to show countdown
var powerProgress = powerUpTimer / powerUpMaxTimer;
var powerBarWidth = 2.5 * powerProgress;
tween(powerBarFill, {
scaleX: powerBarWidth
}, {
duration: 100
});
// Change power bar color during countdown
if (powerProgress <= 0.3) {
powerBarFill.tint = 0xFF0000; // Red when almost finished
powerBarLabel.setText('ENDING!');
} else if (powerProgress <= 0.6) {
powerBarFill.tint = 0xFF6B35; // Orange when halfway
powerBarLabel.setText('ACTIVE');
} else {
powerBarFill.tint = 0x00FF00; // Green when active
powerBarLabel.setText('ACTIVE');
}
// Keep power active permanently - no deactivation when timer reaches 0
if (powerUpTimer <= 0) {
// Power remains active permanently
}
}
// Track mouse movement
if (katanaParalyzed) {
paralyzeTimer--;
if (paralyzeTimer <= 0) {
katanaParalyzed = false;
katanaHealth = maxKatanaHealth; // Restore full health
// Update health bar to full
tween(healthBarFill, {
scaleX: 3
}, {
duration: 300
});
healthBarFill.tint = 0x27AE60; // Green
// Hide health bar after recovery
tween(healthBarContainer, {
alpha: 0
}, {
duration: 1000
});
}
} else {
// Gradually regenerate health when not making rapid movements
if (katanaHealth < maxKatanaHealth) {
katanaHealth += 0.5; // Slow regeneration
if (katanaHealth > maxKatanaHealth) {
katanaHealth = maxKatanaHealth;
}
// Update health bar fill
var healthPercent = katanaHealth / maxKatanaHealth;
healthBarFill.scaleX = 3 * healthPercent;
// Update color
if (healthPercent < 0.3) {
healthBarFill.tint = 0xE74C3C; // Red
} else if (healthPercent < 0.6) {
healthBarFill.tint = 0xF39C12; // Orange
} else {
healthBarFill.tint = 0x27AE60; // Green
}
// Hide health bar when fully recovered and not being used
if (katanaHealth >= maxKatanaHealth && healthBarContainer.alpha > 0) {
tween(healthBarContainer, {
alpha: 0
}, {
duration: 2000
});
}
}
}
};
katana animada. In-Game asset. 2d. High contrast. No shadows
manzana animada. In-Game asset. 2d. High contrast. No shadows
melon animado. In-Game asset. 2d. High contrast. No shadows
Naranja animada. In-Game asset. 2d. High contrast. No shadows
platano animado. In-Game asset. 2d. High contrast. No shadows
piña animada. In-Game asset. 2d. High contrast. No shadows
Tronco completo de un arbol animado. In-Game asset. 2d. High contrast. No shadows
montañas con nieve en la punta animadas. In-Game asset. 2d. High contrast. No shadows
LUna animada. In-Game asset. 2d. High contrast. No shadows
nubes animada. In-Game asset. 2d. High contrast. No shadows
Pasto animado. In-Game asset. 2d. High contrast. No shadows
Flower animada. In-Game asset. 2d. High contrast. No shadows