/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BlueBlock = Container.expand(function () { var self = Container.call(this); var blockGraphics = self.attachAsset('blueBlock', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var BouncingCircle = Container.expand(function () { var self = Container.call(this); var circleGraphics = self.attachAsset('bouncingCircle', { anchorX: 0.5, anchorY: 0.5 }); // Velocity properties self.velocityX = 15; self.velocityY = 13; self.update = function () { // Move the circle self.x += self.velocityX; self.y += self.velocityY; // Check collision with blue blocks for (var i = blocks.length - 1; i >= 0; i--) { var block = blocks[i]; var ballHit = false; // Check collision with all bouncing circles for (var circleIndex = 0; circleIndex < bouncingCircles.length; circleIndex++) { var circle = bouncingCircles[circleIndex]; if (circle.intersects(block)) { ballHit = true; break; } } if (ballHit) { // Play blue block sound and additional sounds LK.getSound('sonidodebloqueazul').play(); var additionalSounds = ['q', 'w', 'e', 'r', 't']; var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)]; LK.getSound(randomAdditionalSound).play(); // Block destroyed // Increment score score += 10; scoreTxt.setText('Score: ' + score); // Add expansion animation to bouncing circle tween(self, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } }); // Spawn red block at random position with minimum distance from other blocks var newRedBlock = game.addChild(new RedBlock()); var validPosition = false; var attempts = 0; while (!validPosition && attempts < 50) { newRedBlock.x = Math.random() * (2048 - 120) + 60; // Random X within screen bounds newRedBlock.y = Math.random() * 800 + 200; // Random Y in upper part of screen validPosition = true; // Check distance from all existing blue blocks for (var b = 0; b < blocks.length; b++) { var existingBlock = blocks[b]; var dx = newRedBlock.x - existingBlock.x; var dy = newRedBlock.y - existingBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing red blocks for (var r = 0; r < redBlocks.length; r++) { var existingRedBlock = redBlocks[r]; var dx = newRedBlock.x - existingRedBlock.x; var dy = newRedBlock.y - existingRedBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing green blocks for (var g = 0; g < greenBlocks.length; g++) { var existingGreenBlock = greenBlocks[g]; var dx = newRedBlock.x - existingGreenBlock.x; var dy = newRedBlock.y - existingGreenBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing purple blocks for (var p = 0; p < purpleBlocks.length; p++) { var existingPurpleBlock = purpleBlocks[p]; var dx = newRedBlock.x - existingPurpleBlock.x; var dy = newRedBlock.y - existingPurpleBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } attempts++; } redBlocks.push(newRedBlock); // 20% chance to spawn power orb if (Math.random() < 0.2) { var powerOrb = game.addChild(new PowerOrb()); powerOrb.x = block.x; powerOrb.y = block.y; powerOrbs.push(powerOrb); } // 20% chance to spawn double ball orb if (Math.random() < 0.2) { var doubleBallOrb = game.addChild(new DoubleBallOrb()); doubleBallOrb.x = block.x; doubleBallOrb.y = block.y; doubleBallOrbs.push(doubleBallOrb); } // 20% chance to spawn slow ball orb if (Math.random() < 0.2) { var slowBallOrb = game.addChild(new SlowBallOrb()); slowBallOrb.x = block.x; slowBallOrb.y = block.y; slowBallOrbs.push(slowBallOrb); } // 20% chance to spawn enlarge paddle orb if (Math.random() < 0.2) { var enlargePaddleOrb = game.addChild(new EnlargePaddleOrb()); enlargePaddleOrb.x = block.x; enlargePaddleOrb.y = block.y; enlargePaddleOrbs.push(enlargePaddleOrb); } // Destroy the block block.destroy(); blocks.splice(i, 1); // Reverse ball Y velocity self.velocityY = -self.velocityY; break; // Only hit one block per frame } } // Check collision with red blocks for (var j = redBlocks.length - 1; j >= 0; j--) { var redBlock = redBlocks[j]; if (self.intersects(redBlock)) { // Play red block sound and additional sounds LK.getSound('sonidodebloquerojo').play(); var additionalSounds = ['q', 'w', 'e', 'r', 't']; var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)]; LK.getSound(randomAdditionalSound).play(); // Block destroyed // Increment score score += 15; scoreTxt.setText('Score: ' + score); // Add expansion animation to bouncing circle tween(self, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } }); // Spawn green block at random position with minimum distance from other blocks var newGreenBlock = game.addChild(new GreenBlock()); var validPosition = false; var attempts = 0; while (!validPosition && attempts < 50) { newGreenBlock.x = Math.random() * (2048 - 120) + 60; // Random X within screen bounds newGreenBlock.y = Math.random() * 800 + 200; // Random Y in upper part of screen validPosition = true; // Check distance from all existing blue blocks for (var b = 0; b < blocks.length; b++) { var existingBlock = blocks[b]; var dx = newGreenBlock.x - existingBlock.x; var dy = newGreenBlock.y - existingBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing red blocks for (var r = 0; r < redBlocks.length; r++) { var existingRedBlock = redBlocks[r]; var dx = newGreenBlock.x - existingRedBlock.x; var dy = newGreenBlock.y - existingRedBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing green blocks for (var g = 0; g < greenBlocks.length; g++) { var existingGreenBlock = greenBlocks[g]; var dx = newGreenBlock.x - existingGreenBlock.x; var dy = newGreenBlock.y - existingGreenBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing purple blocks for (var p = 0; p < purpleBlocks.length; p++) { var existingPurpleBlock = purpleBlocks[p]; var dx = newGreenBlock.x - existingPurpleBlock.x; var dy = newGreenBlock.y - existingPurpleBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } attempts++; } greenBlocks.push(newGreenBlock); // 20% chance to spawn power orb if (Math.random() < 0.2) { var powerOrb = game.addChild(new PowerOrb()); powerOrb.x = redBlock.x; powerOrb.y = redBlock.y; powerOrbs.push(powerOrb); } // 20% chance to spawn double ball orb if (Math.random() < 0.2) { var doubleBallOrb = game.addChild(new DoubleBallOrb()); doubleBallOrb.x = redBlock.x; doubleBallOrb.y = redBlock.y; doubleBallOrbs.push(doubleBallOrb); } // 20% chance to spawn slow ball orb if (Math.random() < 0.2) { var slowBallOrb = game.addChild(new SlowBallOrb()); slowBallOrb.x = redBlock.x; slowBallOrb.y = redBlock.y; slowBallOrbs.push(slowBallOrb); } // 20% chance to spawn enlarge paddle orb if (Math.random() < 0.2) { var enlargePaddleOrb = game.addChild(new EnlargePaddleOrb()); enlargePaddleOrb.x = redBlock.x; enlargePaddleOrb.y = redBlock.y; enlargePaddleOrbs.push(enlargePaddleOrb); } // Destroy the red block redBlock.destroy(); redBlocks.splice(j, 1); // Reverse ball Y velocity self.velocityY = -self.velocityY; break; // Only hit one block per frame } } // Check collision with green blocks for (var k = greenBlocks.length - 1; k >= 0; k--) { var greenBlock = greenBlocks[k]; if (self.intersects(greenBlock)) { // Play green block sound and additional sounds LK.getSound('sonidodebloquerojo').play(); var additionalSounds = ['q', 'w', 'e', 'r', 't']; var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)]; LK.getSound(randomAdditionalSound).play(); // Block destroyed // Increment score score += 20; scoreTxt.setText('Score: ' + score); // Add expansion animation to bouncing circle tween(self, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } }); // Spawn purple block at random position with minimum distance from other blocks var newPurpleBlock = game.addChild(new PurpleBlock()); var validPosition = false; var attempts = 0; while (!validPosition && attempts < 50) { newPurpleBlock.x = Math.random() * (2048 - 120) + 60; // Random X within screen bounds newPurpleBlock.y = Math.random() * 800 + 200; // Random Y in upper part of screen validPosition = true; // Check distance from all existing blue blocks for (var b = 0; b < blocks.length; b++) { var existingBlock = blocks[b]; var dx = newPurpleBlock.x - existingBlock.x; var dy = newPurpleBlock.y - existingBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing red blocks for (var r = 0; r < redBlocks.length; r++) { var existingRedBlock = redBlocks[r]; var dx = newPurpleBlock.x - existingRedBlock.x; var dy = newPurpleBlock.y - existingRedBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing green blocks for (var g = 0; g < greenBlocks.length; g++) { var existingGreenBlock = greenBlocks[g]; var dx = newPurpleBlock.x - existingGreenBlock.x; var dy = newPurpleBlock.y - existingGreenBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing purple blocks for (var p = 0; p < purpleBlocks.length; p++) { var existingPurpleBlock = purpleBlocks[p]; var dx = newPurpleBlock.x - existingPurpleBlock.x; var dy = newPurpleBlock.y - existingPurpleBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } attempts++; } purpleBlocks.push(newPurpleBlock); // 20% chance to spawn power orb if (Math.random() < 0.2) { var powerOrb = game.addChild(new PowerOrb()); powerOrb.x = greenBlock.x; powerOrb.y = greenBlock.y; powerOrbs.push(powerOrb); } // 20% chance to spawn double ball orb if (Math.random() < 0.2) { var doubleBallOrb = game.addChild(new DoubleBallOrb()); doubleBallOrb.x = greenBlock.x; doubleBallOrb.y = greenBlock.y; doubleBallOrbs.push(doubleBallOrb); } // 20% chance to spawn slow ball orb if (Math.random() < 0.2) { var slowBallOrb = game.addChild(new SlowBallOrb()); slowBallOrb.x = greenBlock.x; slowBallOrb.y = greenBlock.y; slowBallOrbs.push(slowBallOrb); } // 20% chance to spawn enlarge paddle orb if (Math.random() < 0.2) { var enlargePaddleOrb = game.addChild(new EnlargePaddleOrb()); enlargePaddleOrb.x = greenBlock.x; enlargePaddleOrb.y = greenBlock.y; enlargePaddleOrbs.push(enlargePaddleOrb); } // Destroy the green block greenBlock.destroy(); greenBlocks.splice(k, 1); // Reverse ball Y velocity self.velocityY = -self.velocityY; break; // Only hit one block per frame } } // Check collision with purple blocks for (var l = purpleBlocks.length - 1; l >= 0; l--) { var purpleBlock = purpleBlocks[l]; if (self.intersects(purpleBlock)) { // Play purple block sound and additional sounds LK.getSound('sonidodebloquerojo').play(); var additionalSounds = ['q', 'w', 'e', 'r', 't']; var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)]; LK.getSound(randomAdditionalSound).play(); // Block destroyed // Increment score score += 25; scoreTxt.setText('Score: ' + score); // Add expansion animation to bouncing circle tween(self, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } }); // 20% chance to spawn power orb if (Math.random() < 0.2) { var powerOrb = game.addChild(new PowerOrb()); powerOrb.x = purpleBlock.x; powerOrb.y = purpleBlock.y; powerOrbs.push(powerOrb); } // 20% chance to spawn double ball orb if (Math.random() < 0.2) { var doubleBallOrb = game.addChild(new DoubleBallOrb()); doubleBallOrb.x = purpleBlock.x; doubleBallOrb.y = purpleBlock.y; doubleBallOrbs.push(doubleBallOrb); } // 20% chance to spawn slow ball orb if (Math.random() < 0.2) { var slowBallOrb = game.addChild(new SlowBallOrb()); slowBallOrb.x = purpleBlock.x; slowBallOrb.y = purpleBlock.y; slowBallOrbs.push(slowBallOrb); } // 20% chance to spawn enlarge paddle orb if (Math.random() < 0.2) { var enlargePaddleOrb = game.addChild(new EnlargePaddleOrb()); enlargePaddleOrb.x = purpleBlock.x; enlargePaddleOrb.y = purpleBlock.y; enlargePaddleOrbs.push(enlargePaddleOrb); } // Destroy the purple block purpleBlock.destroy(); purpleBlocks.splice(l, 1); // Reverse ball Y velocity self.velocityY = -self.velocityY; break; // Only hit one block per frame } } // Bounce off screen edges if (self.x <= 25) { self.x = 25; self.velocityX = -self.velocityX; } if (self.x >= 2048 - 25) { self.x = 2048 - 25; self.velocityX = -self.velocityX; } if (self.y <= 25) { self.y = 25; self.velocityY = -self.velocityY; } if (self.y >= 2732 - 25) { self.y = 2732 - 25; self.velocityY = -self.velocityY; } }; return self; }); var CornerBlock = Container.expand(function () { var self = Container.call(this); var blockGraphics = self.attachAsset('cornerBlock', { anchorX: 0.5, anchorY: 0.5, tint: 0x000000 }); // Track collision state for sound triggering self.lastIntersecting = false; self.update = function () { // Check collision with bouncing circle var currentIntersecting = self.intersects(bouncingCircle); if (!self.lastIntersecting && currentIntersecting) { // Collision just started - play random sound (C, A, or G) var sounds = ['c', 'a', 'g']; var randomSound = sounds[Math.floor(Math.random() * sounds.length)]; LK.getSound(randomSound).play(); var additionalSounds = ['q', 'w', 'e', 'r', 't']; var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)]; LK.getSound(randomAdditionalSound).play(); // Add expansion animation to bouncing circle tween(bouncingCircle, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(bouncingCircle, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } }); } self.lastIntersecting = currentIntersecting; }; return self; }); var CornerBlockRight = Container.expand(function () { var self = Container.call(this); var blockGraphics = self.attachAsset('cornerBlockRight', { anchorX: 0.5, anchorY: 0.5, tint: 0x000000 }); // Track collision state for sound triggering self.lastIntersecting = false; self.update = function () { // Check collision with bouncing circle var currentIntersecting = self.intersects(bouncingCircle); if (!self.lastIntersecting && currentIntersecting) { // Collision just started - play random sound (C, A, or G) var sounds = ['c', 'a', 'g']; var randomSound = sounds[Math.floor(Math.random() * sounds.length)]; LK.getSound(randomSound).play(); var additionalSounds = ['q', 'w', 'e', 'r', 't']; var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)]; LK.getSound(randomAdditionalSound).play(); // Add expansion animation to bouncing circle tween(bouncingCircle, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(bouncingCircle, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } }); } self.lastIntersecting = currentIntersecting; }; return self; }); var CornerBlockTop = Container.expand(function () { var self = Container.call(this); var blockGraphics = self.attachAsset('cornerBlockTop', { anchorX: 0.5, anchorY: 0.5, tint: 0x000000 }); // Track collision state for sound triggering self.lastIntersecting = false; self.update = function () { // Check collision with bouncing circle var currentIntersecting = self.intersects(bouncingCircle); if (!self.lastIntersecting && currentIntersecting) { // Collision just started - play random sound (C, A, or G) var sounds = ['c', 'a', 'g']; var randomSound = sounds[Math.floor(Math.random() * sounds.length)]; LK.getSound(randomSound).play(); var additionalSounds = ['q', 'w', 'e', 'r', 't']; var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)]; LK.getSound(randomAdditionalSound).play(); // Add expansion animation to bouncing circle tween(bouncingCircle, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(bouncingCircle, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } }); } self.lastIntersecting = currentIntersecting; }; return self; }); var DoubleBallOrb = Container.expand(function () { var self = Container.call(this); var orbGraphics = self.attachAsset('doubleBallOrb', { anchorX: 0.5, anchorY: 0.5, tint: 0x00ffff }); // Fall downward self.velocityY = 8; self.update = function () { self.y += self.velocityY; // Remove if goes off screen if (self.y > 2800) { self.destroy(); // Remove from doubleBallOrbs array for (var i = doubleBallOrbs.length - 1; i >= 0; i--) { if (doubleBallOrbs[i] === self) { doubleBallOrbs.splice(i, 1); break; } } } }; return self; }); var EnlargePaddleOrb = Container.expand(function () { var self = Container.call(this); var orbGraphics = self.attachAsset('enlargePaddleOrb', { anchorX: 0.5, anchorY: 0.5, tint: 0xff00ff }); // Fall downward self.velocityY = 8; self.update = function () { self.y += self.velocityY; // Remove if goes off screen if (self.y > 2800) { self.destroy(); // Remove from enlargePaddleOrbs array for (var i = enlargePaddleOrbs.length - 1; i >= 0; i--) { if (enlargePaddleOrbs[i] === self) { enlargePaddleOrbs.splice(i, 1); break; } } } }; return self; }); var GreenBlock = Container.expand(function () { var self = Container.call(this); var blockGraphics = self.attachAsset('greenBlock', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Cache paddle constants var Paddle = Container.expand(function () { var self = Container.call(this); var paddleGraphics = self.attachAsset('paddle', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Prevent paddle from going through left wall if (self.x < PADDLE_HALF_WIDTH) { self.x = PADDLE_HALF_WIDTH; } // Prevent paddle from going through right wall if (self.x > SCREEN_WIDTH - PADDLE_HALF_WIDTH) { self.x = SCREEN_WIDTH - PADDLE_HALF_WIDTH; } }; return self; }); var PowerOrb = Container.expand(function () { var self = Container.call(this); var orbGraphics = self.attachAsset('powerOrb', { anchorX: 0.5, anchorY: 0.5, tint: 0xffff00 }); // Fall downward self.velocityY = 8; self.update = function () { self.y += self.velocityY; // Remove if goes off screen if (self.y > 2800) { self.destroy(); // Remove from powerOrbs array for (var i = powerOrbs.length - 1; i >= 0; i--) { if (powerOrbs[i] === self) { powerOrbs.splice(i, 1); break; } } } }; return self; }); var PurpleBlock = Container.expand(function () { var self = Container.call(this); var blockGraphics = self.attachAsset('purpleBlock', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var RedBlock = Container.expand(function () { var self = Container.call(this); var blockGraphics = self.attachAsset('redBlock', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var SlowBallOrb = Container.expand(function () { var self = Container.call(this); var orbGraphics = self.attachAsset('slowBallOrb', { anchorX: 0.5, anchorY: 0.5, tint: 0xff0000 }); // Fall downward self.velocityY = 8; self.update = function () { self.y += self.velocityY; // Remove if goes off screen if (self.y > 2800) { self.destroy(); // Remove from slowBallOrbs array for (var i = slowBallOrbs.length - 1; i >= 0; i--) { if (slowBallOrbs[i] === self) { slowBallOrbs.splice(i, 1); break; } } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Add scattered musical wave symbols across the background var musicalWaves = []; for (var i = 0; i < 20; i++) { var waveType = 'musicalWave' + (Math.floor(Math.random() * 4) + 1); var wave = game.addChild(LK.getAsset(waveType, { anchorX: 0.5, anchorY: 0.5, x: Math.random() * 2048, y: Math.random() * 2732, alpha: 0.3, rotation: Math.random() * Math.PI * 2 })); musicalWaves.push(wave); } // Add scattered musical notes across the background var musicalNotes = []; for (var i = 0; i < 15; i++) { var noteType = 'musicalNote' + (Math.floor(Math.random() * 3) + 1); var note = game.addChild(LK.getAsset(noteType, { anchorX: 0.5, anchorY: 0.5, x: Math.random() * 2048, y: Math.random() * 2732, alpha: 0.25, rotation: Math.random() * Math.PI * 2 })); musicalNotes.push(note); } // Add staff lines across the background var staffLines = []; for (var i = 0; i < 12; i++) { var staffType = 'staffLine' + (Math.floor(Math.random() * 3) + 1); var staff = game.addChild(LK.getAsset(staffType, { anchorX: 0.5, anchorY: 0.5, x: Math.random() * 2048, y: Math.random() * 2732, alpha: 0.2, rotation: Math.random() * Math.PI * 0.5 })); staffLines.push(staff); } // Add treble clefs scattered in the background var trebleClefs = []; for (var i = 0; i < 8; i++) { var clef = game.addChild(LK.getAsset('trebleClef', { anchorX: 0.5, anchorY: 0.5, x: Math.random() * 2048, y: Math.random() * 2732, alpha: 0.15, rotation: Math.random() * Math.PI * 2 })); trebleClefs.push(clef); } // Add scattered background circles var backgroundCircles = []; for (var i = 0; i < 40; i++) { var circleType = 'backgroundCircle' + (Math.floor(Math.random() * 6) + 1); var circle = game.addChild(LK.getAsset(circleType, { anchorX: 0.5, anchorY: 0.5, x: Math.random() * 2048, y: Math.random() * 2732, alpha: 0.1 })); backgroundCircles.push(circle); } // Cache paddle constants var PADDLE_HALF_WIDTH = 150; var SCREEN_WIDTH = 2048; var blocks = []; var redBlocks = []; var greenBlocks = []; var purpleBlocks = []; var powerOrbs = []; var doubleBallOrbs = []; var slowBallOrbs = []; var enlargePaddleOrbs = []; var bouncingCircles = []; var paddleCollisions = 0; var score = 0; var bouncingCircle = game.addChild(new BouncingCircle()); bouncingCircle.x = 1024; bouncingCircle.y = 2550; // Position above paddle bouncingCircle.lastIntersecting = false; bouncingCircles.push(bouncingCircle); var paddle = game.addChild(new Paddle()); paddle.x = 1024; paddle.y = 2600; var scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); game.move = function (x, y, obj) { paddle.x = x; }; // Add corner block covering entire left side of screen var cornerBlock = game.addChild(new CornerBlock()); cornerBlock.x = 10; // Position at left edge cornerBlock.y = 1366; // Center vertically (half of 2732) // Add corner block covering entire right side of screen var cornerBlockRight = game.addChild(new CornerBlockRight()); cornerBlockRight.x = 2038; // Position at right edge cornerBlockRight.y = 1366; // Center vertically (half of 2732) // Add corner block covering entire top side of screen var cornerBlockTop = game.addChild(new CornerBlockTop()); cornerBlockTop.x = 1024; // Center horizontally (half of 2048) cornerBlockTop.y = 10; // Position at top edge // Play background music LK.playMusic('musica'); game.update = function () { // Track ball-paddle collision state transitions var currentIntersecting = bouncingCircle.intersects(paddle); if (!bouncingCircle.lastIntersecting && currentIntersecting) { // Collision just started - push ball above paddle and reverse Y velocity bouncingCircle.y = paddle.y - 20 - 25; bouncingCircle.velocityY = -Math.abs(bouncingCircle.velocityY); // Increment paddle collision counter paddleCollisions++; // Play random sound (C, A, or G) var sounds = ['c', 'a', 'g']; var randomSound = sounds[Math.floor(Math.random() * sounds.length)]; LK.getSound(randomSound).play(); var additionalSounds = ['q', 'w', 'e', 'r', 't']; var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)]; LK.getSound(randomAdditionalSound).play(); // Add expansion animation to bouncing circle tween(bouncingCircle, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(bouncingCircle, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } }); // Add shake animation to paddle var shakeDistance = 10; var originalX = paddle.x; tween(paddle, { x: originalX - shakeDistance }, { duration: 50, easing: tween.easeOut, onFinish: function onFinish() { tween(paddle, { x: originalX + shakeDistance }, { duration: 50, easing: tween.easeInOut, onFinish: function onFinish() { tween(paddle, { x: originalX - shakeDistance * 0.5 }, { duration: 40, easing: tween.easeInOut, onFinish: function onFinish() { tween(paddle, { x: originalX + shakeDistance * 0.5 }, { duration: 40, easing: tween.easeInOut, onFinish: function onFinish() { tween(paddle, { x: originalX }, { duration: 30, easing: tween.easeIn }); } }); } }); } }); } }); // Spawn new blue block at random position with minimum distance from other blocks var newBlock = game.addChild(new BlueBlock()); var validPosition = false; var attempts = 0; while (!validPosition && attempts < 50) { newBlock.x = Math.random() * (2048 - 120) + 60; // Random X within screen bounds newBlock.y = Math.random() * 800 + 200; // Random Y in upper part of screen validPosition = true; // Check distance from all existing blue blocks for (var b = 0; b < blocks.length; b++) { var existingBlock = blocks[b]; var dx = newBlock.x - existingBlock.x; var dy = newBlock.y - existingBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing red blocks for (var r = 0; r < redBlocks.length; r++) { var existingRedBlock = redBlocks[r]; var dx = newBlock.x - existingRedBlock.x; var dy = newBlock.y - existingRedBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing green blocks for (var g = 0; g < greenBlocks.length; g++) { var existingGreenBlock = greenBlocks[g]; var dx = newBlock.x - existingGreenBlock.x; var dy = newBlock.y - existingGreenBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } // Check distance from all existing purple blocks for (var p = 0; p < purpleBlocks.length; p++) { var existingPurpleBlock = purpleBlocks[p]; var dx = newBlock.x - existingPurpleBlock.x; var dy = newBlock.y - existingPurpleBlock.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { // Minimum distance of 200 pixels validPosition = false; break; } } attempts++; } blocks.push(newBlock); } bouncingCircle.lastIntersecting = currentIntersecting; // Check power orb collisions with paddle for (var k = powerOrbs.length - 1; k >= 0; k--) { var powerOrb = powerOrbs[k]; if (powerOrb.intersects(paddle)) { // Increase ball speed for all balls var speedMultiplier = 1.5; for (var circleIndex = 0; circleIndex < bouncingCircles.length; circleIndex++) { var circle = bouncingCircles[circleIndex]; circle.velocityX *= speedMultiplier; circle.velocityY *= speedMultiplier; // Visual feedback - flash ball green tween(circle, { tint: 0x00ff00 }, { duration: 200, onFinish: function onFinish() { tween(circle, { tint: 0xffffff }, { duration: 200 }); } }); } // Remove power orb powerOrb.destroy(); powerOrbs.splice(k, 1); } } // Check double ball orb collisions with paddle for (var d = doubleBallOrbs.length - 1; d >= 0; d--) { var doubleBallOrb = doubleBallOrbs[d]; if (doubleBallOrb.intersects(paddle)) { // Create new bouncing ball var newBall = game.addChild(new BouncingCircle()); newBall.x = bouncingCircle.x + 50; newBall.y = bouncingCircle.y; newBall.velocityX = -bouncingCircle.velocityX; newBall.velocityY = bouncingCircle.velocityY; newBall.lastIntersecting = false; bouncingCircles.push(newBall); // Visual feedback - flash original ball green tween(bouncingCircle, { tint: 0x00ff00 }, { duration: 200, onFinish: function onFinish() { tween(bouncingCircle, { tint: 0xffffff }, { duration: 200 }); } }); // Remove double ball orb doubleBallOrb.destroy(); doubleBallOrbs.splice(d, 1); } } // Check slow ball orb collisions with paddle for (var s = slowBallOrbs.length - 1; s >= 0; s--) { var slowBallOrb = slowBallOrbs[s]; if (slowBallOrb.intersects(paddle)) { // Slow down all balls var slowMultiplier = 0.7; for (var circleIndex = 0; circleIndex < bouncingCircles.length; circleIndex++) { var circle = bouncingCircles[circleIndex]; circle.velocityX *= slowMultiplier; circle.velocityY *= slowMultiplier; // Visual feedback - flash ball orange tween(circle, { tint: 0xff6600 }, { duration: 200, onFinish: function onFinish() { tween(circle, { tint: 0xffffff }, { duration: 200 }); } }); } // Remove slow ball orb slowBallOrb.destroy(); slowBallOrbs.splice(s, 1); } } // Check enlarge paddle orb collisions with paddle for (var e = enlargePaddleOrbs.length - 1; e >= 0; e--) { var enlargePaddleOrb = enlargePaddleOrbs[e]; if (enlargePaddleOrb.intersects(paddle)) { // Enlarge paddle tween(paddle, { scaleX: 1.5 }, { duration: 300, easing: tween.easeOut }); // Visual feedback - flash paddle blue tween(paddle, { tint: 0x0066ff }, { duration: 200, onFinish: function onFinish() { tween(paddle, { tint: 0xffffff }, { duration: 200 }); } }); // Remove enlarge paddle orb enlargePaddleOrb.destroy(); enlargePaddleOrbs.splice(e, 1); } } // Check if any ball hits bottom area and remove it for (var circleIndex = bouncingCircles.length - 1; circleIndex >= 0; circleIndex--) { var circle = bouncingCircles[circleIndex]; if (circle.y >= 2700) { circle.destroy(); bouncingCircles.splice(circleIndex, 1); } } // Game over if no balls left if (bouncingCircles.length === 0) { LK.showGameOver(); return; } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BlueBlock = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('blueBlock', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var BouncingCircle = Container.expand(function () {
var self = Container.call(this);
var circleGraphics = self.attachAsset('bouncingCircle', {
anchorX: 0.5,
anchorY: 0.5
});
// Velocity properties
self.velocityX = 15;
self.velocityY = 13;
self.update = function () {
// Move the circle
self.x += self.velocityX;
self.y += self.velocityY;
// Check collision with blue blocks
for (var i = blocks.length - 1; i >= 0; i--) {
var block = blocks[i];
var ballHit = false;
// Check collision with all bouncing circles
for (var circleIndex = 0; circleIndex < bouncingCircles.length; circleIndex++) {
var circle = bouncingCircles[circleIndex];
if (circle.intersects(block)) {
ballHit = true;
break;
}
}
if (ballHit) {
// Play blue block sound and additional sounds
LK.getSound('sonidodebloqueazul').play();
var additionalSounds = ['q', 'w', 'e', 'r', 't'];
var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)];
LK.getSound(randomAdditionalSound).play();
// Block destroyed
// Increment score
score += 10;
scoreTxt.setText('Score: ' + score);
// Add expansion animation to bouncing circle
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Spawn red block at random position with minimum distance from other blocks
var newRedBlock = game.addChild(new RedBlock());
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 50) {
newRedBlock.x = Math.random() * (2048 - 120) + 60; // Random X within screen bounds
newRedBlock.y = Math.random() * 800 + 200; // Random Y in upper part of screen
validPosition = true;
// Check distance from all existing blue blocks
for (var b = 0; b < blocks.length; b++) {
var existingBlock = blocks[b];
var dx = newRedBlock.x - existingBlock.x;
var dy = newRedBlock.y - existingBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing red blocks
for (var r = 0; r < redBlocks.length; r++) {
var existingRedBlock = redBlocks[r];
var dx = newRedBlock.x - existingRedBlock.x;
var dy = newRedBlock.y - existingRedBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing green blocks
for (var g = 0; g < greenBlocks.length; g++) {
var existingGreenBlock = greenBlocks[g];
var dx = newRedBlock.x - existingGreenBlock.x;
var dy = newRedBlock.y - existingGreenBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing purple blocks
for (var p = 0; p < purpleBlocks.length; p++) {
var existingPurpleBlock = purpleBlocks[p];
var dx = newRedBlock.x - existingPurpleBlock.x;
var dy = newRedBlock.y - existingPurpleBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
attempts++;
}
redBlocks.push(newRedBlock);
// 20% chance to spawn power orb
if (Math.random() < 0.2) {
var powerOrb = game.addChild(new PowerOrb());
powerOrb.x = block.x;
powerOrb.y = block.y;
powerOrbs.push(powerOrb);
}
// 20% chance to spawn double ball orb
if (Math.random() < 0.2) {
var doubleBallOrb = game.addChild(new DoubleBallOrb());
doubleBallOrb.x = block.x;
doubleBallOrb.y = block.y;
doubleBallOrbs.push(doubleBallOrb);
}
// 20% chance to spawn slow ball orb
if (Math.random() < 0.2) {
var slowBallOrb = game.addChild(new SlowBallOrb());
slowBallOrb.x = block.x;
slowBallOrb.y = block.y;
slowBallOrbs.push(slowBallOrb);
}
// 20% chance to spawn enlarge paddle orb
if (Math.random() < 0.2) {
var enlargePaddleOrb = game.addChild(new EnlargePaddleOrb());
enlargePaddleOrb.x = block.x;
enlargePaddleOrb.y = block.y;
enlargePaddleOrbs.push(enlargePaddleOrb);
}
// Destroy the block
block.destroy();
blocks.splice(i, 1);
// Reverse ball Y velocity
self.velocityY = -self.velocityY;
break; // Only hit one block per frame
}
}
// Check collision with red blocks
for (var j = redBlocks.length - 1; j >= 0; j--) {
var redBlock = redBlocks[j];
if (self.intersects(redBlock)) {
// Play red block sound and additional sounds
LK.getSound('sonidodebloquerojo').play();
var additionalSounds = ['q', 'w', 'e', 'r', 't'];
var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)];
LK.getSound(randomAdditionalSound).play();
// Block destroyed
// Increment score
score += 15;
scoreTxt.setText('Score: ' + score);
// Add expansion animation to bouncing circle
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Spawn green block at random position with minimum distance from other blocks
var newGreenBlock = game.addChild(new GreenBlock());
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 50) {
newGreenBlock.x = Math.random() * (2048 - 120) + 60; // Random X within screen bounds
newGreenBlock.y = Math.random() * 800 + 200; // Random Y in upper part of screen
validPosition = true;
// Check distance from all existing blue blocks
for (var b = 0; b < blocks.length; b++) {
var existingBlock = blocks[b];
var dx = newGreenBlock.x - existingBlock.x;
var dy = newGreenBlock.y - existingBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing red blocks
for (var r = 0; r < redBlocks.length; r++) {
var existingRedBlock = redBlocks[r];
var dx = newGreenBlock.x - existingRedBlock.x;
var dy = newGreenBlock.y - existingRedBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing green blocks
for (var g = 0; g < greenBlocks.length; g++) {
var existingGreenBlock = greenBlocks[g];
var dx = newGreenBlock.x - existingGreenBlock.x;
var dy = newGreenBlock.y - existingGreenBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing purple blocks
for (var p = 0; p < purpleBlocks.length; p++) {
var existingPurpleBlock = purpleBlocks[p];
var dx = newGreenBlock.x - existingPurpleBlock.x;
var dy = newGreenBlock.y - existingPurpleBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
attempts++;
}
greenBlocks.push(newGreenBlock);
// 20% chance to spawn power orb
if (Math.random() < 0.2) {
var powerOrb = game.addChild(new PowerOrb());
powerOrb.x = redBlock.x;
powerOrb.y = redBlock.y;
powerOrbs.push(powerOrb);
}
// 20% chance to spawn double ball orb
if (Math.random() < 0.2) {
var doubleBallOrb = game.addChild(new DoubleBallOrb());
doubleBallOrb.x = redBlock.x;
doubleBallOrb.y = redBlock.y;
doubleBallOrbs.push(doubleBallOrb);
}
// 20% chance to spawn slow ball orb
if (Math.random() < 0.2) {
var slowBallOrb = game.addChild(new SlowBallOrb());
slowBallOrb.x = redBlock.x;
slowBallOrb.y = redBlock.y;
slowBallOrbs.push(slowBallOrb);
}
// 20% chance to spawn enlarge paddle orb
if (Math.random() < 0.2) {
var enlargePaddleOrb = game.addChild(new EnlargePaddleOrb());
enlargePaddleOrb.x = redBlock.x;
enlargePaddleOrb.y = redBlock.y;
enlargePaddleOrbs.push(enlargePaddleOrb);
}
// Destroy the red block
redBlock.destroy();
redBlocks.splice(j, 1);
// Reverse ball Y velocity
self.velocityY = -self.velocityY;
break; // Only hit one block per frame
}
}
// Check collision with green blocks
for (var k = greenBlocks.length - 1; k >= 0; k--) {
var greenBlock = greenBlocks[k];
if (self.intersects(greenBlock)) {
// Play green block sound and additional sounds
LK.getSound('sonidodebloquerojo').play();
var additionalSounds = ['q', 'w', 'e', 'r', 't'];
var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)];
LK.getSound(randomAdditionalSound).play();
// Block destroyed
// Increment score
score += 20;
scoreTxt.setText('Score: ' + score);
// Add expansion animation to bouncing circle
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Spawn purple block at random position with minimum distance from other blocks
var newPurpleBlock = game.addChild(new PurpleBlock());
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 50) {
newPurpleBlock.x = Math.random() * (2048 - 120) + 60; // Random X within screen bounds
newPurpleBlock.y = Math.random() * 800 + 200; // Random Y in upper part of screen
validPosition = true;
// Check distance from all existing blue blocks
for (var b = 0; b < blocks.length; b++) {
var existingBlock = blocks[b];
var dx = newPurpleBlock.x - existingBlock.x;
var dy = newPurpleBlock.y - existingBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing red blocks
for (var r = 0; r < redBlocks.length; r++) {
var existingRedBlock = redBlocks[r];
var dx = newPurpleBlock.x - existingRedBlock.x;
var dy = newPurpleBlock.y - existingRedBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing green blocks
for (var g = 0; g < greenBlocks.length; g++) {
var existingGreenBlock = greenBlocks[g];
var dx = newPurpleBlock.x - existingGreenBlock.x;
var dy = newPurpleBlock.y - existingGreenBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing purple blocks
for (var p = 0; p < purpleBlocks.length; p++) {
var existingPurpleBlock = purpleBlocks[p];
var dx = newPurpleBlock.x - existingPurpleBlock.x;
var dy = newPurpleBlock.y - existingPurpleBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
attempts++;
}
purpleBlocks.push(newPurpleBlock);
// 20% chance to spawn power orb
if (Math.random() < 0.2) {
var powerOrb = game.addChild(new PowerOrb());
powerOrb.x = greenBlock.x;
powerOrb.y = greenBlock.y;
powerOrbs.push(powerOrb);
}
// 20% chance to spawn double ball orb
if (Math.random() < 0.2) {
var doubleBallOrb = game.addChild(new DoubleBallOrb());
doubleBallOrb.x = greenBlock.x;
doubleBallOrb.y = greenBlock.y;
doubleBallOrbs.push(doubleBallOrb);
}
// 20% chance to spawn slow ball orb
if (Math.random() < 0.2) {
var slowBallOrb = game.addChild(new SlowBallOrb());
slowBallOrb.x = greenBlock.x;
slowBallOrb.y = greenBlock.y;
slowBallOrbs.push(slowBallOrb);
}
// 20% chance to spawn enlarge paddle orb
if (Math.random() < 0.2) {
var enlargePaddleOrb = game.addChild(new EnlargePaddleOrb());
enlargePaddleOrb.x = greenBlock.x;
enlargePaddleOrb.y = greenBlock.y;
enlargePaddleOrbs.push(enlargePaddleOrb);
}
// Destroy the green block
greenBlock.destroy();
greenBlocks.splice(k, 1);
// Reverse ball Y velocity
self.velocityY = -self.velocityY;
break; // Only hit one block per frame
}
}
// Check collision with purple blocks
for (var l = purpleBlocks.length - 1; l >= 0; l--) {
var purpleBlock = purpleBlocks[l];
if (self.intersects(purpleBlock)) {
// Play purple block sound and additional sounds
LK.getSound('sonidodebloquerojo').play();
var additionalSounds = ['q', 'w', 'e', 'r', 't'];
var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)];
LK.getSound(randomAdditionalSound).play();
// Block destroyed
// Increment score
score += 25;
scoreTxt.setText('Score: ' + score);
// Add expansion animation to bouncing circle
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// 20% chance to spawn power orb
if (Math.random() < 0.2) {
var powerOrb = game.addChild(new PowerOrb());
powerOrb.x = purpleBlock.x;
powerOrb.y = purpleBlock.y;
powerOrbs.push(powerOrb);
}
// 20% chance to spawn double ball orb
if (Math.random() < 0.2) {
var doubleBallOrb = game.addChild(new DoubleBallOrb());
doubleBallOrb.x = purpleBlock.x;
doubleBallOrb.y = purpleBlock.y;
doubleBallOrbs.push(doubleBallOrb);
}
// 20% chance to spawn slow ball orb
if (Math.random() < 0.2) {
var slowBallOrb = game.addChild(new SlowBallOrb());
slowBallOrb.x = purpleBlock.x;
slowBallOrb.y = purpleBlock.y;
slowBallOrbs.push(slowBallOrb);
}
// 20% chance to spawn enlarge paddle orb
if (Math.random() < 0.2) {
var enlargePaddleOrb = game.addChild(new EnlargePaddleOrb());
enlargePaddleOrb.x = purpleBlock.x;
enlargePaddleOrb.y = purpleBlock.y;
enlargePaddleOrbs.push(enlargePaddleOrb);
}
// Destroy the purple block
purpleBlock.destroy();
purpleBlocks.splice(l, 1);
// Reverse ball Y velocity
self.velocityY = -self.velocityY;
break; // Only hit one block per frame
}
}
// Bounce off screen edges
if (self.x <= 25) {
self.x = 25;
self.velocityX = -self.velocityX;
}
if (self.x >= 2048 - 25) {
self.x = 2048 - 25;
self.velocityX = -self.velocityX;
}
if (self.y <= 25) {
self.y = 25;
self.velocityY = -self.velocityY;
}
if (self.y >= 2732 - 25) {
self.y = 2732 - 25;
self.velocityY = -self.velocityY;
}
};
return self;
});
var CornerBlock = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('cornerBlock', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x000000
});
// Track collision state for sound triggering
self.lastIntersecting = false;
self.update = function () {
// Check collision with bouncing circle
var currentIntersecting = self.intersects(bouncingCircle);
if (!self.lastIntersecting && currentIntersecting) {
// Collision just started - play random sound (C, A, or G)
var sounds = ['c', 'a', 'g'];
var randomSound = sounds[Math.floor(Math.random() * sounds.length)];
LK.getSound(randomSound).play();
var additionalSounds = ['q', 'w', 'e', 'r', 't'];
var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)];
LK.getSound(randomAdditionalSound).play();
// Add expansion animation to bouncing circle
tween(bouncingCircle, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(bouncingCircle, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
self.lastIntersecting = currentIntersecting;
};
return self;
});
var CornerBlockRight = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('cornerBlockRight', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x000000
});
// Track collision state for sound triggering
self.lastIntersecting = false;
self.update = function () {
// Check collision with bouncing circle
var currentIntersecting = self.intersects(bouncingCircle);
if (!self.lastIntersecting && currentIntersecting) {
// Collision just started - play random sound (C, A, or G)
var sounds = ['c', 'a', 'g'];
var randomSound = sounds[Math.floor(Math.random() * sounds.length)];
LK.getSound(randomSound).play();
var additionalSounds = ['q', 'w', 'e', 'r', 't'];
var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)];
LK.getSound(randomAdditionalSound).play();
// Add expansion animation to bouncing circle
tween(bouncingCircle, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(bouncingCircle, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
self.lastIntersecting = currentIntersecting;
};
return self;
});
var CornerBlockTop = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('cornerBlockTop', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x000000
});
// Track collision state for sound triggering
self.lastIntersecting = false;
self.update = function () {
// Check collision with bouncing circle
var currentIntersecting = self.intersects(bouncingCircle);
if (!self.lastIntersecting && currentIntersecting) {
// Collision just started - play random sound (C, A, or G)
var sounds = ['c', 'a', 'g'];
var randomSound = sounds[Math.floor(Math.random() * sounds.length)];
LK.getSound(randomSound).play();
var additionalSounds = ['q', 'w', 'e', 'r', 't'];
var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)];
LK.getSound(randomAdditionalSound).play();
// Add expansion animation to bouncing circle
tween(bouncingCircle, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(bouncingCircle, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
self.lastIntersecting = currentIntersecting;
};
return self;
});
var DoubleBallOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('doubleBallOrb', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x00ffff
});
// Fall downward
self.velocityY = 8;
self.update = function () {
self.y += self.velocityY;
// Remove if goes off screen
if (self.y > 2800) {
self.destroy();
// Remove from doubleBallOrbs array
for (var i = doubleBallOrbs.length - 1; i >= 0; i--) {
if (doubleBallOrbs[i] === self) {
doubleBallOrbs.splice(i, 1);
break;
}
}
}
};
return self;
});
var EnlargePaddleOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('enlargePaddleOrb', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff00ff
});
// Fall downward
self.velocityY = 8;
self.update = function () {
self.y += self.velocityY;
// Remove if goes off screen
if (self.y > 2800) {
self.destroy();
// Remove from enlargePaddleOrbs array
for (var i = enlargePaddleOrbs.length - 1; i >= 0; i--) {
if (enlargePaddleOrbs[i] === self) {
enlargePaddleOrbs.splice(i, 1);
break;
}
}
}
};
return self;
});
var GreenBlock = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('greenBlock', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Cache paddle constants
var Paddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = self.attachAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// Prevent paddle from going through left wall
if (self.x < PADDLE_HALF_WIDTH) {
self.x = PADDLE_HALF_WIDTH;
}
// Prevent paddle from going through right wall
if (self.x > SCREEN_WIDTH - PADDLE_HALF_WIDTH) {
self.x = SCREEN_WIDTH - PADDLE_HALF_WIDTH;
}
};
return self;
});
var PowerOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('powerOrb', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xffff00
});
// Fall downward
self.velocityY = 8;
self.update = function () {
self.y += self.velocityY;
// Remove if goes off screen
if (self.y > 2800) {
self.destroy();
// Remove from powerOrbs array
for (var i = powerOrbs.length - 1; i >= 0; i--) {
if (powerOrbs[i] === self) {
powerOrbs.splice(i, 1);
break;
}
}
}
};
return self;
});
var PurpleBlock = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('purpleBlock', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var RedBlock = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('redBlock', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var SlowBallOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('slowBallOrb', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff0000
});
// Fall downward
self.velocityY = 8;
self.update = function () {
self.y += self.velocityY;
// Remove if goes off screen
if (self.y > 2800) {
self.destroy();
// Remove from slowBallOrbs array
for (var i = slowBallOrbs.length - 1; i >= 0; i--) {
if (slowBallOrbs[i] === self) {
slowBallOrbs.splice(i, 1);
break;
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Add scattered musical wave symbols across the background
var musicalWaves = [];
for (var i = 0; i < 20; i++) {
var waveType = 'musicalWave' + (Math.floor(Math.random() * 4) + 1);
var wave = game.addChild(LK.getAsset(waveType, {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
alpha: 0.3,
rotation: Math.random() * Math.PI * 2
}));
musicalWaves.push(wave);
}
// Add scattered musical notes across the background
var musicalNotes = [];
for (var i = 0; i < 15; i++) {
var noteType = 'musicalNote' + (Math.floor(Math.random() * 3) + 1);
var note = game.addChild(LK.getAsset(noteType, {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
alpha: 0.25,
rotation: Math.random() * Math.PI * 2
}));
musicalNotes.push(note);
}
// Add staff lines across the background
var staffLines = [];
for (var i = 0; i < 12; i++) {
var staffType = 'staffLine' + (Math.floor(Math.random() * 3) + 1);
var staff = game.addChild(LK.getAsset(staffType, {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
alpha: 0.2,
rotation: Math.random() * Math.PI * 0.5
}));
staffLines.push(staff);
}
// Add treble clefs scattered in the background
var trebleClefs = [];
for (var i = 0; i < 8; i++) {
var clef = game.addChild(LK.getAsset('trebleClef', {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
alpha: 0.15,
rotation: Math.random() * Math.PI * 2
}));
trebleClefs.push(clef);
}
// Add scattered background circles
var backgroundCircles = [];
for (var i = 0; i < 40; i++) {
var circleType = 'backgroundCircle' + (Math.floor(Math.random() * 6) + 1);
var circle = game.addChild(LK.getAsset(circleType, {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
alpha: 0.1
}));
backgroundCircles.push(circle);
}
// Cache paddle constants
var PADDLE_HALF_WIDTH = 150;
var SCREEN_WIDTH = 2048;
var blocks = [];
var redBlocks = [];
var greenBlocks = [];
var purpleBlocks = [];
var powerOrbs = [];
var doubleBallOrbs = [];
var slowBallOrbs = [];
var enlargePaddleOrbs = [];
var bouncingCircles = [];
var paddleCollisions = 0;
var score = 0;
var bouncingCircle = game.addChild(new BouncingCircle());
bouncingCircle.x = 1024;
bouncingCircle.y = 2550; // Position above paddle
bouncingCircle.lastIntersecting = false;
bouncingCircles.push(bouncingCircle);
var paddle = game.addChild(new Paddle());
paddle.x = 1024;
paddle.y = 2600;
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
game.move = function (x, y, obj) {
paddle.x = x;
};
// Add corner block covering entire left side of screen
var cornerBlock = game.addChild(new CornerBlock());
cornerBlock.x = 10; // Position at left edge
cornerBlock.y = 1366; // Center vertically (half of 2732)
// Add corner block covering entire right side of screen
var cornerBlockRight = game.addChild(new CornerBlockRight());
cornerBlockRight.x = 2038; // Position at right edge
cornerBlockRight.y = 1366; // Center vertically (half of 2732)
// Add corner block covering entire top side of screen
var cornerBlockTop = game.addChild(new CornerBlockTop());
cornerBlockTop.x = 1024; // Center horizontally (half of 2048)
cornerBlockTop.y = 10; // Position at top edge
// Play background music
LK.playMusic('musica');
game.update = function () {
// Track ball-paddle collision state transitions
var currentIntersecting = bouncingCircle.intersects(paddle);
if (!bouncingCircle.lastIntersecting && currentIntersecting) {
// Collision just started - push ball above paddle and reverse Y velocity
bouncingCircle.y = paddle.y - 20 - 25;
bouncingCircle.velocityY = -Math.abs(bouncingCircle.velocityY);
// Increment paddle collision counter
paddleCollisions++;
// Play random sound (C, A, or G)
var sounds = ['c', 'a', 'g'];
var randomSound = sounds[Math.floor(Math.random() * sounds.length)];
LK.getSound(randomSound).play();
var additionalSounds = ['q', 'w', 'e', 'r', 't'];
var randomAdditionalSound = additionalSounds[Math.floor(Math.random() * additionalSounds.length)];
LK.getSound(randomAdditionalSound).play();
// Add expansion animation to bouncing circle
tween(bouncingCircle, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(bouncingCircle, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Add shake animation to paddle
var shakeDistance = 10;
var originalX = paddle.x;
tween(paddle, {
x: originalX - shakeDistance
}, {
duration: 50,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(paddle, {
x: originalX + shakeDistance
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(paddle, {
x: originalX - shakeDistance * 0.5
}, {
duration: 40,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(paddle, {
x: originalX + shakeDistance * 0.5
}, {
duration: 40,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(paddle, {
x: originalX
}, {
duration: 30,
easing: tween.easeIn
});
}
});
}
});
}
});
}
});
// Spawn new blue block at random position with minimum distance from other blocks
var newBlock = game.addChild(new BlueBlock());
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 50) {
newBlock.x = Math.random() * (2048 - 120) + 60; // Random X within screen bounds
newBlock.y = Math.random() * 800 + 200; // Random Y in upper part of screen
validPosition = true;
// Check distance from all existing blue blocks
for (var b = 0; b < blocks.length; b++) {
var existingBlock = blocks[b];
var dx = newBlock.x - existingBlock.x;
var dy = newBlock.y - existingBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing red blocks
for (var r = 0; r < redBlocks.length; r++) {
var existingRedBlock = redBlocks[r];
var dx = newBlock.x - existingRedBlock.x;
var dy = newBlock.y - existingRedBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing green blocks
for (var g = 0; g < greenBlocks.length; g++) {
var existingGreenBlock = greenBlocks[g];
var dx = newBlock.x - existingGreenBlock.x;
var dy = newBlock.y - existingGreenBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
// Check distance from all existing purple blocks
for (var p = 0; p < purpleBlocks.length; p++) {
var existingPurpleBlock = purpleBlocks[p];
var dx = newBlock.x - existingPurpleBlock.x;
var dy = newBlock.y - existingPurpleBlock.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Minimum distance of 200 pixels
validPosition = false;
break;
}
}
attempts++;
}
blocks.push(newBlock);
}
bouncingCircle.lastIntersecting = currentIntersecting;
// Check power orb collisions with paddle
for (var k = powerOrbs.length - 1; k >= 0; k--) {
var powerOrb = powerOrbs[k];
if (powerOrb.intersects(paddle)) {
// Increase ball speed for all balls
var speedMultiplier = 1.5;
for (var circleIndex = 0; circleIndex < bouncingCircles.length; circleIndex++) {
var circle = bouncingCircles[circleIndex];
circle.velocityX *= speedMultiplier;
circle.velocityY *= speedMultiplier;
// Visual feedback - flash ball green
tween(circle, {
tint: 0x00ff00
}, {
duration: 200,
onFinish: function onFinish() {
tween(circle, {
tint: 0xffffff
}, {
duration: 200
});
}
});
}
// Remove power orb
powerOrb.destroy();
powerOrbs.splice(k, 1);
}
}
// Check double ball orb collisions with paddle
for (var d = doubleBallOrbs.length - 1; d >= 0; d--) {
var doubleBallOrb = doubleBallOrbs[d];
if (doubleBallOrb.intersects(paddle)) {
// Create new bouncing ball
var newBall = game.addChild(new BouncingCircle());
newBall.x = bouncingCircle.x + 50;
newBall.y = bouncingCircle.y;
newBall.velocityX = -bouncingCircle.velocityX;
newBall.velocityY = bouncingCircle.velocityY;
newBall.lastIntersecting = false;
bouncingCircles.push(newBall);
// Visual feedback - flash original ball green
tween(bouncingCircle, {
tint: 0x00ff00
}, {
duration: 200,
onFinish: function onFinish() {
tween(bouncingCircle, {
tint: 0xffffff
}, {
duration: 200
});
}
});
// Remove double ball orb
doubleBallOrb.destroy();
doubleBallOrbs.splice(d, 1);
}
}
// Check slow ball orb collisions with paddle
for (var s = slowBallOrbs.length - 1; s >= 0; s--) {
var slowBallOrb = slowBallOrbs[s];
if (slowBallOrb.intersects(paddle)) {
// Slow down all balls
var slowMultiplier = 0.7;
for (var circleIndex = 0; circleIndex < bouncingCircles.length; circleIndex++) {
var circle = bouncingCircles[circleIndex];
circle.velocityX *= slowMultiplier;
circle.velocityY *= slowMultiplier;
// Visual feedback - flash ball orange
tween(circle, {
tint: 0xff6600
}, {
duration: 200,
onFinish: function onFinish() {
tween(circle, {
tint: 0xffffff
}, {
duration: 200
});
}
});
}
// Remove slow ball orb
slowBallOrb.destroy();
slowBallOrbs.splice(s, 1);
}
}
// Check enlarge paddle orb collisions with paddle
for (var e = enlargePaddleOrbs.length - 1; e >= 0; e--) {
var enlargePaddleOrb = enlargePaddleOrbs[e];
if (enlargePaddleOrb.intersects(paddle)) {
// Enlarge paddle
tween(paddle, {
scaleX: 1.5
}, {
duration: 300,
easing: tween.easeOut
});
// Visual feedback - flash paddle blue
tween(paddle, {
tint: 0x0066ff
}, {
duration: 200,
onFinish: function onFinish() {
tween(paddle, {
tint: 0xffffff
}, {
duration: 200
});
}
});
// Remove enlarge paddle orb
enlargePaddleOrb.destroy();
enlargePaddleOrbs.splice(e, 1);
}
}
// Check if any ball hits bottom area and remove it
for (var circleIndex = bouncingCircles.length - 1; circleIndex >= 0; circleIndex--) {
var circle = bouncingCircles[circleIndex];
if (circle.y >= 2700) {
circle.destroy();
bouncingCircles.splice(circleIndex, 1);
}
}
// Game over if no balls left
if (bouncingCircles.length === 0) {
LK.showGameOver();
return;
}
};