User prompt
Make the score black
User prompt
Make the Background White
User prompt
set the Points to win to 300
User prompt
Set the Points to win to 1000
Code edit (1 edits merged)
Please save this source code
User prompt
Box Drop Frenzy
Initial prompt
A Game Where boxes fall from above and you have to tap them to get Points
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Box = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'regular';
self.speed = 5;
self.points = 1;
self.active = true;
// Different box configurations based on type
if (self.type === 'regular') {
self.boxGraphics = self.attachAsset('regularBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.points = 1;
} else if (self.type === 'bonus') {
self.boxGraphics = self.attachAsset('bonusBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.points = 3;
self.speed = 7;
} else if (self.type === 'special') {
self.boxGraphics = self.attachAsset('specialBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.points = 5;
self.speed = 9;
}
// Add a small rotation to make it visually interesting
self.rotationSpeed = (Math.random() - 0.5) * 0.02;
self.update = function () {
if (!self.active) {
return;
}
self.y += self.speed;
self.boxGraphics.rotation += self.rotationSpeed;
// Check if box moved out of screen
if (self.y > 2732 + self.boxGraphics.height) {
self.active = false;
missedBoxes++;
// Check if the player has missed too many boxes
if (missedBoxes >= maxMissedBoxes) {
LK.effects.flashScreen(0xff0000, 500);
LK.getSound('gameOverSound').play();
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
}
}
};
self.tap = function () {
if (!self.active) {
return;
}
self.active = false;
// Play appropriate sound
if (self.type === 'regular') {
LK.getSound('tap').play();
} else {
LK.getSound('bonus').play();
}
// Update score
LK.setScore(LK.getScore() + self.points);
updateScoreDisplay();
// Show score increase effect
var pointText = new Text2('+' + self.points, {
size: 50,
fill: 0xFFFFFF
});
pointText.anchor.set(0.5, 0.5);
pointText.x = self.x;
pointText.y = self.y;
game.addChild(pointText);
// Animate the text and then remove it
tween(pointText, {
y: pointText.y - 80,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
pointText.destroy();
}
});
// Animate the box explosion
tween(self, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.linear,
onFinish: function onFinish() {
self.destroy();
}
});
// Check if player reached target score
if (LK.getScore() >= winScore) {
LK.showYouWin();
}
};
// Event handler for tapping on boxes
self.down = function () {
self.tap();
};
// Method to handle swipe interactions
self.checkSwipe = function (startX, startY, endX, endY) {
if (!self.active) {
return false;
}
// Calculate swipe line intersection with box
var boxRadius = self.boxGraphics.width / 2;
// Simple check for line-circle intersection
// Calculate the nearest point on the line to the circle center
var dx = endX - startX;
var dy = endY - startY;
var len = Math.sqrt(dx * dx + dy * dy);
// Normalize direction vector
if (len > 0) {
dx /= len;
dy /= len;
}
// Vector from line start to circle center
var cx = self.x - startX;
var cy = self.y - startY;
// Project circle center onto line
var projLen = cx * dx + cy * dy;
// Closest point on line to circle center
var closestX, closestY;
if (projLen < 0) {
// Closest point is line start
closestX = startX;
closestY = startY;
} else if (projLen > len) {
// Closest point is line end
closestX = endX;
closestY = endY;
} else {
// Closest point is on the line
closestX = startX + projLen * dx;
closestY = startY + projLen * dy;
}
// Check if the closest point is within the circle
var distX = self.x - closestX;
var distY = self.y - closestY;
var distance = Math.sqrt(distX * distX + distY * distY);
if (distance <= boxRadius) {
var createBoxHalf = function createBoxHalf(offsetX, offsetY, rotationOffset) {
var halfAssetId = self.type === 'regular' ? 'regularBox' : self.type === 'bonus' ? 'bonusBox' : 'specialBox';
var halfBox = LK.getAsset(halfAssetId, {
anchorX: 0.5,
anchorY: 0.5,
width: self.boxGraphics.width * 0.9,
height: self.boxGraphics.height * 0.5,
alpha: 0.9
});
halfBox.x = self.x + offsetX;
halfBox.y = self.y + offsetY;
halfBox.rotation = swipeAngle + rotationOffset;
game.addChild(halfBox);
// Animate halves flying apart
tween(halfBox, {
x: halfBox.x + Math.cos(swipeAngle + rotationOffset) * 100,
y: halfBox.y + Math.sin(swipeAngle + rotationOffset) * 100,
rotation: halfBox.rotation + Math.random() * 0.5,
alpha: 0
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function (p) {
return function () {
p.destroy();
};
}(halfBox)
});
}; // Create two halves that appear to split from the swipe
// Apply swipe bonus - double the points when swiped instead of tapped
var originalPoints = self.points;
self.points = self.points * 2;
// Show bonus indicator
var bonusText = new Text2('SWIPE BONUS!', {
size: 40,
fill: 0xFFD700
});
bonusText.anchor.set(0.5, 0.5);
bonusText.x = self.x;
bonusText.y = self.y - 50;
game.addChild(bonusText);
// Animate and remove the bonus text
tween(bonusText, {
y: bonusText.y - 60,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
bonusText.destroy();
}
});
// Calculate the angle of the swipe
var swipeAngle = Math.atan2(distY, distX);
// Create box half for slicing effect
createBoxHalf(0, -20, Math.PI / 2);
createBoxHalf(0, 20, -Math.PI / 2);
// Also create particle burst for additional effect
for (var i = 0; i < 10; i++) {
var angle = Math.random() * Math.PI * 2;
var speed = 2 + Math.random() * 3;
var size = 10 + Math.random() * 15;
var particle = LK.getAsset('regularBox', {
anchorX: 0.5,
anchorY: 0.5,
width: size,
height: size,
alpha: 0.8,
tint: 0xFFD700 // Gold color for trail
});
particle.x = self.x;
particle.y = self.y;
game.addChild(particle);
// Animate particle outward from box
tween(particle, {
x: particle.x + Math.cos(angle) * 100 * speed,
y: particle.y + Math.sin(angle) * 100 * speed,
alpha: 0,
width: size / 2,
height: size / 2
}, {
duration: 500 + Math.random() * 300,
easing: tween.easeOut,
onFinish: function (p) {
return function () {
p.destroy();
};
}(particle)
});
}
self.tap();
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xFFFFFF
});
/****
* Game Code
****/
// Game variables
var boxes = [];
var spawnInterval = 1000; // Initial spawn interval in ms
var minSpawnInterval = 300; // Minimum spawn interval
var spawnTimer = null;
var missedBoxes = 0;
var maxMissedBoxes = 10; // Game over after 10 missed boxes
var winScore = 300; // Score needed to win
var difficultyIncreaseInterval = 10000; // Increase difficulty every 10 seconds
var difficultyTimer = null;
var gameStarted = false;
// Swipe variables
var swipeStartX = 0;
var swipeStartY = 0;
var isSwipeActive = false;
var swipeMinDistance = 100; // Minimum distance to register as a swipe
var trailParticles = []; // Array to store trail particles
var lastTrailX = 0; // Last position where trail was created
var lastTrailY = 0; // Last position where trail was created
var trailMinDistance = 10; // Minimum distance between trail particles
var lastTrailX = 0; // Last position where trail was created
var lastTrailY = 0; // Last position where trail was created
var trailMinDistance = 10; // Minimum distance between trail particles
var swipePointDrainTimer = null; // Timer for point drain during swipe
var pointDrainRate = 5; // Points lost per second while swiping
// Initialize UI
var scoreTxt = new Text2('0', {
size: 80,
fill: 0x000000
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var missedBoxesTxt = new Text2('Missed: 0/' + maxMissedBoxes, {
size: 50,
fill: 0xFFFFFF
});
missedBoxesTxt.anchor.set(0, 0);
missedBoxesTxt.x = 150;
missedBoxesTxt.y = 50;
LK.gui.topRight.addChild(missedBoxesTxt);
var instructionsTxt = new Text2('Tap or SLICE the falling boxes! (Slice with swipe for 2X bonus, but lose 1 point/second while swiping!)', {
size: 54,
fill: 0xFFFFFF
});
instructionsTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionsTxt);
// Hide instructions after a delay
LK.setTimeout(function () {
tween(instructionsTxt, {
alpha: 0
}, {
duration: 1000,
easing: tween.linear,
onFinish: function onFinish() {
instructionsTxt.destroy();
}
});
startGame();
}, 2000);
// Function to update score display
function updateScoreDisplay() {
scoreTxt.setText(LK.getScore());
missedBoxesTxt.setText('Missed: ' + missedBoxes + '/' + maxMissedBoxes);
}
// Function to spawn a box
function spawnBox() {
var boxType;
var random = Math.random();
if (random < 0.7) {
boxType = 'regular';
} else if (random < 0.9) {
boxType = 'bonus';
} else {
boxType = 'special';
}
var box = new Box(boxType);
box.x = Math.random() * (2048 - 100) + 50; // Random x position
box.y = -100; // Start above the screen
// Add some variety to the path
box.xSpeed = (Math.random() - 0.5) * 3;
boxes.push(box);
game.addChild(box);
}
// Function to start the game
function startGame() {
if (gameStarted) {
return;
}
gameStarted = true;
// Reset variables
boxes.forEach(function (box) {
box.destroy();
});
boxes = [];
missedBoxes = 0;
LK.setScore(0);
updateScoreDisplay();
// Start spawning boxes
spawnTimer = LK.setInterval(function () {
spawnBox();
}, spawnInterval);
// Increase difficulty over time
difficultyTimer = LK.setInterval(function () {
if (spawnInterval > minSpawnInterval) {
spawnInterval = Math.max(minSpawnInterval, spawnInterval - 100);
// Clear and restart spawn timer with new interval
LK.clearInterval(spawnTimer);
spawnTimer = LK.setInterval(function () {
spawnBox();
}, spawnInterval);
}
}, difficultyIncreaseInterval);
// Play background music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.5,
duration: 1000
}
});
}
// Update function called every frame
game.update = function () {
// Process all active boxes
for (var i = boxes.length - 1; i >= 0; i--) {
var box = boxes[i];
// Remove inactive boxes from the array
if (!box.active) {
boxes.splice(i, 1);
continue;
}
// Add some horizontal movement to make it more interesting
if (box.xSpeed) {
box.x += box.xSpeed;
// Bounce off the edges
if (box.x < 50 || box.x > 2048 - 50) {
box.xSpeed *= -1;
}
}
}
};
// Handle both tapping and swipe start
game.down = function (x, y) {
// Start tracking potential swipe
swipeStartX = x;
swipeStartY = y;
lastTrailX = x;
lastTrailY = y;
isSwipeActive = true;
// Start point drain timer when swiping
if (swipePointDrainTimer) {
LK.clearInterval(swipePointDrainTimer);
}
swipePointDrainTimer = LK.setInterval(function () {
if (LK.getScore() > 0) {
LK.setScore(LK.getScore() - pointDrainRate);
updateScoreDisplay();
// Show point drain indicator
var drainText = new Text2('-' + pointDrainRate, {
size: 30,
fill: 0xFF0000
});
drainText.anchor.set(0.5, 0.5);
drainText.x = lastTrailX;
drainText.y = lastTrailY;
game.addChild(drainText);
// Animate and remove the drain text
tween(drainText, {
y: drainText.y - 40,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
drainText.destroy();
}
});
}
}, 1000); // Drain points every second
// Check if any box was hit (for tap)
var hitBox = false;
for (var i = boxes.length - 1; i >= 0; i--) {
var box = boxes[i];
// Calculate distance from tap to box center
var dx = x - box.x;
var dy = y - box.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If tap is within the box, trigger a tap
if (distance < box.boxGraphics.width / 2 && box.active) {
box.tap();
hitBox = true;
break; // Only tap one box at a time
}
}
// Flash screen very subtly when missing a box
if (!hitBox && boxes.length > 0) {
LK.effects.flashScreen(0x3498db, 100);
}
};
// Handle swipe end
game.up = function (x, y) {
if (!isSwipeActive) {
return;
}
// Calculate swipe distance
var dx = x - swipeStartX;
var dy = y - swipeStartY;
var distance = Math.sqrt(dx * dx + dy * dy);
// Check if this was a valid swipe (minimum distance)
if (distance >= swipeMinDistance) {
// Process the swipe through all boxes
var hitAnyBox = false;
for (var i = boxes.length - 1; i >= 0; i--) {
if (boxes[i].checkSwipe(swipeStartX, swipeStartY, x, y)) {
hitAnyBox = true;
}
}
// Visual feedback for swipe
if (hitAnyBox) {
// Play bonus sound for successful swipes
LK.getSound('bonus').play();
// Add swipe line visual effect with gold color for bonus effect
var lineEffect = new Container();
game.addChild(lineEffect);
// Draw swipe line with multiple dots for trail effect
var steps = Math.min(20, Math.floor(distance / 20));
var dotSize = 20;
for (var s = 0; s < steps; s++) {
var dotPercent = s / (steps - 1);
var dotX = swipeStartX + dx * dotPercent;
var dotY = swipeStartY + dy * dotPercent;
// Create dot with gold color for bonus effect
var dot = LK.getAsset('regularBox', {
anchorX: 0.5,
anchorY: 0.5,
width: dotSize,
height: dotSize,
alpha: 0.5 * (1 - dotPercent),
// Fade out towards the end
tint: 0xFFD700 // Gold color for bonus effect
});
dot.x = dotX;
dot.y = dotY;
lineEffect.addChild(dot);
}
// Animate and remove the effect
tween(lineEffect, {
alpha: 0
}, {
duration: 300,
easing: tween.linear,
onFinish: function onFinish() {
lineEffect.destroy();
}
});
}
}
// Reset swipe tracking
isSwipeActive = false;
// Stop point drain timer
if (swipePointDrainTimer) {
LK.clearInterval(swipePointDrainTimer);
swipePointDrainTimer = null;
}
};
// Add move handler to track active swipes
game.move = function (x, y) {
// For very long swipes, we can process while still moving
if (isSwipeActive) {
var dx = x - swipeStartX;
var dy = y - swipeStartY;
var distance = Math.sqrt(dx * dx + dy * dy);
// Calculate distance from last trail point
var trailDx = x - lastTrailX;
var trailDy = y - lastTrailY;
var trailDistance = Math.sqrt(trailDx * trailDx + trailDy * trailDy);
// Add slice trail effect (more blade-like)
if (trailDistance > trailMinDistance) {
// Update last trail position
lastTrailX = x;
lastTrailY = y;
// Calculate angle of swipe for rotation
var swipeAngle = Math.atan2(dy, dx);
// Create slice trail (elongated particle)
var slice = LK.getAsset('regularBox', {
anchorX: 0.5,
anchorY: 0.5,
width: 30,
height: 6,
alpha: 0.8,
tint: 0xFFD700 // Gold color for trail
});
slice.x = x;
slice.y = y;
slice.rotation = swipeAngle;
game.addChild(slice);
// Animate and remove the slice effect
tween(slice, {
alpha: 0,
width: 40,
height: 3
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
slice.destroy();
}
});
}
// For very long swipes, check boxes during the swipe
if (distance >= swipeMinDistance * 2) {
for (var i = boxes.length - 1; i >= 0; i--) {
boxes[i].checkSwipe(swipeStartX, swipeStartY, x, y);
}
// Update swipe start position to current
swipeStartX = x;
swipeStartY = y;
}
}
};
// Game clean-up function
game.cleanup = function () {
if (spawnTimer) {
LK.clearInterval(spawnTimer);
}
if (difficultyTimer) {
LK.clearInterval(difficultyTimer);
}
if (swipePointDrainTimer) {
LK.clearInterval(swipePointDrainTimer);
}
LK.stopMusic();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Box = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'regular';
self.speed = 5;
self.points = 1;
self.active = true;
// Different box configurations based on type
if (self.type === 'regular') {
self.boxGraphics = self.attachAsset('regularBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.points = 1;
} else if (self.type === 'bonus') {
self.boxGraphics = self.attachAsset('bonusBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.points = 3;
self.speed = 7;
} else if (self.type === 'special') {
self.boxGraphics = self.attachAsset('specialBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.points = 5;
self.speed = 9;
}
// Add a small rotation to make it visually interesting
self.rotationSpeed = (Math.random() - 0.5) * 0.02;
self.update = function () {
if (!self.active) {
return;
}
self.y += self.speed;
self.boxGraphics.rotation += self.rotationSpeed;
// Check if box moved out of screen
if (self.y > 2732 + self.boxGraphics.height) {
self.active = false;
missedBoxes++;
// Check if the player has missed too many boxes
if (missedBoxes >= maxMissedBoxes) {
LK.effects.flashScreen(0xff0000, 500);
LK.getSound('gameOverSound').play();
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
}
}
};
self.tap = function () {
if (!self.active) {
return;
}
self.active = false;
// Play appropriate sound
if (self.type === 'regular') {
LK.getSound('tap').play();
} else {
LK.getSound('bonus').play();
}
// Update score
LK.setScore(LK.getScore() + self.points);
updateScoreDisplay();
// Show score increase effect
var pointText = new Text2('+' + self.points, {
size: 50,
fill: 0xFFFFFF
});
pointText.anchor.set(0.5, 0.5);
pointText.x = self.x;
pointText.y = self.y;
game.addChild(pointText);
// Animate the text and then remove it
tween(pointText, {
y: pointText.y - 80,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
pointText.destroy();
}
});
// Animate the box explosion
tween(self, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.linear,
onFinish: function onFinish() {
self.destroy();
}
});
// Check if player reached target score
if (LK.getScore() >= winScore) {
LK.showYouWin();
}
};
// Event handler for tapping on boxes
self.down = function () {
self.tap();
};
// Method to handle swipe interactions
self.checkSwipe = function (startX, startY, endX, endY) {
if (!self.active) {
return false;
}
// Calculate swipe line intersection with box
var boxRadius = self.boxGraphics.width / 2;
// Simple check for line-circle intersection
// Calculate the nearest point on the line to the circle center
var dx = endX - startX;
var dy = endY - startY;
var len = Math.sqrt(dx * dx + dy * dy);
// Normalize direction vector
if (len > 0) {
dx /= len;
dy /= len;
}
// Vector from line start to circle center
var cx = self.x - startX;
var cy = self.y - startY;
// Project circle center onto line
var projLen = cx * dx + cy * dy;
// Closest point on line to circle center
var closestX, closestY;
if (projLen < 0) {
// Closest point is line start
closestX = startX;
closestY = startY;
} else if (projLen > len) {
// Closest point is line end
closestX = endX;
closestY = endY;
} else {
// Closest point is on the line
closestX = startX + projLen * dx;
closestY = startY + projLen * dy;
}
// Check if the closest point is within the circle
var distX = self.x - closestX;
var distY = self.y - closestY;
var distance = Math.sqrt(distX * distX + distY * distY);
if (distance <= boxRadius) {
var createBoxHalf = function createBoxHalf(offsetX, offsetY, rotationOffset) {
var halfAssetId = self.type === 'regular' ? 'regularBox' : self.type === 'bonus' ? 'bonusBox' : 'specialBox';
var halfBox = LK.getAsset(halfAssetId, {
anchorX: 0.5,
anchorY: 0.5,
width: self.boxGraphics.width * 0.9,
height: self.boxGraphics.height * 0.5,
alpha: 0.9
});
halfBox.x = self.x + offsetX;
halfBox.y = self.y + offsetY;
halfBox.rotation = swipeAngle + rotationOffset;
game.addChild(halfBox);
// Animate halves flying apart
tween(halfBox, {
x: halfBox.x + Math.cos(swipeAngle + rotationOffset) * 100,
y: halfBox.y + Math.sin(swipeAngle + rotationOffset) * 100,
rotation: halfBox.rotation + Math.random() * 0.5,
alpha: 0
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function (p) {
return function () {
p.destroy();
};
}(halfBox)
});
}; // Create two halves that appear to split from the swipe
// Apply swipe bonus - double the points when swiped instead of tapped
var originalPoints = self.points;
self.points = self.points * 2;
// Show bonus indicator
var bonusText = new Text2('SWIPE BONUS!', {
size: 40,
fill: 0xFFD700
});
bonusText.anchor.set(0.5, 0.5);
bonusText.x = self.x;
bonusText.y = self.y - 50;
game.addChild(bonusText);
// Animate and remove the bonus text
tween(bonusText, {
y: bonusText.y - 60,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
bonusText.destroy();
}
});
// Calculate the angle of the swipe
var swipeAngle = Math.atan2(distY, distX);
// Create box half for slicing effect
createBoxHalf(0, -20, Math.PI / 2);
createBoxHalf(0, 20, -Math.PI / 2);
// Also create particle burst for additional effect
for (var i = 0; i < 10; i++) {
var angle = Math.random() * Math.PI * 2;
var speed = 2 + Math.random() * 3;
var size = 10 + Math.random() * 15;
var particle = LK.getAsset('regularBox', {
anchorX: 0.5,
anchorY: 0.5,
width: size,
height: size,
alpha: 0.8,
tint: 0xFFD700 // Gold color for trail
});
particle.x = self.x;
particle.y = self.y;
game.addChild(particle);
// Animate particle outward from box
tween(particle, {
x: particle.x + Math.cos(angle) * 100 * speed,
y: particle.y + Math.sin(angle) * 100 * speed,
alpha: 0,
width: size / 2,
height: size / 2
}, {
duration: 500 + Math.random() * 300,
easing: tween.easeOut,
onFinish: function (p) {
return function () {
p.destroy();
};
}(particle)
});
}
self.tap();
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xFFFFFF
});
/****
* Game Code
****/
// Game variables
var boxes = [];
var spawnInterval = 1000; // Initial spawn interval in ms
var minSpawnInterval = 300; // Minimum spawn interval
var spawnTimer = null;
var missedBoxes = 0;
var maxMissedBoxes = 10; // Game over after 10 missed boxes
var winScore = 300; // Score needed to win
var difficultyIncreaseInterval = 10000; // Increase difficulty every 10 seconds
var difficultyTimer = null;
var gameStarted = false;
// Swipe variables
var swipeStartX = 0;
var swipeStartY = 0;
var isSwipeActive = false;
var swipeMinDistance = 100; // Minimum distance to register as a swipe
var trailParticles = []; // Array to store trail particles
var lastTrailX = 0; // Last position where trail was created
var lastTrailY = 0; // Last position where trail was created
var trailMinDistance = 10; // Minimum distance between trail particles
var lastTrailX = 0; // Last position where trail was created
var lastTrailY = 0; // Last position where trail was created
var trailMinDistance = 10; // Minimum distance between trail particles
var swipePointDrainTimer = null; // Timer for point drain during swipe
var pointDrainRate = 5; // Points lost per second while swiping
// Initialize UI
var scoreTxt = new Text2('0', {
size: 80,
fill: 0x000000
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var missedBoxesTxt = new Text2('Missed: 0/' + maxMissedBoxes, {
size: 50,
fill: 0xFFFFFF
});
missedBoxesTxt.anchor.set(0, 0);
missedBoxesTxt.x = 150;
missedBoxesTxt.y = 50;
LK.gui.topRight.addChild(missedBoxesTxt);
var instructionsTxt = new Text2('Tap or SLICE the falling boxes! (Slice with swipe for 2X bonus, but lose 1 point/second while swiping!)', {
size: 54,
fill: 0xFFFFFF
});
instructionsTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionsTxt);
// Hide instructions after a delay
LK.setTimeout(function () {
tween(instructionsTxt, {
alpha: 0
}, {
duration: 1000,
easing: tween.linear,
onFinish: function onFinish() {
instructionsTxt.destroy();
}
});
startGame();
}, 2000);
// Function to update score display
function updateScoreDisplay() {
scoreTxt.setText(LK.getScore());
missedBoxesTxt.setText('Missed: ' + missedBoxes + '/' + maxMissedBoxes);
}
// Function to spawn a box
function spawnBox() {
var boxType;
var random = Math.random();
if (random < 0.7) {
boxType = 'regular';
} else if (random < 0.9) {
boxType = 'bonus';
} else {
boxType = 'special';
}
var box = new Box(boxType);
box.x = Math.random() * (2048 - 100) + 50; // Random x position
box.y = -100; // Start above the screen
// Add some variety to the path
box.xSpeed = (Math.random() - 0.5) * 3;
boxes.push(box);
game.addChild(box);
}
// Function to start the game
function startGame() {
if (gameStarted) {
return;
}
gameStarted = true;
// Reset variables
boxes.forEach(function (box) {
box.destroy();
});
boxes = [];
missedBoxes = 0;
LK.setScore(0);
updateScoreDisplay();
// Start spawning boxes
spawnTimer = LK.setInterval(function () {
spawnBox();
}, spawnInterval);
// Increase difficulty over time
difficultyTimer = LK.setInterval(function () {
if (spawnInterval > minSpawnInterval) {
spawnInterval = Math.max(minSpawnInterval, spawnInterval - 100);
// Clear and restart spawn timer with new interval
LK.clearInterval(spawnTimer);
spawnTimer = LK.setInterval(function () {
spawnBox();
}, spawnInterval);
}
}, difficultyIncreaseInterval);
// Play background music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.5,
duration: 1000
}
});
}
// Update function called every frame
game.update = function () {
// Process all active boxes
for (var i = boxes.length - 1; i >= 0; i--) {
var box = boxes[i];
// Remove inactive boxes from the array
if (!box.active) {
boxes.splice(i, 1);
continue;
}
// Add some horizontal movement to make it more interesting
if (box.xSpeed) {
box.x += box.xSpeed;
// Bounce off the edges
if (box.x < 50 || box.x > 2048 - 50) {
box.xSpeed *= -1;
}
}
}
};
// Handle both tapping and swipe start
game.down = function (x, y) {
// Start tracking potential swipe
swipeStartX = x;
swipeStartY = y;
lastTrailX = x;
lastTrailY = y;
isSwipeActive = true;
// Start point drain timer when swiping
if (swipePointDrainTimer) {
LK.clearInterval(swipePointDrainTimer);
}
swipePointDrainTimer = LK.setInterval(function () {
if (LK.getScore() > 0) {
LK.setScore(LK.getScore() - pointDrainRate);
updateScoreDisplay();
// Show point drain indicator
var drainText = new Text2('-' + pointDrainRate, {
size: 30,
fill: 0xFF0000
});
drainText.anchor.set(0.5, 0.5);
drainText.x = lastTrailX;
drainText.y = lastTrailY;
game.addChild(drainText);
// Animate and remove the drain text
tween(drainText, {
y: drainText.y - 40,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
drainText.destroy();
}
});
}
}, 1000); // Drain points every second
// Check if any box was hit (for tap)
var hitBox = false;
for (var i = boxes.length - 1; i >= 0; i--) {
var box = boxes[i];
// Calculate distance from tap to box center
var dx = x - box.x;
var dy = y - box.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If tap is within the box, trigger a tap
if (distance < box.boxGraphics.width / 2 && box.active) {
box.tap();
hitBox = true;
break; // Only tap one box at a time
}
}
// Flash screen very subtly when missing a box
if (!hitBox && boxes.length > 0) {
LK.effects.flashScreen(0x3498db, 100);
}
};
// Handle swipe end
game.up = function (x, y) {
if (!isSwipeActive) {
return;
}
// Calculate swipe distance
var dx = x - swipeStartX;
var dy = y - swipeStartY;
var distance = Math.sqrt(dx * dx + dy * dy);
// Check if this was a valid swipe (minimum distance)
if (distance >= swipeMinDistance) {
// Process the swipe through all boxes
var hitAnyBox = false;
for (var i = boxes.length - 1; i >= 0; i--) {
if (boxes[i].checkSwipe(swipeStartX, swipeStartY, x, y)) {
hitAnyBox = true;
}
}
// Visual feedback for swipe
if (hitAnyBox) {
// Play bonus sound for successful swipes
LK.getSound('bonus').play();
// Add swipe line visual effect with gold color for bonus effect
var lineEffect = new Container();
game.addChild(lineEffect);
// Draw swipe line with multiple dots for trail effect
var steps = Math.min(20, Math.floor(distance / 20));
var dotSize = 20;
for (var s = 0; s < steps; s++) {
var dotPercent = s / (steps - 1);
var dotX = swipeStartX + dx * dotPercent;
var dotY = swipeStartY + dy * dotPercent;
// Create dot with gold color for bonus effect
var dot = LK.getAsset('regularBox', {
anchorX: 0.5,
anchorY: 0.5,
width: dotSize,
height: dotSize,
alpha: 0.5 * (1 - dotPercent),
// Fade out towards the end
tint: 0xFFD700 // Gold color for bonus effect
});
dot.x = dotX;
dot.y = dotY;
lineEffect.addChild(dot);
}
// Animate and remove the effect
tween(lineEffect, {
alpha: 0
}, {
duration: 300,
easing: tween.linear,
onFinish: function onFinish() {
lineEffect.destroy();
}
});
}
}
// Reset swipe tracking
isSwipeActive = false;
// Stop point drain timer
if (swipePointDrainTimer) {
LK.clearInterval(swipePointDrainTimer);
swipePointDrainTimer = null;
}
};
// Add move handler to track active swipes
game.move = function (x, y) {
// For very long swipes, we can process while still moving
if (isSwipeActive) {
var dx = x - swipeStartX;
var dy = y - swipeStartY;
var distance = Math.sqrt(dx * dx + dy * dy);
// Calculate distance from last trail point
var trailDx = x - lastTrailX;
var trailDy = y - lastTrailY;
var trailDistance = Math.sqrt(trailDx * trailDx + trailDy * trailDy);
// Add slice trail effect (more blade-like)
if (trailDistance > trailMinDistance) {
// Update last trail position
lastTrailX = x;
lastTrailY = y;
// Calculate angle of swipe for rotation
var swipeAngle = Math.atan2(dy, dx);
// Create slice trail (elongated particle)
var slice = LK.getAsset('regularBox', {
anchorX: 0.5,
anchorY: 0.5,
width: 30,
height: 6,
alpha: 0.8,
tint: 0xFFD700 // Gold color for trail
});
slice.x = x;
slice.y = y;
slice.rotation = swipeAngle;
game.addChild(slice);
// Animate and remove the slice effect
tween(slice, {
alpha: 0,
width: 40,
height: 3
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
slice.destroy();
}
});
}
// For very long swipes, check boxes during the swipe
if (distance >= swipeMinDistance * 2) {
for (var i = boxes.length - 1; i >= 0; i--) {
boxes[i].checkSwipe(swipeStartX, swipeStartY, x, y);
}
// Update swipe start position to current
swipeStartX = x;
swipeStartY = y;
}
}
};
// Game clean-up function
game.cleanup = function () {
if (spawnTimer) {
LK.clearInterval(spawnTimer);
}
if (difficultyTimer) {
LK.clearInterval(difficultyTimer);
}
if (swipePointDrainTimer) {
LK.clearInterval(swipePointDrainTimer);
}
LK.stopMusic();
};