/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// IceBlock: Represents a single moving or stacked ice block
var IceBlock = Container.expand(function () {
var self = Container.call(this);
// Attach the ice block asset
var block = self.attachAsset('iceBlock', {
anchorX: 0.5,
anchorY: 1
});
// Set block size (will be updated on creation)
self.setSize = function (w, h) {
block.width = w;
block.height = h;
self.width = w;
self.height = h;
};
// Animate block drop
self.dropTo = function (targetY, duration, onFinish) {
tween(self, {
y: targetY
}, {
duration: duration,
easing: tween.cubicIn,
onFinish: onFinish
});
};
// Animate block shake (for miss)
self.shake = function () {
var origX = self.x;
tween(self, {
x: origX - 30
}, {
duration: 60,
easing: tween.linear,
onFinish: function onFinish() {
tween(self, {
x: origX + 30
}, {
duration: 60,
easing: tween.linear,
onFinish: function onFinish() {
tween(self, {
x: origX
}, {
duration: 60
});
}
});
}
});
};
return self;
});
// IceShard: Represents a falling broken piece
var IceShard = Container.expand(function () {
var self = Container.call(this);
var shard = self.attachAsset('iceShard', {
anchorX: 0.5,
anchorY: 1
});
self.setSize = function (w, h) {
shard.width = w;
shard.height = h;
self.width = w;
self.height = h;
};
// Animate falling and fading out
self.fallAndFade = function (_onFinish) {
tween(self, {
y: self.y + 400,
alpha: 0
}, {
duration: 600,
easing: tween.cubicIn,
onFinish: function onFinish() {
if (_onFinish) _onFinish();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a2a3a
});
/****
* Game Code
****/
// Shard (falling broken piece)
// Tower base (static base block)
// Ice block (main block for stacking)
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var BASE_Y = GAME_HEIGHT - 200;
var BLOCK_START_Y = 400;
var BLOCK_MIN_WIDTH = 120;
var BLOCK_HEIGHT = 100;
var BLOCK_MOVE_SPEED = 12; // px per frame
// Game state
var stack = []; // Array of stacked blocks (bottom to top)
var movingBlock = null; // The currently moving block
var movingDir = 1; // 1: right, -1: left
var movingSpeed = BLOCK_MOVE_SPEED;
var blockWidth = 600;
var blockHeight = BLOCK_HEIGHT;
var blockX = GAME_WIDTH / 2;
var blockY = BLOCK_START_Y;
var canDrop = true;
var score = 0;
var gameOver = false;
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Tower base
var baseBlock = new IceBlock();
baseBlock.setSize(700, 120);
baseBlock.x = GAME_WIDTH / 2;
baseBlock.y = BASE_Y;
game.addChild(baseBlock);
stack.push(baseBlock);
// Helper: Add a new moving block at the top
function spawnMovingBlock() {
blockWidth = stack[stack.length - 1].width;
if (blockWidth < BLOCK_MIN_WIDTH) {
endGame();
return;
}
blockHeight = BLOCK_HEIGHT;
blockX = 0 + blockWidth / 2 + 80; // Start from left
blockY = BLOCK_START_Y;
movingDir = 1;
movingSpeed = BLOCK_MOVE_SPEED + Math.floor(score / 10) * 2; // Slightly faster as score increases
movingBlock = new IceBlock();
movingBlock.setSize(blockWidth, blockHeight);
movingBlock.x = blockX;
movingBlock.y = blockY;
movingBlock.alpha = 1;
game.addChild(movingBlock);
canDrop = true;
}
// Helper: End the game
function endGame() {
if (gameOver) return;
gameOver = true;
LK.showGameOver();
}
// Helper: Update score display
function updateScore() {
scoreTxt.setText(score);
}
// Helper: Drop the moving block
function dropBlock() {
if (!movingBlock || !canDrop || gameOver) return;
canDrop = false;
// Find the top block to stack on
var prevBlock = stack[stack.length - 1];
var prevX = prevBlock.x;
var prevY = prevBlock.y;
var prevW = prevBlock.width;
// Target Y for stacking
var targetY = prevY - blockHeight;
// Animate drop
movingBlock.dropTo(targetY, 220, function () {
// Check overlap
var leftEdge = movingBlock.x - blockWidth / 2;
var rightEdge = movingBlock.x + blockWidth / 2;
var prevLeft = prevX - prevW / 2;
var prevRight = prevX + prevW / 2;
var overlapLeft = Math.max(leftEdge, prevLeft);
var overlapRight = Math.min(rightEdge, prevRight);
var overlapWidth = overlapRight - overlapLeft;
if (overlapWidth <= 0) {
// Missed completely
movingBlock.shake();
tween(movingBlock, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
endGame();
}
});
return;
}
// If overhang, break off the left or right part
var overhangLeft = overlapLeft - leftEdge;
var overhangRight = rightEdge - overlapRight;
// Animate left shard
if (overhangLeft > 2) {
var shardL = new IceShard();
shardL.setSize(overhangLeft, blockHeight);
shardL.x = leftEdge + overhangLeft / 2;
shardL.y = targetY;
game.addChild(shardL);
shardL.fallAndFade(function () {
shardL.destroy();
});
}
// Animate right shard
if (overhangRight > 2) {
var shardR = new IceShard();
shardR.setSize(overhangRight, blockHeight);
shardR.x = rightEdge - overhangRight / 2;
shardR.y = targetY;
game.addChild(shardR);
shardR.fallAndFade(function () {
shardR.destroy();
});
}
// Shrink the block to the overlap
movingBlock.setSize(overlapWidth, blockHeight);
movingBlock.x = overlapLeft + overlapWidth / 2;
movingBlock.y = targetY;
stack.push(movingBlock);
// Update score
score += 1;
updateScore();
// Move camera up if needed (optional: not implemented, as LK handles scaling)
// Spawn next block
spawnMovingBlock();
});
}
// Handle tap/click to drop block
game.down = function (x, y, obj) {
if (canDrop && !gameOver) {
dropBlock();
}
};
// Main game update loop
game.update = function () {
if (gameOver) return;
// Move the moving block horizontally
if (movingBlock && canDrop) {
blockX += movingDir * movingSpeed;
// Clamp and bounce at edges
var minX = blockWidth / 2 + 80;
var maxX = GAME_WIDTH - blockWidth / 2 - 80;
if (blockX > maxX) {
blockX = maxX;
movingDir = -1;
}
if (blockX < minX) {
blockX = minX;
movingDir = 1;
}
movingBlock.x = blockX;
}
};
// Start the game
function startGame() {
// Reset state
for (var i = stack.length - 1; i >= 1; i--) {
stack[i].destroy();
stack.splice(i, 1);
}
if (movingBlock) {
movingBlock.destroy();
movingBlock = null;
}
score = 0;
updateScore();
gameOver = false;
spawnMovingBlock();
}
// On game start
startGame();
// On game over, restart game when LK resets
// (LK will re-initialize the Game class, so no need to handle reset here) ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,284 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// IceBlock: Represents a single moving or stacked ice block
+var IceBlock = Container.expand(function () {
+ var self = Container.call(this);
+ // Attach the ice block asset
+ var block = self.attachAsset('iceBlock', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ // Set block size (will be updated on creation)
+ self.setSize = function (w, h) {
+ block.width = w;
+ block.height = h;
+ self.width = w;
+ self.height = h;
+ };
+ // Animate block drop
+ self.dropTo = function (targetY, duration, onFinish) {
+ tween(self, {
+ y: targetY
+ }, {
+ duration: duration,
+ easing: tween.cubicIn,
+ onFinish: onFinish
+ });
+ };
+ // Animate block shake (for miss)
+ self.shake = function () {
+ var origX = self.x;
+ tween(self, {
+ x: origX - 30
+ }, {
+ duration: 60,
+ easing: tween.linear,
+ onFinish: function onFinish() {
+ tween(self, {
+ x: origX + 30
+ }, {
+ duration: 60,
+ easing: tween.linear,
+ onFinish: function onFinish() {
+ tween(self, {
+ x: origX
+ }, {
+ duration: 60
+ });
+ }
+ });
+ }
+ });
+ };
+ return self;
+});
+// IceShard: Represents a falling broken piece
+var IceShard = Container.expand(function () {
+ var self = Container.call(this);
+ var shard = self.attachAsset('iceShard', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ self.setSize = function (w, h) {
+ shard.width = w;
+ shard.height = h;
+ self.width = w;
+ self.height = h;
+ };
+ // Animate falling and fading out
+ self.fallAndFade = function (_onFinish) {
+ tween(self, {
+ y: self.y + 400,
+ alpha: 0
+ }, {
+ duration: 600,
+ easing: tween.cubicIn,
+ onFinish: function onFinish() {
+ if (_onFinish) _onFinish();
+ }
+ });
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x1a2a3a
+});
+
+/****
+* Game Code
+****/
+// Shard (falling broken piece)
+// Tower base (static base block)
+// Ice block (main block for stacking)
+// Game constants
+var GAME_WIDTH = 2048;
+var GAME_HEIGHT = 2732;
+var BASE_Y = GAME_HEIGHT - 200;
+var BLOCK_START_Y = 400;
+var BLOCK_MIN_WIDTH = 120;
+var BLOCK_HEIGHT = 100;
+var BLOCK_MOVE_SPEED = 12; // px per frame
+// Game state
+var stack = []; // Array of stacked blocks (bottom to top)
+var movingBlock = null; // The currently moving block
+var movingDir = 1; // 1: right, -1: left
+var movingSpeed = BLOCK_MOVE_SPEED;
+var blockWidth = 600;
+var blockHeight = BLOCK_HEIGHT;
+var blockX = GAME_WIDTH / 2;
+var blockY = BLOCK_START_Y;
+var canDrop = true;
+var score = 0;
+var gameOver = false;
+// Score display
+var scoreTxt = new Text2('0', {
+ size: 120,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+// Tower base
+var baseBlock = new IceBlock();
+baseBlock.setSize(700, 120);
+baseBlock.x = GAME_WIDTH / 2;
+baseBlock.y = BASE_Y;
+game.addChild(baseBlock);
+stack.push(baseBlock);
+// Helper: Add a new moving block at the top
+function spawnMovingBlock() {
+ blockWidth = stack[stack.length - 1].width;
+ if (blockWidth < BLOCK_MIN_WIDTH) {
+ endGame();
+ return;
+ }
+ blockHeight = BLOCK_HEIGHT;
+ blockX = 0 + blockWidth / 2 + 80; // Start from left
+ blockY = BLOCK_START_Y;
+ movingDir = 1;
+ movingSpeed = BLOCK_MOVE_SPEED + Math.floor(score / 10) * 2; // Slightly faster as score increases
+ movingBlock = new IceBlock();
+ movingBlock.setSize(blockWidth, blockHeight);
+ movingBlock.x = blockX;
+ movingBlock.y = blockY;
+ movingBlock.alpha = 1;
+ game.addChild(movingBlock);
+ canDrop = true;
+}
+// Helper: End the game
+function endGame() {
+ if (gameOver) return;
+ gameOver = true;
+ LK.showGameOver();
+}
+// Helper: Update score display
+function updateScore() {
+ scoreTxt.setText(score);
+}
+// Helper: Drop the moving block
+function dropBlock() {
+ if (!movingBlock || !canDrop || gameOver) return;
+ canDrop = false;
+ // Find the top block to stack on
+ var prevBlock = stack[stack.length - 1];
+ var prevX = prevBlock.x;
+ var prevY = prevBlock.y;
+ var prevW = prevBlock.width;
+ // Target Y for stacking
+ var targetY = prevY - blockHeight;
+ // Animate drop
+ movingBlock.dropTo(targetY, 220, function () {
+ // Check overlap
+ var leftEdge = movingBlock.x - blockWidth / 2;
+ var rightEdge = movingBlock.x + blockWidth / 2;
+ var prevLeft = prevX - prevW / 2;
+ var prevRight = prevX + prevW / 2;
+ var overlapLeft = Math.max(leftEdge, prevLeft);
+ var overlapRight = Math.min(rightEdge, prevRight);
+ var overlapWidth = overlapRight - overlapLeft;
+ if (overlapWidth <= 0) {
+ // Missed completely
+ movingBlock.shake();
+ tween(movingBlock, {
+ alpha: 0
+ }, {
+ duration: 300,
+ onFinish: function onFinish() {
+ endGame();
+ }
+ });
+ return;
+ }
+ // If overhang, break off the left or right part
+ var overhangLeft = overlapLeft - leftEdge;
+ var overhangRight = rightEdge - overlapRight;
+ // Animate left shard
+ if (overhangLeft > 2) {
+ var shardL = new IceShard();
+ shardL.setSize(overhangLeft, blockHeight);
+ shardL.x = leftEdge + overhangLeft / 2;
+ shardL.y = targetY;
+ game.addChild(shardL);
+ shardL.fallAndFade(function () {
+ shardL.destroy();
+ });
+ }
+ // Animate right shard
+ if (overhangRight > 2) {
+ var shardR = new IceShard();
+ shardR.setSize(overhangRight, blockHeight);
+ shardR.x = rightEdge - overhangRight / 2;
+ shardR.y = targetY;
+ game.addChild(shardR);
+ shardR.fallAndFade(function () {
+ shardR.destroy();
+ });
+ }
+ // Shrink the block to the overlap
+ movingBlock.setSize(overlapWidth, blockHeight);
+ movingBlock.x = overlapLeft + overlapWidth / 2;
+ movingBlock.y = targetY;
+ stack.push(movingBlock);
+ // Update score
+ score += 1;
+ updateScore();
+ // Move camera up if needed (optional: not implemented, as LK handles scaling)
+ // Spawn next block
+ spawnMovingBlock();
+ });
+}
+// Handle tap/click to drop block
+game.down = function (x, y, obj) {
+ if (canDrop && !gameOver) {
+ dropBlock();
+ }
+};
+// Main game update loop
+game.update = function () {
+ if (gameOver) return;
+ // Move the moving block horizontally
+ if (movingBlock && canDrop) {
+ blockX += movingDir * movingSpeed;
+ // Clamp and bounce at edges
+ var minX = blockWidth / 2 + 80;
+ var maxX = GAME_WIDTH - blockWidth / 2 - 80;
+ if (blockX > maxX) {
+ blockX = maxX;
+ movingDir = -1;
+ }
+ if (blockX < minX) {
+ blockX = minX;
+ movingDir = 1;
+ }
+ movingBlock.x = blockX;
+ }
+};
+// Start the game
+function startGame() {
+ // Reset state
+ for (var i = stack.length - 1; i >= 1; i--) {
+ stack[i].destroy();
+ stack.splice(i, 1);
+ }
+ if (movingBlock) {
+ movingBlock.destroy();
+ movingBlock = null;
+ }
+ score = 0;
+ updateScore();
+ gameOver = false;
+ spawnMovingBlock();
+}
+// On game start
+startGame();
+// On game over, restart game when LK resets
+// (LK will re-initialize the Game class, so no need to handle reset here)
\ No newline at end of file