User prompt
cloud, wind and flying birds
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var highScore = storage.getItem('citybloxx_highscore') || 0;' Line Number: 173 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var highScore = storage.get('citybloxx_highscore') || 0;' Line Number: 173
User prompt
Please fix the bug: 'storage.load is not a function' in or related to this line: 'storage.load('citybloxx_highscore', function (val) {' Line Number: 182
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var highScore = storage.get('citybloxx_highscore') || 0;' Line Number: 173
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var highScore = storage.getItem('citybloxx_highscore') || 0;' Line Number: 173
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var highScore = storage.get('citybloxx_highscore') || 0;' Line Number: 173
User prompt
Scoring and Competition Updates
User prompt
May the tower continue forever until we lose
User prompt
Relaxing music while playing the game
User prompt
Add day and night transition to the game
User prompt
Add Combo System to the game
Code edit (1 edits merged)
Please save this source code
User prompt
City Bloxx
Initial prompt
make me a game City Bloxx
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Block class: represents a single swinging/dropping block var Block = Container.expand(function () { var self = Container.call(this); // Block properties self.blockWidth = 600; // Default, will be set on creation self.blockHeight = 100; // Constant height self.color = 0x4a90e2; // Default color, can be changed // State self.isDropping = false; self.isLanded = false; self.swingDirection = 1; // 1: right, -1: left self.swingSpeed = 8; // px per frame self.swingRange = 700; // How far from center to swing self.baseY = 350; // Y position for swinging self.targetY = 0; // Where to land self.minX = 0; // Left limit for swinging self.maxX = 0; // Right limit for swinging // Graphics var blockAsset = self.attachAsset('blockShape', { width: self.blockWidth, height: self.blockHeight, color: self.color, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); // Set block size and color self.setBlock = function (width, color) { self.blockWidth = width; blockAsset.width = width; blockAsset.height = self.blockHeight; if (color !== undefined) { self.color = color; blockAsset.color = color; } }; // Set swing limits self.setSwingLimits = function (minX, maxX) { self.minX = minX; self.maxX = maxX; }; // Start swinging self.startSwing = function () { self.isDropping = false; self.isLanded = false; self.y = self.baseY; self.swingDirection = 1; }; // Drop the block self.drop = function () { self.isDropping = true; }; // Called every frame self.update = function () { if (!self.isDropping && !self.isLanded) { // Swing left/right self.x += self.swingDirection * self.swingSpeed; if (self.x > self.maxX) { self.x = self.maxX; self.swingDirection = -1; } if (self.x < self.minX) { self.x = self.minX; self.swingDirection = 1; } } else if (self.isDropping && !self.isLanded) { // Drop down self.y += 32; // Drop speed if (self.y >= self.targetY) { self.y = self.targetY; self.isDropping = false; self.isLanded = true; } } }; // Animate block cut (for overhangs) self.animateCut = function (cutX, cutWidth, _onFinish) { // Animate the overhanging piece falling off var overhang = LK.getAsset('blockShape', { width: cutWidth, height: self.blockHeight, color: 0xcccccc, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: cutX, y: self.y }); game.addChild(overhang); tween(overhang, { y: self.y + 400, alpha: 0 }, { duration: 600, easing: tween.easeIn, onFinish: function onFinish() { overhang.destroy(); if (_onFinish) _onFinish(); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ // No title, no description // Always backgroundColor is black backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var BLOCK_START_WIDTH = 600; var BLOCK_HEIGHT = 100; var BLOCK_MIN_WIDTH = 80; var SWING_MARGIN = 200; // Margin from edge for swinging var TOWER_BASE_Y = GAME_HEIGHT - 350; // Where the first block lands // Game state var blocks = []; var currentBlock = null; var lastBlock = null; var isGameOver = false; var score = 0; // Day/Night state var isDay = true; var dayNightTimer = 0; var DAY_DURATION = 1800; // frames (~30s at 60fps) var NIGHT_DURATION = 1200; // frames (~20s at 60fps) var dayColor = 0x87ceeb; // Light blue var nightColor = 0x222a36; // Dark blue // Combo system state var combo = 0; var maxCombo = 0; var comboTxt = new Text2('', { size: 80, fill: 0xFFD700 }); comboTxt.anchor.set(0.5, 0); comboTxt.visible = false; LK.gui.top.addChild(comboTxt); // Score display var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Helper: get random color for block function getBlockColor(idx) { var palette = [0x4a90e2, 0xf5a623, 0x7ed321, 0xd0021b, 0x9013fe, 0x50e3c2]; return palette[idx % palette.length]; } // Helper: create a new block function createBlock(width, y, color) { var block = new Block(); block.setBlock(width, color); block.baseY = 350; block.targetY = y; block.setSwingLimits(SWING_MARGIN + width / 2, GAME_WIDTH - SWING_MARGIN - width / 2); block.x = GAME_WIDTH / 2; block.y = block.baseY; block.startSwing(); return block; } // Start the game function startGame() { // Reset state for (var i = 0; i < blocks.length; i++) { blocks[i].destroy(); } blocks = []; currentBlock = null; lastBlock = null; isGameOver = false; score = 0; scoreTxt.setText(score); // Reset combo system combo = 0; maxCombo = 0; comboTxt.setText(''); comboTxt.visible = false; // Reset day/night state isDay = true; dayNightTimer = 0; game.setBackgroundColor(dayColor); // Place the first block (static, as tower base) var baseBlock = new Block(); baseBlock.setBlock(BLOCK_START_WIDTH, getBlockColor(0)); baseBlock.x = GAME_WIDTH / 2; baseBlock.y = TOWER_BASE_Y; baseBlock.isDropping = false; baseBlock.isLanded = true; game.addChild(baseBlock); blocks.push(baseBlock); lastBlock = baseBlock; // Place the first swinging block spawnNextBlock(); } // Spawn the next swinging block function spawnNextBlock() { var idx = blocks.length; var width = lastBlock.blockWidth; var color = getBlockColor(idx); var y = lastBlock.y - BLOCK_HEIGHT; var block = createBlock(width, y, color); game.addChild(block); blocks.push(block); currentBlock = block; } // Handle tap to drop block game.down = function (x, y, obj) { if (isGameOver) return; if (!currentBlock || currentBlock.isDropping || currentBlock.isLanded) return; currentBlock.drop(); }; // Main update loop game.update = function () { if (isGameOver) return; // Day/Night transition logic dayNightTimer++; if (isDay && dayNightTimer >= DAY_DURATION) { isDay = false; dayNightTimer = 0; // Smooth transition to night tween(game, { backgroundColor: nightColor }, { duration: 1200, onUpdate: function onUpdate() { // Interpolate color for smoothness var t = this.progress; var r1 = dayColor >> 16 & 0xff, g1 = dayColor >> 8 & 0xff, b1 = dayColor & 0xff; var r2 = nightColor >> 16 & 0xff, g2 = nightColor >> 8 & 0xff, b2 = nightColor & 0xff; var r = Math.round(r1 + (r2 - r1) * t); var g = Math.round(g1 + (g2 - g1) * t); var b = Math.round(b1 + (b2 - b1) * t); game.setBackgroundColor(r << 16 | g << 8 | b); } }); } if (!isDay && dayNightTimer >= NIGHT_DURATION) { isDay = true; dayNightTimer = 0; // Smooth transition to day tween(game, { backgroundColor: dayColor }, { duration: 1200, onUpdate: function onUpdate() { var t = this.progress; var r1 = nightColor >> 16 & 0xff, g1 = nightColor >> 8 & 0xff, b1 = nightColor & 0xff; var r2 = dayColor >> 16 & 0xff, g2 = dayColor >> 8 & 0xff, b2 = dayColor & 0xff; var r = Math.round(r1 + (r2 - r1) * t); var g = Math.round(g1 + (g2 - g1) * t); var b = Math.round(b1 + (b2 - b1) * t); game.setBackgroundColor(r << 16 | g << 8 | b); } }); } // Update all blocks for (var i = 0; i < blocks.length; i++) { blocks[i].update(); } // If current block has landed, check alignment if (currentBlock && currentBlock.isLanded && !isGameOver) { // Check overlap with last block var prev = lastBlock; var curr = currentBlock; var prevLeft = prev.x - prev.blockWidth / 2; var prevRight = prev.x + prev.blockWidth / 2; var currLeft = curr.x - curr.blockWidth / 2; var currRight = curr.x + curr.blockWidth / 2; var overlapLeft = Math.max(prevLeft, currLeft); var overlapRight = Math.min(prevRight, currRight); var overlapWidth = overlapRight - overlapLeft; if (overlapWidth <= 0) { // No overlap: game over endGame(); return; } // If block is perfectly aligned, no cut var perfectAlign = Math.abs(curr.x - prev.x) < 2 && overlapWidth === curr.blockWidth; if (overlapWidth < curr.blockWidth) { // Cut off overhangs var cutLeft = currLeft < prevLeft; var cutRight = currRight > prevRight; // Animate left overhang if (cutLeft) { var cutW = prevLeft - currLeft; var cutX = curr.x - curr.blockWidth / 2 + cutW / 2; curr.animateCut(cutX, cutW); } // Animate right overhang if (cutRight) { var cutW = currRight - prevRight; var cutX = curr.x + curr.blockWidth / 2 - cutW / 2; curr.animateCut(cutX, cutW); } // Shrink block to overlap curr.setBlock(overlapWidth, curr.color); curr.x = (overlapLeft + overlapRight) / 2; } // Combo system: check for perfect alignment if (perfectAlign) { combo += 1; if (combo > maxCombo) maxCombo = combo; comboTxt.setText('COMBO x' + combo); comboTxt.visible = true; comboTxt.x = GAME_WIDTH / 2; comboTxt.y = 180; // Animate combo text comboTxt.alpha = 1; tween(comboTxt, { alpha: 0 }, { duration: 900, onFinish: function onFinish() { comboTxt.visible = false; } }); } else { combo = 0; comboTxt.visible = false; } // Update score score += 1; scoreTxt.setText(score); // Prepare for next block lastBlock = curr; // If block is too small, game over if (curr.blockWidth < BLOCK_MIN_WIDTH) { endGame(); return; } // If tower reaches top, do nothing (game continues) // Spawn next block spawnNextBlock(); } }; // End the game function endGame() { isGameOver = true; // Flash screen red LK.effects.flashScreen(0xff0000, 800); // Show game over popup LK.showGameOver(); } // Asset initialization (shapes) // Start the game on load startGame(); ; // Play relaxing background music (loops by default) LK.playMusic('relaxing_music');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Block class: represents a single swinging/dropping block
var Block = Container.expand(function () {
var self = Container.call(this);
// Block properties
self.blockWidth = 600; // Default, will be set on creation
self.blockHeight = 100; // Constant height
self.color = 0x4a90e2; // Default color, can be changed
// State
self.isDropping = false;
self.isLanded = false;
self.swingDirection = 1; // 1: right, -1: left
self.swingSpeed = 8; // px per frame
self.swingRange = 700; // How far from center to swing
self.baseY = 350; // Y position for swinging
self.targetY = 0; // Where to land
self.minX = 0; // Left limit for swinging
self.maxX = 0; // Right limit for swinging
// Graphics
var blockAsset = self.attachAsset('blockShape', {
width: self.blockWidth,
height: self.blockHeight,
color: self.color,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
// Set block size and color
self.setBlock = function (width, color) {
self.blockWidth = width;
blockAsset.width = width;
blockAsset.height = self.blockHeight;
if (color !== undefined) {
self.color = color;
blockAsset.color = color;
}
};
// Set swing limits
self.setSwingLimits = function (minX, maxX) {
self.minX = minX;
self.maxX = maxX;
};
// Start swinging
self.startSwing = function () {
self.isDropping = false;
self.isLanded = false;
self.y = self.baseY;
self.swingDirection = 1;
};
// Drop the block
self.drop = function () {
self.isDropping = true;
};
// Called every frame
self.update = function () {
if (!self.isDropping && !self.isLanded) {
// Swing left/right
self.x += self.swingDirection * self.swingSpeed;
if (self.x > self.maxX) {
self.x = self.maxX;
self.swingDirection = -1;
}
if (self.x < self.minX) {
self.x = self.minX;
self.swingDirection = 1;
}
} else if (self.isDropping && !self.isLanded) {
// Drop down
self.y += 32; // Drop speed
if (self.y >= self.targetY) {
self.y = self.targetY;
self.isDropping = false;
self.isLanded = true;
}
}
};
// Animate block cut (for overhangs)
self.animateCut = function (cutX, cutWidth, _onFinish) {
// Animate the overhanging piece falling off
var overhang = LK.getAsset('blockShape', {
width: cutWidth,
height: self.blockHeight,
color: 0xcccccc,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: cutX,
y: self.y
});
game.addChild(overhang);
tween(overhang, {
y: self.y + 400,
alpha: 0
}, {
duration: 600,
easing: tween.easeIn,
onFinish: function onFinish() {
overhang.destroy();
if (_onFinish) _onFinish();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
// No title, no description
// Always backgroundColor is black
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var BLOCK_START_WIDTH = 600;
var BLOCK_HEIGHT = 100;
var BLOCK_MIN_WIDTH = 80;
var SWING_MARGIN = 200; // Margin from edge for swinging
var TOWER_BASE_Y = GAME_HEIGHT - 350; // Where the first block lands
// Game state
var blocks = [];
var currentBlock = null;
var lastBlock = null;
var isGameOver = false;
var score = 0;
// Day/Night state
var isDay = true;
var dayNightTimer = 0;
var DAY_DURATION = 1800; // frames (~30s at 60fps)
var NIGHT_DURATION = 1200; // frames (~20s at 60fps)
var dayColor = 0x87ceeb; // Light blue
var nightColor = 0x222a36; // Dark blue
// Combo system state
var combo = 0;
var maxCombo = 0;
var comboTxt = new Text2('', {
size: 80,
fill: 0xFFD700
});
comboTxt.anchor.set(0.5, 0);
comboTxt.visible = false;
LK.gui.top.addChild(comboTxt);
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Helper: get random color for block
function getBlockColor(idx) {
var palette = [0x4a90e2, 0xf5a623, 0x7ed321, 0xd0021b, 0x9013fe, 0x50e3c2];
return palette[idx % palette.length];
}
// Helper: create a new block
function createBlock(width, y, color) {
var block = new Block();
block.setBlock(width, color);
block.baseY = 350;
block.targetY = y;
block.setSwingLimits(SWING_MARGIN + width / 2, GAME_WIDTH - SWING_MARGIN - width / 2);
block.x = GAME_WIDTH / 2;
block.y = block.baseY;
block.startSwing();
return block;
}
// Start the game
function startGame() {
// Reset state
for (var i = 0; i < blocks.length; i++) {
blocks[i].destroy();
}
blocks = [];
currentBlock = null;
lastBlock = null;
isGameOver = false;
score = 0;
scoreTxt.setText(score);
// Reset combo system
combo = 0;
maxCombo = 0;
comboTxt.setText('');
comboTxt.visible = false;
// Reset day/night state
isDay = true;
dayNightTimer = 0;
game.setBackgroundColor(dayColor);
// Place the first block (static, as tower base)
var baseBlock = new Block();
baseBlock.setBlock(BLOCK_START_WIDTH, getBlockColor(0));
baseBlock.x = GAME_WIDTH / 2;
baseBlock.y = TOWER_BASE_Y;
baseBlock.isDropping = false;
baseBlock.isLanded = true;
game.addChild(baseBlock);
blocks.push(baseBlock);
lastBlock = baseBlock;
// Place the first swinging block
spawnNextBlock();
}
// Spawn the next swinging block
function spawnNextBlock() {
var idx = blocks.length;
var width = lastBlock.blockWidth;
var color = getBlockColor(idx);
var y = lastBlock.y - BLOCK_HEIGHT;
var block = createBlock(width, y, color);
game.addChild(block);
blocks.push(block);
currentBlock = block;
}
// Handle tap to drop block
game.down = function (x, y, obj) {
if (isGameOver) return;
if (!currentBlock || currentBlock.isDropping || currentBlock.isLanded) return;
currentBlock.drop();
};
// Main update loop
game.update = function () {
if (isGameOver) return;
// Day/Night transition logic
dayNightTimer++;
if (isDay && dayNightTimer >= DAY_DURATION) {
isDay = false;
dayNightTimer = 0;
// Smooth transition to night
tween(game, {
backgroundColor: nightColor
}, {
duration: 1200,
onUpdate: function onUpdate() {
// Interpolate color for smoothness
var t = this.progress;
var r1 = dayColor >> 16 & 0xff,
g1 = dayColor >> 8 & 0xff,
b1 = dayColor & 0xff;
var r2 = nightColor >> 16 & 0xff,
g2 = nightColor >> 8 & 0xff,
b2 = nightColor & 0xff;
var r = Math.round(r1 + (r2 - r1) * t);
var g = Math.round(g1 + (g2 - g1) * t);
var b = Math.round(b1 + (b2 - b1) * t);
game.setBackgroundColor(r << 16 | g << 8 | b);
}
});
}
if (!isDay && dayNightTimer >= NIGHT_DURATION) {
isDay = true;
dayNightTimer = 0;
// Smooth transition to day
tween(game, {
backgroundColor: dayColor
}, {
duration: 1200,
onUpdate: function onUpdate() {
var t = this.progress;
var r1 = nightColor >> 16 & 0xff,
g1 = nightColor >> 8 & 0xff,
b1 = nightColor & 0xff;
var r2 = dayColor >> 16 & 0xff,
g2 = dayColor >> 8 & 0xff,
b2 = dayColor & 0xff;
var r = Math.round(r1 + (r2 - r1) * t);
var g = Math.round(g1 + (g2 - g1) * t);
var b = Math.round(b1 + (b2 - b1) * t);
game.setBackgroundColor(r << 16 | g << 8 | b);
}
});
}
// Update all blocks
for (var i = 0; i < blocks.length; i++) {
blocks[i].update();
}
// If current block has landed, check alignment
if (currentBlock && currentBlock.isLanded && !isGameOver) {
// Check overlap with last block
var prev = lastBlock;
var curr = currentBlock;
var prevLeft = prev.x - prev.blockWidth / 2;
var prevRight = prev.x + prev.blockWidth / 2;
var currLeft = curr.x - curr.blockWidth / 2;
var currRight = curr.x + curr.blockWidth / 2;
var overlapLeft = Math.max(prevLeft, currLeft);
var overlapRight = Math.min(prevRight, currRight);
var overlapWidth = overlapRight - overlapLeft;
if (overlapWidth <= 0) {
// No overlap: game over
endGame();
return;
}
// If block is perfectly aligned, no cut
var perfectAlign = Math.abs(curr.x - prev.x) < 2 && overlapWidth === curr.blockWidth;
if (overlapWidth < curr.blockWidth) {
// Cut off overhangs
var cutLeft = currLeft < prevLeft;
var cutRight = currRight > prevRight;
// Animate left overhang
if (cutLeft) {
var cutW = prevLeft - currLeft;
var cutX = curr.x - curr.blockWidth / 2 + cutW / 2;
curr.animateCut(cutX, cutW);
}
// Animate right overhang
if (cutRight) {
var cutW = currRight - prevRight;
var cutX = curr.x + curr.blockWidth / 2 - cutW / 2;
curr.animateCut(cutX, cutW);
}
// Shrink block to overlap
curr.setBlock(overlapWidth, curr.color);
curr.x = (overlapLeft + overlapRight) / 2;
}
// Combo system: check for perfect alignment
if (perfectAlign) {
combo += 1;
if (combo > maxCombo) maxCombo = combo;
comboTxt.setText('COMBO x' + combo);
comboTxt.visible = true;
comboTxt.x = GAME_WIDTH / 2;
comboTxt.y = 180;
// Animate combo text
comboTxt.alpha = 1;
tween(comboTxt, {
alpha: 0
}, {
duration: 900,
onFinish: function onFinish() {
comboTxt.visible = false;
}
});
} else {
combo = 0;
comboTxt.visible = false;
}
// Update score
score += 1;
scoreTxt.setText(score);
// Prepare for next block
lastBlock = curr;
// If block is too small, game over
if (curr.blockWidth < BLOCK_MIN_WIDTH) {
endGame();
return;
}
// If tower reaches top, do nothing (game continues)
// Spawn next block
spawnNextBlock();
}
};
// End the game
function endGame() {
isGameOver = true;
// Flash screen red
LK.effects.flashScreen(0xff0000, 800);
// Show game over popup
LK.showGameOver();
}
// Asset initialization (shapes)
// Start the game on load
startGame();
;
// Play relaxing background music (loops by default)
LK.playMusic('relaxing_music');