User prompt
Clear the screen atthe end of a level
User prompt
Increase the number of fruits spawned by level 4 boss
User prompt
Increase the number of fruits spawned by level 4 boss
User prompt
Make level 4 boss spawn fruit 1, 2, 3 and 4 at random
User prompt
Make level 5 boss spawn level 5 fruits
User prompt
Make level 3 boss spawn level 3 fruits
User prompt
Let level 4 boss spawn level 4 fruits
User prompt
Make fruits bounce agains each other and not overlap ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Increase number of level 4 fruit types spawned by level 4 boss
User prompt
Increase number of level 3 fruit types spawned by level 3 boss
User prompt
Let level 4 boss spawn level 4 fruit types
User prompt
Let level 3 boss spawn level 3 fruit types
User prompt
Let level 5 boss spawn level 5 fruit types
User prompt
Let level 4 boss spawn level 4 fruit types
User prompt
Increase blitz, life and bullet time powerups spawned in level 5
User prompt
Increase blitz, life and bullet time powerups spawned in level 4
User prompt
Increase lifefruit spawn chances in all levels
User prompt
Increase powerup spawn chances in level 4 and 5
User prompt
Increase blitz, life and bullet time powerups spawned in level 3
User prompt
Increase blitz, life and bullet time powerups spawned in level 4
User prompt
Increase blitz, life and bullet time powerups spawned in level 3
User prompt
Add more blitz, life and bullet time powerups to levels 3, 4 and 5
User prompt
Let level 3 boss spawn level 3 fruit types
User prompt
Reduce delay between fruit spawns in level 1 by 20%
User prompt
Reduce delay between fruit spawns in level 1, 2 and 3 by 30%
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Blade = Container.expand(function () { var self = Container.call(this); self.active = false; self.points = []; self.maxPoints = 20; // Increased from 10 to 20 to track more points for smoother detection self.trail = []; for (var i = 0; i < self.maxPoints; i++) { var trailPart = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.trail.push(trailPart); } self.update = function () { // Update trail visuals for (var i = 0; i < self.trail.length; i++) { if (i < self.points.length) { var point = self.points[i]; var trailPart = self.trail[i]; trailPart.x = point.x; trailPart.y = point.y; trailPart.alpha = 0; // Keep blade invisible if (i > 0) { var prevPoint = self.points[i - 1]; var angle = Math.atan2(point.y - prevPoint.y, point.x - prevPoint.x); trailPart.rotation = angle; } } else { self.trail[i].alpha = 0; } } }; self.addPoint = function (x, y) { self.points.unshift({ x: x, y: y }); if (self.points.length > self.maxPoints) { self.points.pop(); } }; self.reset = function () { self.points = []; self.active = false; for (var i = 0; i < self.trail.length; i++) { self.trail[i].alpha = 0; } }; return self; }); var BlitzPowerup = Container.expand(function () { var self = Container.call(this); self.type = 'blitz'; self.sliced = false; self.width = 300; self.height = 300; self.points = 0; self.baseSpeed = 1.5; // Create a red lightning bolt-shaped fruit for blitz var blitzGraphics = self.attachAsset('kiwi', { anchorX: 0.5, anchorY: 0.5 }); blitzGraphics.tint = 0xFF0000; // Red color for blitz power // Create lightning bolt symbol var boltTop = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 20, height: 100 }); boltTop.tint = 0xFFFFFF; boltTop.rotation = Math.PI / 4; boltTop.y = -30; var boltBottom = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 20, height: 100 }); boltBottom.tint = 0xFFFFFF; boltBottom.rotation = -Math.PI / 4; boltBottom.y = 30; self.vx = 0; self.vy = 0; self.gravity = 0.01; self.rotationSpeed = (Math.random() - 0.5) * 0.015; self.init = function (x, y, direction) { self.x = x; self.y = y; var angle = direction * (Math.PI / 4) + Math.random() * Math.PI / 8 - Math.PI / 16; var speed = self.baseSpeed + Math.random() * 0.8; self.vx = Math.cos(angle) * speed * 1.15; self.vy = -Math.sin(angle) * speed - 8; }; self.slice = function () { if (self.sliced) { return; } self.sliced = true; // Flash effect blitzGraphics.tint = 0xFFFFFF; boltTop.tint = 0xFF0000; boltBottom.tint = 0xFF0000; tween(blitzGraphics, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { blitzGraphics.tint = 0xFF0000; } }); // Display "Blitzkrieg!" text in the middle of screen var blitzText = new Text2('Blitzkrieg!', { size: 120, fill: 0xFF0000, weight: 'bold' }); blitzText.anchor.set(0.5, 0.5); blitzText.x = GAME_WIDTH / 2; blitzText.y = GAME_HEIGHT / 2; game.addChild(blitzText); // Animate the text tween(blitzText, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 1500, easing: tween.elasticOut, onFinish: function onFinish() { blitzText.destroy(); } }); // Shake the screen effect var originalX = game.x; var originalY = game.y; var shakeCount = 0; var maxShakes = 10; var shakeIntensity = 20; var shakeInterval = LK.setInterval(function () { if (shakeCount >= maxShakes) { LK.clearInterval(shakeInterval); game.x = originalX; game.y = originalY; // After shake is done, destroy all fruits LK.getSound('explosion').play(); // Destroy all fruits on screen (including bombs) for (var i = fruits.length - 1; i >= 0; i--) { var fruit = fruits[i]; if (fruit.type !== 'lifefruit' && fruit.type !== 'bullettime' && fruit.type !== 'blitz') { // Add points for each destroyed fruit if (fruit.type !== 'bomb') { LK.setScore(LK.getScore() + fruit.points); } // Create explosive effect for each fruit var fruitGraphics = fruit.children[0]; fruitGraphics.tint = 0xFFFFFF; tween(fruitGraphics, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut }); // Play squash sound for each fruit LK.getSound('squash').play(); // Remove fruit fruit.destroy(); fruits.splice(i, 1); } } // Update score display scoreTxt.setText(LK.getScore()); return; } // Apply random shake offset game.x = originalX + (Math.random() - 0.5) * shakeIntensity; game.y = originalY + (Math.random() - 0.5) * shakeIntensity; shakeCount++; }, 50); // Play slice sound LK.getSound('slice').play(); LK.getSound('squash').play(); }; self.down = function (x, y, obj) { if (!self.sliced) { self.slice(); // Update combo comboCount++; comboTimer = Date.now() + comboTimeout; } }; self.update = function () { // Don't update movement if gameActive is false (leaderboard is visible) if (!gameActive) { return; } if (!self.sliced) { // Update whole fruit self.vy += self.gravity; self.x += self.vx; self.y += self.vy; self.rotation += self.rotationSpeed; // Bounce off walls if not sliced if (self.x < self.width / 2 && self.vx < 0) { self.vx = -self.vx * 0.8; self.x = self.width / 2; } if (self.x > GAME_WIDTH - self.width / 2 && self.vx > 0) { self.vx = -self.vx * 0.8; self.x = GAME_WIDTH - self.width / 2; } } }; self.isOffScreen = function () { return self.y > 2732 + self.height || self.x > GAME_WIDTH + self.width; }; return self; }); var Boss = Container.expand(function (level) { var self = Container.call(this); // Boss properties self.level = level || 1; self.health = 5 + self.level; // Health increases with level self.maxHealth = self.health; self.width = 800; self.height = 800; self.active = false; self.attackTimer = 0; self.attackInterval = self.level === 5 ? 833 : 3000 - self.level * 250; // Level 5 boss spawn speed reduced by 25% (increased from 667ms to 833ms) // Ensure level is within valid range (1-5) if (self.level < 1) { self.level = 1; } if (self.level > 5) { self.level = 5; } // Determine boss type based on level var bossType = BOSS_FRUIT_TYPES[self.level - 1] || 'strawberry'; // Create boss visual var bossGraphic = self.attachAsset(bossType, { anchorX: 0.5, anchorY: 0.5, scaleX: self.level === 1 ? 1.95 : self.level === 2 ? 2.8 : self.level === 5 ? 3.5 : 4, // Make level 1 boss smaller by 35%, level 2 boss smaller by 30%, level 5 boss 30% smaller (from 5 to 3.5) scaleY: self.level === 1 ? 1.95 : self.level === 2 ? 2.8 : self.level === 5 ? 3.5 : 4 // Make level 1 boss smaller by 35%, level 2 boss smaller by 30%, level 5 boss 30% smaller (from 5 to 3.5) }); // Health bar background var healthBarBg = new Container(); healthBarBg.x = -200; healthBarBg.y = -450; var healthBarBack = LK.getAsset('blade', { anchorX: 0, anchorY: 0.5, width: 400, height: 30 }); healthBarBack.tint = 0x333333; // Health bar fill var healthBarFill = LK.getAsset('blade', { anchorX: 0, anchorY: 0.5, width: 400, height: 30 }); healthBarFill.tint = 0xFF0000; healthBarBg.addChild(healthBarBack); healthBarBg.addChild(healthBarFill); self.addChild(healthBarBg); self.healthBar = healthBarFill; // Boss movement self.vx = self.level === 5 ? 8 : 2 + self.level * 0.5; // Level 5 boss moves much faster self.targetX = GAME_WIDTH / 2; self.activate = function () { self.active = true; self.health = self.maxHealth; self.x = GAME_WIDTH / 2; // Position boss below the top boundary (320px) with enough space to not overlap // Boss dimensions depend on the asset scale (4x) and boss type // Account for boss height and health bar to ensure it appears fully below the boundary // Position bosses at different heights based on level to avoid overlapping the top boundary if (self.level === 2) { self.y = 320 + 570; // Level 2 boss: 60px lower } else if (self.level === 3) { self.y = 320 + 690; // Level 3 boss: 170px lower (moved additional 30px lower) } else if (self.level === 4) { self.y = 320 + 750; // Level 4 boss: 200px lower } else if (self.level === 5) { self.y = 320 + 900; // Level 5 boss: 300px lower (moved from 600 to 900) } else { self.y = 320 + 570; // Default position for level 1 boss } self.updateHealthBar(); }; self.updateHealthBar = function () { self.healthBar.width = self.health / self.maxHealth * 400; }; self.hit = function () { if (!self.active) { return; } self.health--; self.updateHealthBar(); // Flash the boss red bossGraphic.tint = 0xFF0000; LK.setTimeout(function () { bossGraphic.tint = 0xFFFFFF; }, 200); // Check if boss is defeated if (self.health <= 0) { self.defeat(); return true; } return false; }; self.defeat = function () { self.active = false; // Make the health bar transparent healthBarBg.alpha = 0; // Create explosion effect bossGraphic.tint = 0xFFFFFF; tween(bossGraphic, { alpha: 0, scaleX: 3, scaleY: 3, rotation: Math.PI * 2 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Add bonus points (increased for higher level bosses) var bonus = 25 * self.level; LK.setScore(LK.getScore() + bonus); scoreTxt.setText(LK.getScore()); LK.effects.flashScreen(0x00FF00, 500); } }); // Play explosion sound LK.getSound('explosion').play(); }; self.throwFruit = function () { if (!self.active) { return; } // Launch multiple bombs at the player var bombCount = self.level === 5 ? Math.floor(Math.random() * 3) + 2 : // Level 5: 2-4 bombs (reduced from 3-6) Math.floor(Math.random() * self.level) + 1; // Other levels: 1-level bombs // For level 5, also spawn random fruits alongside bombs // Also spawn random fruits with level 1 and level 2 bosses var fruitCount = self.level === 5 || self.level === 1 || self.level === 2 ? Math.floor(Math.random() * 2) : 0; // Reduced from 1-2 to 0-1 // Spawn bombs for (var i = 0; i < bombCount; i++) { var fruit = new Fruit('bomb'); // Generate random position on the boss perimeter var spawnAngle = Math.random() * Math.PI * 2; // Full 360 degrees var spawnRadius = self.width / 3; // Radius to spawn from (edge of boss) // Position the bomb on the perimeter fruit.x = self.x + Math.cos(spawnAngle) * spawnRadius; fruit.y = self.y + Math.sin(spawnAngle) * spawnRadius; // Aim outward from the spawn point with spread var angle = spawnAngle + Math.PI + (Math.random() - 0.5); // Outward direction with randomness var speed = self.level === 5 ? 5 + Math.random() * 3 : // Level 5: Much faster bombs 3 + Math.random() * 2 + self.level * 0.5; // Other levels: Normal speed fruit.vx = Math.cos(angle) * speed; fruit.vy = Math.sin(angle) * speed; game.addChild(fruit); fruits.push(fruit); } // For level 5, level 1, level 2, or level 3, also spawn random fruits if (self.level === 5 || self.level === 1 || self.level === 2 || self.level === 3) { // Level 2 boss spawns fewer fruits (1-2 instead of 2-3) var fruitCount = self.level === 2 ? Math.floor(Math.random() * 2) + 1 : self.level === 3 ? Math.floor(Math.random() * 3) + 2 : // Level 3 boss: 2-4 fruits self.level === 5 || self.level === 1 ? Math.floor(Math.random() * 2) : 0; for (var j = 0; j < fruitCount; j++) { // Select a random fruit type // For level 1, only use level 1 fruits (strawberry) // For level 2, use level 2 fruits (strawberry, kiwi) // For level 3, use level 3 fruits (strawberry, kiwi, orange) // For level 4, use level 4 fruits (strawberry, kiwi, orange, apple) var availableFruits; if (self.level === 1) { availableFruits = ['strawberry']; // Level 1 fruits } else if (self.level === 2) { availableFruits = ['strawberry', 'kiwi']; // Level 2 fruits } else if (self.level === 3) { availableFruits = ['strawberry', 'kiwi', 'orange']; // Level 3 fruits } else if (self.level === 4) { availableFruits = ['strawberry', 'kiwi', 'orange', 'apple']; // Level 4 fruits // Spawn more fruits for level 4 boss fruitCount = Math.floor(Math.random() * 3) + 3; // Level 4 boss: 3-5 fruits // Ensure we spawn level 4 fruits for (var j = 0; j < fruitCount; j++) { var fruitType = availableFruits[Math.floor(Math.random() * availableFruits.length)]; var randomFruit = new Fruit(fruitType); // Generate random position on the boss perimeter var fruitAngle = Math.random() * Math.PI * 2; var fruitRadius = self.width / 3; // Position the fruit on the perimeter randomFruit.x = self.x + Math.cos(fruitAngle) * fruitRadius; randomFruit.y = self.y + Math.sin(fruitAngle) * fruitRadius; // Aim outward with different trajectory var fruitDirection = fruitAngle + Math.PI + (Math.random() - 0.5) * 0.5; var fruitSpeed = 4 + Math.random() * 2; randomFruit.vx = Math.cos(fruitDirection) * fruitSpeed; randomFruit.vy = Math.sin(fruitDirection) * fruitSpeed; game.addChild(randomFruit); fruits.push(randomFruit); } return; // Skip the regular fruit spawning below } else { availableFruits = ['strawberry', 'kiwi', 'orange', 'apple', 'watermelon']; // Level 5 fruits } var fruitType = availableFruits[Math.floor(Math.random() * availableFruits.length)]; var randomFruit = new Fruit(fruitType); // Generate random position on the boss perimeter var fruitAngle = Math.random() * Math.PI * 2; var fruitRadius = self.width / 3; // Position the fruit on the perimeter randomFruit.x = self.x + Math.cos(fruitAngle) * fruitRadius; randomFruit.y = self.y + Math.sin(fruitAngle) * fruitRadius; // Aim outward with different trajectory var fruitDirection = fruitAngle + Math.PI + (Math.random() - 0.5) * 0.5; var fruitSpeed = 4 + Math.random() * 2; randomFruit.vx = Math.cos(fruitDirection) * fruitSpeed; randomFruit.vy = Math.sin(fruitDirection) * fruitSpeed; game.addChild(randomFruit); fruits.push(randomFruit); } } }; self.update = function (delta) { if (!self.active) { return; } // Apply bullet time effect if active (slow down by 75%) var speedMultiplier = bulletTimeActive ? 0.25 : 1; // Move boss back and forth if (Math.abs(self.x - self.targetX) < 10) { self.targetX = Math.random() * (GAME_WIDTH - 400) + 200; } var dirX = self.targetX - self.x; self.x += dirX / Math.abs(dirX) * self.vx * speedMultiplier; // Attack on timer var currentTime = Date.now(); if (currentTime >= self.attackTimer) { self.throwFruit(); // Extend attack interval during bullet time self.attackTimer = currentTime + self.attackInterval * (bulletTimeActive ? 4 : 1); } }; self.down = function (x, y, obj) { // Allow clicking on boss to damage it if (self.active) { self.hit(); } }; return self; }); var BulletTimePowerup = Container.expand(function () { var self = Container.call(this); self.type = 'bullettime'; self.sliced = false; self.width = 300; self.height = 300; self.points = 0; self.baseSpeed = 1.5; // Create a blue hourglass-shaped fruit for bullet time var bulletTimeGraphics = self.attachAsset('kiwi', { anchorX: 0.5, anchorY: 0.5 }); bulletTimeGraphics.tint = 0x00BFFF; // Deep sky blue color // Create hourglass symbol var hourglassTop = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 140, height: 20 }); hourglassTop.tint = 0xFFFFFF; hourglassTop.y = -50; var hourglassBottom = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 140, height: 20 }); hourglassBottom.tint = 0xFFFFFF; hourglassBottom.y = 50; var hourglassLeft = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 20, height: 100 }); hourglassLeft.tint = 0xFFFFFF; hourglassLeft.x = -60; var hourglassRight = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 20, height: 100 }); hourglassRight.tint = 0xFFFFFF; hourglassRight.x = 60; self.vx = 0; self.vy = 0; self.gravity = 0.01; self.rotationSpeed = (Math.random() - 0.5) * 0.015; self.init = function (x, y, direction) { self.x = x; self.y = y; var angle = direction * (Math.PI / 4) + Math.random() * Math.PI / 8 - Math.PI / 16; var speed = self.baseSpeed + Math.random() * 0.8; self.vx = Math.cos(angle) * speed * 1.15; self.vy = -Math.sin(angle) * speed - 8; }; self.slice = function () { if (self.sliced) { return; } self.sliced = true; // Flash effect bulletTimeGraphics.tint = 0xFFFFFF; hourglassTop.tint = 0x00BFFF; hourglassBottom.tint = 0x00BFFF; hourglassLeft.tint = 0x00BFFF; hourglassRight.tint = 0x00BFFF; tween(bulletTimeGraphics, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { bulletTimeGraphics.tint = 0x00BFFF; } }); // Activate bullet time effect activateBulletTime(); // Play slice and bullet sounds only (no squash) LK.getSound('slice').play(); LK.getSound('bullet').play(); }; self.down = function (x, y, obj) { if (!self.sliced) { self.slice(); // Update combo comboCount++; comboTimer = Date.now() + comboTimeout; } }; self.update = function () { // Don't update movement if gameActive is false (leaderboard is visible) if (!gameActive) { return; } if (!self.sliced) { // Update whole fruit self.vy += self.gravity; self.x += self.vx; self.y += self.vy; self.rotation += self.rotationSpeed; // Bounce off walls if not sliced if (self.x < self.width / 2 && self.vx < 0) { self.vx = -self.vx * 0.8; self.x = self.width / 2; } if (self.x > GAME_WIDTH - self.width / 2 && self.vx > 0) { self.vx = -self.vx * 0.8; self.x = GAME_WIDTH - self.width / 2; } } }; self.isOffScreen = function () { return self.y > 2732 + self.height || self.x > GAME_WIDTH + self.width; }; return self; }); var Fruit = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'apple'; self.sliced = false; self.width = 0; self.height = 0; self.points = 0; self.baseSpeed = 0; var fruitGraphics; switch (self.type) { case 'watermelon': self.width = 200; self.height = 200; self.points = 5; self.baseSpeed = 1.6; // Faster base speed break; case 'apple': self.width = 240; self.height = 240; self.points = 4; self.baseSpeed = 1.7; // Faster base speed break; case 'orange': self.width = 280; self.height = 280; self.points = 3; self.baseSpeed = 1.8; // Faster base speed break; case 'kiwi': self.width = 320; self.height = 320; self.points = 2; self.baseSpeed = 2.0; // Faster base speed break; case 'passion_fruit': self.width = 360; self.height = 360; self.points = 6; self.baseSpeed = 2.3; // Even faster base speed break; case 'strawberry': self.width = 480; self.height = 480; self.points = 1; self.baseSpeed = 2.2; // Faster base speed break; case 'bomb': self.width = 320; self.height = 320; self.points = -10; self.baseSpeed = 1.7; // Faster base speed break; } fruitGraphics = self.attachAsset(self.type, { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.gravity = 0.01; // Reduced gravity to make fruits go higher self.rotationSpeed = (Math.random() - 0.5) * 0.018; // Slightly faster rotation self.init = function (x, y, direction) { self.x = x; self.y = y; var angle = direction * (Math.PI / 4) + Math.random() * Math.PI / 8 - Math.PI / 16; var currentLevel = Math.floor(LK.getScore() / 50) + 1; var levelMultiplier = 1 + (currentLevel - 1) * 0.1; // 10% increase per level // Use constant base speed without random factor to keep speed consistent within level var speed = self.baseSpeed * levelMultiplier; // Apply 30% speed reduction for level 1 if (currentLevel === 1) { speed *= 0.7; // 30% slower for level 1 } self.vx = Math.cos(angle) * speed * 1.15; // Slightly faster horizontal movement self.vy = -Math.sin(angle) * speed - 8; // Higher initial upward velocity }; self.slice = function () { if (self.sliced) { return; } self.sliced = true; // Create explosive flash effect fruitGraphics.tint = 0xFFFFFF; fruitGraphics.alpha = 1; // Animate explosive flash effect with scaling tween(fruitGraphics, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeOut, onUpdate: function onUpdate(progress) { // Create a pulsing effect with rotation during explosion fruitGraphics.rotation += 0.1; }, onFinish: function onFinish() { // Clean up after animation fruitGraphics.tint = 0xFFFFFF; fruitGraphics.scaleX = 1; fruitGraphics.scaleY = 1; } }); // Play slice and squash sounds LK.getSound('slice').play(); LK.getSound('squash').play(); return self.points; }; self.down = function (x, y, obj) { if (!self.sliced) { // Slice the fruit when clicked var points = self.slice(); // Check if it's a bomb if (self.type === 'bomb') { // Lose a life when clicking a bomb LK.getSound('explosion').play(); LK.effects.flashScreen(0xFF0000, 500); playerLives--; // Reduce lives by 1 updateLivesDisplay(); // Update hearts display // Make bomb disappear self.sliced = true; // Create explosive flash effect for bomb fruitGraphics.tint = 0xFFFFFF; // Animate bomb disappearing tween(fruitGraphics, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Remove bomb from game self.destroy(); // Find and remove from fruits array var index = fruits.indexOf(self); if (index > -1) { fruits.splice(index, 1); } } }); // If no lives left, game over if (playerLives <= 0) { // Update high score if current score is higher if (LK.getScore() > highScore) { highScore = LK.getScore(); storage.highScore = highScore; } // Add score to global leaderboard addScoreToLeaderboard(LK.getScore()); // Pass the current score and high score to game over display LK.showGameOver({ score: LK.getScore(), highScore: highScore }); } return; } // Add points to score LK.setScore(LK.getScore() + points); scoreTxt.setText(LK.getScore()); // Increment sliced fruits counter for current level slicedFruitsInLevel++; // Update combo comboCount++; comboTimer = Date.now() + comboTimeout; } }; self.update = function () { // Don't update movement if gameActive is false (leaderboard is visible) if (!gameActive) { return; } if (!self.sliced) { // Update whole fruit // Apply bullet time effect if active (slow down by 75%) var speedMultiplier = bulletTimeActive ? 0.25 : 1; self.vy += self.gravity * speedMultiplier; self.x += self.vx * speedMultiplier; self.y += self.vy * speedMultiplier; self.rotation += self.rotationSpeed * speedMultiplier; // Bounce off walls if not sliced if (self.x < self.width / 2 && self.vx < 0) { self.vx = -self.vx * 0.8; // Bounce with some energy loss self.x = self.width / 2; } if (self.x > GAME_WIDTH - self.width / 2 && self.vx > 0) { self.vx = -self.vx * 0.8; // Bounce with some energy loss self.x = GAME_WIDTH - self.width / 2; } } else { // No update for sliced fruit since we're just flashing and fading them } }; self.isOffScreen = function () { return self.y > 2732 + self.height || self.x > GAME_WIDTH + self.width; }; return self; }); var Heart = Container.expand(function () { var self = Container.call(this); // Create a red heart shape (using blade asset tinted red) var heartShape = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60 }); heartShape.tint = 0xFF0000; return self; }); var Leaderboard = Container.expand(function () { var self = Container.call(this); self.visible = false; // Background panel var panel = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 1500, height: 1800 }); panel.tint = 0x111111; // Very dark color (almost black) for better contrast panel.alpha = 0.9; // Slightly transparent for better visibility // Title var title = new Text2('GLOBAL LEADERBOARD', { size: 100, fill: 0xFFFFFF }); title.anchor.set(0.5, 0); title.y = -800; self.addChild(title); // Scores container var scoresContainer = new Container(); scoresContainer.y = -650; self.addChild(scoresContainer); self.scoresContainer = scoresContainer; // Close button var closeBtn = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 80 }); closeBtn.tint = 0xFF0000; closeBtn.x = 700; closeBtn.y = -800; // X symbol on close button var closeX1 = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 40, height: 8 }); closeX1.tint = 0xFFFFFF; closeX1.rotation = Math.PI / 4; closeX1.x = 700; closeX1.y = -800; var closeX2 = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 40, height: 8 }); closeX2.tint = 0xFFFFFF; closeX2.rotation = -Math.PI / 4; closeX2.x = 700; closeX2.y = -800; // Close button interaction closeBtn.interactive = true; closeBtn.down = function (x, y, obj) { self.hide(); }; // Show leaderboard self.show = function (scores) { self.visible = true; self.updateScores(scores); // Pause the game when leaderboard is visible gameActive = false; // Make game area 50% transparent game.alpha = 0.5; // Make leaderboard panel fully opaque (0% transparent) panel.alpha = 1.0; // Bring leaderboard to front layer if (self.parent) { var parent = self.parent; parent.removeChild(self); parent.addChild(self); } }; // Hide leaderboard self.hide = function () { self.visible = false; // Resume the game when leaderboard is hidden gameActive = true; // Restore game area opacity game.alpha = 1.0; }; // Update scores display self.updateScores = function (scores) { // Clear existing score entries while (scoresContainer.children.length > 0) { scoresContainer.removeChildAt(0); } // Add score entries for (var i = 0; i < scores.length; i++) { var entry = scores[i]; var yPos = i * 120; // Rank var rank = new Text2(i + 1 + '.', { size: 80, fill: 0xFFFFFF }); rank.anchor.set(1, 0); rank.x = -600; rank.y = yPos; scoresContainer.addChild(rank); // Username var username = entry.username || "Player"; var usernameText = new Text2(username, { size: 60, fill: 0xFFFFFF }); usernameText.anchor.set(0, 0); usernameText.x = -500; usernameText.y = yPos; scoresContainer.addChild(usernameText); // Score value var scoreText = new Text2(entry.score.toString(), { size: 80, fill: 0xFFF200 // Brighter yellow color for better visibility }); scoreText.anchor.set(0, 0); scoreText.x = 0; scoreText.y = yPos; scoresContainer.addChild(scoreText); } // Add message if no scores if (scores.length === 0) { var noScores = new Text2("No scores yet!", { size: 80, fill: 0x00FFFF //{3Y} // Bright cyan color for better visibility }); noScores.anchor.set(0.5, 0); noScores.y = 100; scoresContainer.addChild(noScores); } }; return self; }); var LeaderboardButton = Container.expand(function () { var self = Container.call(this); // Create button background var buttonBg = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 400, height: 120 }); buttonBg.tint = 0x3498db; // Create button text that says LEADERBOARD var buttonText = new Text2('LEADERBOARD', { size: 60, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); // Button interaction self.down = function (x, y, obj) { // Scale down effect on press tween(self, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100 }); // Toggle leaderboard visibility if (leaderboard && leaderboard.visible) { leaderboard.hide(); } else { showLeaderboard(); } }; self.up = function (x, y, obj) { // Scale back to normal on release tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); }; return self; }); var LifeFruit = Container.expand(function () { var self = Container.call(this); self.type = 'lifefruit'; self.sliced = false; self.width = 320; self.height = 320; self.points = 0; self.baseSpeed = 1.5; // Create a white fruit with heart shape for extra life var lifeGraphics = self.attachAsset('kiwi', { anchorX: 0.5, anchorY: 0.5 }); lifeGraphics.tint = 0xFFFFFF; // White color for life fruit var heartShape = self.attachAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 120, height: 120 }); heartShape.tint = 0xFF0000; self.vx = 0; self.vy = 0; self.gravity = 0.01; self.rotationSpeed = (Math.random() - 0.5) * 0.015; self.init = function (x, y, direction) { self.x = x; self.y = y; var angle = direction * (Math.PI / 4) + Math.random() * Math.PI / 8 - Math.PI / 16; var speed = self.baseSpeed + Math.random() * 0.8; self.vx = Math.cos(angle) * speed * 1.15; self.vy = -Math.sin(angle) * speed - 8; }; self.slice = function () { if (self.sliced) { return; } self.sliced = true; // Add an extra life playerLives = Math.min(playerLives + 1, 5); // Cap at maximum 5 lives updateLivesDisplay(); // Flash effect lifeGraphics.tint = 0xFFFFFF; heartShape.tint = 0xFFFFFF; tween(lifeGraphics, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { lifeGraphics.tint = 0xFFFFFF; heartShape.tint = 0xFF0000; } }); // Play slice and squash sounds LK.getSound('slice').play(); LK.getSound('squash').play(); }; self.down = function (x, y, obj) { if (!self.sliced) { self.slice(); // Update combo comboCount++; comboTimer = Date.now() + comboTimeout; } }; self.update = function () { // Don't update movement if gameActive is false (leaderboard is visible) if (!gameActive) { return; } if (!self.sliced) { // Update whole fruit // Apply bullet time effect if active (slow down by 75%) var speedMultiplier = bulletTimeActive ? 0.25 : 1; self.vy += self.gravity * speedMultiplier; self.x += self.vx * speedMultiplier; self.y += self.vy * speedMultiplier; self.rotation += self.rotationSpeed * speedMultiplier; // Bounce off walls if not sliced if (self.x < self.width / 2 && self.vx < 0) { self.vx = -self.vx * 0.8; self.x = self.width / 2; } if (self.x > GAME_WIDTH - self.width / 2 && self.vx > 0) { self.vx = -self.vx * 0.8; self.x = GAME_WIDTH - self.width / 2; } } }; self.isOffScreen = function () { return self.y > 2732 + self.height || self.x > GAME_WIDTH + self.width; }; return self; }); var PlayAreaBoundary = Container.expand(function (isTop) { var self = Container.call(this); var line = self.attachAsset('blade', { anchorX: 0, anchorY: 0.5, width: GAME_WIDTH, height: 10 }); line.tint = 0xFFFFFF; line.alpha = 0.7; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x3498DB }); /**** * Game Code ****/ // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var SPAWN_INTERVAL_MIN = 1000; // Decreased spawn interval minimum for more frequent spawning var SPAWN_INTERVAL_MAX = 2000; // Decreased spawn interval maximum for more frequent spawning var SPAWN_COUNT_MIN = 1; var SPAWN_COUNT_MAX = 2; // Increased to spawn more fruits at once var FRUIT_TYPES = ['watermelon', 'apple', 'orange', 'kiwi', 'strawberry', 'passion_fruit']; var BOSS_FRUIT_TYPES = ['strawberry', 'kiwi', 'orange', 'apple', 'passion_fruit']; // Boss type matches newest fruit type introduced in each level var LEVEL_THRESHOLDS = [5, 50, 150, 300, 450]; // Score thresholds for each level boss var LEVEL_FRUITS = [['strawberry'], // Level 1 fruits ['strawberry', 'kiwi'], // Level 2 fruits ['strawberry', 'kiwi', 'orange'], // Level 3 fruits ['strawberry', 'kiwi', 'orange', 'apple'], // Level 4 fruits ['strawberry', 'kiwi', 'orange', 'apple', 'watermelon'] // Level 5 fruits ]; var BOMB_PROBABILITY = 0.2; // Increased bomb probability // Game variables var fruits = []; var blade = null; // Boss-related variables var boss = null; var bossActivated = false; var slicedFruitsInLevel = 0; // Track how many fruits sliced in current level for boss activation var bossFlashed = false; // Track if boss has been flashed in current level // Bullet time variables var bulletTimeActive = false; var bulletTimeEndTime = 0; var bulletTimeBar; // Progress bar for bullet time var bulletTimeDuration = 10000; // 10 seconds // Level tracking var currentLevel = 1; var nextLevelNotified = false; var showingLevelText = false; var levelTextTimer = 0; var levelText; // Level notification text var levelDisplay; // Text to display current level // Spawn timers var lastSpawnTime = 0; var nextSpawnTime = 0; // Combo system var comboCount = 0; var comboTimer = 0; var comboTimeout = 1000; // ms to reset combo var comboTxt; // Text to display combo // Player state var gameActive = true; var playerLives = 3; // Player starts with 3 lives var heartsDisplay; // Container for heart icons var missedFruits = 0; // Counter for missed fruits var missedText; // Text to display missed count var lifeFruitSpawned = 0; // Track how many life fruits we've spawned // Score-related var scoreTxt; // Text to display score var highScore = storage.highScore || 0; // Get high score from storage or default to 0 var highScoreText; // Text to display high score // Leaderboard var leaderboardButton; // Button to open leaderboard var leaderboard; // Leaderboard UI component // Parse leaderboard scores from storage or use empty array if none exists var leaderboardScores = []; if (storage.leaderboardScores) { var scoresArray = storage.leaderboardScores.split(';'); for (var i = 0; i < scoresArray.length; i++) { if (scoresArray[i]) { var parts = scoresArray[i].split(','); var scoreObj = { score: parseInt(parts[0]) }; if (parts.length > 1) { scoreObj.username = parts[1]; } leaderboardScores.push(scoreObj); } } } // Global leaderboard data var playerName = storage.playerName || "Player"; // Get saved player name or use default // UI elements var scoreTxt; var comboTxt; function setupGame() { // Prompt for player name if not already stored if (!storage.playerName) { var defaultName = "Player"; // Skip popup for now and just use default name // LK.showPopup is not available in the current version storage.playerName = defaultName; playerName = defaultName; } // Create blade blade = game.addChild(new Blade()); // Create boss reference but don't create the actual boss instance yet // We'll create it only when needed for the boss fight boss = null; // Set up score display scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF, weight: 'bold' // Make text bold }); scoreTxt.anchor.set(0.5, 0); scoreTxt.y = 30; LK.gui.top.addChild(scoreTxt); // Set up combo display comboTxt = new Text2('', { size: 60, fill: 0xFFFF00 }); comboTxt.anchor.set(0.5, 0); comboTxt.y = 140; comboTxt.alpha = 0; LK.gui.top.addChild(comboTxt); // Set up level text display levelText = new Text2('Level 1', { size: 120, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0.5); levelText.x = GAME_WIDTH / 2; levelText.y = GAME_HEIGHT / 2; levelText.alpha = 0; game.addChild(levelText); // Add level display to top right levelDisplay = new Text2('Level: 1', { size: 100, fill: 0xFFFFFF, weight: 'bold' // Make text bold }); levelDisplay.anchor.set(1, 0); levelDisplay.x = GAME_WIDTH - 50; // Right justified 50px from right wall levelDisplay.y = 100; game.addChild(levelDisplay); // Initialize missed counter missedFruits = 0; // Initialize the missed counter display through the dedicated function updateMissedCounter(); // Set up high score display highScoreText = new Text2('Your High Score: ' + highScore, { size: 60, fill: 0xFFFFFF }); highScoreText.anchor.set(0, 1); highScoreText.x = 50; highScoreText.y = -30; // Position at the bottom, moved 20 pixels below LK.gui.bottomLeft.addChild(highScoreText); // Create bullet time bar (initially hidden) bulletTimeBar = new Container(); bulletTimeBar.x = GAME_WIDTH / 2; bulletTimeBar.y = 280; // Moved 80px down from the top bulletTimeBar.visible = false; game.addChild(bulletTimeBar); // Bullet time bar background var bulletTimeBarBg = LK.getAsset('blade', { anchorX: 0.5, anchorY: 0.5, width: 1000, height: 30 }); bulletTimeBarBg.tint = 0x333333; // Bullet time bar fill var bulletTimeBarFill = LK.getAsset('blade', { anchorX: 0, anchorY: 0.5, width: 1000, height: 30 }); bulletTimeBarFill.tint = 0x00BFFF; // Match bullet time powerup color bulletTimeBarFill.x = -500; // Center the bar // Bullet time text var bulletTimeText = new Text2('BULLET TIME', { size: 60, fill: 0xFFFFFF }); bulletTimeText.anchor.set(0.5, 0.5); bulletTimeText.y = -60; // Add elements to bullet time bar bulletTimeBar.addChild(bulletTimeBarBg); bulletTimeBar.addChild(bulletTimeBarFill); bulletTimeBar.addChild(bulletTimeText); bulletTimeBar.barFill = bulletTimeBarFill; // Store reference to the fill for updates // Create hearts display for lives heartsDisplay = new Container(); heartsDisplay.x = GAME_WIDTH - 100; // Right justified 100px from right wall heartsDisplay.y = 250; // 250px from top game.addChild(heartsDisplay); // Add initial hearts (3 lives) updateLivesDisplay(); // Set up leaderboard button leaderboardButton = new LeaderboardButton(); leaderboardButton.x = GAME_WIDTH - 250; // Moved 30px to the left (from 220 to 250) leaderboardButton.y = GAME_HEIGHT - 100; game.addChild(leaderboardButton); // Create and position leaderboard UI leaderboard = new Leaderboard(); leaderboard.x = GAME_WIDTH / 2; leaderboard.y = GAME_HEIGHT / 2; leaderboard.visible = false; game.addChild(leaderboard); // Set initial spawn time nextSpawnTime = Date.now() + Math.random() * (SPAWN_INTERVAL_MAX - SPAWN_INTERVAL_MIN) + SPAWN_INTERVAL_MIN; // Special level 1 powerup spawning removed // Play background music LK.playMusic('gameMusic'); // Reset all game state currentLevel = 1; bossActivated = false; nextLevelNotified = false; LK.setScore(0); missedFruits = 0; playerLives = 3; // Reset lives to 3 lifeFruitSpawned = 0; // Reset life fruit spawn counter slicedFruitsInLevel = 0; // Reset sliced fruits counter comboCount = 0; // Reset combo counter comboTimer = 0; // Reset combo timer // Add play area boundary lines var topBoundary = new PlayAreaBoundary(true); topBoundary.y = 320; // Position 320px from the top game.addChild(topBoundary); var bottomBoundary = new PlayAreaBoundary(false); bottomBoundary.y = GAME_HEIGHT - 200; // Position 200px from the bottom game.addChild(bottomBoundary); // Show level 1 text at start showLevelText(1); } // Function to display level text and reset level-specific state function showLevelText(level) { // Set level text content levelText.setText('Level ' + level); levelText.alpha = 0; showingLevelText = true; // Reset level-specific counters missedFruits = 0; updateMissedCounter(); slicedFruitsInLevel = 0; // Reset boss state for new level bossActivated = false; bossFlashed = false; // Reset boss flash state for new level // Reset bullet time bulletTimeActive = false; bulletTimeBar.visible = false; // Update level display in top right levelDisplay.setText('Level: ' + level); // Animate the level text tween(levelText, { alpha: 1 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Hold the text visible for a moment levelTextTimer = Date.now() + 2000; } }); } function spawnFruits() { var count = currentLevel === 1 ? Math.ceil((Math.floor(Math.random() * (SPAWN_COUNT_MAX - SPAWN_COUNT_MIN + 1)) + SPAWN_COUNT_MIN) / 2) : // 50% reduction for level 1 Math.floor(Math.random() * (SPAWN_COUNT_MAX - SPAWN_COUNT_MIN + 1)) + SPAWN_COUNT_MIN; // Get appropriate fruit types for current level var availableFruits = LEVEL_FRUITS[currentLevel - 1] || ['strawberry']; // Check if we should spawn a life fruit based on the current level var spawnLifeFruit = false; var spawnBulletTime = false; var spawnBlitz = false; var maxLifeFruits = currentLevel; if (currentLevel === 4) { maxLifeFruits = 5; // Level 4 gets 5 life fruits (increased from 3) } // Level 4 gets 5 life fruits if (currentLevel === 1) { maxLifeFruits = 3; // Level 1 gets 3 life fruits } else if (currentLevel === 3) { maxLifeFruits = 5; // Level 3 gets 5 life fruits } // Increase spawn chances for level 3, 4 and 5 if (lifeFruitSpawned < maxLifeFruits && Math.random() < (currentLevel === 3 ? 0.2 : currentLevel === 4 ? 0.2 : currentLevel === 5 ? 0.25 : 0.1)) { // 25% chance to spawn a life fruit in level 5, 20% chance in level 3 and level 4, 10% in other levels spawnLifeFruit = true; lifeFruitSpawned++; } else if (!bulletTimeActive && Math.random() < (currentLevel === 3 ? 0.12 : currentLevel === 4 ? 0.15 : currentLevel === 5 ? 0.2 : 0.05)) { // 20% chance to spawn bullet time powerup in level 5, 15% in level 4, 12% in level 3, 5% in other levels spawnBulletTime = true; } else if (Math.random() < (currentLevel === 1 ? 0.12 : currentLevel === 3 ? 0.12 : currentLevel === 4 ? 0.15 : currentLevel === 5 ? 0.2 : 0.05)) { // 20% chance to spawn blitz powerup in level 5, 15% in level 4, 12% in level 1 and level 3, 5% in other levels spawnBlitz = true; } // Loop through and create fruits for (var i = 0; i < count; i++) { var fruit; // Create life fruit if it's time if (i === 0 && spawnLifeFruit) { fruit = new LifeFruit(); } else if (i === 0 && spawnBulletTime) { fruit = new BulletTimePowerup(); } else if (i === 0 && spawnBlitz) { fruit = new BlitzPowerup(); } else { var isBomb = Math.random() < BOMB_PROBABILITY; var type = isBomb ? 'bomb' : availableFruits[Math.floor(Math.random() * availableFruits.length)]; fruit = new Fruit(type); } // Determine flight pattern var pattern = Math.random(); if (pattern < 0.5) { // Horizontal flight from left to right var x = -fruit.width; var y = Math.random() * (GAME_HEIGHT / 3) + 300; // Higher position range fruit.x = x; fruit.y = y; fruit.vx = fruit.baseSpeed + Math.random() * 2.5; // Slightly faster fruit.vy = -Math.random() * 2; // Add slight upward movement } else { // Vertical drop var x = Math.random() * (GAME_WIDTH - 200) + 100; var direction = Math.random(); // Random direction between 0 and 1 fruit.init(x, GAME_HEIGHT, direction); } game.addChild(fruit); fruits.push(fruit); } // Schedule next spawn with appropriate delay based on level // Level 1, 2, & 3: 30% shorter delay // Level 4+: normal delay var delayMultiplier = 1; if (currentLevel === 1) { delayMultiplier = 0.8; // 20% shorter delay for level 1 } else if (currentLevel === 2 || currentLevel === 3) { delayMultiplier = 0.7; // 30% shorter delay for level 2 and 3 } nextSpawnTime = Date.now() + delayMultiplier * (Math.random() * (SPAWN_INTERVAL_MAX - SPAWN_INTERVAL_MIN) + SPAWN_INTERVAL_MIN); } function updateCombo() { if (comboCount > 1) { comboTxt.setText('COMBO x' + comboCount + '!'); comboTxt.alpha = 1; // Add combo bonus points LK.setScore(LK.getScore() + comboCount * 2); // Play combo sound LK.getSound('combo').play(); // Animate combo text tween(comboTxt, { alpha: 0 }, { duration: 1000, easing: tween.easeOut }); } comboCount = 0; } function handleBladeCollisions() { // Return early if the blade isn't active or doesn't have enough points to form a line if (!blade.active || blade.points.length < 2) { return; } // Process multiple segments for more accurate detection var segmentsToCheck = Math.min(5, blade.points.length - 1); // Check multiple segments of the blade for better sensitivity var hitFruits = {}; var hitBoss = false; for (var j = 0; j < segmentsToCheck; j++) { var startPoint = blade.points[j]; var endPoint = blade.points[j + 1]; // Check boss collision if active if (boss && boss.active && !hitBoss && lineIntersectsCircle(startPoint.x, startPoint.y, endPoint.x, endPoint.y, boss.x, boss.y, boss.width / 3)) { // Hit the boss var defeated = boss.hit(); // Play slice and squash sounds LK.getSound('slice').play(); LK.getSound('squash').play(); // Update combo comboCount++; comboTimer = Date.now() + comboTimeout; hitBoss = true; } // Check collisions with fruits for (var i = 0; i < fruits.length; i++) { var fruit = fruits[i]; if (!fruit.sliced && !hitFruits[i] && lineIntersectsCircle(startPoint.x, startPoint.y, endPoint.x, endPoint.y, fruit.x, fruit.y, fruit.width / 2)) { hitFruits[i] = true; if (fruit.type === 'bomb') { // Lose a life when hitting a bomb LK.getSound('explosion').play(); LK.effects.flashScreen(0xFF0000, 500); playerLives--; // Reduce lives by 1 updateLivesDisplay(); // Update hearts display // If no lives left, game over if (playerLives <= 0) { // Update high score if current score is higher if (LK.getScore() > highScore) { highScore = LK.getScore(); storage.highScore = highScore; } // Add score to global leaderboard addScoreToLeaderboard(LK.getScore()); // Pass the current score and high score to game over display LK.showGameOver({ score: LK.getScore(), highScore: highScore }); } break; // Exit the inner loop since we hit a bomb } } // Handle life fruit else if (fruit.type === 'lifefruit') { // Slice the life fruit and gain an extra life fruit.slice(); // Play a special sound LK.getSound('combo').play(); // Flash green for the extra life LK.effects.flashScreen(0x00FF00, 300); // Update combo comboCount++; comboTimer = Date.now() + comboTimeout; } else { // Slice regular fruit var points = fruit.slice(); LK.setScore(LK.getScore() + points); scoreTxt.setText(LK.getScore()); // Increment sliced fruits counter for current level slicedFruitsInLevel++; // Play slice sound LK.getSound('slice').play(); // Update combo comboCount++; comboTimer = Date.now() + comboTimeout; } } } } function lineIntersectsCircle(x1, y1, x2, y2, cx, cy, r) { // Increase detection radius by 30% to make blade more sensitive r = r * 1.3; // Find the closest point on the line segment to the circle center var dx = x2 - x1; var dy = y2 - y1; var len = Math.sqrt(dx * dx + dy * dy); // Normalize direction vector dx /= len; dy /= len; // Vector from line start to circle center var vx = cx - x1; var vy = cy - y1; // Project this vector onto the line direction var projection = vx * dx + vy * dy; // Clamp projection to line segment projection = Math.max(0, Math.min(len, projection)); // Find the closest point on the line segment var closestX = x1 + projection * dx; var closestY = y1 + projection * dy; // Check if this point is within the circle var distanceSquared = (cx - closestX) * (cx - closestX) + (cy - closestY) * (cy - closestY); return distanceSquared <= r * r; } // Show the leaderboard UI function showLeaderboard() { if (leaderboard) { leaderboard.show(leaderboardScores); } } // Update the hearts display based on current lives function updateLivesDisplay() { // Clear existing hearts while (heartsDisplay.children.length > 0) { heartsDisplay.removeChildAt(0); } // Add new hearts based on current lives for (var i = 0; i < playerLives; i++) { var heart = new Heart(); heart.x = -i * 80; // Space hearts horizontally from right to left heartsDisplay.addChild(heart); } // Update the missed counter updateMissedCounter(); } // Dedicated function to update missed fruits counter and its color function updateMissedCounter() { // Determine color based on missed count var missedColor; if (missedFruits <= 3) { missedColor = 0x00FF00; // Green for 0-3 misses } else if (missedFruits <= 6) { missedColor = 0xFFA500; // Orange for 4-6 misses } else { missedColor = 0xFF0000; // Red for 7-10 misses } // Remove old text from parent if it exists if (missedText && missedText.parent) { missedText.parent.removeChild(missedText); } // Create new Text2 with the appropriate color missedText = new Text2('Missed: ' + missedFruits + '/10', { size: 100, fill: missedColor, // Apply the color based on missed count weight: 'bold' // Make text bold }); missedText.anchor.set(1, 0); missedText.x = GAME_WIDTH - 50; missedText.y = 10; game.addChild(missedText); } // Activate bullet time effect function activateBulletTime() { bulletTimeActive = true; bulletTimeEndTime = Date.now() + bulletTimeDuration; bulletTimeBar.visible = true; // Flash screen blue to indicate bullet time activation LK.effects.flashScreen(0x00BFFF, 500); // Play a sound LK.getSound('combo').play(); } // Update bullet time progress bar function updateBulletTime() { if (!bulletTimeActive) { return; } var currentTime = Date.now(); var remaining = bulletTimeEndTime - currentTime; if (remaining <= 0) { // Bullet time has ended bulletTimeActive = false; bulletTimeBar.visible = false; return; } // Update progress bar var progress = remaining / bulletTimeDuration; bulletTimeBar.barFill.width = 1000 * progress; } // Add a score to the leaderboard function addScoreToLeaderboard(score) { // Only add score if it's greater than 0 if (score <= 0) { return; } // Add new score to leaderboard with Upit username or 'Anon' var username = LK.getUptUsername ? LK.getUptUsername() : 'Anon'; leaderboardScores.push({ score: score, username: username }); // Sort leaderboard by score (highest first) leaderboardScores.sort(function (a, b) { return b.score - a.score; }); // Limit to top 10 scores if (leaderboardScores.length > 10) { leaderboardScores = leaderboardScores.slice(0, 10); } // Save to storage - convert to simple string format to avoid undefined JSON error var scoresString = ''; for (var i = 0; i < leaderboardScores.length; i++) { scoresString += leaderboardScores[i].score + "," + (leaderboardScores[i].username || "Player"); if (i < leaderboardScores.length - 1) { scoresString += ';'; } } storage.leaderboardScores = scoresString; } ; // Game update function game.update = function () { // Don't update game state if game is paused (leaderboard is shown) if (!gameActive) { return; } var currentTime = Date.now(); // Handle level text animation if (showingLevelText && currentTime > levelTextTimer && levelText.alpha > 0) { tween(levelText, { alpha: 0 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { showingLevelText = false; } }); } // Check if we should flash the boss at 80% into the level (4 fruits sliced out of 5) if (currentLevel >= 1 && currentLevel <= 5 && slicedFruitsInLevel >= 4 && !bossFlashed && !bossActivated) { var _doMultipleFlashes = function doMultipleFlashes(flashCount) { if (flashCount <= 0) { tempBoss.destroy(); return; } // Flash in tween(tempBoss, { alpha: 1 }, { duration: 250, // Half second total per flash (250ms in, 250ms out) easing: tween.easeOut, onFinish: function onFinish() { // Flash out tween(tempBoss, { alpha: 0 }, { duration: 250, // Half second total per flash (250ms in, 250ms out) easing: tween.easeIn, onFinish: function onFinish() { // Continue with next flash _doMultipleFlashes(flashCount - 1); } }); } }); }; // Start the sequence with 3 flashes bossFlashed = true; // Create a temporary boss image for flashing var tempBoss = new Boss(currentLevel); tempBoss.x = GAME_WIDTH / 2; tempBoss.y = GAME_HEIGHT / 2; tempBoss.alpha = 0; game.addChild(tempBoss); // Function to perform multiple boss flashes _doMultipleFlashes(3); } // Check if we should activate the boss fight based on fruit count // All levels: After 5 sliced fruits consistently var shouldActivateBoss = false; if (currentLevel >= 1 && currentLevel <= 5) { shouldActivateBoss = slicedFruitsInLevel >= 5 && !bossActivated && !nextLevelNotified; } else { // Fallback for any future levels beyond 5 shouldActivateBoss = LK.getScore() >= LEVEL_THRESHOLDS[currentLevel - 1] && !bossActivated && !nextLevelNotified; } if (currentLevel <= 5 && shouldActivateBoss) { bossActivated = true; // Create a new boss for the current level if (boss) { boss.destroy(); } boss = game.addChild(new Boss(currentLevel)); boss.activate(); // Clear existing fruits during boss transition for (var i = fruits.length - 1; i >= 0; i--) { fruits[i].destroy(); fruits.splice(i, 1); } } // Only spawn normal fruits if we're not in a boss fight if (currentTime >= nextSpawnTime && (!bossActivated || !boss.active)) { spawnFruits(); } // Update all fruits for (var i = fruits.length - 1; i >= 0; i--) { var fruit = fruits[i]; fruit.update(); // Remove fruits that are off-screen if (fruit.isOffScreen()) { // Only count missed fruits that aren't bombs or already sliced if (!fruit.sliced && fruit.type !== 'bomb') { missedFruits++; // Update the missed counter with new value and color updateMissedCounter(); // If 10 fruits are missed, lose a life and reset miss counter if (missedFruits >= 10) { LK.effects.flashScreen(0xFF0000, 500); playerLives--; // Reduce lives by 1 updateLivesDisplay(); // Update hearts display missedFruits = 0; // Reset missed fruits counter updateMissedCounter(); // Update missed counter display // Only show game over if no lives left if (playerLives <= 0) { // Update high score if current score is higher if (LK.getScore() > highScore) { highScore = LK.getScore(); storage.highScore = highScore; } // Add score to global leaderboard addScoreToLeaderboard(LK.getScore()); // Pass the current score and high score to game over display LK.showGameOver({ score: LK.getScore(), highScore: highScore }); } } } fruit.destroy(); fruits.splice(i, 1); } } // Check for blade collisions handleBladeCollisions(); // Update blade blade.update(); // Update boss if active if (boss && boss.active) { boss.update(1 / 60); // Pass approximate delta time } // If boss was defeated, move to next level if (bossActivated && boss && !boss.active) { bossActivated = false; nextLevelNotified = false; // Move to next level if we haven't reached level 5 yet if (currentLevel < 5) { currentLevel++; // Show level notification showLevelText(currentLevel); } else if (currentLevel === 5) { // Player has beaten all levels LK.effects.flashScreen(0x00FF00, 800); // Show "You Win" screen after completing all levels if (LK.getScore() > highScore) { highScore = LK.getScore(); storage.highScore = highScore; } // Add score to global leaderboard addScoreToLeaderboard(LK.getScore()); // Show you win screen LK.showYouWin({ score: LK.getScore(), highScore: highScore }); } } // Check combo timer if (comboCount > 0 && Date.now() > comboTimer) { updateCombo(); } // Update bullet time effect if (bulletTimeActive) { updateBulletTime(); } }; // Handle touch/mouse events game.down = function (x, y, obj) { blade.active = true; blade.reset(); blade.addPoint(x, y); }; game.move = function (x, y, obj) { if (blade.active) { blade.addPoint(x, y); handleBladeCollisions(); } }; game.up = function (x, y, obj) { blade.active = false; }; // Start the game setupGame();
===================================================================
--- original.js
+++ change.js
@@ -382,12 +382,14 @@
fruit.vy = Math.sin(angle) * speed;
game.addChild(fruit);
fruits.push(fruit);
}
- // For level 5, level 1, or level 2, also spawn random fruits
- if (self.level === 5 || self.level === 1 || self.level === 2) {
+ // For level 5, level 1, level 2, or level 3, also spawn random fruits
+ if (self.level === 5 || self.level === 1 || self.level === 2 || self.level === 3) {
// Level 2 boss spawns fewer fruits (1-2 instead of 2-3)
- var fruitCount = self.level === 2 ? Math.floor(Math.random() * 2) + 1 : self.level === 5 || self.level === 1 ? Math.floor(Math.random() * 2) : 0;
+ var fruitCount = self.level === 2 ? Math.floor(Math.random() * 2) + 1 : self.level === 3 ? Math.floor(Math.random() * 3) + 2 :
+ // Level 3 boss: 2-4 fruits
+ self.level === 5 || self.level === 1 ? Math.floor(Math.random() * 2) : 0;
for (var j = 0; j < fruitCount; j++) {
// Select a random fruit type
// For level 1, only use level 1 fruits (strawberry)
// For level 2, use level 2 fruits (strawberry, kiwi)
@@ -399,10 +401,8 @@
} else if (self.level === 2) {
availableFruits = ['strawberry', 'kiwi']; // Level 2 fruits
} else if (self.level === 3) {
availableFruits = ['strawberry', 'kiwi', 'orange']; // Level 3 fruits
- // Spawn more fruits for level 3 boss
- fruitCount = Math.floor(Math.random() * 3) + 2; // Level 3 boss: 2-4 fruits
} else if (self.level === 4) {
availableFruits = ['strawberry', 'kiwi', 'orange', 'apple']; // Level 4 fruits
// Spawn more fruits for level 4 boss
fruitCount = Math.floor(Math.random() * 3) + 3; // Level 4 boss: 3-5 fruits
red bomb. In-Game asset. 2d. High contrast. No shadows
Head of pepe meme. each face shaped as a marble shaped face made in blender 3D. In-Game asset. 2d. High contrast. No shadows
Head of doge meme. face shaped as a marble shaped face made in blender 3D. In-Game asset. 2d. High contrast. No shadows
Head of troll face meme. face shaped as a marble shaped face made in blender 3D. In-Game asset. 2d. High contrast. No shadows
Head of think smart guy meme. face shaped as a marble shaped face made in blender 3D. In-Game asset. 2d. High contrast. No shadows
Head of white y u no meme. face shaped as a marble shaped face made in blender 3D. In-Game asset. 2d. High contrast. No shadows
Explosion. In-Game asset. 2d. High contrast. No shadows
Clock. In-Game asset. 3d. High contrast. No shadows
Red Heart. In-Game asset. 3d. High contrast. No shadows
gattling gun. In-Game asset. 2d. High contrast. No shadows