/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Fruit = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'fruit_red'; self.isBomb = self.type === 'bomb'; self.isSpecial = self.type === 'fruit_special'; var fruitGraphics = self.attachAsset(self.type, { anchorX: 0.5, anchorY: 0.5 }); self.sliced = false; self.speed = { x: Math.random() * 10 - 5, y: -(Math.random() * 15) - 10 }; self.gravity = 0.3; self.rotationSpeed = Math.random() * 0.1 - 0.05; self.update = function () { // Store last position for tracking self.lastX = self.x; self.lastY = self.y; if (self.sliced) return; // Apply gravity self.speed.y += self.gravity; // Update position self.x += self.speed.x; self.y += self.speed.y; // Rotate the fruit self.rotation += self.rotationSpeed; // Check if out of bounds if (self.y > 2732 + 100 || self.x < -100 || self.x > 2048 + 100) { self.outOfBounds = true; } }; self.slice = function () { if (self.sliced) return false; self.sliced = true; // Visual effect for slicing fruitGraphics.alpha = 0.5; fruitGraphics.scaleX = 1.2; fruitGraphics.scaleY = 0.8; // Create split effect with two halves if (!self.isBomb) { // Create two halves of the fruit var leftHalf = self.attachAsset(self.type, { anchorX: 0.5, anchorY: 0.5, x: -20, scaleX: 0.8 }); var rightHalf = self.attachAsset(self.type, { anchorX: 0.5, anchorY: 0.5, x: 20, scaleX: 0.8 }); // Animate the halves falling apart tween(leftHalf, { x: -50, y: 50, rotation: -0.3 }, { duration: 500 }); tween(rightHalf, { x: 50, y: 50, rotation: 0.3 }, { duration: 500 }); // Hide the original fruit fruitGraphics.alpha = 0; // Add juice particles var fruitColor; switch (self.type) { case 'fruit_red': fruitColor = 0xFF0000; break; case 'fruit_green': fruitColor = 0x00FF00; break; case 'fruit_yellow': fruitColor = 0xFFFF00; break; case 'fruit_purple': fruitColor = 0x8A2BE2; break; case 'fruit_special': fruitColor = 0xFFD700; break; default: fruitColor = 0xFF0000; } // Create 8-10 particles var particleCount = 8 + Math.floor(Math.random() * 3); for (var i = 0; i < particleCount; i++) { var particle = new Particle(fruitColor); particle.x = self.x; particle.y = self.y; game.addChild(particle); } } // Play sound if (self.isBomb) { LK.getSound('bomb').play(); } else if (self.isSpecial) { LK.getSound('special').play(); } else { LK.getSound('slice').play(); } // Start tween to fade out tween(self, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { self.destroy(); } }); return true; }; return self; }); var Particle = Container.expand(function (color) { var self = Container.call(this); // Create particle based on color var particleGraphics = self.attachAsset('fruit_red', { // Using fruit asset for juice anchorX: 0.5, anchorY: 0.5, scaleX: 0.2, scaleY: 0.2 }); // Set the color tint of the particle particleGraphics.tint = color || 0xFF0000; // Set random movement properties self.speed = { x: (Math.random() - 0.5) * 8, y: (Math.random() - 0.5) * 8 }; self.gravity = 0.2; self.life = 400 + Math.random() * 300; self.update = function () { // Apply gravity self.speed.y += self.gravity; // Update position self.x += self.speed.x; self.y += self.speed.y; // Reduce life self.life -= 16.67; // Fade out as life decreases self.alpha = self.life / 700; // Remove when life is over if (self.life <= 0) { self.destroy(); } }; return self; }); var Slash = Container.expand(function () { var self = Container.call(this); var slashGraphics = self.attachAsset('slash', { anchorX: 0.5, anchorY: 0.5 }); self.life = 300; // Slash display time in ms self.setup = function (startX, startY, endX, endY) { // Position at start point self.x = startX; self.y = startY; // Calculate angle for rotation var angle = Math.atan2(endY - startY, endX - startX); self.rotation = angle; // Calculate length based on start and end points var length = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2)); slashGraphics.width = Math.max(50, length); }; self.update = function () { self.life -= 16.67; // Approximately 16.67ms per frame at 60fps if (self.life <= 0) { self.alpha = 0; self.destroy(); } else { self.alpha = self.life / 300; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game variables var fruits = []; var slashes = []; var swipeStart = null; var score = 0; var comboCount = 0; var comboTimer = 0; var lastSpawnTime = 0; var spawnInterval = 1000; // Time in ms between fruit spawns var level = 1; var gameActive = true; var missedFruits = 0; var maxMissedFruits = 3; // Set game background to a nice sky blue game.setBackgroundColor(0x3366CC); // Create score text var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 50; // Create combo text var comboTxt = new Text2('', { size: 80, fill: 0xFFFF00 }); comboTxt.anchor.set(0.5, 0); LK.gui.top.addChild(comboTxt); comboTxt.y = 180; comboTxt.alpha = 0; // Level indicator var levelTxt = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); LK.gui.topRight.addChild(levelTxt); levelTxt.x = -200; levelTxt.y = 50; // Missed fruits counter var missedTxt = new Text2('❌ 0/' + maxMissedFruits, { size: 60, fill: 0xFF0000 }); missedTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(missedTxt); missedTxt.x = 120; // Keep away from top-left menu icon missedTxt.y = 50; // Game swipe handlers game.down = function (x, y) { swipeStart = { x: x, y: y }; }; game.move = function (x, y) { if (swipeStart && gameActive) { // Calculate distance between current position and start var dx = x - swipeStart.x; var dy = y - swipeStart.y; var distance = Math.sqrt(dx * dx + dy * dy); // Only create a slash if the swipe is long enough if (distance > 50) { var slash = new Slash(); slash.setup(swipeStart.x, swipeStart.y, x, y); slashes.push(slash); game.addChild(slash); // Check for fruit collisions along the swipe path var slicedFruits = 0; var bombSliced = false; // Simple line-circle collision for each fruit fruits.forEach(function (fruit) { if (fruit.sliced) return; // Check if fruit is near the line segment of the swipe var fruitHit = lineCircleCollision(swipeStart.x, swipeStart.y, x, y, fruit.x, fruit.y, fruit.children[0].width / 2); if (fruitHit) { if (fruit.slice()) { if (fruit.isBomb) { bombSliced = true; } else { slicedFruits++; // Award points var pointsAwarded = fruit.isSpecial ? 25 : 10; // Apply combo bonus if (comboTimer > 0) { comboCount++; pointsAwarded = Math.floor(pointsAwarded * (1 + comboCount * 0.1)); } else { comboCount = 1; } // Reset combo timer comboTimer = 1000; // Update score score += pointsAwarded; scoreTxt.setText(score); // Show combo text if (comboCount > 1) { comboTxt.setText(comboCount + "x COMBO!"); comboTxt.alpha = 1; tween(comboTxt, { alpha: 0 }, { duration: 800 }); } // Check for level up var newLevel = Math.floor(score / 100) + 1; if (newLevel > level) { level = newLevel; levelTxt.setText("Level: " + level); // Increase spawn rate with level spawnInterval = Math.max(400, 1000 - (level - 1) * 100); } } } } }); // Game over if bomb sliced if (bombSliced) { gameActive = false; // Flash screen red LK.effects.flashScreen(0xff0000, 1000); // Show game over LK.setTimeout(function () { LK.showGameOver(); }, 1000); } // Update swipe start for continuous swiping swipeStart = { x: x, y: y }; } } }; game.up = function () { swipeStart = null; }; // Collision detection between line (swipe) and circle (fruit) function lineCircleCollision(x1, y1, x2, y2, cx, cy, r) { // Calculate vector from start to end of swipe var lineVecX = x2 - x1; var lineVecY = y2 - y1; // Calculate vector from start to circle center var startToCenterX = cx - x1; var startToCenterY = cy - y1; // Calculate dot product var dotProduct = (startToCenterX * lineVecX + startToCenterY * lineVecY) / (lineVecX * lineVecX + lineVecY * lineVecY); // Clamp dot product to [0,1] to get point on line segment dotProduct = Math.max(0, Math.min(1, dotProduct)); // Find nearest point on line to circle center var nearestX = x1 + dotProduct * lineVecX; var nearestY = y1 + dotProduct * lineVecY; // Calculate distance from nearest point to circle center var distance = Math.sqrt(Math.pow(nearestX - cx, 2) + Math.pow(nearestY - cy, 2)); // Check if distance is less than circle radius return distance <= r; } // Random fruit generator function spawnFruit() { // Determine the fruit type to spawn var types = ['fruit_red', 'fruit_green', 'fruit_yellow', 'fruit_purple']; // Add special fruit with lower probability if (Math.random() < 0.1) { types.push('fruit_special'); } // Add bombs with increasing probability based on level var bombChance = Math.min(0.3, 0.05 + (level - 1) * 0.02); if (Math.random() < bombChance) { types.push('bomb'); } // Randomly select a type var type = types[Math.floor(Math.random() * types.length)]; // Create and position the fruit var fruit = new Fruit(type); // Set random starting position at bottom of screen fruit.x = Math.random() * 1848 + 100; // Keep away from edges fruit.y = 2732 + 50; // Start below screen // Add to game fruits.push(fruit); game.addChild(fruit); // For higher levels, spawn multiple fruits sometimes if (level > 2 && Math.random() < 0.3) { LK.setTimeout(function () { spawnFruit(); }, 200); } } // Game update loop game.update = function () { if (!gameActive) return; // Update combo timer if (comboTimer > 0) { comboTimer -= 16.67; // Approximate ms per frame at 60fps if (comboTimer <= 0) { comboCount = 0; } } // Spawn fruits var currentTime = Date.now(); if (currentTime - lastSpawnTime > spawnInterval) { spawnFruit(); lastSpawnTime = currentTime; } // Update fruits for (var i = fruits.length - 1; i >= 0; i--) { var fruit = fruits[i]; // Remove fruits that are out of bounds or destroyed if (fruit.outOfBounds || fruit.destroyed) { // Count missed fruits (only if not sliced and not a bomb) if (!fruit.sliced && !fruit.isBomb && fruit.outOfBounds && fruit.y > 2732) { missedFruits++; missedTxt.setText('❌ ' + missedFruits + '/' + maxMissedFruits); // Game over if too many fruits missed if (missedFruits >= maxMissedFruits && gameActive) { gameActive = false; LK.effects.flashScreen(0xFF0000, 1000); LK.setTimeout(function () { LK.showGameOver(); }, 1000); } } fruits.splice(i, 1); continue; } } // Update slashes for (var j = slashes.length - 1; j >= 0; j--) { var slash = slashes[j]; // Remove destroyed slashes if (slash.destroyed) { slashes.splice(j, 1); } } }; // Start game LK.playMusic('gameMusic');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Fruit = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'fruit_red';
self.isBomb = self.type === 'bomb';
self.isSpecial = self.type === 'fruit_special';
var fruitGraphics = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
self.sliced = false;
self.speed = {
x: Math.random() * 10 - 5,
y: -(Math.random() * 15) - 10
};
self.gravity = 0.3;
self.rotationSpeed = Math.random() * 0.1 - 0.05;
self.update = function () {
// Store last position for tracking
self.lastX = self.x;
self.lastY = self.y;
if (self.sliced) return;
// Apply gravity
self.speed.y += self.gravity;
// Update position
self.x += self.speed.x;
self.y += self.speed.y;
// Rotate the fruit
self.rotation += self.rotationSpeed;
// Check if out of bounds
if (self.y > 2732 + 100 || self.x < -100 || self.x > 2048 + 100) {
self.outOfBounds = true;
}
};
self.slice = function () {
if (self.sliced) return false;
self.sliced = true;
// Visual effect for slicing
fruitGraphics.alpha = 0.5;
fruitGraphics.scaleX = 1.2;
fruitGraphics.scaleY = 0.8;
// Create split effect with two halves
if (!self.isBomb) {
// Create two halves of the fruit
var leftHalf = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5,
x: -20,
scaleX: 0.8
});
var rightHalf = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5,
x: 20,
scaleX: 0.8
});
// Animate the halves falling apart
tween(leftHalf, {
x: -50,
y: 50,
rotation: -0.3
}, {
duration: 500
});
tween(rightHalf, {
x: 50,
y: 50,
rotation: 0.3
}, {
duration: 500
});
// Hide the original fruit
fruitGraphics.alpha = 0;
// Add juice particles
var fruitColor;
switch (self.type) {
case 'fruit_red':
fruitColor = 0xFF0000;
break;
case 'fruit_green':
fruitColor = 0x00FF00;
break;
case 'fruit_yellow':
fruitColor = 0xFFFF00;
break;
case 'fruit_purple':
fruitColor = 0x8A2BE2;
break;
case 'fruit_special':
fruitColor = 0xFFD700;
break;
default:
fruitColor = 0xFF0000;
}
// Create 8-10 particles
var particleCount = 8 + Math.floor(Math.random() * 3);
for (var i = 0; i < particleCount; i++) {
var particle = new Particle(fruitColor);
particle.x = self.x;
particle.y = self.y;
game.addChild(particle);
}
}
// Play sound
if (self.isBomb) {
LK.getSound('bomb').play();
} else if (self.isSpecial) {
LK.getSound('special').play();
} else {
LK.getSound('slice').play();
}
// Start tween to fade out
tween(self, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
return true;
};
return self;
});
var Particle = Container.expand(function (color) {
var self = Container.call(this);
// Create particle based on color
var particleGraphics = self.attachAsset('fruit_red', {
// Using fruit asset for juice
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.2
});
// Set the color tint of the particle
particleGraphics.tint = color || 0xFF0000;
// Set random movement properties
self.speed = {
x: (Math.random() - 0.5) * 8,
y: (Math.random() - 0.5) * 8
};
self.gravity = 0.2;
self.life = 400 + Math.random() * 300;
self.update = function () {
// Apply gravity
self.speed.y += self.gravity;
// Update position
self.x += self.speed.x;
self.y += self.speed.y;
// Reduce life
self.life -= 16.67;
// Fade out as life decreases
self.alpha = self.life / 700;
// Remove when life is over
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
var Slash = Container.expand(function () {
var self = Container.call(this);
var slashGraphics = self.attachAsset('slash', {
anchorX: 0.5,
anchorY: 0.5
});
self.life = 300; // Slash display time in ms
self.setup = function (startX, startY, endX, endY) {
// Position at start point
self.x = startX;
self.y = startY;
// Calculate angle for rotation
var angle = Math.atan2(endY - startY, endX - startX);
self.rotation = angle;
// Calculate length based on start and end points
var length = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2));
slashGraphics.width = Math.max(50, length);
};
self.update = function () {
self.life -= 16.67; // Approximately 16.67ms per frame at 60fps
if (self.life <= 0) {
self.alpha = 0;
self.destroy();
} else {
self.alpha = self.life / 300;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game variables
var fruits = [];
var slashes = [];
var swipeStart = null;
var score = 0;
var comboCount = 0;
var comboTimer = 0;
var lastSpawnTime = 0;
var spawnInterval = 1000; // Time in ms between fruit spawns
var level = 1;
var gameActive = true;
var missedFruits = 0;
var maxMissedFruits = 3;
// Set game background to a nice sky blue
game.setBackgroundColor(0x3366CC);
// Create score text
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
// Create combo text
var comboTxt = new Text2('', {
size: 80,
fill: 0xFFFF00
});
comboTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(comboTxt);
comboTxt.y = 180;
comboTxt.alpha = 0;
// Level indicator
var levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(levelTxt);
levelTxt.x = -200;
levelTxt.y = 50;
// Missed fruits counter
var missedTxt = new Text2('❌ 0/' + maxMissedFruits, {
size: 60,
fill: 0xFF0000
});
missedTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(missedTxt);
missedTxt.x = 120; // Keep away from top-left menu icon
missedTxt.y = 50;
// Game swipe handlers
game.down = function (x, y) {
swipeStart = {
x: x,
y: y
};
};
game.move = function (x, y) {
if (swipeStart && gameActive) {
// Calculate distance between current position and start
var dx = x - swipeStart.x;
var dy = y - swipeStart.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Only create a slash if the swipe is long enough
if (distance > 50) {
var slash = new Slash();
slash.setup(swipeStart.x, swipeStart.y, x, y);
slashes.push(slash);
game.addChild(slash);
// Check for fruit collisions along the swipe path
var slicedFruits = 0;
var bombSliced = false;
// Simple line-circle collision for each fruit
fruits.forEach(function (fruit) {
if (fruit.sliced) return;
// Check if fruit is near the line segment of the swipe
var fruitHit = lineCircleCollision(swipeStart.x, swipeStart.y, x, y, fruit.x, fruit.y, fruit.children[0].width / 2);
if (fruitHit) {
if (fruit.slice()) {
if (fruit.isBomb) {
bombSliced = true;
} else {
slicedFruits++;
// Award points
var pointsAwarded = fruit.isSpecial ? 25 : 10;
// Apply combo bonus
if (comboTimer > 0) {
comboCount++;
pointsAwarded = Math.floor(pointsAwarded * (1 + comboCount * 0.1));
} else {
comboCount = 1;
}
// Reset combo timer
comboTimer = 1000;
// Update score
score += pointsAwarded;
scoreTxt.setText(score);
// Show combo text
if (comboCount > 1) {
comboTxt.setText(comboCount + "x COMBO!");
comboTxt.alpha = 1;
tween(comboTxt, {
alpha: 0
}, {
duration: 800
});
}
// Check for level up
var newLevel = Math.floor(score / 100) + 1;
if (newLevel > level) {
level = newLevel;
levelTxt.setText("Level: " + level);
// Increase spawn rate with level
spawnInterval = Math.max(400, 1000 - (level - 1) * 100);
}
}
}
}
});
// Game over if bomb sliced
if (bombSliced) {
gameActive = false;
// Flash screen red
LK.effects.flashScreen(0xff0000, 1000);
// Show game over
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Update swipe start for continuous swiping
swipeStart = {
x: x,
y: y
};
}
}
};
game.up = function () {
swipeStart = null;
};
// Collision detection between line (swipe) and circle (fruit)
function lineCircleCollision(x1, y1, x2, y2, cx, cy, r) {
// Calculate vector from start to end of swipe
var lineVecX = x2 - x1;
var lineVecY = y2 - y1;
// Calculate vector from start to circle center
var startToCenterX = cx - x1;
var startToCenterY = cy - y1;
// Calculate dot product
var dotProduct = (startToCenterX * lineVecX + startToCenterY * lineVecY) / (lineVecX * lineVecX + lineVecY * lineVecY);
// Clamp dot product to [0,1] to get point on line segment
dotProduct = Math.max(0, Math.min(1, dotProduct));
// Find nearest point on line to circle center
var nearestX = x1 + dotProduct * lineVecX;
var nearestY = y1 + dotProduct * lineVecY;
// Calculate distance from nearest point to circle center
var distance = Math.sqrt(Math.pow(nearestX - cx, 2) + Math.pow(nearestY - cy, 2));
// Check if distance is less than circle radius
return distance <= r;
}
// Random fruit generator
function spawnFruit() {
// Determine the fruit type to spawn
var types = ['fruit_red', 'fruit_green', 'fruit_yellow', 'fruit_purple'];
// Add special fruit with lower probability
if (Math.random() < 0.1) {
types.push('fruit_special');
}
// Add bombs with increasing probability based on level
var bombChance = Math.min(0.3, 0.05 + (level - 1) * 0.02);
if (Math.random() < bombChance) {
types.push('bomb');
}
// Randomly select a type
var type = types[Math.floor(Math.random() * types.length)];
// Create and position the fruit
var fruit = new Fruit(type);
// Set random starting position at bottom of screen
fruit.x = Math.random() * 1848 + 100; // Keep away from edges
fruit.y = 2732 + 50; // Start below screen
// Add to game
fruits.push(fruit);
game.addChild(fruit);
// For higher levels, spawn multiple fruits sometimes
if (level > 2 && Math.random() < 0.3) {
LK.setTimeout(function () {
spawnFruit();
}, 200);
}
}
// Game update loop
game.update = function () {
if (!gameActive) return;
// Update combo timer
if (comboTimer > 0) {
comboTimer -= 16.67; // Approximate ms per frame at 60fps
if (comboTimer <= 0) {
comboCount = 0;
}
}
// Spawn fruits
var currentTime = Date.now();
if (currentTime - lastSpawnTime > spawnInterval) {
spawnFruit();
lastSpawnTime = currentTime;
}
// Update fruits
for (var i = fruits.length - 1; i >= 0; i--) {
var fruit = fruits[i];
// Remove fruits that are out of bounds or destroyed
if (fruit.outOfBounds || fruit.destroyed) {
// Count missed fruits (only if not sliced and not a bomb)
if (!fruit.sliced && !fruit.isBomb && fruit.outOfBounds && fruit.y > 2732) {
missedFruits++;
missedTxt.setText('❌ ' + missedFruits + '/' + maxMissedFruits);
// Game over if too many fruits missed
if (missedFruits >= maxMissedFruits && gameActive) {
gameActive = false;
LK.effects.flashScreen(0xFF0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
fruits.splice(i, 1);
continue;
}
}
// Update slashes
for (var j = slashes.length - 1; j >= 0; j--) {
var slash = slashes[j];
// Remove destroyed slashes
if (slash.destroyed) {
slashes.splice(j, 1);
}
}
};
// Start game
LK.playMusic('gameMusic');
Bomb . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
watermelon . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Grape. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Tomato. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Apple Green. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Blade Power . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Peach. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat