User prompt
Add a new Level 5 with a new fruit and new boss. Let boss appear after 50 fruit slashes by user
User prompt
Let level 4 boss appear after user slashes 40 fruits in level 4
User prompt
Let level 3 boss appear after user slashes 30 fruits in level 3
User prompt
Let level 2 boss appear after user slashes 20 fruits in level 2
User prompt
Let level 2 boss appear after user slashes 10 fruits in level 2
User prompt
Let level 1 boss appear after user slashes 10 fruits in level 1
User prompt
when player misses 10 fruits, remove a life and reset the missed balls counterinstead of directly ending the game. Game only ends when all lives have been exhausted by player
User prompt
Reset mossed count when a new level starts
User prompt
Make leaderboard background color navy blue
User prompt
Please fix the bug: 'TypeError: self.parent is undefined' in or related to this line: 'self.parent.addChild(self);' Line Number: 475
User prompt
Put leaderboard in Front layer when visible
User prompt
Make leaderboard 0% transparent
User prompt
Make game area behind leaderboard 50% transparent when leaderboard is visible
User prompt
Make leaderboard in front layer and fully opaque when it is being viewed
User prompt
Make the leaaderboard 100% opaque when it is being viewed
User prompt
Please fix the bug: 'TypeError: self.parent.swapChildren is not a function' in or related to this line: 'self.parent.swapChildren(self, self.parent.children[self.parent.children.length - 1]);' Line Number: 473
User prompt
When leaderboard is open, put it in the frontmost layer and make the play area 50% transparent
User prompt
Close the leaderboard if the leaderboard button isclicked while the leaderboard is visible
User prompt
Make the fruits freeze and stop wherever they are while the leaderboard is visible
User prompt
Pause game when global leaderboard is being viewed
User prompt
Spawn it once in level 1, twice in level 2, twice in level 3 and thrice in level 4
User prompt
Color the life fruit white and make it appear twice in level 2
User prompt
Add new life power up fruit. Make it appear once in level one. Tapping give an extra life
User prompt
Increase it from 310 to 320
User prompt
Move the top horizontal line 10 pixels lower
/****
* 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 = 10;
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 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 = 3000 - self.level * 250; // Attacks more frequently with higher levels
// 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: 4,
scaleY: 4
});
// 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 = 2 + self.level * 0.5; // Speed increases with level
self.targetX = GAME_WIDTH / 2;
self.activate = function () {
self.active = true;
self.health = self.maxHealth;
self.x = GAME_WIDTH / 2;
self.y = GAME_HEIGHT / 3;
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 = Math.floor(Math.random() * self.level) + 1; // More bombs at higher levels
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 = 3 + Math.random() * 2 + self.level * 0.5; // Faster bombs at higher levels
fruit.vx = Math.cos(angle) * speed;
fruit.vy = Math.sin(angle) * speed;
game.addChild(fruit);
fruits.push(fruit);
}
};
self.update = function (delta) {
if (!self.active) {
return;
}
// 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;
// Attack on timer
var currentTime = Date.now();
if (currentTime >= self.attackTimer) {
self.throwFruit();
self.attackTimer = currentTime + self.attackInterval;
}
};
self.down = function (x, y, obj) {
// Allow clicking on boss to damage it
if (self.active) {
self.hit();
}
};
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 = 480;
self.height = 480;
self.points = 5;
self.baseSpeed = 1.6; // Faster base speed
break;
case 'apple':
self.width = 360;
self.height = 360;
self.points = 4;
self.baseSpeed = 1.7; // Faster base speed
break;
case 'orange':
self.width = 320;
self.height = 320;
self.points = 3;
self.baseSpeed = 1.8; // Faster base speed
break;
case 'kiwi':
self.width = 240;
self.height = 240;
self.points = 2;
self.baseSpeed = 2.0; // Faster base speed
break;
case 'strawberry':
self.width = 200;
self.height = 200;
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
var speed = (self.baseSpeed + Math.random() * 0.8) * levelMultiplier; // Further reduced random speed component
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 || self.type === 'bomb') {
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 sound
LK.getSound('slice').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
// 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());
// 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; // 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 = 0x2c3e50;
panel.alpha = 0.9;
// 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: 0xFFD700
});
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: 0xFFFFFF
});
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 = 240;
self.height = 240;
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 sound
LK.getSound('slice').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 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'];
var BOSS_FRUIT_TYPES = ['strawberry', 'kiwi', 'orange', 'apple']; // Boss fruit for each level
var LEVEL_THRESHOLDS = [5, 50, 150, 300]; // 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
];
var BOMB_PROBABILITY = 0.2; // Increased bomb probability
// Game variables
var fruits = [];
var blade = null;
var boss = null;
var lastSpawnTime = 0;
var nextSpawnTime = 0;
var gameActive = true;
var comboCount = 0;
var comboTimer = 0;
var comboTimeout = 1000; // ms to reset combo
var currentLevel = 1;
var bossActivated = false;
var nextLevelNotified = false;
var showingLevelText = false;
var levelTextTimer = 0;
var levelText; // Level notification text
var missedFruits = 0; // Counter for missed fruits
var missedText; // Text to display missed count
var highScore = storage.highScore || 0; // Get high score from storage or default to 0
var highScoreText; // Text to display high score
var leaderboardButton; // Button to open leaderboard
var leaderboard; // Leaderboard UI component
var playerLives = 3; // Player starts with 3 lives
var heartsDisplay; // Container for heart icons
var lifeFruitSpawned = 0; // Track how many life fruits we've spawned
// 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 but don't activate it yet
boss = game.addChild(new Boss(currentLevel));
// 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 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 - 220;
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;
// Play background music
LK.playMusic('gameMusic');
// Reset level tracking
currentLevel = 1;
bossActivated = false;
nextLevelNotified = false;
LK.setScore(0);
missedFruits = 0;
playerLives = 3; // Reset lives to 3
lifeFruitSpawned = 0; // Reset life fruit spawn counter
// 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
function showLevelText(level) {
levelText.setText('Level ' + level);
levelText.alpha = 0;
showingLevelText = true;
// Reset missed fruits counter when new level starts
missedFruits = 0;
updateMissedCounter();
// 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 = 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 maxLifeFruits = currentLevel;
if (currentLevel === 4) {
maxLifeFruits = 3;
} // Level 4 gets 3 life fruits
if (lifeFruitSpawned < maxLifeFruits && Math.random() < 0.1) {
// 10% chance to spawn a life fruit
spawnLifeFruit = true;
lifeFruitSpawned++;
}
// 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 {
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
nextSpawnTime = Date.now() + 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() {
if (!blade.active || blade.points.length < 2) {
return;
}
var startPoint = blade.points[0];
var endPoint = blade.points[1];
// Check boss collision if active
if (boss && boss.active && 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 sound
LK.getSound('slice').play();
// Update combo
comboCount++;
comboTimer = Date.now() + comboTimeout;
}
for (var i = 0; i < fruits.length; i++) {
var fruit = fruits[i];
if (!fruit.sliced && lineIntersectsCircle(startPoint.x, startPoint.y, endPoint.x, endPoint.y, fruit.x, fruit.y, fruit.width / 2)) {
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
});
}
return;
}
// 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());
// Play slice sound
LK.getSound('slice').play();
// Update combo
comboCount++;
comboTimer = Date.now() + comboTimeout;
}
}
}
}
function lineIntersectsCircle(x1, y1, x2, y2, cx, cy, r) {
// 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);
}
// 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 activate the boss fight based on score or fruit count
// Level 1: After 10 sliced fruits
// Level 2: After 20 sliced fruits
// Levels 3-4: Based on score thresholds
var shouldActivateBoss = false;
if (currentLevel === 1) {
shouldActivateBoss = LK.getScore() >= 10 && !bossActivated && !nextLevelNotified;
} else if (currentLevel === 2) {
shouldActivateBoss = LK.getScore() >= 20 && !bossActivated && !nextLevelNotified;
} else {
shouldActivateBoss = LK.getScore() >= LEVEL_THRESHOLDS[currentLevel - 1] && !bossActivated && !nextLevelNotified;
}
if (currentLevel <= 4 && 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 4 yet
if (currentLevel < 4) {
currentLevel++;
// Show level notification
showLevelText(currentLevel);
} else if (currentLevel === 4) {
// 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();
}
};
// 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
@@ -1122,13 +1122,15 @@
});
}
// Check if we should activate the boss fight based on score or fruit count
// Level 1: After 10 sliced fruits
- // Level 2: After 10 sliced fruits
+ // Level 2: After 20 sliced fruits
// Levels 3-4: Based on score thresholds
var shouldActivateBoss = false;
- if (currentLevel === 1 || currentLevel === 2) {
+ if (currentLevel === 1) {
shouldActivateBoss = LK.getScore() >= 10 && !bossActivated && !nextLevelNotified;
+ } else if (currentLevel === 2) {
+ shouldActivateBoss = LK.getScore() >= 20 && !bossActivated && !nextLevelNotified;
} else {
shouldActivateBoss = LK.getScore() >= LEVEL_THRESHOLDS[currentLevel - 1] && !bossActivated && !nextLevelNotified;
}
if (currentLevel <= 4 && shouldActivateBoss) {
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