/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ExplosionPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('explosionPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.gravity = 0.2;
self.lastY = 0;
self.update = function () {
if (!isGamePaused) {
self.lastY = self.y;
self.x += self.speedX;
self.y += self.speedY;
self.speedY += self.gravity;
self.rotation += 0.05;
// Bounce off walls
if (self.x <= 60) {
self.x = 60;
self.speedX = Math.abs(self.speedX);
} else if (self.x >= 1988) {
self.x = 1988;
self.speedX = -Math.abs(self.speedX);
}
}
};
return self;
});
var FreezePowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('freezePowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.gravity = 0.2;
self.lastY = 0;
self.update = function () {
if (!isGamePaused) {
self.lastY = self.y;
self.x += self.speedX;
self.y += self.speedY;
self.speedY += self.gravity;
self.rotation += 0.05;
// Bounce off walls
if (self.x <= 60) {
self.x = 60;
self.speedX = Math.abs(self.speedX);
} else if (self.x >= 1988) {
self.x = 1988;
self.speedX = -Math.abs(self.speedX);
}
}
};
return self;
});
var Fruit = Container.expand(function (fruitType) {
var self = Container.call(this);
self.fruitType = fruitType || 'pineapple';
var fruitGraphics = self.attachAsset(self.fruitType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.gravity = 0.3;
self.sliced = false;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
if (!self.sliced && !isFrozen && !isGamePaused) {
self.lastX = self.x;
self.lastY = self.y;
self.x += self.speedX;
self.y += self.speedY;
// Check if fruit reached the top of the screen and apply natural falling physics
if (self.speedY < 0 && self.y <= 0) {
self.y = 0; // Keep fruit at top boundary
self.speedY = 0; // Reset velocity to start natural fall
// Add slight bounce effect with tween for more natural motion
tween(self, {
speedY: 2
}, {
duration: 100,
easing: tween.easeOut
});
}
// Check horizontal boundaries and bounce off walls
if (self.x <= 0) {
self.x = 0;
self.speedX = Math.abs(self.speedX); // Bounce right
} else if (self.x >= 2048) {
self.x = 2048;
self.speedX = -Math.abs(self.speedX); // Bounce left
}
// Remove bottom boundary collision - let fruits fall through
// Fruits can now fall off the bottom of the screen naturally
self.speedY += self.gravity; // Apply gravity to make fruits fall
}
};
return self;
});
var FruitPiece = Container.expand(function (fruitType) {
var self = Container.call(this);
self.fruitType = fruitType || 'pineapple';
var pieceAsset = self.fruitType + 'Piece';
var pieceGraphics = self.attachAsset(pieceAsset, {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.gravity = 0.5;
self.life = 60;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.speedY += self.gravity;
self.rotation += 0.1;
// Keep pieces within screen boundaries
if (self.x <= 0) {
self.x = 0;
self.speedX = Math.abs(self.speedX) * 0.8; // Bounce with damping
} else if (self.x >= 2048) {
self.x = 2048;
self.speedX = -Math.abs(self.speedX) * 0.8; // Bounce with damping
}
if (self.y >= 2732) {
self.y = 2732;
self.speedY = -Math.abs(self.speedY) * 0.6; // Bounce with more damping
}
self.life--;
if (self.life <= 0) {
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.toDestroy = true;
}
});
}
};
return self;
});
var SwipeLine = Container.expand(function () {
var self = Container.call(this);
var lineGraphics = self.attachAsset('swipeLine', {
anchorX: 0.5,
anchorY: 0
});
self.life = 10;
self.update = function () {
self.life--;
self.alpha = self.life / 10;
if (self.life <= 0) {
self.toDestroy = true;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var fruits = [];
var fruitPieces = [];
var swipeLines = [];
var freezePowerUps = [];
var explosionPowerUps = [];
var lives = 3;
var combo = 0;
var multiplier = 1;
var spawnTimer = 0;
var spawnRate = 40;
var gameSpeed = 1;
var isGameOver = false;
var lastScoreCheckpoint = 0; // Track score milestones for increasing sustain
var powerUpSpawnTimer = 0;
var isFrozen = false;
var freezeTimer = 0;
var isGamePaused = false;
var isMusicOn = true;
// Swiping variables
var isSwipeDown = false;
var lastSwipeX = 0;
var lastSwipeY = 0;
var activeTouch = null;
// UI
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var livesTxt = new Text2('Lives: 3', {
size: 60,
fill: 0xFF6B6B
});
livesTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(livesTxt);
var comboTxt = new Text2('', {
size: 50,
fill: 0xFFD700
});
comboTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(comboTxt);
var musicBtn = new Text2('♪', {
size: 80,
fill: 0xFFFFFF
});
musicBtn.anchor.set(1, 0);
musicBtn.x = -20;
musicBtn.y = 80;
LK.gui.topRight.addChild(musicBtn);
function updateUI() {
scoreTxt.setText('Score: ' + LK.getScore());
livesTxt.setText('Lives: ' + lives);
if (combo > 1) {
comboTxt.setText('Combo x' + multiplier);
comboTxt.x = 120;
} else {
comboTxt.setText('');
}
// Update music button display
musicBtn.setText(isMusicOn ? '♪' : '♪̸');
musicBtn.alpha = isMusicOn ? 1.0 : 0.5;
}
function toggleMusic() {
isMusicOn = !isMusicOn;
if (isMusicOn) {
LK.playMusic('ambientMusic');
} else {
LK.stopMusic();
}
updateUI();
}
function checkScoreProgression() {
var currentScore = LK.getScore();
// Check if we've reached a new 100-point milestone
if (Math.floor(currentScore / 100) > Math.floor(lastScoreCheckpoint / 100)) {
// Increase game sustain/difficulty with smaller increments
gameSpeed += 0.1; // Smaller increase to game speed
if (spawnRate > 15) {
spawnRate -= 1; // Smaller decrease to spawn rate (spawn fruits less frequently)
}
lastScoreCheckpoint = currentScore;
}
}
function spawnFruit() {
var fruitTypes = ['pineapple', 'apple', 'orange', 'watermelon'];
var randomIndex = Math.floor(Math.random() * fruitTypes.length);
var randomType = fruitTypes[randomIndex];
var fruit = new Fruit(randomType);
// Spawn from bottom of screen
fruit.x = Math.random() * 2048;
fruit.y = 2732 + 75;
// Give upward velocity with some horizontal variation
var upwardSpeed = -(25 + Math.random() * 15) * gameSpeed; // Negative for upward movement - much higher velocity
var horizontalSpeed = (Math.random() - 0.5) * 4 * gameSpeed; // Small horizontal drift
fruit.speedY = upwardSpeed;
fruit.speedX = horizontalSpeed;
fruit.lastX = fruit.x;
fruit.lastY = fruit.y;
fruits.push(fruit);
game.addChild(fruit);
}
function spawnFreezePowerUp() {
var powerUp = new FreezePowerUp();
powerUp.x = Math.random() * 1928 + 60; // Keep away from edges
powerUp.y = 2732 + 60;
var upwardSpeed = -(20 + Math.random() * 10);
var horizontalSpeed = (Math.random() - 0.5) * 3;
powerUp.speedY = upwardSpeed;
powerUp.speedX = horizontalSpeed;
powerUp.lastY = powerUp.y;
freezePowerUps.push(powerUp);
game.addChild(powerUp);
}
function spawnExplosionPowerUp() {
var powerUp = new ExplosionPowerUp();
powerUp.x = Math.random() * 1928 + 60; // Keep away from edges
powerUp.y = 2732 + 60;
var upwardSpeed = -(20 + Math.random() * 10);
var horizontalSpeed = (Math.random() - 0.5) * 3;
powerUp.speedY = upwardSpeed;
powerUp.speedX = horizontalSpeed;
powerUp.lastY = powerUp.y;
explosionPowerUps.push(powerUp);
game.addChild(powerUp);
}
function activateFreeze() {
isFrozen = true;
freezeTimer = 180; // 3 seconds at 60fps
// Flash screen blue to indicate freeze
LK.effects.flashScreen(0x00FFFF, 500);
}
function activateExplosion(x, y) {
// Flash screen orange to indicate explosion
LK.effects.flashScreen(0xFF4500, 500);
// Destroy all fruits on screen
for (var i = fruits.length - 1; i >= 0; i--) {
var fruit = fruits[i];
if (!fruit.sliced) {
sliceFruit(fruit);
}
}
}
function createFruitPieces(x, y, fruitType) {
for (var i = 0; i < 4; i++) {
var piece = new FruitPiece(fruitType);
piece.x = x + (Math.random() - 0.5) * 40;
piece.y = y + (Math.random() - 0.5) * 40;
piece.speedX = (Math.random() - 0.5) * 8;
piece.speedY = (Math.random() - 0.5) * 6 - 2;
piece.rotation = Math.random() * Math.PI * 2;
fruitPieces.push(piece);
game.addChild(piece);
}
}
function createSwipeLine(x1, y1, x2, y2) {
var distance = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
var steps = Math.floor(distance / 20);
for (var i = 0; i <= steps; i++) {
var t = i / steps;
var x = x1 + (x2 - x1) * t;
var y = y1 + (y2 - y1) * t;
var line = new SwipeLine();
line.x = x;
line.y = y;
line.rotation = Math.atan2(y2 - y1, x2 - x1) + Math.PI / 2;
swipeLines.push(line);
game.addChild(line);
}
}
function checkSwipeIntersection(x1, y1, x2, y2, fruit) {
var px = fruit.x;
var py = fruit.y;
var radius = 90;
// Distance from point to line segment
var A = px - x1;
var B = py - y1;
var C = x2 - x1;
var D = y2 - y1;
var dot = A * C + B * D;
var lenSq = C * C + D * D;
var param = lenSq !== 0 ? dot / lenSq : -1;
var xx, yy;
if (param < 0) {
xx = x1;
yy = y1;
} else if (param > 1) {
xx = x2;
yy = y2;
} else {
xx = x1 + param * C;
yy = y1 + param * D;
}
var dx = px - xx;
var dy = py - yy;
var distance = Math.sqrt(dx * dx + dy * dy);
return distance <= radius;
}
function sliceFruit(fruit) {
if (!fruit.sliced) {
fruit.sliced = true;
// Award points with combo multiplier
var points = 10 * multiplier;
LK.setScore(LK.getScore() + points);
// Increase combo
combo++;
if (combo >= 5) {
multiplier = 3;
} else if (combo >= 3) {
multiplier = 2;
} else {
multiplier = 1;
}
// Create pieces
createFruitPieces(fruit.x, fruit.y, fruit.fruitType);
// Play sound
LK.getSound('slice').play();
// Flash effect
LK.effects.flashObject(fruit, 0xFFFFFF, 200);
// Mark for destruction
fruit.toDestroy = true;
}
}
function loseFruit() {
lives--;
combo = 0;
multiplier = 1;
LK.getSound('miss').play();
LK.effects.flashScreen(0xFF0000, 300);
if (lives <= 0) {
isGameOver = true;
LK.showGameOver();
}
}
// Event handlers
game.down = function (x, y, obj) {
if (isGameOver) return;
// Check if music button was clicked - simple click detection in top right area
var musicBtnArea = {
x: 1900,
// Right side of screen
y: 80,
// Top area where button is positioned
width: 148,
height: 120
};
if (x >= musicBtnArea.x && x <= musicBtnArea.x + musicBtnArea.width && y >= musicBtnArea.y && y <= musicBtnArea.y + musicBtnArea.height) {
toggleMusic();
return;
}
// Only allow one finger - ignore if already swiping
if (isSwipeDown) return;
isSwipeDown = true;
activeTouch = obj && obj.event && obj.event.identifier !== undefined ? obj.event.identifier : 0; // Track the specific touch
lastSwipeX = x;
lastSwipeY = y;
};
game.move = function (x, y, obj) {
if (isGameOver || !isSwipeDown) return;
// Only respond to the same touch that initiated the swipe
var currentTouch = obj && obj.event && obj.event.identifier !== undefined ? obj.event.identifier : 0;
if (currentTouch !== activeTouch) return;
// Ensure we only track the same finger that started the swipe
var distance = Math.sqrt((x - lastSwipeX) * (x - lastSwipeX) + (y - lastSwipeY) * (y - lastSwipeY));
if (distance > 20) {
createSwipeLine(lastSwipeX, lastSwipeY, x, y);
// Check for fruit intersections
for (var i = 0; i < fruits.length; i++) {
var fruit = fruits[i];
if (!fruit.sliced && checkSwipeIntersection(lastSwipeX, lastSwipeY, x, y, fruit)) {
sliceFruit(fruit);
}
}
// Check for freeze power-up intersections
for (var i = 0; i < freezePowerUps.length; i++) {
var powerUp = freezePowerUps[i];
if (checkSwipeIntersection(lastSwipeX, lastSwipeY, x, y, powerUp)) {
activateFreeze();
powerUp.toDestroy = true;
}
}
// Check for explosion power-up intersections
for (var i = 0; i < explosionPowerUps.length; i++) {
var powerUp = explosionPowerUps[i];
if (checkSwipeIntersection(lastSwipeX, lastSwipeY, x, y, powerUp)) {
activateExplosion(powerUp.x, powerUp.y);
powerUp.toDestroy = true;
}
}
lastSwipeX = x;
lastSwipeY = y;
}
};
game.up = function (x, y, obj) {
// Only respond to the same touch that initiated the swipe
var currentTouch = obj && obj.event && obj.event.identifier !== undefined ? obj.event.identifier : 0;
if (currentTouch === activeTouch) {
isSwipeDown = false;
activeTouch = null;
}
};
// Main game loop
game.update = function () {
if (isGameOver) return;
// Handle freeze timer
if (isFrozen) {
freezeTimer--;
if (freezeTimer <= 0) {
isFrozen = false;
}
}
// Spawn power-ups occasionally (only when not paused and not frozen)
if (!isGamePaused && !isFrozen) {
powerUpSpawnTimer++;
if (powerUpSpawnTimer >= 600) {
// Every 10 seconds at 60fps
if (Math.random() < 0.5) {
spawnFreezePowerUp();
} else {
spawnExplosionPowerUp();
}
powerUpSpawnTimer = 0;
}
// Spawn fruits
spawnTimer++;
if (spawnTimer >= spawnRate) {
// Spawn fewer fruits for better gameplay
var fruitsToSpawn = 1; // Spawn only 1 fruit
for (var s = 0; s < fruitsToSpawn; s++) {
spawnFruit();
}
spawnTimer = 0;
// Increase difficulty over time - faster spawning
if (spawnRate > 25) {
spawnRate -= 1;
}
if (gameSpeed < 3) {
gameSpeed += 0.02;
}
}
}
// Update and check fruits
for (var i = fruits.length - 1; i >= 0; i--) {
var fruit = fruits[i];
if (fruit.toDestroy) {
fruit.destroy();
fruits.splice(i, 1);
continue;
}
// Only lose fruit if it falls off the bottom (increased threshold to allow natural falling)
if (!fruit.sliced && fruit.y > 3000) {
loseFruit();
fruit.destroy();
fruits.splice(i, 1);
}
}
// Update and clean up pieces
for (var i = fruitPieces.length - 1; i >= 0; i--) {
var piece = fruitPieces[i];
if (piece.toDestroy) {
piece.destroy();
fruitPieces.splice(i, 1);
}
}
// Update and clean up swipe lines
for (var i = swipeLines.length - 1; i >= 0; i--) {
var line = swipeLines[i];
if (line.toDestroy) {
line.destroy();
swipeLines.splice(i, 1);
}
}
// Update and clean up freeze power-ups
for (var i = freezePowerUps.length - 1; i >= 0; i--) {
var powerUp = freezePowerUps[i];
if (powerUp.toDestroy) {
powerUp.destroy();
freezePowerUps.splice(i, 1);
continue;
}
// Remove if falls off bottom (don't lose lives)
if (powerUp.y > 3000) {
powerUp.destroy();
freezePowerUps.splice(i, 1);
}
}
// Update and clean up explosion power-ups
for (var i = explosionPowerUps.length - 1; i >= 0; i--) {
var powerUp = explosionPowerUps[i];
if (powerUp.toDestroy) {
powerUp.destroy();
explosionPowerUps.splice(i, 1);
continue;
}
// Remove if falls off bottom (don't lose lives)
if (powerUp.y > 3000) {
powerUp.destroy();
explosionPowerUps.splice(i, 1);
}
}
updateUI();
checkScoreProgression(); // Check for score milestones and increase sustain
};
// Track game pause state
LK.on('pause', function () {
isGamePaused = true;
});
LK.on('resume', function () {
isGamePaused = false;
});
// Initialize UI
updateUI();
// Start ambient music at game start
LK.playMusic('ambientMusic'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ExplosionPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('explosionPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.gravity = 0.2;
self.lastY = 0;
self.update = function () {
if (!isGamePaused) {
self.lastY = self.y;
self.x += self.speedX;
self.y += self.speedY;
self.speedY += self.gravity;
self.rotation += 0.05;
// Bounce off walls
if (self.x <= 60) {
self.x = 60;
self.speedX = Math.abs(self.speedX);
} else if (self.x >= 1988) {
self.x = 1988;
self.speedX = -Math.abs(self.speedX);
}
}
};
return self;
});
var FreezePowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('freezePowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.gravity = 0.2;
self.lastY = 0;
self.update = function () {
if (!isGamePaused) {
self.lastY = self.y;
self.x += self.speedX;
self.y += self.speedY;
self.speedY += self.gravity;
self.rotation += 0.05;
// Bounce off walls
if (self.x <= 60) {
self.x = 60;
self.speedX = Math.abs(self.speedX);
} else if (self.x >= 1988) {
self.x = 1988;
self.speedX = -Math.abs(self.speedX);
}
}
};
return self;
});
var Fruit = Container.expand(function (fruitType) {
var self = Container.call(this);
self.fruitType = fruitType || 'pineapple';
var fruitGraphics = self.attachAsset(self.fruitType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.gravity = 0.3;
self.sliced = false;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
if (!self.sliced && !isFrozen && !isGamePaused) {
self.lastX = self.x;
self.lastY = self.y;
self.x += self.speedX;
self.y += self.speedY;
// Check if fruit reached the top of the screen and apply natural falling physics
if (self.speedY < 0 && self.y <= 0) {
self.y = 0; // Keep fruit at top boundary
self.speedY = 0; // Reset velocity to start natural fall
// Add slight bounce effect with tween for more natural motion
tween(self, {
speedY: 2
}, {
duration: 100,
easing: tween.easeOut
});
}
// Check horizontal boundaries and bounce off walls
if (self.x <= 0) {
self.x = 0;
self.speedX = Math.abs(self.speedX); // Bounce right
} else if (self.x >= 2048) {
self.x = 2048;
self.speedX = -Math.abs(self.speedX); // Bounce left
}
// Remove bottom boundary collision - let fruits fall through
// Fruits can now fall off the bottom of the screen naturally
self.speedY += self.gravity; // Apply gravity to make fruits fall
}
};
return self;
});
var FruitPiece = Container.expand(function (fruitType) {
var self = Container.call(this);
self.fruitType = fruitType || 'pineapple';
var pieceAsset = self.fruitType + 'Piece';
var pieceGraphics = self.attachAsset(pieceAsset, {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.gravity = 0.5;
self.life = 60;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.speedY += self.gravity;
self.rotation += 0.1;
// Keep pieces within screen boundaries
if (self.x <= 0) {
self.x = 0;
self.speedX = Math.abs(self.speedX) * 0.8; // Bounce with damping
} else if (self.x >= 2048) {
self.x = 2048;
self.speedX = -Math.abs(self.speedX) * 0.8; // Bounce with damping
}
if (self.y >= 2732) {
self.y = 2732;
self.speedY = -Math.abs(self.speedY) * 0.6; // Bounce with more damping
}
self.life--;
if (self.life <= 0) {
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.toDestroy = true;
}
});
}
};
return self;
});
var SwipeLine = Container.expand(function () {
var self = Container.call(this);
var lineGraphics = self.attachAsset('swipeLine', {
anchorX: 0.5,
anchorY: 0
});
self.life = 10;
self.update = function () {
self.life--;
self.alpha = self.life / 10;
if (self.life <= 0) {
self.toDestroy = true;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var fruits = [];
var fruitPieces = [];
var swipeLines = [];
var freezePowerUps = [];
var explosionPowerUps = [];
var lives = 3;
var combo = 0;
var multiplier = 1;
var spawnTimer = 0;
var spawnRate = 40;
var gameSpeed = 1;
var isGameOver = false;
var lastScoreCheckpoint = 0; // Track score milestones for increasing sustain
var powerUpSpawnTimer = 0;
var isFrozen = false;
var freezeTimer = 0;
var isGamePaused = false;
var isMusicOn = true;
// Swiping variables
var isSwipeDown = false;
var lastSwipeX = 0;
var lastSwipeY = 0;
var activeTouch = null;
// UI
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var livesTxt = new Text2('Lives: 3', {
size: 60,
fill: 0xFF6B6B
});
livesTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(livesTxt);
var comboTxt = new Text2('', {
size: 50,
fill: 0xFFD700
});
comboTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(comboTxt);
var musicBtn = new Text2('♪', {
size: 80,
fill: 0xFFFFFF
});
musicBtn.anchor.set(1, 0);
musicBtn.x = -20;
musicBtn.y = 80;
LK.gui.topRight.addChild(musicBtn);
function updateUI() {
scoreTxt.setText('Score: ' + LK.getScore());
livesTxt.setText('Lives: ' + lives);
if (combo > 1) {
comboTxt.setText('Combo x' + multiplier);
comboTxt.x = 120;
} else {
comboTxt.setText('');
}
// Update music button display
musicBtn.setText(isMusicOn ? '♪' : '♪̸');
musicBtn.alpha = isMusicOn ? 1.0 : 0.5;
}
function toggleMusic() {
isMusicOn = !isMusicOn;
if (isMusicOn) {
LK.playMusic('ambientMusic');
} else {
LK.stopMusic();
}
updateUI();
}
function checkScoreProgression() {
var currentScore = LK.getScore();
// Check if we've reached a new 100-point milestone
if (Math.floor(currentScore / 100) > Math.floor(lastScoreCheckpoint / 100)) {
// Increase game sustain/difficulty with smaller increments
gameSpeed += 0.1; // Smaller increase to game speed
if (spawnRate > 15) {
spawnRate -= 1; // Smaller decrease to spawn rate (spawn fruits less frequently)
}
lastScoreCheckpoint = currentScore;
}
}
function spawnFruit() {
var fruitTypes = ['pineapple', 'apple', 'orange', 'watermelon'];
var randomIndex = Math.floor(Math.random() * fruitTypes.length);
var randomType = fruitTypes[randomIndex];
var fruit = new Fruit(randomType);
// Spawn from bottom of screen
fruit.x = Math.random() * 2048;
fruit.y = 2732 + 75;
// Give upward velocity with some horizontal variation
var upwardSpeed = -(25 + Math.random() * 15) * gameSpeed; // Negative for upward movement - much higher velocity
var horizontalSpeed = (Math.random() - 0.5) * 4 * gameSpeed; // Small horizontal drift
fruit.speedY = upwardSpeed;
fruit.speedX = horizontalSpeed;
fruit.lastX = fruit.x;
fruit.lastY = fruit.y;
fruits.push(fruit);
game.addChild(fruit);
}
function spawnFreezePowerUp() {
var powerUp = new FreezePowerUp();
powerUp.x = Math.random() * 1928 + 60; // Keep away from edges
powerUp.y = 2732 + 60;
var upwardSpeed = -(20 + Math.random() * 10);
var horizontalSpeed = (Math.random() - 0.5) * 3;
powerUp.speedY = upwardSpeed;
powerUp.speedX = horizontalSpeed;
powerUp.lastY = powerUp.y;
freezePowerUps.push(powerUp);
game.addChild(powerUp);
}
function spawnExplosionPowerUp() {
var powerUp = new ExplosionPowerUp();
powerUp.x = Math.random() * 1928 + 60; // Keep away from edges
powerUp.y = 2732 + 60;
var upwardSpeed = -(20 + Math.random() * 10);
var horizontalSpeed = (Math.random() - 0.5) * 3;
powerUp.speedY = upwardSpeed;
powerUp.speedX = horizontalSpeed;
powerUp.lastY = powerUp.y;
explosionPowerUps.push(powerUp);
game.addChild(powerUp);
}
function activateFreeze() {
isFrozen = true;
freezeTimer = 180; // 3 seconds at 60fps
// Flash screen blue to indicate freeze
LK.effects.flashScreen(0x00FFFF, 500);
}
function activateExplosion(x, y) {
// Flash screen orange to indicate explosion
LK.effects.flashScreen(0xFF4500, 500);
// Destroy all fruits on screen
for (var i = fruits.length - 1; i >= 0; i--) {
var fruit = fruits[i];
if (!fruit.sliced) {
sliceFruit(fruit);
}
}
}
function createFruitPieces(x, y, fruitType) {
for (var i = 0; i < 4; i++) {
var piece = new FruitPiece(fruitType);
piece.x = x + (Math.random() - 0.5) * 40;
piece.y = y + (Math.random() - 0.5) * 40;
piece.speedX = (Math.random() - 0.5) * 8;
piece.speedY = (Math.random() - 0.5) * 6 - 2;
piece.rotation = Math.random() * Math.PI * 2;
fruitPieces.push(piece);
game.addChild(piece);
}
}
function createSwipeLine(x1, y1, x2, y2) {
var distance = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
var steps = Math.floor(distance / 20);
for (var i = 0; i <= steps; i++) {
var t = i / steps;
var x = x1 + (x2 - x1) * t;
var y = y1 + (y2 - y1) * t;
var line = new SwipeLine();
line.x = x;
line.y = y;
line.rotation = Math.atan2(y2 - y1, x2 - x1) + Math.PI / 2;
swipeLines.push(line);
game.addChild(line);
}
}
function checkSwipeIntersection(x1, y1, x2, y2, fruit) {
var px = fruit.x;
var py = fruit.y;
var radius = 90;
// Distance from point to line segment
var A = px - x1;
var B = py - y1;
var C = x2 - x1;
var D = y2 - y1;
var dot = A * C + B * D;
var lenSq = C * C + D * D;
var param = lenSq !== 0 ? dot / lenSq : -1;
var xx, yy;
if (param < 0) {
xx = x1;
yy = y1;
} else if (param > 1) {
xx = x2;
yy = y2;
} else {
xx = x1 + param * C;
yy = y1 + param * D;
}
var dx = px - xx;
var dy = py - yy;
var distance = Math.sqrt(dx * dx + dy * dy);
return distance <= radius;
}
function sliceFruit(fruit) {
if (!fruit.sliced) {
fruit.sliced = true;
// Award points with combo multiplier
var points = 10 * multiplier;
LK.setScore(LK.getScore() + points);
// Increase combo
combo++;
if (combo >= 5) {
multiplier = 3;
} else if (combo >= 3) {
multiplier = 2;
} else {
multiplier = 1;
}
// Create pieces
createFruitPieces(fruit.x, fruit.y, fruit.fruitType);
// Play sound
LK.getSound('slice').play();
// Flash effect
LK.effects.flashObject(fruit, 0xFFFFFF, 200);
// Mark for destruction
fruit.toDestroy = true;
}
}
function loseFruit() {
lives--;
combo = 0;
multiplier = 1;
LK.getSound('miss').play();
LK.effects.flashScreen(0xFF0000, 300);
if (lives <= 0) {
isGameOver = true;
LK.showGameOver();
}
}
// Event handlers
game.down = function (x, y, obj) {
if (isGameOver) return;
// Check if music button was clicked - simple click detection in top right area
var musicBtnArea = {
x: 1900,
// Right side of screen
y: 80,
// Top area where button is positioned
width: 148,
height: 120
};
if (x >= musicBtnArea.x && x <= musicBtnArea.x + musicBtnArea.width && y >= musicBtnArea.y && y <= musicBtnArea.y + musicBtnArea.height) {
toggleMusic();
return;
}
// Only allow one finger - ignore if already swiping
if (isSwipeDown) return;
isSwipeDown = true;
activeTouch = obj && obj.event && obj.event.identifier !== undefined ? obj.event.identifier : 0; // Track the specific touch
lastSwipeX = x;
lastSwipeY = y;
};
game.move = function (x, y, obj) {
if (isGameOver || !isSwipeDown) return;
// Only respond to the same touch that initiated the swipe
var currentTouch = obj && obj.event && obj.event.identifier !== undefined ? obj.event.identifier : 0;
if (currentTouch !== activeTouch) return;
// Ensure we only track the same finger that started the swipe
var distance = Math.sqrt((x - lastSwipeX) * (x - lastSwipeX) + (y - lastSwipeY) * (y - lastSwipeY));
if (distance > 20) {
createSwipeLine(lastSwipeX, lastSwipeY, x, y);
// Check for fruit intersections
for (var i = 0; i < fruits.length; i++) {
var fruit = fruits[i];
if (!fruit.sliced && checkSwipeIntersection(lastSwipeX, lastSwipeY, x, y, fruit)) {
sliceFruit(fruit);
}
}
// Check for freeze power-up intersections
for (var i = 0; i < freezePowerUps.length; i++) {
var powerUp = freezePowerUps[i];
if (checkSwipeIntersection(lastSwipeX, lastSwipeY, x, y, powerUp)) {
activateFreeze();
powerUp.toDestroy = true;
}
}
// Check for explosion power-up intersections
for (var i = 0; i < explosionPowerUps.length; i++) {
var powerUp = explosionPowerUps[i];
if (checkSwipeIntersection(lastSwipeX, lastSwipeY, x, y, powerUp)) {
activateExplosion(powerUp.x, powerUp.y);
powerUp.toDestroy = true;
}
}
lastSwipeX = x;
lastSwipeY = y;
}
};
game.up = function (x, y, obj) {
// Only respond to the same touch that initiated the swipe
var currentTouch = obj && obj.event && obj.event.identifier !== undefined ? obj.event.identifier : 0;
if (currentTouch === activeTouch) {
isSwipeDown = false;
activeTouch = null;
}
};
// Main game loop
game.update = function () {
if (isGameOver) return;
// Handle freeze timer
if (isFrozen) {
freezeTimer--;
if (freezeTimer <= 0) {
isFrozen = false;
}
}
// Spawn power-ups occasionally (only when not paused and not frozen)
if (!isGamePaused && !isFrozen) {
powerUpSpawnTimer++;
if (powerUpSpawnTimer >= 600) {
// Every 10 seconds at 60fps
if (Math.random() < 0.5) {
spawnFreezePowerUp();
} else {
spawnExplosionPowerUp();
}
powerUpSpawnTimer = 0;
}
// Spawn fruits
spawnTimer++;
if (spawnTimer >= spawnRate) {
// Spawn fewer fruits for better gameplay
var fruitsToSpawn = 1; // Spawn only 1 fruit
for (var s = 0; s < fruitsToSpawn; s++) {
spawnFruit();
}
spawnTimer = 0;
// Increase difficulty over time - faster spawning
if (spawnRate > 25) {
spawnRate -= 1;
}
if (gameSpeed < 3) {
gameSpeed += 0.02;
}
}
}
// Update and check fruits
for (var i = fruits.length - 1; i >= 0; i--) {
var fruit = fruits[i];
if (fruit.toDestroy) {
fruit.destroy();
fruits.splice(i, 1);
continue;
}
// Only lose fruit if it falls off the bottom (increased threshold to allow natural falling)
if (!fruit.sliced && fruit.y > 3000) {
loseFruit();
fruit.destroy();
fruits.splice(i, 1);
}
}
// Update and clean up pieces
for (var i = fruitPieces.length - 1; i >= 0; i--) {
var piece = fruitPieces[i];
if (piece.toDestroy) {
piece.destroy();
fruitPieces.splice(i, 1);
}
}
// Update and clean up swipe lines
for (var i = swipeLines.length - 1; i >= 0; i--) {
var line = swipeLines[i];
if (line.toDestroy) {
line.destroy();
swipeLines.splice(i, 1);
}
}
// Update and clean up freeze power-ups
for (var i = freezePowerUps.length - 1; i >= 0; i--) {
var powerUp = freezePowerUps[i];
if (powerUp.toDestroy) {
powerUp.destroy();
freezePowerUps.splice(i, 1);
continue;
}
// Remove if falls off bottom (don't lose lives)
if (powerUp.y > 3000) {
powerUp.destroy();
freezePowerUps.splice(i, 1);
}
}
// Update and clean up explosion power-ups
for (var i = explosionPowerUps.length - 1; i >= 0; i--) {
var powerUp = explosionPowerUps[i];
if (powerUp.toDestroy) {
powerUp.destroy();
explosionPowerUps.splice(i, 1);
continue;
}
// Remove if falls off bottom (don't lose lives)
if (powerUp.y > 3000) {
powerUp.destroy();
explosionPowerUps.splice(i, 1);
}
}
updateUI();
checkScoreProgression(); // Check for score milestones and increase sustain
};
// Track game pause state
LK.on('pause', function () {
isGamePaused = true;
});
LK.on('resume', function () {
isGamePaused = false;
});
// Initialize UI
updateUI();
// Start ambient music at game start
LK.playMusic('ambientMusic');
Naranja fruta. In-Game asset. 2d. High contrast. No shadows
Trozo de naranja fruta. In-Game asset. 2d. High contrast. No shadows
Apple. In-Game asset. 2d. High contrast. No shadows
Aple piece. In-Game asset. 2d. High contrast. No shadows
Bomba. In-Game asset. 2d. High contrast. No shadows
Cubito de hielo. In-Game asset. 2d. High contrast. No shadows
Pineaple. In-Game asset. 2d. High contrast. No shadows
Trozo piña. In-Game asset. 2d. High contrast. No shadows
Watermelon. In-Game asset. 2d. High contrast. No shadows
Una sandía individual. In-Game asset. 2d. High contrast. No shadows