/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Block = Container.expand(function (blockType) {
var self = Container.call(this);
var blockGraphics = self.attachAsset(blockType + 'Block', {
anchorX: 0.5,
anchorY: 0.5
});
self.blockType = blockType;
self.gridX = -1;
self.gridY = -1;
self.isPlaced = false;
self.isDragging = false;
self.fallSpeed = 0;
self.isStable = true;
self.lastStable = true;
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = GRID_START_X + gridX * GRID_SIZE + GRID_SIZE / 2;
self.y = GRID_START_Y + gridY * GRID_SIZE + GRID_SIZE / 2;
};
self.checkStability = function () {
if (self.gridY >= GRID_HEIGHT - 1) {
return true; // Ground level is stable
}
// Check if there's a block below
for (var i = 0; i < placedBlocks.length; i++) {
var otherBlock = placedBlocks[i];
if (otherBlock !== self && otherBlock.gridX === self.gridX && otherBlock.gridY === self.gridY + 1) {
return true;
}
}
return false;
};
self.update = function () {
if (!self.isPlaced || self.isDragging) return;
self.lastStable = self.isStable;
self.isStable = self.checkStability();
// If block becomes unstable, make it fall
if (self.lastStable && !self.isStable) {
self.fallSpeed = 2;
}
// Apply falling physics
if (!self.isStable && self.fallSpeed > 0) {
self.y += self.fallSpeed;
self.fallSpeed += 0.5; // Gravity
// Check if block has hit the ground or another block
var targetY = GRID_START_Y + (GRID_HEIGHT - 1) * GRID_SIZE + GRID_SIZE / 2;
if (self.y >= targetY) {
self.y = targetY;
self.gridY = GRID_HEIGHT - 1;
self.fallSpeed = 0;
self.isStable = true;
LK.getSound('place').play();
updateScore();
} else {
// Check collision with other blocks
for (var i = 0; i < placedBlocks.length; i++) {
var otherBlock = placedBlocks[i];
if (otherBlock !== self && Math.abs(otherBlock.x - self.x) < GRID_SIZE && Math.abs(otherBlock.y - self.y) < GRID_SIZE && self.y >= otherBlock.y - GRID_SIZE) {
self.y = otherBlock.y - GRID_SIZE;
self.gridY = otherBlock.gridY - 1;
self.fallSpeed = 0;
self.isStable = true;
LK.getSound('place').play();
updateScore();
break;
}
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game constants
var GRID_SIZE = 120;
var GRID_WIDTH = 16;
var GRID_HEIGHT = 14;
var GRID_START_X = 64;
var GRID_START_Y = 300;
var PALETTE_HEIGHT = 200;
// Game variables
var placedBlocks = [];
var draggedBlock = null;
var blockTypes = ['red', 'blue', 'green', 'yellow'];
var paletteBlocks = [];
// Create grid background
var gridBg = game.attachAsset('gridBackground', {
x: 0,
y: 300,
anchorX: 0,
anchorY: 0
});
// Create palette background
var paletteBg = game.attachAsset('paletteBackground', {
x: 0,
y: 2732 - PALETTE_HEIGHT,
anchorX: 0,
anchorY: 0
});
// Create palette blocks
for (var i = 0; i < blockTypes.length; i++) {
var paletteBlock = new Block(blockTypes[i]);
paletteBlock.x = 200 + i * 300;
paletteBlock.y = 2732 - PALETTE_HEIGHT / 2;
paletteBlock.isPaletteBlock = true;
paletteBlocks.push(paletteBlock);
game.addChild(paletteBlock);
}
// Score display
var scoreTxt = new Text2('Height: 0 | Blocks: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// High score display
var highScoreTxt = new Text2('Best: ' + (storage.highScore || 0), {
size: 60,
fill: 0xFFFF00
});
highScoreTxt.anchor.set(0.5, 0);
highScoreTxt.y = 100;
LK.gui.top.addChild(highScoreTxt);
function updateScore() {
var maxHeight = 0;
var blockCount = placedBlocks.length;
// Calculate maximum height
for (var i = 0; i < placedBlocks.length; i++) {
var block = placedBlocks[i];
if (block.isPlaced && block.isStable) {
var height = GRID_HEIGHT - block.gridY;
if (height > maxHeight) {
maxHeight = height;
}
}
}
var currentScore = maxHeight * 10 + blockCount;
LK.setScore(currentScore);
scoreTxt.setText('Height: ' + maxHeight + ' | Blocks: ' + blockCount);
// Update high score
var highScore = storage.highScore || 0;
if (currentScore > highScore) {
storage.highScore = currentScore;
highScoreTxt.setText('Best: ' + currentScore);
}
}
function isValidPlacement(gridX, gridY) {
if (gridX < 0 || gridX >= GRID_WIDTH || gridY < 0 || gridY >= GRID_HEIGHT) {
return false;
}
// Check if position is occupied
for (var i = 0; i < placedBlocks.length; i++) {
var block = placedBlocks[i];
if (block.gridX === gridX && block.gridY === gridY) {
return false;
}
}
return true;
}
function getGridPosition(x, y) {
var gridX = Math.floor((x - GRID_START_X) / GRID_SIZE);
var gridY = Math.floor((y - GRID_START_Y) / GRID_SIZE);
return {
x: gridX,
y: gridY
};
}
function checkForCollapses() {
var collapsedAny = false;
// Check all blocks for stability
for (var i = placedBlocks.length - 1; i >= 0; i--) {
var block = placedBlocks[i];
if (block.isPlaced && !block.checkStability() && block.isStable) {
block.isStable = false;
collapsedAny = true;
}
}
if (collapsedAny) {
LK.getSound('collapse').play();
}
}
game.down = function (x, y, obj) {
// Check if clicking on palette block
for (var i = 0; i < paletteBlocks.length; i++) {
var paletteBlock = paletteBlocks[i];
if (Math.abs(x - paletteBlock.x) < GRID_SIZE / 2 && Math.abs(y - paletteBlock.y) < GRID_SIZE / 2) {
// Create new block from palette
draggedBlock = new Block(paletteBlock.blockType);
draggedBlock.x = x;
draggedBlock.y = y;
draggedBlock.isDragging = true;
game.addChild(draggedBlock);
return;
}
}
// Check if clicking on placed block
for (var i = 0; i < placedBlocks.length; i++) {
var block = placedBlocks[i];
if (Math.abs(x - block.x) < GRID_SIZE / 2 && Math.abs(y - block.y) < GRID_SIZE / 2) {
draggedBlock = block;
draggedBlock.isDragging = true;
if (block.isPlaced) {
// Remove from grid
block.isPlaced = false;
var index = placedBlocks.indexOf(block);
placedBlocks.splice(index, 1);
checkForCollapses();
}
return;
}
}
};
game.move = function (x, y, obj) {
if (draggedBlock) {
draggedBlock.x = x;
draggedBlock.y = y;
// Visual feedback for valid placement
var gridPos = getGridPosition(x, y);
if (y >= GRID_START_Y && y < GRID_START_Y + GRID_HEIGHT * GRID_SIZE) {
if (isValidPlacement(gridPos.x, gridPos.y)) {
draggedBlock.alpha = 1.0;
} else {
draggedBlock.alpha = 0.5;
}
} else {
draggedBlock.alpha = 0.7;
}
}
};
game.up = function (x, y, obj) {
if (draggedBlock) {
draggedBlock.isDragging = false;
draggedBlock.alpha = 1.0;
var gridPos = getGridPosition(x, y);
// Check if dropping in valid grid position
if (y >= GRID_START_Y && y < GRID_START_Y + GRID_HEIGHT * GRID_SIZE && isValidPlacement(gridPos.x, gridPos.y)) {
draggedBlock.setGridPosition(gridPos.x, gridPos.y);
draggedBlock.isPlaced = true;
placedBlocks.push(draggedBlock);
LK.getSound('place').play();
updateScore();
} else if (y < GRID_START_Y || y >= 2732 - PALETTE_HEIGHT) {
// Dropped outside grid area - remove block
if (!draggedBlock.isPaletteBlock) {
draggedBlock.destroy();
}
} else {
// Invalid placement - snap back or remove
if (draggedBlock.isPlaced) {
// Was previously placed, return to grid
draggedBlock.setGridPosition(draggedBlock.gridX, draggedBlock.gridY);
placedBlocks.push(draggedBlock);
} else {
// New block dropped in invalid location
draggedBlock.destroy();
}
}
draggedBlock = null;
}
};
game.update = function () {
// Update all placed blocks
for (var i = 0; i < placedBlocks.length; i++) {
placedBlocks[i].update();
}
// Clean up blocks that have fallen off screen
for (var i = placedBlocks.length - 1; i >= 0; i--) {
var block = placedBlocks[i];
if (block.y > 2732 + 200) {
block.destroy();
placedBlocks.splice(i, 1);
updateScore();
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Block = Container.expand(function (blockType) {
var self = Container.call(this);
var blockGraphics = self.attachAsset(blockType + 'Block', {
anchorX: 0.5,
anchorY: 0.5
});
self.blockType = blockType;
self.gridX = -1;
self.gridY = -1;
self.isPlaced = false;
self.isDragging = false;
self.fallSpeed = 0;
self.isStable = true;
self.lastStable = true;
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = GRID_START_X + gridX * GRID_SIZE + GRID_SIZE / 2;
self.y = GRID_START_Y + gridY * GRID_SIZE + GRID_SIZE / 2;
};
self.checkStability = function () {
if (self.gridY >= GRID_HEIGHT - 1) {
return true; // Ground level is stable
}
// Check if there's a block below
for (var i = 0; i < placedBlocks.length; i++) {
var otherBlock = placedBlocks[i];
if (otherBlock !== self && otherBlock.gridX === self.gridX && otherBlock.gridY === self.gridY + 1) {
return true;
}
}
return false;
};
self.update = function () {
if (!self.isPlaced || self.isDragging) return;
self.lastStable = self.isStable;
self.isStable = self.checkStability();
// If block becomes unstable, make it fall
if (self.lastStable && !self.isStable) {
self.fallSpeed = 2;
}
// Apply falling physics
if (!self.isStable && self.fallSpeed > 0) {
self.y += self.fallSpeed;
self.fallSpeed += 0.5; // Gravity
// Check if block has hit the ground or another block
var targetY = GRID_START_Y + (GRID_HEIGHT - 1) * GRID_SIZE + GRID_SIZE / 2;
if (self.y >= targetY) {
self.y = targetY;
self.gridY = GRID_HEIGHT - 1;
self.fallSpeed = 0;
self.isStable = true;
LK.getSound('place').play();
updateScore();
} else {
// Check collision with other blocks
for (var i = 0; i < placedBlocks.length; i++) {
var otherBlock = placedBlocks[i];
if (otherBlock !== self && Math.abs(otherBlock.x - self.x) < GRID_SIZE && Math.abs(otherBlock.y - self.y) < GRID_SIZE && self.y >= otherBlock.y - GRID_SIZE) {
self.y = otherBlock.y - GRID_SIZE;
self.gridY = otherBlock.gridY - 1;
self.fallSpeed = 0;
self.isStable = true;
LK.getSound('place').play();
updateScore();
break;
}
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game constants
var GRID_SIZE = 120;
var GRID_WIDTH = 16;
var GRID_HEIGHT = 14;
var GRID_START_X = 64;
var GRID_START_Y = 300;
var PALETTE_HEIGHT = 200;
// Game variables
var placedBlocks = [];
var draggedBlock = null;
var blockTypes = ['red', 'blue', 'green', 'yellow'];
var paletteBlocks = [];
// Create grid background
var gridBg = game.attachAsset('gridBackground', {
x: 0,
y: 300,
anchorX: 0,
anchorY: 0
});
// Create palette background
var paletteBg = game.attachAsset('paletteBackground', {
x: 0,
y: 2732 - PALETTE_HEIGHT,
anchorX: 0,
anchorY: 0
});
// Create palette blocks
for (var i = 0; i < blockTypes.length; i++) {
var paletteBlock = new Block(blockTypes[i]);
paletteBlock.x = 200 + i * 300;
paletteBlock.y = 2732 - PALETTE_HEIGHT / 2;
paletteBlock.isPaletteBlock = true;
paletteBlocks.push(paletteBlock);
game.addChild(paletteBlock);
}
// Score display
var scoreTxt = new Text2('Height: 0 | Blocks: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// High score display
var highScoreTxt = new Text2('Best: ' + (storage.highScore || 0), {
size: 60,
fill: 0xFFFF00
});
highScoreTxt.anchor.set(0.5, 0);
highScoreTxt.y = 100;
LK.gui.top.addChild(highScoreTxt);
function updateScore() {
var maxHeight = 0;
var blockCount = placedBlocks.length;
// Calculate maximum height
for (var i = 0; i < placedBlocks.length; i++) {
var block = placedBlocks[i];
if (block.isPlaced && block.isStable) {
var height = GRID_HEIGHT - block.gridY;
if (height > maxHeight) {
maxHeight = height;
}
}
}
var currentScore = maxHeight * 10 + blockCount;
LK.setScore(currentScore);
scoreTxt.setText('Height: ' + maxHeight + ' | Blocks: ' + blockCount);
// Update high score
var highScore = storage.highScore || 0;
if (currentScore > highScore) {
storage.highScore = currentScore;
highScoreTxt.setText('Best: ' + currentScore);
}
}
function isValidPlacement(gridX, gridY) {
if (gridX < 0 || gridX >= GRID_WIDTH || gridY < 0 || gridY >= GRID_HEIGHT) {
return false;
}
// Check if position is occupied
for (var i = 0; i < placedBlocks.length; i++) {
var block = placedBlocks[i];
if (block.gridX === gridX && block.gridY === gridY) {
return false;
}
}
return true;
}
function getGridPosition(x, y) {
var gridX = Math.floor((x - GRID_START_X) / GRID_SIZE);
var gridY = Math.floor((y - GRID_START_Y) / GRID_SIZE);
return {
x: gridX,
y: gridY
};
}
function checkForCollapses() {
var collapsedAny = false;
// Check all blocks for stability
for (var i = placedBlocks.length - 1; i >= 0; i--) {
var block = placedBlocks[i];
if (block.isPlaced && !block.checkStability() && block.isStable) {
block.isStable = false;
collapsedAny = true;
}
}
if (collapsedAny) {
LK.getSound('collapse').play();
}
}
game.down = function (x, y, obj) {
// Check if clicking on palette block
for (var i = 0; i < paletteBlocks.length; i++) {
var paletteBlock = paletteBlocks[i];
if (Math.abs(x - paletteBlock.x) < GRID_SIZE / 2 && Math.abs(y - paletteBlock.y) < GRID_SIZE / 2) {
// Create new block from palette
draggedBlock = new Block(paletteBlock.blockType);
draggedBlock.x = x;
draggedBlock.y = y;
draggedBlock.isDragging = true;
game.addChild(draggedBlock);
return;
}
}
// Check if clicking on placed block
for (var i = 0; i < placedBlocks.length; i++) {
var block = placedBlocks[i];
if (Math.abs(x - block.x) < GRID_SIZE / 2 && Math.abs(y - block.y) < GRID_SIZE / 2) {
draggedBlock = block;
draggedBlock.isDragging = true;
if (block.isPlaced) {
// Remove from grid
block.isPlaced = false;
var index = placedBlocks.indexOf(block);
placedBlocks.splice(index, 1);
checkForCollapses();
}
return;
}
}
};
game.move = function (x, y, obj) {
if (draggedBlock) {
draggedBlock.x = x;
draggedBlock.y = y;
// Visual feedback for valid placement
var gridPos = getGridPosition(x, y);
if (y >= GRID_START_Y && y < GRID_START_Y + GRID_HEIGHT * GRID_SIZE) {
if (isValidPlacement(gridPos.x, gridPos.y)) {
draggedBlock.alpha = 1.0;
} else {
draggedBlock.alpha = 0.5;
}
} else {
draggedBlock.alpha = 0.7;
}
}
};
game.up = function (x, y, obj) {
if (draggedBlock) {
draggedBlock.isDragging = false;
draggedBlock.alpha = 1.0;
var gridPos = getGridPosition(x, y);
// Check if dropping in valid grid position
if (y >= GRID_START_Y && y < GRID_START_Y + GRID_HEIGHT * GRID_SIZE && isValidPlacement(gridPos.x, gridPos.y)) {
draggedBlock.setGridPosition(gridPos.x, gridPos.y);
draggedBlock.isPlaced = true;
placedBlocks.push(draggedBlock);
LK.getSound('place').play();
updateScore();
} else if (y < GRID_START_Y || y >= 2732 - PALETTE_HEIGHT) {
// Dropped outside grid area - remove block
if (!draggedBlock.isPaletteBlock) {
draggedBlock.destroy();
}
} else {
// Invalid placement - snap back or remove
if (draggedBlock.isPlaced) {
// Was previously placed, return to grid
draggedBlock.setGridPosition(draggedBlock.gridX, draggedBlock.gridY);
placedBlocks.push(draggedBlock);
} else {
// New block dropped in invalid location
draggedBlock.destroy();
}
}
draggedBlock = null;
}
};
game.update = function () {
// Update all placed blocks
for (var i = 0; i < placedBlocks.length; i++) {
placedBlocks[i].update();
}
// Clean up blocks that have fallen off screen
for (var i = placedBlocks.length - 1; i >= 0; i--) {
var block = placedBlocks[i];
if (block.y > 2732 + 200) {
block.destroy();
placedBlocks.splice(i, 1);
updateScore();
}
}
};