/**** * 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