/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Block = Container.expand(function () { var self = Container.call(this); // Properties self.blockWidth = 400; self.blockHeight = 100; self.movingDirection = 1; // 1 for right, -1 for left self.speed = 10; self.moving = true; self.trimmedAmount = 0; // Create block visual var blockGraphics = self.attachAsset('block', { anchorX: 0.5, anchorY: 0.5, width: self.blockWidth, height: self.blockHeight }); // Method to update block position self.update = function () { if (self.moving) { self.x += self.speed * self.movingDirection; // Bounce off the edges of the screen if (self.x + self.blockWidth / 2 > 2048) { self.x = 2048 - self.blockWidth / 2; self.movingDirection = -1; } else if (self.x - self.blockWidth / 2 < 0) { self.x = self.blockWidth / 2; self.movingDirection = 1; } } }; // Method to stop the block from moving self.stopMoving = function () { self.moving = false; }; // Method to trim the block based on the block below self.trimToFit = function (prevBlockX, prevBlockWidth) { // Calculate the trim amount var leftEdge = self.x - self.blockWidth / 2; var rightEdge = self.x + self.blockWidth / 2; var prevLeftEdge = prevBlockX - prevBlockWidth / 2; var prevRightEdge = prevBlockX + prevBlockWidth / 2; // The block is completely off the stack if (rightEdge < prevLeftEdge || leftEdge > prevRightEdge) { self.blockWidth = 0; self.trimmedAmount = self.blockWidth; return false; } // Calculate new dimensions after trimming var newLeftEdge = Math.max(leftEdge, prevLeftEdge); var newRightEdge = Math.min(rightEdge, prevRightEdge); var newWidth = newRightEdge - newLeftEdge; // Store the trimmed amount self.trimmedAmount = self.blockWidth - newWidth; // Update the block width self.blockWidth = newWidth; // Update the visual representation blockGraphics.width = self.blockWidth; // Center the block on its visible portion self.x = newLeftEdge + newWidth / 2; return true; }; // Method to highlight block when it's a miss self.highlightMiss = function () { // Replace current graphics with red block blockGraphics.destroy(); blockGraphics = self.attachAsset('gameOverBlock', { anchorX: 0.5, anchorY: 0.5, width: self.blockWidth, height: self.blockHeight }); }; return self; }); var StackedBlock = Container.expand(function () { var self = Container.call(this); // Properties self.blockWidth = 400; self.blockHeight = 100; // Create block visual var blockGraphics = self.attachAsset('stackBlock', { anchorX: 0.5, anchorY: 0.5, width: self.blockWidth, height: self.blockHeight }); // Method to set the width self.setWidth = function (width) { self.blockWidth = width; blockGraphics.width = width; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Game state variables var currentBlock; var stackedBlocks = []; var baseY = 2400; var score = 0; var gameActive = false; var difficultyLevel = 1; var lastBlockWidth = 400; var lastBlockX = 2048 / 2; // Create base platform var base = game.addChild(LK.getAsset('base', { anchorX: 0.5, anchorY: 0.5 })); base.x = 2048 / 2; base.y = baseY; base.width = 480; // UI Elements var scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var instructionTxt = new Text2('Tap to drop blocks and build your tower!', { size: 60, fill: 0xFFFFFF }); instructionTxt.anchor.set(0.5, 0.5); instructionTxt.x = 0; instructionTxt.y = 300; LK.gui.center.addChild(instructionTxt); // Game logic methods function startGame() { // Reset game state for (var i = 0; i < stackedBlocks.length; i++) { stackedBlocks[i].destroy(); } stackedBlocks = []; score = 0; difficultyLevel = 1; baseY = 2400; lastBlockWidth = 400; lastBlockX = 2048 / 2; gameActive = true; // Update score display scoreTxt.setText('0'); // Hide instruction text instructionTxt.visible = false; // Create first block spawnNewBlock(); // Start background music LK.playMusic('bgMusic'); } function spawnNewBlock() { currentBlock = new Block(); currentBlock.blockWidth = lastBlockWidth; var blockGraphics = currentBlock.getChildAt(0); blockGraphics.width = currentBlock.blockWidth; // Randomly start from left or right currentBlock.x = Math.random() > 0.5 ? 0 + currentBlock.blockWidth / 2 : 2048 - currentBlock.blockWidth / 2; currentBlock.y = baseY - (stackedBlocks.length + 1) * 110; currentBlock.movingDirection = currentBlock.x < 1024 ? 1 : -1; // Increase speed based on difficulty level currentBlock.speed = 5 + difficultyLevel; game.addChild(currentBlock); } function dropBlock() { if (!currentBlock || !gameActive) { return; } // Stop the block from moving currentBlock.stopMoving(); // Check if the block fits on the previous block var successfulPlacement = true; if (stackedBlocks.length > 0) { successfulPlacement = currentBlock.trimToFit(lastBlockX, lastBlockWidth); } if (successfulPlacement && currentBlock.blockWidth > 0) { // Play placement sound LK.getSound('place').play(); // Update variables for next block lastBlockWidth = currentBlock.blockWidth; lastBlockX = currentBlock.x; // Create a stacked version of the block var stackedBlock = new StackedBlock(); stackedBlock.setWidth(lastBlockWidth); stackedBlock.x = lastBlockX; stackedBlock.y = currentBlock.y; game.addChild(stackedBlock); stackedBlocks.push(stackedBlock); // Remove the moving block currentBlock.destroy(); currentBlock = null; // Update score score += 10; scoreTxt.setText(score.toString()); // Increase difficulty every 5 points if (score % 5 === 0) { difficultyLevel++; } // After a short delay, spawn a new block LK.setTimeout(function () { spawnNewBlock(); }, 300); } else { // Game over gameActive = false; // Play miss sound LK.getSound('miss').play(); // Highlight the missed block in red currentBlock.highlightMiss(); // Make the block fall off screen tween(currentBlock, { y: 3000, rotation: Math.PI * 2 }, { duration: 1500, easing: tween.easeIn, onFinish: function onFinish() { // Check if this is a new high score var highScore = storage.highScore || 0; if (score > highScore) { storage.highScore = score; } // Show game over screen after a short delay LK.setTimeout(function () { LK.showGameOver(); }, 500); } }); } } function moveCamera() { // Only move camera if we have enough stacked blocks if (stackedBlocks.length > 8) { // Target Y for the topmost block var targetY = 2732 / 2; // Calculate how much to move everything down var moveAmount = baseY - (stackedBlocks.length + 1) * 110 - targetY; // Move everything down base.y -= moveAmount; for (var i = 0; i < stackedBlocks.length; i++) { stackedBlocks[i].y -= moveAmount; } if (currentBlock) { currentBlock.y -= moveAmount; } baseY -= moveAmount; } } // Input handlers game.down = function (x, y, obj) { if (!gameActive) { startGame(); } else { dropBlock(); } }; // Update method game.update = function () { if (currentBlock && gameActive) { currentBlock.update(); } // Move camera to follow the tower moveCamera(); }; // Show instruction text at start instructionTxt.visible = true;
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Block = Container.expand(function () {
var self = Container.call(this);
// Properties
self.blockWidth = 400;
self.blockHeight = 100;
self.movingDirection = 1; // 1 for right, -1 for left
self.speed = 10;
self.moving = true;
self.trimmedAmount = 0;
// Create block visual
var blockGraphics = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5,
width: self.blockWidth,
height: self.blockHeight
});
// Method to update block position
self.update = function () {
if (self.moving) {
self.x += self.speed * self.movingDirection;
// Bounce off the edges of the screen
if (self.x + self.blockWidth / 2 > 2048) {
self.x = 2048 - self.blockWidth / 2;
self.movingDirection = -1;
} else if (self.x - self.blockWidth / 2 < 0) {
self.x = self.blockWidth / 2;
self.movingDirection = 1;
}
}
};
// Method to stop the block from moving
self.stopMoving = function () {
self.moving = false;
};
// Method to trim the block based on the block below
self.trimToFit = function (prevBlockX, prevBlockWidth) {
// Calculate the trim amount
var leftEdge = self.x - self.blockWidth / 2;
var rightEdge = self.x + self.blockWidth / 2;
var prevLeftEdge = prevBlockX - prevBlockWidth / 2;
var prevRightEdge = prevBlockX + prevBlockWidth / 2;
// The block is completely off the stack
if (rightEdge < prevLeftEdge || leftEdge > prevRightEdge) {
self.blockWidth = 0;
self.trimmedAmount = self.blockWidth;
return false;
}
// Calculate new dimensions after trimming
var newLeftEdge = Math.max(leftEdge, prevLeftEdge);
var newRightEdge = Math.min(rightEdge, prevRightEdge);
var newWidth = newRightEdge - newLeftEdge;
// Store the trimmed amount
self.trimmedAmount = self.blockWidth - newWidth;
// Update the block width
self.blockWidth = newWidth;
// Update the visual representation
blockGraphics.width = self.blockWidth;
// Center the block on its visible portion
self.x = newLeftEdge + newWidth / 2;
return true;
};
// Method to highlight block when it's a miss
self.highlightMiss = function () {
// Replace current graphics with red block
blockGraphics.destroy();
blockGraphics = self.attachAsset('gameOverBlock', {
anchorX: 0.5,
anchorY: 0.5,
width: self.blockWidth,
height: self.blockHeight
});
};
return self;
});
var StackedBlock = Container.expand(function () {
var self = Container.call(this);
// Properties
self.blockWidth = 400;
self.blockHeight = 100;
// Create block visual
var blockGraphics = self.attachAsset('stackBlock', {
anchorX: 0.5,
anchorY: 0.5,
width: self.blockWidth,
height: self.blockHeight
});
// Method to set the width
self.setWidth = function (width) {
self.blockWidth = width;
blockGraphics.width = width;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game state variables
var currentBlock;
var stackedBlocks = [];
var baseY = 2400;
var score = 0;
var gameActive = false;
var difficultyLevel = 1;
var lastBlockWidth = 400;
var lastBlockX = 2048 / 2;
// Create base platform
var base = game.addChild(LK.getAsset('base', {
anchorX: 0.5,
anchorY: 0.5
}));
base.x = 2048 / 2;
base.y = baseY;
base.width = 480;
// UI Elements
var scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var instructionTxt = new Text2('Tap to drop blocks and build your tower!', {
size: 60,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
instructionTxt.x = 0;
instructionTxt.y = 300;
LK.gui.center.addChild(instructionTxt);
// Game logic methods
function startGame() {
// Reset game state
for (var i = 0; i < stackedBlocks.length; i++) {
stackedBlocks[i].destroy();
}
stackedBlocks = [];
score = 0;
difficultyLevel = 1;
baseY = 2400;
lastBlockWidth = 400;
lastBlockX = 2048 / 2;
gameActive = true;
// Update score display
scoreTxt.setText('0');
// Hide instruction text
instructionTxt.visible = false;
// Create first block
spawnNewBlock();
// Start background music
LK.playMusic('bgMusic');
}
function spawnNewBlock() {
currentBlock = new Block();
currentBlock.blockWidth = lastBlockWidth;
var blockGraphics = currentBlock.getChildAt(0);
blockGraphics.width = currentBlock.blockWidth;
// Randomly start from left or right
currentBlock.x = Math.random() > 0.5 ? 0 + currentBlock.blockWidth / 2 : 2048 - currentBlock.blockWidth / 2;
currentBlock.y = baseY - (stackedBlocks.length + 1) * 110;
currentBlock.movingDirection = currentBlock.x < 1024 ? 1 : -1;
// Increase speed based on difficulty level
currentBlock.speed = 5 + difficultyLevel;
game.addChild(currentBlock);
}
function dropBlock() {
if (!currentBlock || !gameActive) {
return;
}
// Stop the block from moving
currentBlock.stopMoving();
// Check if the block fits on the previous block
var successfulPlacement = true;
if (stackedBlocks.length > 0) {
successfulPlacement = currentBlock.trimToFit(lastBlockX, lastBlockWidth);
}
if (successfulPlacement && currentBlock.blockWidth > 0) {
// Play placement sound
LK.getSound('place').play();
// Update variables for next block
lastBlockWidth = currentBlock.blockWidth;
lastBlockX = currentBlock.x;
// Create a stacked version of the block
var stackedBlock = new StackedBlock();
stackedBlock.setWidth(lastBlockWidth);
stackedBlock.x = lastBlockX;
stackedBlock.y = currentBlock.y;
game.addChild(stackedBlock);
stackedBlocks.push(stackedBlock);
// Remove the moving block
currentBlock.destroy();
currentBlock = null;
// Update score
score += 10;
scoreTxt.setText(score.toString());
// Increase difficulty every 5 points
if (score % 5 === 0) {
difficultyLevel++;
}
// After a short delay, spawn a new block
LK.setTimeout(function () {
spawnNewBlock();
}, 300);
} else {
// Game over
gameActive = false;
// Play miss sound
LK.getSound('miss').play();
// Highlight the missed block in red
currentBlock.highlightMiss();
// Make the block fall off screen
tween(currentBlock, {
y: 3000,
rotation: Math.PI * 2
}, {
duration: 1500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Check if this is a new high score
var highScore = storage.highScore || 0;
if (score > highScore) {
storage.highScore = score;
}
// Show game over screen after a short delay
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
}
});
}
}
function moveCamera() {
// Only move camera if we have enough stacked blocks
if (stackedBlocks.length > 8) {
// Target Y for the topmost block
var targetY = 2732 / 2;
// Calculate how much to move everything down
var moveAmount = baseY - (stackedBlocks.length + 1) * 110 - targetY;
// Move everything down
base.y -= moveAmount;
for (var i = 0; i < stackedBlocks.length; i++) {
stackedBlocks[i].y -= moveAmount;
}
if (currentBlock) {
currentBlock.y -= moveAmount;
}
baseY -= moveAmount;
}
}
// Input handlers
game.down = function (x, y, obj) {
if (!gameActive) {
startGame();
} else {
dropBlock();
}
};
// Update method
game.update = function () {
if (currentBlock && gameActive) {
currentBlock.update();
}
// Move camera to follow the tower
moveCamera();
};
// Show instruction text at start
instructionTxt.visible = true;