User prompt
for one block make 10 points
Code edit (1 edits merged)
Please save this source code
User prompt
Stack the Blocks
Initial prompt
"Stack the Blocks" is a simple yet addictive casual game where players aim to build the tallest tower by stacking moving blocks on top of each other. Each block moves horizontally across the screen, and the player must tap at the right moment to drop it onto the previous one. If the block is not perfectly aligned, the overhanging part gets trimmed off, making the next block smaller and increasing the challenge. The game continues until a block completely misses the stack. With smooth animations, responsive tap controls, and progressively increasing speed, this game tests the player's timing and precision. Ideal for FRVR, it offers an endless gameplay loop perfect for mobile and web platforms.
/****
* 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++;
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; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,282 @@
-/****
+/****
+* 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: 0x000000
-});
\ No newline at end of file
+ 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++;
+ 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;
\ No newline at end of file