User prompt
Dahada büyült
User prompt
Alt blok ve üst blok boyutlarını eşitle ve büyüt
User prompt
Üstteki kutuyu ipe yapıştır ve ip nereye giderse kutu oraya gitsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Üstteki blok ip ile kordineli saga sola sallanmal ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Şimdi bu ipin ucuna bir kare yap bu kare iple baraber sallanıcak ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Biraz daha sallansın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Bu ip saga ve sola sallanıcak ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Şimdi bana tam ortadan aşagı inecek şekilde bir ip yap aşagı uzunlugu orta kısmın biraz üzerinde kalsın
User prompt
Ozaman ipi ve blogu sil tekrar kodlıcaz
User prompt
Üstteki blok ve ipi birleştir ikisi kordine hareket etsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Üstteki ip be blok ekran dısında kalıyor
User prompt
Üstten gelen blogu iple birleştir ve ekran tepesine sabitle
User prompt
Blokları kare yap ve büyüt
User prompt
Blok dimini ekran bitişinde kayboluyor neden oyun sonsuza kadar yukarı dogru ddvam etmeli
Code edit (1 edits merged)
Please save this source code
User prompt
City Bloxx - Stack the Blocks
Initial prompt
Ctiy bloxx oyunu yapıcaz anlatıyorum zemine bir kutu koyucaz sonra yukardan bir ip ucunda yeni bir blok dogacak dogan blok saga sola sallanıcak oyuncu dokundugunda aşagı düşecek amac blokları üst üste yerleştirmek
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var CutPiece = Container.expand(function () { var self = Container.call(this); var piece = self.attachAsset('cutPiece', { anchorX: 0.5, anchorY: 0.5 }); self.animate = function (direction, blockWidth) { // Set initial appearance piece.alpha = 1; piece.width = blockWidth; // Animate piece falling and rotating var fallDirection = direction === 'left' ? -1 : 1; tween(self, { x: self.x + fallDirection * 400, y: self.y + 600, rotation: fallDirection * Math.PI * 2 }, { duration: 1200, easing: tween.easeIn }); tween(piece, { alpha: 0 }, { duration: 1200, easing: tween.linear, onFinish: function onFinish() { self.destroyed = true; returnCutPieceToPool(self); } }); }; return self; }); var Particle = Container.expand(function () { var self = Container.call(this); var particle = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); particle.width = 28; particle.height = 28; self.animate = function (velocityX, velocityY, color) { // Set particle color with slight brightness variation particle.tint = color || 0xFFFFFF; // Randomize particle size for more variety var sizeVariation = 0.5 + Math.random() * 1.0; // Size between 0.5x and 1.5x particle.width = 28 * sizeVariation; particle.height = 28 * sizeVariation; // Set initial velocity with slight randomness self.velocityX = velocityX + (Math.random() - 0.5) * 2; self.velocityY = velocityY + (Math.random() - 0.5) * 2; // Vary gravity for different particle behavior self.gravity = 0.3 + Math.random() * 0.4; // Gravity between 0.3 and 0.7 // Vary particle lifetime for more dynamic effect self.life = 45 + Math.random() * 30; // Lifetime between 45-75 frames self.maxLife = self.life; // Add initial scale animation for spawn effect particle.scaleX = 0.1; particle.scaleY = 0.1; tween(particle, { scaleX: sizeVariation, scaleY: sizeVariation }, { duration: 200, easing: tween.easeOut }); }; self.update = function () { if (self.life <= 0) { self.destroyed = true; returnParticleToPool(self); return; } // Update position with velocity self.x += self.velocityX; self.y += self.velocityY; // Apply gravity with slight randomness self.velocityY += self.gravity + (Math.random() - 0.5) * 0.1; // Apply air resistance to create more realistic movement self.velocityX *= 0.98; self.velocityY *= 0.99; // Add slight rotation for visual interest particle.rotation += self.velocityX * 0.02; // Enhanced fade out with scale reduction var alpha = self.life / self.maxLife; particle.alpha = alpha; particle.scaleX = alpha * 0.8 + 0.2; // Scale down as it fades particle.scaleY = alpha * 0.8 + 0.2; // Reduce life self.life--; }; return self; }); var StackedBlock = Container.expand(function () { var self = Container.call(this); var block = self.attachAsset('block', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x808080 }); /**** * Game Code ****/ // Game state var stackedBlocks = []; var particles = []; var gameHeight = 2732; var gameWidth = 2048; var groundLevel = gameHeight - 120; var stackHeight = 0; var gameActive = true; // Object pools for memory optimization var particlePool = []; var cutPiecePool = []; var swingingBlockPool = []; // Pool management functions function getParticleFromPool() { if (particlePool.length > 0) { var particle = particlePool.pop(); particle.visible = true; particle.destroyed = false; return particle; } return new Particle(); } function returnParticleToPool(particle) { if (particle && !particle.pooled) { particle.visible = false; particle.pooled = true; particlePool.push(particle); } } function getCutPieceFromPool() { if (cutPiecePool.length > 0) { var cutPiece = cutPiecePool.pop(); cutPiece.visible = true; cutPiece.destroyed = false; return cutPiece; } return new CutPiece(); } function returnCutPieceToPool(cutPiece) { if (cutPiece && !cutPiece.pooled) { cutPiece.visible = false; cutPiece.pooled = true; cutPiecePool.push(cutPiece); } } function getSwingingBlockFromPool() { if (swingingBlockPool.length > 0) { var block = swingingBlockPool.pop(); block.visible = true; block.destroyed = false; block.falling = false; block.rotationStarted = false; block.velocityY = 0; block.rotation = 0; block.scaleX = 1; block.scaleY = 1; block.width = 350; block.pooled = false; return block; } return LK.getAsset('swingingBlock', { anchorX: 0.5, anchorY: 0.5 }); } function returnSwingingBlockToPool(block) { if (block && !block.pooled) { block.visible = false; block.pooled = true; swingingBlockPool.push(block); } } // Create foundation block var foundation = new StackedBlock(); foundation.x = gameWidth / 2; foundation.y = gameHeight - 120; // Move to bottom of screen game.addChild(foundation); stackedBlocks.push(foundation); stackHeight = foundation.y; // Create rope hanging from top center var rope = LK.getAsset('rope', { anchorX: 0.5, anchorY: 0 }); rope.x = gameWidth / 2; rope.y = 0; // Rope starts at top of screen game.addChild(rope); // Create swinging block at the end of rope var swingingBlock = getSwingingBlockFromPool(); swingingBlock.x = 0; swingingBlock.y = rope.height + 100; // Extend the rope length by moving block further down rope.addChild(swingingBlock); // Natural pendulum swing variables var swingTime = 0; var swingSpeed = 0.015; // Controls swing speed - reduced for slower initial swing var swingAmplitude = 1.2; // Controls swing range (max rotation) - increased for wider swing // Score display var scoreTxt = new Text2('Blocks: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Touch handler to drop the block game.down = function (x, y, obj) { if (!gameActive || !swingingBlock.parent || swingingBlock.falling) return; // Get the current world position of the swinging block var worldPos = rope.toGlobal(swingingBlock.position); var gamePos = game.toLocal(worldPos); // Detach from rope and add to game rope.removeChild(swingingBlock); game.addChild(swingingBlock); // Set position in game coordinates swingingBlock.x = gamePos.x; swingingBlock.y = gamePos.y; // Add falling velocity swingingBlock.velocityY = 25; // Start with constant speed swingingBlock.falling = true; // Play falling sound LK.getSound('fall').play(); }; // Update function for falling blocks game.update = function () { // Update particles for (var i = particles.length - 1; i >= 0; i--) { var particle = particles[i]; if (particle.destroyed) { particles.splice(i, 1); } } // Update rope swing with natural pendulum motion if (rope) { // Gradually increase swing speed based on score - every 5 blocks var currentSwingSpeed = swingSpeed + Math.floor(LK.getScore() / 5) * 0.005; // Increase speed by 0.005 every 5 blocks swingTime += currentSwingSpeed; rope.rotation = Math.sin(swingTime) * swingAmplitude; // Add vertical swinging motion to the swinging block only if it exists and is not falling if (swingingBlock && swingingBlock.parent === rope && !swingingBlock.falling) { var verticalOffset = Math.cos(swingTime * 2) * 30; // Vertical swing with smaller amplitude swingingBlock.y = rope.height + 100 + verticalOffset; } } if (swingingBlock.falling) { // Use constant falling speed instead of accelerating gravity swingingBlock.velocityY = 25; // Fixed falling speed swingingBlock.y += swingingBlock.velocityY; // Rotation animation removed - blocks fall straight down if (!swingingBlock.rotationStarted) { swingingBlock.rotationStarted = true; } // Check collision with any stacked block using built-in intersects method var hasCollision = false; for (var i = 0; i < stackedBlocks.length; i++) { var block = stackedBlocks[i]; if (swingingBlock.intersects(block)) { hasCollision = true; break; } } if (hasCollision) { // Find the topmost block that the swinging block collided with var targetBlock = null; var highestY = gameHeight; for (var k = 0; k < stackedBlocks.length; k++) { if (swingingBlock.intersects(stackedBlocks[k]) && stackedBlocks[k].y < highestY) { targetBlock = stackedBlocks[k]; highestY = stackedBlocks[k].y; } } if (targetBlock) { // Check if block is close enough to the top of the target block to land var blockBottom = swingingBlock.y + swingingBlock.height / 2; var targetTop = targetBlock.y - targetBlock.height / 2; var landingDistance = Math.abs(blockBottom - targetTop); // Only land if we're within reasonable landing distance (less than falling speed) if (landingDistance <= 30) { // Award 1 point LK.setScore(LK.getScore() + 1); scoreTxt.setText('Blocks: ' + LK.getScore()); // Calculate collision overlap and trim the block var targetLeft = targetBlock.x - targetBlock.width / 2; var targetRight = targetBlock.x + targetBlock.width / 2; var swingingLeft = swingingBlock.x - swingingBlock.width / 2; var swingingRight = swingingBlock.x + swingingBlock.width / 2; // Find the overlapping area var overlapLeft = Math.max(targetLeft, swingingLeft); var overlapRight = Math.min(targetRight, swingingRight); var overlapWidth = overlapRight - overlapLeft; // Only proceed if there's actual overlap if (overlapWidth > 0) { // Place block exactly on top of target block swingingBlock.falling = false; swingingBlock.velocityY = 0; swingingBlock.y = targetBlock.y - 300; // Place exactly one block height above // Stop rotation animation and reset to straight position tween.stop(swingingBlock, { rotation: true }); swingingBlock.rotation = 0; // Add collision impact animation // Scale the landing block and target block for impact effect var originalScale = swingingBlock.scaleX; swingingBlock.scaleX = originalScale * 1.2; swingingBlock.scaleY = originalScale * 1.2; targetBlock.scaleX = originalScale * 1.1; targetBlock.scaleY = originalScale * 1.1; // Animate back to normal size tween(swingingBlock, { scaleX: originalScale, scaleY: originalScale }, { duration: 300, easing: tween.easeOut }); tween(targetBlock, { scaleX: originalScale, scaleY: originalScale }, { duration: 300, easing: tween.easeOut }); // Create enhanced particle explosion effect var particleCount = 20; // Increased from 8 to 20 var collisionCenterX = swingingBlock.x; var collisionCenterY = swingingBlock.y; for (var p = 0; p < particleCount; p++) { var particle = getParticleFromPool(); // Larger spawn area for more spread particle.x = collisionCenterX + (Math.random() - 0.5) * 80; particle.y = collisionCenterY + (Math.random() - 0.5) * 50; // Create more varied velocity directions with bursts var angle = Math.PI * 2 * p / particleCount + (Math.random() - 0.5) * 0.8; var speed = 12 + Math.random() * 12; // Increased speed range var velocityX = Math.cos(angle) * speed; var velocityY = Math.sin(angle) * speed - Math.random() * 8; // More upward bias // Random particle colors (yellows, oranges, whites) var colors = [0xFFD700, 0xFFA500, 0xFFFFFF, 0xFFE4B5, 0xFFF8DC]; var color = colors[Math.floor(Math.random() * colors.length)]; particle.animate(velocityX, velocityY, color); particles.push(particle); game.addChild(particle); } // Add secondary burst of smaller, faster particles var secondaryParticleCount = 15; for (var s = 0; s < secondaryParticleCount; s++) { var secondaryParticle = getParticleFromPool(); // Tighter spawn area for secondary burst secondaryParticle.x = collisionCenterX + (Math.random() - 0.5) * 30; secondaryParticle.y = collisionCenterY + (Math.random() - 0.5) * 20; // Faster, more chaotic movement var secondaryAngle = Math.random() * Math.PI * 2; var secondarySpeed = 15 + Math.random() * 15; var secondaryVelocityX = Math.cos(secondaryAngle) * secondarySpeed; var secondaryVelocityY = Math.sin(secondaryAngle) * secondarySpeed - Math.random() * 10; // Brighter colors for secondary particles var secondaryColors = [0xFFFFFF, 0xFFFF00, 0xFF6600, 0xFF3300]; var secondaryColor = secondaryColors[Math.floor(Math.random() * secondaryColors.length)]; secondaryParticle.animate(secondaryVelocityX, secondaryVelocityY, secondaryColor); particles.push(secondaryParticle); game.addChild(secondaryParticle); } // Play collision sound LK.getSound('collision').play(); // Add screen shake effect by moving the game container var originalGameX = game.x; var originalGameY = game.y; var shakeIntensity = 15; // Quick shake animation tween(game, { x: originalGameX + shakeIntensity, y: originalGameY + shakeIntensity * 0.5 }, { duration: 50, easing: tween.linear, onFinish: function onFinish() { tween(game, { x: originalGameX - shakeIntensity * 0.8, y: originalGameY - shakeIntensity * 0.3 }, { duration: 50, easing: tween.linear, onFinish: function onFinish() { tween(game, { x: originalGameX, y: originalGameY }, { duration: 100, easing: tween.easeOut }); } }); } }); // Create cut pieces for trimmed parts var leftTrimmed = swingingLeft < overlapLeft; var rightTrimmed = swingingRight > overlapRight; if (leftTrimmed) { // Create cut piece for left trimmed part var leftCutPiece = getCutPieceFromPool(); game.addChild(leftCutPiece); var leftTrimWidth = overlapLeft - swingingLeft; leftCutPiece.x = swingingLeft + leftTrimWidth / 2; leftCutPiece.y = swingingBlock.y; leftCutPiece.animate('left', leftTrimWidth); } if (rightTrimmed) { // Create cut piece for right trimmed part var rightCutPiece = getCutPieceFromPool(); game.addChild(rightCutPiece); var rightTrimWidth = swingingRight - overlapRight; rightCutPiece.x = overlapRight + rightTrimWidth / 2; rightCutPiece.y = swingingBlock.y; rightCutPiece.animate('right', rightTrimWidth); } // Calculate how much of the original block remains var originalWidth = 350; // Original block width var remainingPercentage = overlapWidth / originalWidth * 100; // Check if 70% or more was trimmed (only 30% or less remains) if (remainingPercentage <= 30) { // Game over - too much of the block was cut off gameActive = false; LK.showGameOver(); return; } // Trim the block to only show the overlapping area var newCenterX = overlapLeft + overlapWidth / 2; swingingBlock.x = newCenterX; swingingBlock.width = overlapWidth; stackedBlocks.push(swingingBlock); } else { // No overlap, block falls off swingingBlock.falling = true; } // Update stack height to the new top stackHeight = swingingBlock.y; // After 2 blocks are placed (3rd block landing), start sliding all blocks down if (LK.getScore() > 2) { // Animate all blocks sliding down by one block height (300px) for (var b = 0; b < stackedBlocks.length; b++) { var block = stackedBlocks[b]; tween(block, { y: block.y + 300 }, { duration: 800, easing: tween.easeInOut }); } // Get the bottom block for destruction after animation var bottomBlock = stackedBlocks[0]; // Set a timeout to destroy the bottom block after animation completes LK.setTimeout(function () { bottomBlock.destroy(); stackedBlocks.splice(0, 1); }, 800); } // Create new swinging block swingingBlock = getSwingingBlockFromPool(); swingingBlock.x = 0; swingingBlock.y = rope.height + 100; swingingBlock.rotationStarted = false; // Reset rotation flag rope.addChild(swingingBlock); // Start background music LK.playMusic('bgmusic'); } else { // Not close enough to land - continue falling swingingBlock.falling = true; } } } // Check if block has fallen below the screen else if (swingingBlock.y > gameHeight + 200) { // Game over - player missed the target gameActive = false; LK.showGameOver(); } } }; ;
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var CutPiece = Container.expand(function () {
var self = Container.call(this);
var piece = self.attachAsset('cutPiece', {
anchorX: 0.5,
anchorY: 0.5
});
self.animate = function (direction, blockWidth) {
// Set initial appearance
piece.alpha = 1;
piece.width = blockWidth;
// Animate piece falling and rotating
var fallDirection = direction === 'left' ? -1 : 1;
tween(self, {
x: self.x + fallDirection * 400,
y: self.y + 600,
rotation: fallDirection * Math.PI * 2
}, {
duration: 1200,
easing: tween.easeIn
});
tween(piece, {
alpha: 0
}, {
duration: 1200,
easing: tween.linear,
onFinish: function onFinish() {
self.destroyed = true;
returnCutPieceToPool(self);
}
});
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
var particle = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
particle.width = 28;
particle.height = 28;
self.animate = function (velocityX, velocityY, color) {
// Set particle color with slight brightness variation
particle.tint = color || 0xFFFFFF;
// Randomize particle size for more variety
var sizeVariation = 0.5 + Math.random() * 1.0; // Size between 0.5x and 1.5x
particle.width = 28 * sizeVariation;
particle.height = 28 * sizeVariation;
// Set initial velocity with slight randomness
self.velocityX = velocityX + (Math.random() - 0.5) * 2;
self.velocityY = velocityY + (Math.random() - 0.5) * 2;
// Vary gravity for different particle behavior
self.gravity = 0.3 + Math.random() * 0.4; // Gravity between 0.3 and 0.7
// Vary particle lifetime for more dynamic effect
self.life = 45 + Math.random() * 30; // Lifetime between 45-75 frames
self.maxLife = self.life;
// Add initial scale animation for spawn effect
particle.scaleX = 0.1;
particle.scaleY = 0.1;
tween(particle, {
scaleX: sizeVariation,
scaleY: sizeVariation
}, {
duration: 200,
easing: tween.easeOut
});
};
self.update = function () {
if (self.life <= 0) {
self.destroyed = true;
returnParticleToPool(self);
return;
}
// Update position with velocity
self.x += self.velocityX;
self.y += self.velocityY;
// Apply gravity with slight randomness
self.velocityY += self.gravity + (Math.random() - 0.5) * 0.1;
// Apply air resistance to create more realistic movement
self.velocityX *= 0.98;
self.velocityY *= 0.99;
// Add slight rotation for visual interest
particle.rotation += self.velocityX * 0.02;
// Enhanced fade out with scale reduction
var alpha = self.life / self.maxLife;
particle.alpha = alpha;
particle.scaleX = alpha * 0.8 + 0.2; // Scale down as it fades
particle.scaleY = alpha * 0.8 + 0.2;
// Reduce life
self.life--;
};
return self;
});
var StackedBlock = Container.expand(function () {
var self = Container.call(this);
var block = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x808080
});
/****
* Game Code
****/
// Game state
var stackedBlocks = [];
var particles = [];
var gameHeight = 2732;
var gameWidth = 2048;
var groundLevel = gameHeight - 120;
var stackHeight = 0;
var gameActive = true;
// Object pools for memory optimization
var particlePool = [];
var cutPiecePool = [];
var swingingBlockPool = [];
// Pool management functions
function getParticleFromPool() {
if (particlePool.length > 0) {
var particle = particlePool.pop();
particle.visible = true;
particle.destroyed = false;
return particle;
}
return new Particle();
}
function returnParticleToPool(particle) {
if (particle && !particle.pooled) {
particle.visible = false;
particle.pooled = true;
particlePool.push(particle);
}
}
function getCutPieceFromPool() {
if (cutPiecePool.length > 0) {
var cutPiece = cutPiecePool.pop();
cutPiece.visible = true;
cutPiece.destroyed = false;
return cutPiece;
}
return new CutPiece();
}
function returnCutPieceToPool(cutPiece) {
if (cutPiece && !cutPiece.pooled) {
cutPiece.visible = false;
cutPiece.pooled = true;
cutPiecePool.push(cutPiece);
}
}
function getSwingingBlockFromPool() {
if (swingingBlockPool.length > 0) {
var block = swingingBlockPool.pop();
block.visible = true;
block.destroyed = false;
block.falling = false;
block.rotationStarted = false;
block.velocityY = 0;
block.rotation = 0;
block.scaleX = 1;
block.scaleY = 1;
block.width = 350;
block.pooled = false;
return block;
}
return LK.getAsset('swingingBlock', {
anchorX: 0.5,
anchorY: 0.5
});
}
function returnSwingingBlockToPool(block) {
if (block && !block.pooled) {
block.visible = false;
block.pooled = true;
swingingBlockPool.push(block);
}
}
// Create foundation block
var foundation = new StackedBlock();
foundation.x = gameWidth / 2;
foundation.y = gameHeight - 120; // Move to bottom of screen
game.addChild(foundation);
stackedBlocks.push(foundation);
stackHeight = foundation.y;
// Create rope hanging from top center
var rope = LK.getAsset('rope', {
anchorX: 0.5,
anchorY: 0
});
rope.x = gameWidth / 2;
rope.y = 0; // Rope starts at top of screen
game.addChild(rope);
// Create swinging block at the end of rope
var swingingBlock = getSwingingBlockFromPool();
swingingBlock.x = 0;
swingingBlock.y = rope.height + 100; // Extend the rope length by moving block further down
rope.addChild(swingingBlock);
// Natural pendulum swing variables
var swingTime = 0;
var swingSpeed = 0.015; // Controls swing speed - reduced for slower initial swing
var swingAmplitude = 1.2; // Controls swing range (max rotation) - increased for wider swing
// Score display
var scoreTxt = new Text2('Blocks: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Touch handler to drop the block
game.down = function (x, y, obj) {
if (!gameActive || !swingingBlock.parent || swingingBlock.falling) return;
// Get the current world position of the swinging block
var worldPos = rope.toGlobal(swingingBlock.position);
var gamePos = game.toLocal(worldPos);
// Detach from rope and add to game
rope.removeChild(swingingBlock);
game.addChild(swingingBlock);
// Set position in game coordinates
swingingBlock.x = gamePos.x;
swingingBlock.y = gamePos.y;
// Add falling velocity
swingingBlock.velocityY = 25; // Start with constant speed
swingingBlock.falling = true;
// Play falling sound
LK.getSound('fall').play();
};
// Update function for falling blocks
game.update = function () {
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
var particle = particles[i];
if (particle.destroyed) {
particles.splice(i, 1);
}
}
// Update rope swing with natural pendulum motion
if (rope) {
// Gradually increase swing speed based on score - every 5 blocks
var currentSwingSpeed = swingSpeed + Math.floor(LK.getScore() / 5) * 0.005; // Increase speed by 0.005 every 5 blocks
swingTime += currentSwingSpeed;
rope.rotation = Math.sin(swingTime) * swingAmplitude;
// Add vertical swinging motion to the swinging block only if it exists and is not falling
if (swingingBlock && swingingBlock.parent === rope && !swingingBlock.falling) {
var verticalOffset = Math.cos(swingTime * 2) * 30; // Vertical swing with smaller amplitude
swingingBlock.y = rope.height + 100 + verticalOffset;
}
}
if (swingingBlock.falling) {
// Use constant falling speed instead of accelerating gravity
swingingBlock.velocityY = 25; // Fixed falling speed
swingingBlock.y += swingingBlock.velocityY;
// Rotation animation removed - blocks fall straight down
if (!swingingBlock.rotationStarted) {
swingingBlock.rotationStarted = true;
}
// Check collision with any stacked block using built-in intersects method
var hasCollision = false;
for (var i = 0; i < stackedBlocks.length; i++) {
var block = stackedBlocks[i];
if (swingingBlock.intersects(block)) {
hasCollision = true;
break;
}
}
if (hasCollision) {
// Find the topmost block that the swinging block collided with
var targetBlock = null;
var highestY = gameHeight;
for (var k = 0; k < stackedBlocks.length; k++) {
if (swingingBlock.intersects(stackedBlocks[k]) && stackedBlocks[k].y < highestY) {
targetBlock = stackedBlocks[k];
highestY = stackedBlocks[k].y;
}
}
if (targetBlock) {
// Check if block is close enough to the top of the target block to land
var blockBottom = swingingBlock.y + swingingBlock.height / 2;
var targetTop = targetBlock.y - targetBlock.height / 2;
var landingDistance = Math.abs(blockBottom - targetTop);
// Only land if we're within reasonable landing distance (less than falling speed)
if (landingDistance <= 30) {
// Award 1 point
LK.setScore(LK.getScore() + 1);
scoreTxt.setText('Blocks: ' + LK.getScore());
// Calculate collision overlap and trim the block
var targetLeft = targetBlock.x - targetBlock.width / 2;
var targetRight = targetBlock.x + targetBlock.width / 2;
var swingingLeft = swingingBlock.x - swingingBlock.width / 2;
var swingingRight = swingingBlock.x + swingingBlock.width / 2;
// Find the overlapping area
var overlapLeft = Math.max(targetLeft, swingingLeft);
var overlapRight = Math.min(targetRight, swingingRight);
var overlapWidth = overlapRight - overlapLeft;
// Only proceed if there's actual overlap
if (overlapWidth > 0) {
// Place block exactly on top of target block
swingingBlock.falling = false;
swingingBlock.velocityY = 0;
swingingBlock.y = targetBlock.y - 300; // Place exactly one block height above
// Stop rotation animation and reset to straight position
tween.stop(swingingBlock, {
rotation: true
});
swingingBlock.rotation = 0;
// Add collision impact animation
// Scale the landing block and target block for impact effect
var originalScale = swingingBlock.scaleX;
swingingBlock.scaleX = originalScale * 1.2;
swingingBlock.scaleY = originalScale * 1.2;
targetBlock.scaleX = originalScale * 1.1;
targetBlock.scaleY = originalScale * 1.1;
// Animate back to normal size
tween(swingingBlock, {
scaleX: originalScale,
scaleY: originalScale
}, {
duration: 300,
easing: tween.easeOut
});
tween(targetBlock, {
scaleX: originalScale,
scaleY: originalScale
}, {
duration: 300,
easing: tween.easeOut
});
// Create enhanced particle explosion effect
var particleCount = 20; // Increased from 8 to 20
var collisionCenterX = swingingBlock.x;
var collisionCenterY = swingingBlock.y;
for (var p = 0; p < particleCount; p++) {
var particle = getParticleFromPool();
// Larger spawn area for more spread
particle.x = collisionCenterX + (Math.random() - 0.5) * 80;
particle.y = collisionCenterY + (Math.random() - 0.5) * 50;
// Create more varied velocity directions with bursts
var angle = Math.PI * 2 * p / particleCount + (Math.random() - 0.5) * 0.8;
var speed = 12 + Math.random() * 12; // Increased speed range
var velocityX = Math.cos(angle) * speed;
var velocityY = Math.sin(angle) * speed - Math.random() * 8; // More upward bias
// Random particle colors (yellows, oranges, whites)
var colors = [0xFFD700, 0xFFA500, 0xFFFFFF, 0xFFE4B5, 0xFFF8DC];
var color = colors[Math.floor(Math.random() * colors.length)];
particle.animate(velocityX, velocityY, color);
particles.push(particle);
game.addChild(particle);
}
// Add secondary burst of smaller, faster particles
var secondaryParticleCount = 15;
for (var s = 0; s < secondaryParticleCount; s++) {
var secondaryParticle = getParticleFromPool();
// Tighter spawn area for secondary burst
secondaryParticle.x = collisionCenterX + (Math.random() - 0.5) * 30;
secondaryParticle.y = collisionCenterY + (Math.random() - 0.5) * 20;
// Faster, more chaotic movement
var secondaryAngle = Math.random() * Math.PI * 2;
var secondarySpeed = 15 + Math.random() * 15;
var secondaryVelocityX = Math.cos(secondaryAngle) * secondarySpeed;
var secondaryVelocityY = Math.sin(secondaryAngle) * secondarySpeed - Math.random() * 10;
// Brighter colors for secondary particles
var secondaryColors = [0xFFFFFF, 0xFFFF00, 0xFF6600, 0xFF3300];
var secondaryColor = secondaryColors[Math.floor(Math.random() * secondaryColors.length)];
secondaryParticle.animate(secondaryVelocityX, secondaryVelocityY, secondaryColor);
particles.push(secondaryParticle);
game.addChild(secondaryParticle);
}
// Play collision sound
LK.getSound('collision').play();
// Add screen shake effect by moving the game container
var originalGameX = game.x;
var originalGameY = game.y;
var shakeIntensity = 15;
// Quick shake animation
tween(game, {
x: originalGameX + shakeIntensity,
y: originalGameY + shakeIntensity * 0.5
}, {
duration: 50,
easing: tween.linear,
onFinish: function onFinish() {
tween(game, {
x: originalGameX - shakeIntensity * 0.8,
y: originalGameY - shakeIntensity * 0.3
}, {
duration: 50,
easing: tween.linear,
onFinish: function onFinish() {
tween(game, {
x: originalGameX,
y: originalGameY
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
// Create cut pieces for trimmed parts
var leftTrimmed = swingingLeft < overlapLeft;
var rightTrimmed = swingingRight > overlapRight;
if (leftTrimmed) {
// Create cut piece for left trimmed part
var leftCutPiece = getCutPieceFromPool();
game.addChild(leftCutPiece);
var leftTrimWidth = overlapLeft - swingingLeft;
leftCutPiece.x = swingingLeft + leftTrimWidth / 2;
leftCutPiece.y = swingingBlock.y;
leftCutPiece.animate('left', leftTrimWidth);
}
if (rightTrimmed) {
// Create cut piece for right trimmed part
var rightCutPiece = getCutPieceFromPool();
game.addChild(rightCutPiece);
var rightTrimWidth = swingingRight - overlapRight;
rightCutPiece.x = overlapRight + rightTrimWidth / 2;
rightCutPiece.y = swingingBlock.y;
rightCutPiece.animate('right', rightTrimWidth);
}
// Calculate how much of the original block remains
var originalWidth = 350; // Original block width
var remainingPercentage = overlapWidth / originalWidth * 100;
// Check if 70% or more was trimmed (only 30% or less remains)
if (remainingPercentage <= 30) {
// Game over - too much of the block was cut off
gameActive = false;
LK.showGameOver();
return;
}
// Trim the block to only show the overlapping area
var newCenterX = overlapLeft + overlapWidth / 2;
swingingBlock.x = newCenterX;
swingingBlock.width = overlapWidth;
stackedBlocks.push(swingingBlock);
} else {
// No overlap, block falls off
swingingBlock.falling = true;
}
// Update stack height to the new top
stackHeight = swingingBlock.y;
// After 2 blocks are placed (3rd block landing), start sliding all blocks down
if (LK.getScore() > 2) {
// Animate all blocks sliding down by one block height (300px)
for (var b = 0; b < stackedBlocks.length; b++) {
var block = stackedBlocks[b];
tween(block, {
y: block.y + 300
}, {
duration: 800,
easing: tween.easeInOut
});
}
// Get the bottom block for destruction after animation
var bottomBlock = stackedBlocks[0];
// Set a timeout to destroy the bottom block after animation completes
LK.setTimeout(function () {
bottomBlock.destroy();
stackedBlocks.splice(0, 1);
}, 800);
}
// Create new swinging block
swingingBlock = getSwingingBlockFromPool();
swingingBlock.x = 0;
swingingBlock.y = rope.height + 100;
swingingBlock.rotationStarted = false; // Reset rotation flag
rope.addChild(swingingBlock);
// Start background music
LK.playMusic('bgmusic');
} else {
// Not close enough to land - continue falling
swingingBlock.falling = true;
}
}
}
// Check if block has fallen below the screen
else if (swingingBlock.y > gameHeight + 200) {
// Game over - player missed the target
gameActive = false;
LK.showGameOver();
}
}
};
;