User prompt
code the shape of fruits
Code edit (1 edits merged)
Please save this source code
User prompt
Color Stack Tower
User prompt
Please continue polishing my design document.
Initial prompt
Game: Pop the Balloons Objective: Tap to pop balloons and earn points before time runs out. Gameplay: Balloons float upward. Player taps to pop them. Each balloon has different points or effects. Balloon Types: Red: +1 point Blue: +5 points Green: +10 points Black: -5 points (avoid) Golden: Slows time for 5 seconds Features: 60-second timer Score display Increasing difficulty Sound effects and fun visuals Optional Add-ons: Levels with faster balloons Power-ups (freeze time, double score) Leaderboard and background themes
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Block = Container.expand(function (color, width) { var self = Container.call(this); // Default values if not provided color = color || 0x3498db; width = width || 512; // Create block graphics var blockGraphics = self.attachAsset('block', { anchorX: 0.5, anchorY: 0.5, width: width, tint: color }); // State tracking self.placed = false; self.originalWidth = width; self.fallDirection = 0; // 0: none, -1: left, 1: right self.movementSpeed = 8; self.movementDirection = 1; // 1: right, -1: left // Resize the block (used when block partially falls off) self.resize = function (newWidth, offsetX) { if (newWidth <= 0) { return; } blockGraphics.width = newWidth; if (offsetX !== undefined) { self.x += offsetX; } }; // Update method called every frame self.update = function () { if (!self.placed) { // Move block back and forth self.x += self.movementSpeed * self.movementDirection; // Check if we need to change direction if (self.x > 2048 - self.originalWidth / 2) { self.movementDirection = -1; } else if (self.x < self.originalWidth / 2) { self.movementDirection = 1; } } else if (self.fallDirection !== 0) { // If block is set to fall, make it fall and rotate self.y += 15; self.rotation += 0.1 * self.fallDirection; // Remove the block when it's off-screen if (self.y > 2732 + 200) { self.destroy(); } } }; return self; }); var Fruit = Container.expand(function (type) { var self = Container.call(this); // Define fruit types and their properties var fruitTypes = { apple: { width: 80, height: 80, color: 0xe74c3c, shape: 'ellipse' }, banana: { width: 120, height: 60, color: 0xf1c40f, shape: 'ellipse' }, orange: { width: 75, height: 75, color: 0xf39c12, shape: 'ellipse' }, grape: { width: 60, height: 60, color: 0x9b59b6, shape: 'ellipse' }, watermelon: { width: 120, height: 90, color: 0x2ecc71, shape: 'ellipse' } }; // Set default if type not provided or invalid type = fruitTypes[type] ? type : 'apple'; // Initialize fruit properties var props = fruitTypes[type]; // Create shape for the fruit // Attach fruit asset var fruitGraphics = self.attachAsset('fruit_' + type, { anchorX: 0.5, anchorY: 0.5 }); // Add movement properties self.speedY = 2 + Math.random() * 3; self.speedX = (Math.random() * 2 - 1) * 2; self.rotationSpeed = Math.random() * 0.04 - 0.02; // Track last position for collision detection self.lastY = self.y; self.lastX = self.x; self.value = 0; switch (type) { case 'apple': self.value = 1; break; case 'banana': self.value = 2; break; case 'orange': self.value = 5; break; case 'grape': self.value = 3; break; case 'watermelon': self.value = 10; break; } // Update method called every frame self.update = function () { // Store last position self.lastY = self.y; self.lastX = self.x; // Move fruit self.y -= self.speedY; self.x += self.speedX; // Rotate fruit self.rotation += self.rotationSpeed; // Bounce off walls if (self.x < self.width / 2 || self.x > 2048 - self.width / 2) { self.speedX *= -1; } // Remove if off screen at top if (self.y < -100) { self.destroy(); } }; return self; }); var ScoreDisplay = Container.expand(function () { var self = Container.call(this); // Background for score var background = self.attachAsset('scoreBackground', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); // Score text self.scoreText = new Text2('0', { size: 60, fill: 0xFFFFFF }); self.scoreText.anchor.set(0.5, 0.5); self.addChild(self.scoreText); // Height text self.heightText = new Text2('Height: 0m', { size: 30, fill: 0xFFFFFF }); self.heightText.anchor.set(0.5, 0.5); self.heightText.y = 50; self.addChild(self.heightText); // Update score display self.updateScore = function (score, height) { self.scoreText.setText(score.toString()); self.heightText.setText('Height: ' + height.toFixed(1) + 'm'); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB // Sky blue background }); /**** * Game Code ****/ // Game state variables var score = 0; var towerHeight = 0; var gameActive = true; var level = 1; var blockSpeed = 8; var perfectMatches = 0; var blockColors = [0x3498db, // Blue 0xe74c3c, // Red 0x2ecc71, // Green 0xf39c12, // Orange 0x9b59b6, // Purple 0x1abc9c // Turquoise ]; // Fruit variables var fruits = []; var fruitTypes = ['apple', 'banana', 'orange', 'grape', 'watermelon']; var lastFruitTime = 0; var fruitGenerationRate = 120; // frames between fruit generation // Game objects var blocks = []; var currentBlock = null; var baseFloor = null; var scoreDisplay = null; var lastBlockPosition = { x: 2048 / 2, width: 512 }; var dropY = 200; // Starting Y position for dropping blocks // Initialize the game function initGame() { // Create base floor baseFloor = LK.getAsset('baseFloor', { anchorX: 0.5, anchorY: 0.5 }); baseFloor.x = 2048 / 2; baseFloor.y = 2732 - 100; game.addChild(baseFloor); // Set last block position to match the base floor lastBlockPosition = { x: baseFloor.x, width: baseFloor.width, y: baseFloor.y - baseFloor.height / 2 }; // Initialize score display scoreDisplay = new ScoreDisplay(); scoreDisplay.x = 2048 / 2; scoreDisplay.y = 100; game.addChild(scoreDisplay); // Create first block createNewBlock(); // Play background music LK.playMusic('backgroundMusic'); } // Create a new block to drop function createNewBlock() { if (!gameActive) { return; } // Select a random color var color = blockColors[Math.floor(Math.random() * blockColors.length)]; // Create new block with the current platform width currentBlock = new Block(color, lastBlockPosition.width); currentBlock.y = dropY; currentBlock.movementSpeed = blockSpeed; // Add block to the game and blocks array game.addChild(currentBlock); blocks.push(currentBlock); } // Handle game clicks/taps function handleTap() { if (!currentBlock || !gameActive) { return; } // Calculate overlap with previous block var overlapLeft = Math.max(lastBlockPosition.x - lastBlockPosition.width / 2, currentBlock.x - currentBlock.originalWidth / 2); var overlapRight = Math.min(lastBlockPosition.x + lastBlockPosition.width / 2, currentBlock.x + currentBlock.originalWidth / 2); var overlapWidth = overlapRight - overlapLeft; // If blocks don't overlap at all, game over if (overlapWidth <= 0) { gameOver(); return; } // Play place block sound LK.getSound('placeBlock').play(); // Mark the block as placed currentBlock.placed = true; // Calculate the new position and width for the current block var newCenterX = overlapLeft + overlapWidth / 2; var newWidth = overlapWidth; // Handle partial block if (newWidth < currentBlock.originalWidth) { // Determine which side falls off var fallBlockWidth = currentBlock.originalWidth - newWidth; var fallBlock = new Block(currentBlock.tint, fallBlockWidth); if (currentBlock.x < newCenterX) { // Left part falls off fallBlock.x = currentBlock.x - newWidth / 2; fallBlock.fallDirection = -1; currentBlock.resize(newWidth, newCenterX - currentBlock.x); } else { // Right part falls off fallBlock.x = currentBlock.x + newWidth / 2; fallBlock.fallDirection = 1; currentBlock.resize(newWidth, newCenterX - currentBlock.x); } fallBlock.y = currentBlock.y; fallBlock.placed = true; game.addChild(fallBlock); blocks.push(fallBlock); // Play falling sound LK.getSound('fallBlock').play(); } else { // Perfect match! perfectMatches++; LK.getSound('perfectMatch').play(); // Visual effect for perfect match LK.effects.flashObject(currentBlock, 0xFFFFFF, 300); } // Update the position of the current block currentBlock.x = newCenterX; // Calculate score based on match accuracy var accuracy = newWidth / currentBlock.originalWidth; var blockScore = Math.round(accuracy * 100); // Perfect bonus if (accuracy >= 0.95) { blockScore += 50; } score += blockScore; // Update tower height (each block adds height) towerHeight += currentBlock.height / 150; // Convert to "meters" // Update last block position for next block lastBlockPosition = { x: currentBlock.x, width: newWidth, y: currentBlock.y - currentBlock.height / 2 }; // Update score display scoreDisplay.updateScore(score, towerHeight); // Move the tower down if it's getting too high if (currentBlock.y < 2732 / 2) { var shiftAmount = 100; for (var i = 0; i < blocks.length; i++) { if (blocks[i].placed && !blocks[i].fallDirection) { blocks[i].y += shiftAmount; } } lastBlockPosition.y += shiftAmount; } // Increase difficulty based on tower height increaseGameDifficulty(); // Create a new block createNewBlock(); } // Increase game difficulty as tower gets higher function increaseGameDifficulty() { // Increase movement speed based on tower height level = Math.floor(towerHeight / 10) + 1; blockSpeed = 8 + level; // Every 5 levels, reduce block width by 10% (min 30% of original) var widthReduction = Math.min(0.7, 1 - Math.floor(level / 5) * 0.1); lastBlockPosition.width = Math.max(150, baseFloor.width * widthReduction); } // Game over function function gameOver() { gameActive = false; // Play falling sound LK.getSound('fallBlock').play(); // Make current block fall if (currentBlock) { currentBlock.fallDirection = currentBlock.x > 2048 / 2 ? 1 : -1; } // Flash screen LK.effects.flashScreen(0xff0000, 500); // Show game over after a short delay LK.setTimeout(function () { LK.showGameOver(); }, 1000); } // Game tick update game.update = function () { // Update all blocks for (var i = blocks.length - 1; i >= 0; i--) { if (blocks[i]) { blocks[i].update(); } } // Generate fruits periodically when game is active if (gameActive && LK.ticks - lastFruitTime > fruitGenerationRate) { lastFruitTime = LK.ticks; // Create a random fruit var fruitType = fruitTypes[Math.floor(Math.random() * fruitTypes.length)]; var fruit = new Fruit(fruitType); // Position at bottom of screen with random x fruit.x = Math.random() * 2048; fruit.y = 2732 + 50; // Add to game game.addChild(fruit); fruits.push(fruit); // Adjust generation rate based on level (faster fruit generation at higher levels) fruitGenerationRate = Math.max(60, 120 - level * 5); } // Update fruits and check for collisions for (var i = fruits.length - 1; i >= 0; i--) { if (fruits[i]) { fruits[i].update(); // Check if fruit has been tapped if (fruits[i].tapped) { // Add points based on fruit value score += fruits[i].value; scoreDisplay.updateScore(score, towerHeight); // Remove the fruit fruits[i].destroy(); fruits.splice(i, 1); } // Remove if off screen if (fruits[i] && fruits[i].y < -100) { fruits[i].destroy(); fruits.splice(i, 1); } } } }; // Event handlers game.down = function (x, y, obj) { // First check if we tapped on a fruit var fruitTapped = false; for (var i = 0; i < fruits.length; i++) { // Convert tap position to fruit's parent coordinates var localPos = fruits[i].parent.toLocal({ x: x, y: y }); // Check if tap is within fruit bounds if (Math.abs(localPos.x - fruits[i].x) < fruits[i].width / 2 && Math.abs(localPos.y - fruits[i].y) < fruits[i].height / 2) { // Mark fruit as tapped fruits[i].tapped = true; // Visual effect for tapped fruit LK.effects.flashObject(fruits[i], 0xFFFFFF, 100); fruitTapped = true; break; } } // If no fruit was tapped, handle normal block tap if (!fruitTapped) { handleTap(); } }; // Initialize the game initGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Block = Container.expand(function (color, width) {
var self = Container.call(this);
// Default values if not provided
color = color || 0x3498db;
width = width || 512;
// Create block graphics
var blockGraphics = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5,
width: width,
tint: color
});
// State tracking
self.placed = false;
self.originalWidth = width;
self.fallDirection = 0; // 0: none, -1: left, 1: right
self.movementSpeed = 8;
self.movementDirection = 1; // 1: right, -1: left
// Resize the block (used when block partially falls off)
self.resize = function (newWidth, offsetX) {
if (newWidth <= 0) {
return;
}
blockGraphics.width = newWidth;
if (offsetX !== undefined) {
self.x += offsetX;
}
};
// Update method called every frame
self.update = function () {
if (!self.placed) {
// Move block back and forth
self.x += self.movementSpeed * self.movementDirection;
// Check if we need to change direction
if (self.x > 2048 - self.originalWidth / 2) {
self.movementDirection = -1;
} else if (self.x < self.originalWidth / 2) {
self.movementDirection = 1;
}
} else if (self.fallDirection !== 0) {
// If block is set to fall, make it fall and rotate
self.y += 15;
self.rotation += 0.1 * self.fallDirection;
// Remove the block when it's off-screen
if (self.y > 2732 + 200) {
self.destroy();
}
}
};
return self;
});
var Fruit = Container.expand(function (type) {
var self = Container.call(this);
// Define fruit types and their properties
var fruitTypes = {
apple: {
width: 80,
height: 80,
color: 0xe74c3c,
shape: 'ellipse'
},
banana: {
width: 120,
height: 60,
color: 0xf1c40f,
shape: 'ellipse'
},
orange: {
width: 75,
height: 75,
color: 0xf39c12,
shape: 'ellipse'
},
grape: {
width: 60,
height: 60,
color: 0x9b59b6,
shape: 'ellipse'
},
watermelon: {
width: 120,
height: 90,
color: 0x2ecc71,
shape: 'ellipse'
}
};
// Set default if type not provided or invalid
type = fruitTypes[type] ? type : 'apple';
// Initialize fruit properties
var props = fruitTypes[type];
// Create shape for the fruit
// Attach fruit asset
var fruitGraphics = self.attachAsset('fruit_' + type, {
anchorX: 0.5,
anchorY: 0.5
});
// Add movement properties
self.speedY = 2 + Math.random() * 3;
self.speedX = (Math.random() * 2 - 1) * 2;
self.rotationSpeed = Math.random() * 0.04 - 0.02;
// Track last position for collision detection
self.lastY = self.y;
self.lastX = self.x;
self.value = 0;
switch (type) {
case 'apple':
self.value = 1;
break;
case 'banana':
self.value = 2;
break;
case 'orange':
self.value = 5;
break;
case 'grape':
self.value = 3;
break;
case 'watermelon':
self.value = 10;
break;
}
// Update method called every frame
self.update = function () {
// Store last position
self.lastY = self.y;
self.lastX = self.x;
// Move fruit
self.y -= self.speedY;
self.x += self.speedX;
// Rotate fruit
self.rotation += self.rotationSpeed;
// Bounce off walls
if (self.x < self.width / 2 || self.x > 2048 - self.width / 2) {
self.speedX *= -1;
}
// Remove if off screen at top
if (self.y < -100) {
self.destroy();
}
};
return self;
});
var ScoreDisplay = Container.expand(function () {
var self = Container.call(this);
// Background for score
var background = self.attachAsset('scoreBackground', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
// Score text
self.scoreText = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
self.scoreText.anchor.set(0.5, 0.5);
self.addChild(self.scoreText);
// Height text
self.heightText = new Text2('Height: 0m', {
size: 30,
fill: 0xFFFFFF
});
self.heightText.anchor.set(0.5, 0.5);
self.heightText.y = 50;
self.addChild(self.heightText);
// Update score display
self.updateScore = function (score, height) {
self.scoreText.setText(score.toString());
self.heightText.setText('Height: ' + height.toFixed(1) + 'm');
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Game state variables
var score = 0;
var towerHeight = 0;
var gameActive = true;
var level = 1;
var blockSpeed = 8;
var perfectMatches = 0;
var blockColors = [0x3498db,
// Blue
0xe74c3c,
// Red
0x2ecc71,
// Green
0xf39c12,
// Orange
0x9b59b6,
// Purple
0x1abc9c // Turquoise
];
// Fruit variables
var fruits = [];
var fruitTypes = ['apple', 'banana', 'orange', 'grape', 'watermelon'];
var lastFruitTime = 0;
var fruitGenerationRate = 120; // frames between fruit generation
// Game objects
var blocks = [];
var currentBlock = null;
var baseFloor = null;
var scoreDisplay = null;
var lastBlockPosition = {
x: 2048 / 2,
width: 512
};
var dropY = 200; // Starting Y position for dropping blocks
// Initialize the game
function initGame() {
// Create base floor
baseFloor = LK.getAsset('baseFloor', {
anchorX: 0.5,
anchorY: 0.5
});
baseFloor.x = 2048 / 2;
baseFloor.y = 2732 - 100;
game.addChild(baseFloor);
// Set last block position to match the base floor
lastBlockPosition = {
x: baseFloor.x,
width: baseFloor.width,
y: baseFloor.y - baseFloor.height / 2
};
// Initialize score display
scoreDisplay = new ScoreDisplay();
scoreDisplay.x = 2048 / 2;
scoreDisplay.y = 100;
game.addChild(scoreDisplay);
// Create first block
createNewBlock();
// Play background music
LK.playMusic('backgroundMusic');
}
// Create a new block to drop
function createNewBlock() {
if (!gameActive) {
return;
}
// Select a random color
var color = blockColors[Math.floor(Math.random() * blockColors.length)];
// Create new block with the current platform width
currentBlock = new Block(color, lastBlockPosition.width);
currentBlock.y = dropY;
currentBlock.movementSpeed = blockSpeed;
// Add block to the game and blocks array
game.addChild(currentBlock);
blocks.push(currentBlock);
}
// Handle game clicks/taps
function handleTap() {
if (!currentBlock || !gameActive) {
return;
}
// Calculate overlap with previous block
var overlapLeft = Math.max(lastBlockPosition.x - lastBlockPosition.width / 2, currentBlock.x - currentBlock.originalWidth / 2);
var overlapRight = Math.min(lastBlockPosition.x + lastBlockPosition.width / 2, currentBlock.x + currentBlock.originalWidth / 2);
var overlapWidth = overlapRight - overlapLeft;
// If blocks don't overlap at all, game over
if (overlapWidth <= 0) {
gameOver();
return;
}
// Play place block sound
LK.getSound('placeBlock').play();
// Mark the block as placed
currentBlock.placed = true;
// Calculate the new position and width for the current block
var newCenterX = overlapLeft + overlapWidth / 2;
var newWidth = overlapWidth;
// Handle partial block
if (newWidth < currentBlock.originalWidth) {
// Determine which side falls off
var fallBlockWidth = currentBlock.originalWidth - newWidth;
var fallBlock = new Block(currentBlock.tint, fallBlockWidth);
if (currentBlock.x < newCenterX) {
// Left part falls off
fallBlock.x = currentBlock.x - newWidth / 2;
fallBlock.fallDirection = -1;
currentBlock.resize(newWidth, newCenterX - currentBlock.x);
} else {
// Right part falls off
fallBlock.x = currentBlock.x + newWidth / 2;
fallBlock.fallDirection = 1;
currentBlock.resize(newWidth, newCenterX - currentBlock.x);
}
fallBlock.y = currentBlock.y;
fallBlock.placed = true;
game.addChild(fallBlock);
blocks.push(fallBlock);
// Play falling sound
LK.getSound('fallBlock').play();
} else {
// Perfect match!
perfectMatches++;
LK.getSound('perfectMatch').play();
// Visual effect for perfect match
LK.effects.flashObject(currentBlock, 0xFFFFFF, 300);
}
// Update the position of the current block
currentBlock.x = newCenterX;
// Calculate score based on match accuracy
var accuracy = newWidth / currentBlock.originalWidth;
var blockScore = Math.round(accuracy * 100);
// Perfect bonus
if (accuracy >= 0.95) {
blockScore += 50;
}
score += blockScore;
// Update tower height (each block adds height)
towerHeight += currentBlock.height / 150; // Convert to "meters"
// Update last block position for next block
lastBlockPosition = {
x: currentBlock.x,
width: newWidth,
y: currentBlock.y - currentBlock.height / 2
};
// Update score display
scoreDisplay.updateScore(score, towerHeight);
// Move the tower down if it's getting too high
if (currentBlock.y < 2732 / 2) {
var shiftAmount = 100;
for (var i = 0; i < blocks.length; i++) {
if (blocks[i].placed && !blocks[i].fallDirection) {
blocks[i].y += shiftAmount;
}
}
lastBlockPosition.y += shiftAmount;
}
// Increase difficulty based on tower height
increaseGameDifficulty();
// Create a new block
createNewBlock();
}
// Increase game difficulty as tower gets higher
function increaseGameDifficulty() {
// Increase movement speed based on tower height
level = Math.floor(towerHeight / 10) + 1;
blockSpeed = 8 + level;
// Every 5 levels, reduce block width by 10% (min 30% of original)
var widthReduction = Math.min(0.7, 1 - Math.floor(level / 5) * 0.1);
lastBlockPosition.width = Math.max(150, baseFloor.width * widthReduction);
}
// Game over function
function gameOver() {
gameActive = false;
// Play falling sound
LK.getSound('fallBlock').play();
// Make current block fall
if (currentBlock) {
currentBlock.fallDirection = currentBlock.x > 2048 / 2 ? 1 : -1;
}
// Flash screen
LK.effects.flashScreen(0xff0000, 500);
// Show game over after a short delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Game tick update
game.update = function () {
// Update all blocks
for (var i = blocks.length - 1; i >= 0; i--) {
if (blocks[i]) {
blocks[i].update();
}
}
// Generate fruits periodically when game is active
if (gameActive && LK.ticks - lastFruitTime > fruitGenerationRate) {
lastFruitTime = LK.ticks;
// Create a random fruit
var fruitType = fruitTypes[Math.floor(Math.random() * fruitTypes.length)];
var fruit = new Fruit(fruitType);
// Position at bottom of screen with random x
fruit.x = Math.random() * 2048;
fruit.y = 2732 + 50;
// Add to game
game.addChild(fruit);
fruits.push(fruit);
// Adjust generation rate based on level (faster fruit generation at higher levels)
fruitGenerationRate = Math.max(60, 120 - level * 5);
}
// Update fruits and check for collisions
for (var i = fruits.length - 1; i >= 0; i--) {
if (fruits[i]) {
fruits[i].update();
// Check if fruit has been tapped
if (fruits[i].tapped) {
// Add points based on fruit value
score += fruits[i].value;
scoreDisplay.updateScore(score, towerHeight);
// Remove the fruit
fruits[i].destroy();
fruits.splice(i, 1);
}
// Remove if off screen
if (fruits[i] && fruits[i].y < -100) {
fruits[i].destroy();
fruits.splice(i, 1);
}
}
}
};
// Event handlers
game.down = function (x, y, obj) {
// First check if we tapped on a fruit
var fruitTapped = false;
for (var i = 0; i < fruits.length; i++) {
// Convert tap position to fruit's parent coordinates
var localPos = fruits[i].parent.toLocal({
x: x,
y: y
});
// Check if tap is within fruit bounds
if (Math.abs(localPos.x - fruits[i].x) < fruits[i].width / 2 && Math.abs(localPos.y - fruits[i].y) < fruits[i].height / 2) {
// Mark fruit as tapped
fruits[i].tapped = true;
// Visual effect for tapped fruit
LK.effects.flashObject(fruits[i], 0xFFFFFF, 100);
fruitTapped = true;
break;
}
}
// If no fruit was tapped, handle normal block tap
if (!fruitTapped) {
handleTap();
}
};
// Initialize the game
initGame();