/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Block = Container.expand(function (color, width, height) { var self = Container.call(this); // Default values if not provided color = color || 0x4287f5; width = width || 100; height = height || 100; // Create custom block shape with specified color and dimensions var blockShape = self.attachAsset('block', { anchorX: 0.5, anchorY: 0.5, width: width, height: height }); // Set the block's color blockShape.tint = color; // Properties self.isPlaced = false; self.velocity = { x: 0, y: 0 }; self.acceleration = { x: 0, y: 0.2 }; // Gravity self.onGround = false; self.width = width; self.height = height; // Physics update self.updatePhysics = function () { if (self.isPlaced && !self.onGround) { // Apply physics only if the block is placed but not on ground self.velocity.x += self.acceleration.x; self.velocity.y += self.acceleration.y; self.x += self.velocity.x; self.y += self.velocity.y; // Check boundaries if (self.x < self.width / 2) { self.x = self.width / 2; self.velocity.x = -self.velocity.x * 0.5; // Bounce with damping } else if (self.x > 2048 - self.width / 2) { self.x = 2048 - self.width / 2; self.velocity.x = -self.velocity.x * 0.5; // Bounce with damping } // Check if block has hit the ground if (self.y >= groundY - self.height / 2) { self.y = groundY - self.height / 2; self.velocity.y = 0; self.velocity.x *= 0.9; // Friction self.onGround = true; LK.getSound('fall').play(); } } }; // Dragging handlers self.down = function (x, y, obj) { if (!self.isPlaced) { currentDraggedBlock = self; } }; return self; }); var Platform = Container.expand(function (x, y, width) { var self = Container.call(this); width = width || 500; // Create platform shape var platformShape = self.attachAsset('platform', { anchorX: 0.5, anchorY: 0.5, width: width, height: 20 }); // Position platform self.x = x; self.y = y; // Platform properties self.width = width; self.height = 20; return self; }); var ScoreZone = Container.expand(function (x, y, width) { var self = Container.call(this); width = width || 500; // Create score zone shape - this will be invisible in the game var zoneShape = self.attachAsset('scoreZone', { anchorX: 0.5, anchorY: 0, width: width, height: 2000, alpha: 0.1 // Almost invisible }); // Position zone self.x = x; self.y = y; // Zone properties self.width = width; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB // Sky blue background }); /**** * Game Code ****/ // Game variables var currentLevel = storage.level || 1; var score = 0; var currentDraggedBlock = null; var blocks = []; var placedBlocks = []; var maxStackHeight = 0; var groundY = 2500; var platformY = groundY - 20; var centerX = 2048 / 2; var levelCompleted = false; var windStrength = 0; var windDirection = 1; var blockColors = [0x4287f5, 0xff5757, 0x57ff57, 0xffff57, 0xff57ff, 0x57ffff]; var nextBlockColor = blockColors[Math.floor(Math.random() * blockColors.length)]; var nextBlockWidth = 100; var nextBlockHeight = 100; var blockWidths = [80, 100, 120, 150]; var blockHeights = [60, 80, 100, 120]; // Set up game environment game.setBackgroundColor(0x87CEEB); // Sky blue background // Create ground var ground = game.addChild(LK.getAsset('ground', { anchorX: 0.5, anchorY: 0, width: 2048, height: 100 })); ground.x = centerX; ground.y = groundY; // Create main platform var mainPlatform = game.addChild(new Platform(centerX, platformY, 500)); // Create score zone (for checking if blocks are within scoring area) var scoreZone = game.addChild(new ScoreZone(centerX, 0, 500)); // Score display var scoreTxt = new Text2('Score: 0', { size: 70, fill: 0xFFFFFF }); scoreTxt.anchor.set(1, 0); // Top right anchor LK.gui.topRight.addChild(scoreTxt); // Level display var levelTxt = new Text2('Level: ' + currentLevel, { size: 70, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); // Top left anchor LK.gui.topRight.addChild(levelTxt); levelTxt.y = 80; // Position below score // Height display var heightTxt = new Text2('Tower Height: 0m', { size: 50, fill: 0xFFFFFF }); heightTxt.anchor.set(0.5, 0); // Top center anchor LK.gui.top.addChild(heightTxt); heightTxt.y = 20; // Message text for level completion, etc. var messageTxt = new Text2('', { size: 80, fill: 0xFFFF00 }); messageTxt.anchor.set(0.5, 0.5); // Center anchor LK.gui.center.addChild(messageTxt); messageTxt.alpha = 0; // Create initial block function createNewBlock() { var newBlock = new Block(nextBlockColor, nextBlockWidth, nextBlockHeight); newBlock.x = centerX; newBlock.y = 200; // Set next block's properties nextBlockColor = blockColors[Math.floor(Math.random() * blockColors.length)]; // As levels progress, vary block sizes more if (currentLevel > 1) { nextBlockWidth = blockWidths[Math.floor(Math.random() * blockWidths.length)]; nextBlockHeight = blockHeights[Math.floor(Math.random() * blockHeights.length)]; } blocks.push(newBlock); game.addChild(newBlock); return newBlock; } // Create first block createNewBlock(); // Update score function updateScore(points) { score += points; scoreTxt.setText('Score: ' + score); } // Update level function setLevel(level) { currentLevel = level; storage.level = level; levelTxt.setText('Level: ' + currentLevel); // Adjust difficulty based on level windStrength = (currentLevel - 1) * 0.02; } // Check tower height and update function updateTowerHeight() { if (placedBlocks.length === 0) { return 0; } // Find the highest block's top edge var highestY = groundY; for (var i = 0; i < placedBlocks.length; i++) { var blockTopY = placedBlocks[i].y - placedBlocks[i].height / 2; if (blockTopY < highestY) { highestY = blockTopY; } } // Calculate height from ground var height = groundY - highestY; var heightInMeters = Math.floor(height / 50); // Convert pixels to "meters" for display heightTxt.setText('Tower Height: ' + heightInMeters + 'm'); // Update max height if needed if (height > maxStackHeight) { maxStackHeight = height; // Check for level completion var requiredHeight = 200 + currentLevel * 100; if (maxStackHeight >= requiredHeight && !levelCompleted) { levelCompleted = true; showLevelCompleteMessage(); } } return height; } // Show level complete message function showLevelCompleteMessage() { messageTxt.setText('Level ' + currentLevel + ' Complete!'); messageTxt.alpha = 1; // Play success sound LK.getSound('success').play(); // Award bonus points for level completion updateScore(currentLevel * 100); // Set timeout to advance to next level LK.setTimeout(function () { setLevel(currentLevel + 1); levelCompleted = false; // Hide message with fade tween(messageTxt, { alpha: 0 }, { duration: 1000 }); // Create new block if needed if (blocks.length === 0) { createNewBlock(); } }, 3000); } // Check stability of the tower function checkTowerStability() { // Simple implementation: if blocks are stacked too high without sufficient width, they become unstable var unstableBlocks = 0; for (var i = 0; i < placedBlocks.length; i++) { var block = placedBlocks[i]; // Skip blocks that are already on the ground if (block.onGround) { continue; } var isSupported = false; // Check if block is supported by platform if (block.y + block.height / 2 >= platformY - 10 && block.x + block.width / 2 >= mainPlatform.x - mainPlatform.width / 2 && block.x - block.width / 2 <= mainPlatform.x + mainPlatform.width / 2) { isSupported = true; } else { // Check if supported by other blocks for (var j = 0; j < placedBlocks.length; j++) { if (i !== j) { var supportBlock = placedBlocks[j]; // Simple overlap check if (block.y + block.height / 2 >= supportBlock.y - supportBlock.height / 2 - 5 && block.y + block.height / 2 <= supportBlock.y - supportBlock.height / 2 + 5 && block.x + block.width / 2 >= supportBlock.x - supportBlock.width / 2 && block.x - block.width / 2 <= supportBlock.x + supportBlock.width / 2) { isSupported = true; break; } } } } if (!isSupported) { // Make block fall block.velocity.y = 1; block.onGround = false; unstableBlocks++; } } return unstableBlocks; } // Apply wind effects based on level function applyWindEffects() { if (windStrength > 0) { // Occasionally change wind direction if (Math.random() < 0.01) { windDirection = -windDirection; } // Apply wind force to blocks for (var i = 0; i < placedBlocks.length; i++) { var block = placedBlocks[i]; if (!block.onGround) { block.velocity.x += windDirection * windStrength; } } } } // Handle touch/mouse move function handleMove(x, y, obj) { if (currentDraggedBlock) { currentDraggedBlock.x = x; currentDraggedBlock.y = y; } } // Game event handlers game.move = handleMove; game.down = function (x, y, obj) { // Already handled in Block class }; game.up = function (x, y, obj) { if (currentDraggedBlock && !currentDraggedBlock.isPlaced) { // Place the block currentDraggedBlock.isPlaced = true; placedBlocks.push(currentDraggedBlock); // Play placement sound LK.getSound('place').play(); // Check if block is within score zone var inScoreZone = currentDraggedBlock.x + currentDraggedBlock.width / 2 >= scoreZone.x - scoreZone.width / 2 && currentDraggedBlock.x - currentDraggedBlock.width / 2 <= scoreZone.x + scoreZone.width / 2; // Award points based on placement height and zone var points = 10; if (inScoreZone) { points += 20; } // Bonus points for height var height = groundY - currentDraggedBlock.y; points += Math.floor(height / 50) * 5; updateScore(points); // Create a new block after a short delay LK.setTimeout(function () { if (!levelCompleted && blocks.length < 2) { createNewBlock(); } }, 500); currentDraggedBlock = null; } }; // Main game update loop game.update = function () { // Skip updates if game is in level transition if (messageTxt.alpha > 0) { return; } // Update all placed blocks for (var i = 0; i < placedBlocks.length; i++) { placedBlocks[i].updatePhysics(); } // Check tower stability checkTowerStability(); // Apply wind effects applyWindEffects(); // Update tower height updateTowerHeight(); // Check for game over (structure collapse) var unstableCount = 0; for (var j = 0; j < placedBlocks.length; j++) { if (placedBlocks[j].onGround && (placedBlocks[j].x < centerX - 500 || placedBlocks[j].x > centerX + 500)) { unstableCount++; } } // If too many blocks have fallen off the platform, game over if (unstableCount > 3 && placedBlocks.length > 5) { LK.showGameOver(); } // Every 5 seconds, check if tower is completely stable if (LK.ticks % 300 === 0 && placedBlocks.length > 0) { var allStable = true; for (var k = 0; k < placedBlocks.length; k++) { if (!placedBlocks[k].onGround && (Math.abs(placedBlocks[k].velocity.x) > 0.1 || Math.abs(placedBlocks[k].velocity.y) > 0.1)) { allStable = false; break; } } // If tower is completely stable and tall enough, award stability bonus if (allStable && maxStackHeight > 200) { updateScore(25); // Show small message messageTxt.setText('Stability Bonus: +25'); messageTxt.alpha = 1; // Fade out message tween(messageTxt, { alpha: 0 }, { duration: 1500 }); } } }; // Play background music LK.playMusic('bgmusic', { fade: { start: 0, end: 0.3, duration: 2000 } });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Block = Container.expand(function (color, width, height) {
var self = Container.call(this);
// Default values if not provided
color = color || 0x4287f5;
width = width || 100;
height = height || 100;
// Create custom block shape with specified color and dimensions
var blockShape = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5,
width: width,
height: height
});
// Set the block's color
blockShape.tint = color;
// Properties
self.isPlaced = false;
self.velocity = {
x: 0,
y: 0
};
self.acceleration = {
x: 0,
y: 0.2
}; // Gravity
self.onGround = false;
self.width = width;
self.height = height;
// Physics update
self.updatePhysics = function () {
if (self.isPlaced && !self.onGround) {
// Apply physics only if the block is placed but not on ground
self.velocity.x += self.acceleration.x;
self.velocity.y += self.acceleration.y;
self.x += self.velocity.x;
self.y += self.velocity.y;
// Check boundaries
if (self.x < self.width / 2) {
self.x = self.width / 2;
self.velocity.x = -self.velocity.x * 0.5; // Bounce with damping
} else if (self.x > 2048 - self.width / 2) {
self.x = 2048 - self.width / 2;
self.velocity.x = -self.velocity.x * 0.5; // Bounce with damping
}
// Check if block has hit the ground
if (self.y >= groundY - self.height / 2) {
self.y = groundY - self.height / 2;
self.velocity.y = 0;
self.velocity.x *= 0.9; // Friction
self.onGround = true;
LK.getSound('fall').play();
}
}
};
// Dragging handlers
self.down = function (x, y, obj) {
if (!self.isPlaced) {
currentDraggedBlock = self;
}
};
return self;
});
var Platform = Container.expand(function (x, y, width) {
var self = Container.call(this);
width = width || 500;
// Create platform shape
var platformShape = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5,
width: width,
height: 20
});
// Position platform
self.x = x;
self.y = y;
// Platform properties
self.width = width;
self.height = 20;
return self;
});
var ScoreZone = Container.expand(function (x, y, width) {
var self = Container.call(this);
width = width || 500;
// Create score zone shape - this will be invisible in the game
var zoneShape = self.attachAsset('scoreZone', {
anchorX: 0.5,
anchorY: 0,
width: width,
height: 2000,
alpha: 0.1 // Almost invisible
});
// Position zone
self.x = x;
self.y = y;
// Zone properties
self.width = width;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Game variables
var currentLevel = storage.level || 1;
var score = 0;
var currentDraggedBlock = null;
var blocks = [];
var placedBlocks = [];
var maxStackHeight = 0;
var groundY = 2500;
var platformY = groundY - 20;
var centerX = 2048 / 2;
var levelCompleted = false;
var windStrength = 0;
var windDirection = 1;
var blockColors = [0x4287f5, 0xff5757, 0x57ff57, 0xffff57, 0xff57ff, 0x57ffff];
var nextBlockColor = blockColors[Math.floor(Math.random() * blockColors.length)];
var nextBlockWidth = 100;
var nextBlockHeight = 100;
var blockWidths = [80, 100, 120, 150];
var blockHeights = [60, 80, 100, 120];
// Set up game environment
game.setBackgroundColor(0x87CEEB); // Sky blue background
// Create ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 0,
width: 2048,
height: 100
}));
ground.x = centerX;
ground.y = groundY;
// Create main platform
var mainPlatform = game.addChild(new Platform(centerX, platformY, 500));
// Create score zone (for checking if blocks are within scoring area)
var scoreZone = game.addChild(new ScoreZone(centerX, 0, 500));
// Score display
var scoreTxt = new Text2('Score: 0', {
size: 70,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(1, 0); // Top right anchor
LK.gui.topRight.addChild(scoreTxt);
// Level display
var levelTxt = new Text2('Level: ' + currentLevel, {
size: 70,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0); // Top left anchor
LK.gui.topRight.addChild(levelTxt);
levelTxt.y = 80; // Position below score
// Height display
var heightTxt = new Text2('Tower Height: 0m', {
size: 50,
fill: 0xFFFFFF
});
heightTxt.anchor.set(0.5, 0); // Top center anchor
LK.gui.top.addChild(heightTxt);
heightTxt.y = 20;
// Message text for level completion, etc.
var messageTxt = new Text2('', {
size: 80,
fill: 0xFFFF00
});
messageTxt.anchor.set(0.5, 0.5); // Center anchor
LK.gui.center.addChild(messageTxt);
messageTxt.alpha = 0;
// Create initial block
function createNewBlock() {
var newBlock = new Block(nextBlockColor, nextBlockWidth, nextBlockHeight);
newBlock.x = centerX;
newBlock.y = 200;
// Set next block's properties
nextBlockColor = blockColors[Math.floor(Math.random() * blockColors.length)];
// As levels progress, vary block sizes more
if (currentLevel > 1) {
nextBlockWidth = blockWidths[Math.floor(Math.random() * blockWidths.length)];
nextBlockHeight = blockHeights[Math.floor(Math.random() * blockHeights.length)];
}
blocks.push(newBlock);
game.addChild(newBlock);
return newBlock;
}
// Create first block
createNewBlock();
// Update score
function updateScore(points) {
score += points;
scoreTxt.setText('Score: ' + score);
}
// Update level
function setLevel(level) {
currentLevel = level;
storage.level = level;
levelTxt.setText('Level: ' + currentLevel);
// Adjust difficulty based on level
windStrength = (currentLevel - 1) * 0.02;
}
// Check tower height and update
function updateTowerHeight() {
if (placedBlocks.length === 0) {
return 0;
}
// Find the highest block's top edge
var highestY = groundY;
for (var i = 0; i < placedBlocks.length; i++) {
var blockTopY = placedBlocks[i].y - placedBlocks[i].height / 2;
if (blockTopY < highestY) {
highestY = blockTopY;
}
}
// Calculate height from ground
var height = groundY - highestY;
var heightInMeters = Math.floor(height / 50); // Convert pixels to "meters" for display
heightTxt.setText('Tower Height: ' + heightInMeters + 'm');
// Update max height if needed
if (height > maxStackHeight) {
maxStackHeight = height;
// Check for level completion
var requiredHeight = 200 + currentLevel * 100;
if (maxStackHeight >= requiredHeight && !levelCompleted) {
levelCompleted = true;
showLevelCompleteMessage();
}
}
return height;
}
// Show level complete message
function showLevelCompleteMessage() {
messageTxt.setText('Level ' + currentLevel + ' Complete!');
messageTxt.alpha = 1;
// Play success sound
LK.getSound('success').play();
// Award bonus points for level completion
updateScore(currentLevel * 100);
// Set timeout to advance to next level
LK.setTimeout(function () {
setLevel(currentLevel + 1);
levelCompleted = false;
// Hide message with fade
tween(messageTxt, {
alpha: 0
}, {
duration: 1000
});
// Create new block if needed
if (blocks.length === 0) {
createNewBlock();
}
}, 3000);
}
// Check stability of the tower
function checkTowerStability() {
// Simple implementation: if blocks are stacked too high without sufficient width, they become unstable
var unstableBlocks = 0;
for (var i = 0; i < placedBlocks.length; i++) {
var block = placedBlocks[i];
// Skip blocks that are already on the ground
if (block.onGround) {
continue;
}
var isSupported = false;
// Check if block is supported by platform
if (block.y + block.height / 2 >= platformY - 10 && block.x + block.width / 2 >= mainPlatform.x - mainPlatform.width / 2 && block.x - block.width / 2 <= mainPlatform.x + mainPlatform.width / 2) {
isSupported = true;
} else {
// Check if supported by other blocks
for (var j = 0; j < placedBlocks.length; j++) {
if (i !== j) {
var supportBlock = placedBlocks[j];
// Simple overlap check
if (block.y + block.height / 2 >= supportBlock.y - supportBlock.height / 2 - 5 && block.y + block.height / 2 <= supportBlock.y - supportBlock.height / 2 + 5 && block.x + block.width / 2 >= supportBlock.x - supportBlock.width / 2 && block.x - block.width / 2 <= supportBlock.x + supportBlock.width / 2) {
isSupported = true;
break;
}
}
}
}
if (!isSupported) {
// Make block fall
block.velocity.y = 1;
block.onGround = false;
unstableBlocks++;
}
}
return unstableBlocks;
}
// Apply wind effects based on level
function applyWindEffects() {
if (windStrength > 0) {
// Occasionally change wind direction
if (Math.random() < 0.01) {
windDirection = -windDirection;
}
// Apply wind force to blocks
for (var i = 0; i < placedBlocks.length; i++) {
var block = placedBlocks[i];
if (!block.onGround) {
block.velocity.x += windDirection * windStrength;
}
}
}
}
// Handle touch/mouse move
function handleMove(x, y, obj) {
if (currentDraggedBlock) {
currentDraggedBlock.x = x;
currentDraggedBlock.y = y;
}
}
// Game event handlers
game.move = handleMove;
game.down = function (x, y, obj) {
// Already handled in Block class
};
game.up = function (x, y, obj) {
if (currentDraggedBlock && !currentDraggedBlock.isPlaced) {
// Place the block
currentDraggedBlock.isPlaced = true;
placedBlocks.push(currentDraggedBlock);
// Play placement sound
LK.getSound('place').play();
// Check if block is within score zone
var inScoreZone = currentDraggedBlock.x + currentDraggedBlock.width / 2 >= scoreZone.x - scoreZone.width / 2 && currentDraggedBlock.x - currentDraggedBlock.width / 2 <= scoreZone.x + scoreZone.width / 2;
// Award points based on placement height and zone
var points = 10;
if (inScoreZone) {
points += 20;
}
// Bonus points for height
var height = groundY - currentDraggedBlock.y;
points += Math.floor(height / 50) * 5;
updateScore(points);
// Create a new block after a short delay
LK.setTimeout(function () {
if (!levelCompleted && blocks.length < 2) {
createNewBlock();
}
}, 500);
currentDraggedBlock = null;
}
};
// Main game update loop
game.update = function () {
// Skip updates if game is in level transition
if (messageTxt.alpha > 0) {
return;
}
// Update all placed blocks
for (var i = 0; i < placedBlocks.length; i++) {
placedBlocks[i].updatePhysics();
}
// Check tower stability
checkTowerStability();
// Apply wind effects
applyWindEffects();
// Update tower height
updateTowerHeight();
// Check for game over (structure collapse)
var unstableCount = 0;
for (var j = 0; j < placedBlocks.length; j++) {
if (placedBlocks[j].onGround && (placedBlocks[j].x < centerX - 500 || placedBlocks[j].x > centerX + 500)) {
unstableCount++;
}
}
// If too many blocks have fallen off the platform, game over
if (unstableCount > 3 && placedBlocks.length > 5) {
LK.showGameOver();
}
// Every 5 seconds, check if tower is completely stable
if (LK.ticks % 300 === 0 && placedBlocks.length > 0) {
var allStable = true;
for (var k = 0; k < placedBlocks.length; k++) {
if (!placedBlocks[k].onGround && (Math.abs(placedBlocks[k].velocity.x) > 0.1 || Math.abs(placedBlocks[k].velocity.y) > 0.1)) {
allStable = false;
break;
}
}
// If tower is completely stable and tall enough, award stability bonus
if (allStable && maxStackHeight > 200) {
updateScore(25);
// Show small message
messageTxt.setText('Stability Bonus: +25');
messageTxt.alpha = 1;
// Fade out message
tween(messageTxt, {
alpha: 0
}, {
duration: 1500
});
}
}
};
// Play background music
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 0.3,
duration: 2000
}
});