/****
* 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;