Code edit (1 edits merged)
Please save this source code
User prompt
Whatever the music, it must not be interrupted.
Code edit (1 edits merged)
Please save this source code
User prompt
There are a lot of bugs with breaking blocks and then new blocks coming in, fix them all.
User prompt
enlarge the background of the meter by 2 times.
User prompt
The block must be exactly the size of the new incoming block field exactly as the last incoming block was truncated.
User prompt
Here's a breakdown: Major Issues & Bugs: Restart Functionality Still Missing: Problem: This is the most critical omission. The game ends with gameOver, but there is no way provided for the player to start a new game without reloading everything. Impact: Players have to refresh the page/app to play again, which is a poor user experience. Solution: Implement a restart mechanism: Add a "Restart" button or tap area, perhaps shown after LK.showGameOver() is called or triggered by tapping after game over. When triggered, this function must: Stop all currently playing music and sounds. Stop all active tweens (on blocks, backgrounds, score display, etc.). Iterate through the blocks array and call destroy() on each block. Iterate through the fruits array and call destroy() on each fruit. Clear the blocks = [] and fruits = [] arrays. Destroy the current scoreDisplay if it exists (if (scoreDisplay) scoreDisplay.destroy(); scoreDisplay = null;). Destroy the current baseFloor if it exists (if (baseFloor) baseFloor.destroy(); baseFloor = null;). Call initGame() to reset all variables (score, height, level, etc.), recreate the initial elements (base floor, score display), and start the game flow again. Difficulty Width Reduction Logic Still Flawed: Problem: This is the same fundamental issue as identified before. The increaseGameDifficulty function modifies lastBlockPosition.width, which is the width of the target (the block underneath the currently moving one). Impact: As the level increases, the target block the player is trying to align with suddenly shrinks while the current block is moving. This makes accurate placement incredibly difficult and feels unfair, as the goalpost moves unexpectedly. Solution: The difficulty modification needs to affect the width of the next block being created, not the target width stored in lastBlockPosition. Remove the line lastBlockPosition.width = Math.max(150, baseFloor.width * widthReduction); from increaseGameDifficulty. Inside createNewBlock, before creating the Block instance, calculate the width the new block should have based on the current level: // Inside createNewBlock, before creating the Block: var currentLevel = Math.floor(towerHeight / 10) + 1; // Calculate level based on current height var widthReductionFactor = Math.min(0.7, 1 - Math.floor(currentLevel / 5) * 0.1); // Calculate reduction var calculatedNewBlockWidth = Math.max(150, baseFloor.width * widthReductionFactor); // Determine the width for this new block // Now, create the block using this potentially reduced width: currentBlock = new Block(color, calculatedNewBlockWidth); // currentBlock.originalWidth will now reflect the width based on difficulty. // IMPORTANT: The target width for alignment remains the width of the block below it. // The `handleTap` function already uses `lastBlockPosition.width` (the target) // and `currentBlock.originalWidth` (the falling block's width) correctly // for the overlap calculation, so that part should be okay *if* the new block // is created with the `calculatedNewBlockWidth`. Use code with caution. JavaScript Music Logic - Sequential Play & No Loop: Problem: The music is set up with LK.onMusicEnd to play the tracks sequentially (loop: false). While this works, it means once the last track finishes, there will be silence. Also, the changeMusic function is still never called, and the comment in changeBackground explicitly says not to change music with the background. Impact: Music stops eventually. Music doesn't sync with background changes (which might be intended, but the setup is slightly confusing). Solution: If looping is desired: Change loop: false to loop: true in initGame and remove the LK.onMusicEnd = onMusicEnd; line and the onMusicEnd function. Only the first track will play. If sequential looping is desired: Modify onMusicEnd to check if it was the last track and then loop back to the first track instead of just stopping. If syncing with background is desired: Call changeMusic() from changeBackground(). Ensure changeMusic correctly stops the previous track (LK.stopMusic(...)) before playing the new one (LK.playMusic(...) with loop: true). Minor Issues & Potential Improvements: lastBlockPosition.y Calculation: Problem: In handleTap, lastBlockPosition.y is updated as currentBlock.y - currentBlock.height. If currentBlock.y is the center position (due to anchorY: 0.5), this calculation gives a Y position below the top edge of the placed block. Impact: The next block created in createNewBlock using this Y value will likely spawn slightly too low, potentially overlapping the block below it visually before its animation starts. Solution: Update lastBlockPosition.y to represent the top edge of the newly placed block: lastBlockPosition.y = currentBlock.y - currentBlock.height / 2; Fruit Destruction Redundancy: Problem: The game.update loop still checks if (fruits[i].tapped) and destroys the fruit. This logic is already handled more effectively (with visual effects) in game.down. Impact: Redundant code. The fruit might be destroyed by game.update before its tap animation in game.down fully completes. Solution: Remove the entire if (fruits[i].tapped) { ... } block from the game.update loop. Let game.down handle the scoring and destruction logic after tapping. Initial Block Y Position: Problem: Related to #4. The first block's spawn position in createNewBlock (y: lastBlockPosition.y - currentBlock.height) depends on the potentially incorrect lastBlockPosition.y initialized in initGame and updated in handleTap. Solution: Ensure initGame sets lastBlockPosition.y = baseFloor.y - baseFloor.height / 2; (top edge of base floor). Then, ensure handleTap updates it correctly as lastBlockPosition.y = currentBlock.y - currentBlock.height / 2;. Finally, createNewBlock should position the new block's bottom edge at this lastBlockPosition.y, meaning its center should be at y: lastBlockPosition.y - currentBlock.height / 2;. Defensive Coding in game.down: Problem: The check if (fruits[i] && fruits[i].parent) before calling toLocal is good, but the rest of the loop accesses fruits[i].x, fruits[i].width, etc., without checking if fruits[i] still exists (it might have been destroyed by game.update in the same frame, although less likely now if redundancy is removed). Solution: Add an if (fruits[i]) check right at the beginning of the for loop iteration in game.down. dropY Variable: Problem: The variable dropY is initialized but appears completely unused. Solution: Remove the dropY variable declaration and initialization.
User prompt
Enlarge Glaud text 3 times
User prompt
In the upper right corner, write “Glaud” in tiny little letters. Make it orange.
User prompt
in the upper right corner, write “Glaud” in the tiny little way.
User prompt
After backgraundMusic finishes, let backgraundMusic1 start and after it finishes, let backgraundMusic2 start.
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'toLocal')' in or related to this line: 'var localPos = fruits[i].parent.toLocal({' Line Number: 797
User prompt
Leg de basisvloer lager dan de y-coördinaat
User prompt
You misunderstood, the last block will be placed and after it is placed, the excess is cut from the sides, after cutting, the remaining block size is formed and a new block will come according to this block size. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
new block as the size of the block at the top of the last tower.
User prompt
let the music play without stopping, independently, in order of 1, 2, countless ones.
User prompt
The blocks should not overlap, that is, their positions should not overlap. Also, the game should be slightly above the y-axis of the basefloor, that is, it should be high enough so that their positions do not overlap.
User prompt
so the game start point is right on top of the basefloor at its location.
User prompt
assign a music to each background and the backgrounds change at 22 second intervals.
User prompt
I want the frit acetine like those berries in the back.
User prompt
the game ends 5 seconds after defeat.
User prompt
Now what you need to do is to add 3 backgrounds and 2 more background music, in order to play background music backgroundmusic1 backgroundmusic2 in a loop.
User prompt
Now what you need to do is to add 3 backgrounds and 2 more background music, in order to play background music backgroundmusic1 backgroundmusic2 in a loop.
Remix started
Make a completely seamless tower stacking game, when each piece is added, it will overlap, the aim is to create the tower, of course, it will become difficult because the tower decreases with each wrong placement. if we put it in the gap, we will lose. it should be more stylish, beautiful and dynamic. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/**** * 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 self.scale.y = 0; self.targetY = 0; self.initialY = 0; // Resize the block (used when block partially falls off) self.resize = function (newWidth, offsetX) { if (newWidth <= 0) { return; } // Animate the resize with tween tween.stop(blockGraphics, { width: true }); tween(blockGraphics, { width: newWidth }, { duration: 300, easing: tween.easeOut }); if (offsetX !== undefined) { tween.stop(self, { x: true }); tween(self, { x: self.x + offsetX }, { duration: 300, easing: tween.easeOut }); } }; // Drop the block into position with animation self.dropIntoPlace = function (targetYPos) { self.targetY = targetYPos; self.initialY = self.y; // First expand the y-scale tween(self.scale, { y: 1 }, { duration: 400, easing: tween.bounceOut }); // Then animate moving down to its target position tween(self, { y: targetYPos }, { duration: 500, easing: tween.bounceOut }); }; // 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: 0x000000 // Black background }); /**** * Game Code ****/ // Set real background with gradient game.setBackgroundColor(0x1e3c72); // Deep blue gradient start // 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 with animation baseFloor = LK.getAsset('baseFloor', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); baseFloor.x = 2048 / 2; baseFloor.y = 2732 - 100; baseFloor.scale.x = 0.5; game.addChild(baseFloor); // Animate the base floor appearing tween(baseFloor, { alpha: 1 }, { duration: 800, easing: tween.easeOut }); tween(baseFloor.scale, { x: 1 }, { duration: 800, easing: tween.elasticOut }); // 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 with animation scoreDisplay = new ScoreDisplay(); scoreDisplay.x = 2048 / 2; scoreDisplay.y = -50; // Start off-screen scoreDisplay.alpha = 0; game.addChild(scoreDisplay); // Animate score display tween(scoreDisplay, { y: 100, alpha: 1 }, { duration: 800, easing: tween.easeOut }); // Reset game state variables score = 0; towerHeight = 0; gameActive = true; level = 1; blockSpeed = 8; perfectMatches = 0; blocks = []; fruits = []; lastFruitTime = 0; // Create first block with a slight delay for better game flow LK.setTimeout(function () { createNewBlock(); }, 500); // Play background music LK.playMusic('backgroundMusic'); } // Create a new block to drop function createNewBlock() { if (!gameActive) { return; } // Choose a random color that's different from the last block var color; do { color = blockColors[Math.floor(Math.random() * blockColors.length)]; } while (blocks.length > 0 && blocks[blocks.length - 1].tint === color && blockColors.length > 1); // Create new block with the current platform width currentBlock = new Block(color, lastBlockPosition.width); currentBlock.y = dropY - 50; // Start slightly above for animation currentBlock.movementSpeed = blockSpeed; // Scale initially set to 0 in y axis (will animate in) currentBlock.scale.y = 0; // Add block to the game and blocks array game.addChild(currentBlock); blocks.push(currentBlock); // Animate the block entry tween(currentBlock, { y: dropY }, { duration: 500, easing: tween.bounceOut }); // Animate the scale of the block tween(currentBlock.scale, { y: 1 }, { duration: 400, easing: tween.easeOut }); // Apply a subtle shadow effect if (blocks.length > 1) { // Get reference to the top block in the tower var topBlock = null; for (var i = blocks.length - 2; i >= 0; i--) { if (blocks[i].placed && !blocks[i].fallDirection) { topBlock = blocks[i]; break; } } if (topBlock) { // Slight tint adjustment to create shadow effect on blocks beneath tween(topBlock, { alpha: 0.9 }, { duration: 500, easing: tween.linear }); } } } // 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; fallBlock.scale.y = 1; game.addChild(fallBlock); blocks.push(fallBlock); // Animate falling block with rotation tween(fallBlock, { rotation: fallBlock.fallDirection * Math.PI * 0.5 }, { duration: 800, easing: tween.easeIn }); // Play falling sound LK.getSound('fallBlock').play(); } else { // Perfect match! perfectMatches++; LK.getSound('perfectMatch').play(); // Enhanced visual effect for perfect match LK.effects.flashObject(currentBlock, 0xFFFFFF, 300); // Extra animation to emphasize perfect match tween(currentBlock.scale, { x: 1.1, y: 1.05 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(currentBlock.scale, { x: 1, y: 1 }, { duration: 150, easing: tween.bounceOut }); } }); } // Smoothly move the current block to its final position tween.stop(currentBlock, { x: true }); tween(currentBlock, { x: newCenterX }, { duration: 300, easing: tween.easeOut }); // 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) { // Animate the shift tween.stop(blocks[i], { y: true }); tween(blocks[i], { y: blocks[i].y + shiftAmount }, { duration: 400, easing: tween.easeInOut }); } } lastBlockPosition.y += shiftAmount; } // Increase difficulty based on tower height increaseGameDifficulty(); // Create a new block with a slight delay for better game flow LK.setTimeout(function () { createNewBlock(); }, 300); } // 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 with enhanced animation if (currentBlock) { currentBlock.fallDirection = currentBlock.x > 2048 / 2 ? 1 : -1; // Enhance the fall animation with tween tween(currentBlock, { y: currentBlock.y + 300, rotation: currentBlock.fallDirection * Math.PI }, { duration: 1000, easing: tween.easeIn }); } // Create a cascade effect where blocks fall one after another var fallDelay = 100; for (var i = blocks.length - 2; i >= 0; i--) { // Only animate placed blocks that aren't already falling if (blocks[i].placed && blocks[i].fallDirection === 0) { // Determine random fall direction var dir = Math.random() > 0.5 ? 1 : -1; // Create closure to preserve the block reference (function (block, delay, direction) { LK.setTimeout(function () { block.fallDirection = direction; // Add tween animation for falling tween(block, { y: block.y + 300, rotation: direction * Math.PI * (0.5 + Math.random() * 0.5) }, { duration: 800 + Math.random() * 400, easing: tween.easeIn }); }, delay); })(blocks[i], fallDelay * (blocks.length - i), dir); } } // Flash screen with animation LK.effects.flashScreen(0xff0000, 500); // Show game over after a short delay LK.setTimeout(function () { LK.showGameOver(); }, 1500); } // 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
self.scale.y = 0;
self.targetY = 0;
self.initialY = 0;
// Resize the block (used when block partially falls off)
self.resize = function (newWidth, offsetX) {
if (newWidth <= 0) {
return;
}
// Animate the resize with tween
tween.stop(blockGraphics, {
width: true
});
tween(blockGraphics, {
width: newWidth
}, {
duration: 300,
easing: tween.easeOut
});
if (offsetX !== undefined) {
tween.stop(self, {
x: true
});
tween(self, {
x: self.x + offsetX
}, {
duration: 300,
easing: tween.easeOut
});
}
};
// Drop the block into position with animation
self.dropIntoPlace = function (targetYPos) {
self.targetY = targetYPos;
self.initialY = self.y;
// First expand the y-scale
tween(self.scale, {
y: 1
}, {
duration: 400,
easing: tween.bounceOut
});
// Then animate moving down to its target position
tween(self, {
y: targetYPos
}, {
duration: 500,
easing: tween.bounceOut
});
};
// 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: 0x000000 // Black background
});
/****
* Game Code
****/
// Set real background with gradient
game.setBackgroundColor(0x1e3c72); // Deep blue gradient start
// 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 with animation
baseFloor = LK.getAsset('baseFloor', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
baseFloor.x = 2048 / 2;
baseFloor.y = 2732 - 100;
baseFloor.scale.x = 0.5;
game.addChild(baseFloor);
// Animate the base floor appearing
tween(baseFloor, {
alpha: 1
}, {
duration: 800,
easing: tween.easeOut
});
tween(baseFloor.scale, {
x: 1
}, {
duration: 800,
easing: tween.elasticOut
});
// 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 with animation
scoreDisplay = new ScoreDisplay();
scoreDisplay.x = 2048 / 2;
scoreDisplay.y = -50; // Start off-screen
scoreDisplay.alpha = 0;
game.addChild(scoreDisplay);
// Animate score display
tween(scoreDisplay, {
y: 100,
alpha: 1
}, {
duration: 800,
easing: tween.easeOut
});
// Reset game state variables
score = 0;
towerHeight = 0;
gameActive = true;
level = 1;
blockSpeed = 8;
perfectMatches = 0;
blocks = [];
fruits = [];
lastFruitTime = 0;
// Create first block with a slight delay for better game flow
LK.setTimeout(function () {
createNewBlock();
}, 500);
// Play background music
LK.playMusic('backgroundMusic');
}
// Create a new block to drop
function createNewBlock() {
if (!gameActive) {
return;
}
// Choose a random color that's different from the last block
var color;
do {
color = blockColors[Math.floor(Math.random() * blockColors.length)];
} while (blocks.length > 0 && blocks[blocks.length - 1].tint === color && blockColors.length > 1);
// Create new block with the current platform width
currentBlock = new Block(color, lastBlockPosition.width);
currentBlock.y = dropY - 50; // Start slightly above for animation
currentBlock.movementSpeed = blockSpeed;
// Scale initially set to 0 in y axis (will animate in)
currentBlock.scale.y = 0;
// Add block to the game and blocks array
game.addChild(currentBlock);
blocks.push(currentBlock);
// Animate the block entry
tween(currentBlock, {
y: dropY
}, {
duration: 500,
easing: tween.bounceOut
});
// Animate the scale of the block
tween(currentBlock.scale, {
y: 1
}, {
duration: 400,
easing: tween.easeOut
});
// Apply a subtle shadow effect
if (blocks.length > 1) {
// Get reference to the top block in the tower
var topBlock = null;
for (var i = blocks.length - 2; i >= 0; i--) {
if (blocks[i].placed && !blocks[i].fallDirection) {
topBlock = blocks[i];
break;
}
}
if (topBlock) {
// Slight tint adjustment to create shadow effect on blocks beneath
tween(topBlock, {
alpha: 0.9
}, {
duration: 500,
easing: tween.linear
});
}
}
}
// 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;
fallBlock.scale.y = 1;
game.addChild(fallBlock);
blocks.push(fallBlock);
// Animate falling block with rotation
tween(fallBlock, {
rotation: fallBlock.fallDirection * Math.PI * 0.5
}, {
duration: 800,
easing: tween.easeIn
});
// Play falling sound
LK.getSound('fallBlock').play();
} else {
// Perfect match!
perfectMatches++;
LK.getSound('perfectMatch').play();
// Enhanced visual effect for perfect match
LK.effects.flashObject(currentBlock, 0xFFFFFF, 300);
// Extra animation to emphasize perfect match
tween(currentBlock.scale, {
x: 1.1,
y: 1.05
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(currentBlock.scale, {
x: 1,
y: 1
}, {
duration: 150,
easing: tween.bounceOut
});
}
});
}
// Smoothly move the current block to its final position
tween.stop(currentBlock, {
x: true
});
tween(currentBlock, {
x: newCenterX
}, {
duration: 300,
easing: tween.easeOut
});
// 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) {
// Animate the shift
tween.stop(blocks[i], {
y: true
});
tween(blocks[i], {
y: blocks[i].y + shiftAmount
}, {
duration: 400,
easing: tween.easeInOut
});
}
}
lastBlockPosition.y += shiftAmount;
}
// Increase difficulty based on tower height
increaseGameDifficulty();
// Create a new block with a slight delay for better game flow
LK.setTimeout(function () {
createNewBlock();
}, 300);
}
// 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 with enhanced animation
if (currentBlock) {
currentBlock.fallDirection = currentBlock.x > 2048 / 2 ? 1 : -1;
// Enhance the fall animation with tween
tween(currentBlock, {
y: currentBlock.y + 300,
rotation: currentBlock.fallDirection * Math.PI
}, {
duration: 1000,
easing: tween.easeIn
});
}
// Create a cascade effect where blocks fall one after another
var fallDelay = 100;
for (var i = blocks.length - 2; i >= 0; i--) {
// Only animate placed blocks that aren't already falling
if (blocks[i].placed && blocks[i].fallDirection === 0) {
// Determine random fall direction
var dir = Math.random() > 0.5 ? 1 : -1;
// Create closure to preserve the block reference
(function (block, delay, direction) {
LK.setTimeout(function () {
block.fallDirection = direction;
// Add tween animation for falling
tween(block, {
y: block.y + 300,
rotation: direction * Math.PI * (0.5 + Math.random() * 0.5)
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeIn
});
}, delay);
})(blocks[i], fallDelay * (blocks.length - i), dir);
}
}
// Flash screen with animation
LK.effects.flashScreen(0xff0000, 500);
// Show game over after a short delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
}
// 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();
Glaud text. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Produce an image that says G. This G will be big.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
bakstenen muurpatroon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows