Code edit (4 edits merged)
Please save this source code
Code edit (14 edits merged)
Please save this source code
User prompt
Please fix the bug: 'customFrameGraphics is not defined' in or related to this line: 'tween(customFrameGraphics, {' Line Number: 475 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
/**** * Plugins ****/ var storage = LK.import("@upit/storage.v1"); var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'normal'; var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); ballGraphics.tint = type === 'splash' ? 0xff0066 : type === 'sniper' ? 0x00ff99 : type === 'scatter' ? 0xffff00 : type === 'smallScatter' ? 0xffff00 : 0xffffff; if (type === 'smallScatter') { ballGraphics.scaleX = 0.5; ballGraphics.scaleY = 0.5; } self.type = type; self.speed = type === 'splash' ? upgrades.splashSpeed : type === 'sniper' ? upgrades.sniperSpeed : type === 'scatter' ? upgrades.scatterSpeed : type === 'smallScatter' ? upgrades.scatterSpeed * 1.5 : upgrades.normalSpeed; self.power = type === 'splash' ? upgrades.splashPower : type === 'sniper' ? upgrades.sniperPower : type === 'scatter' ? upgrades.scatterPower : type === 'smallScatter' ? Math.max(1, Math.floor(upgrades.scatterPower * 0.8)) : upgrades.normalPower; self.velocity = { x: 1, y: -1 }; self.sniperCooldown = 0; self.sniperCooldownMax = 60; self.interactive = true; self.down = function (x, y, obj) { var angle = Math.random() * 2 * Math.PI; self.velocity.x = Math.cos(angle); self.velocity.y = Math.sin(angle); var magnitude = Math.sqrt(self.velocity.x * self.velocity.x + self.velocity.y * self.velocity.y); self.velocity.x /= magnitude; self.velocity.y /= magnitude; }; self.update = function () { var SHIELD_BUFFER = 5; var MAX_STEP = BALL_RADIUS / 2; var totalDistance = self.speed; var steps = Math.ceil(totalDistance / MAX_STEP); var stepDistance = totalDistance / steps; var splashApplied = false; if (self.type === 'sniper') { self.sniperCooldown--; if (self.sniperCooldown <= 0) { var nearestBrick = findNearestBrick(self.x, self.y); if (nearestBrick) { var dx = nearestBrick.x - self.x; var dy = nearestBrick.y - self.y; var magnitude = Math.sqrt(dx * dx + dy * dy); self.velocity.x = dx / magnitude; self.velocity.y = dy / magnitude; self.sniperCooldown = self.sniperCooldownMax; } } } for (var step = 0; step < steps; step++) { var dx = self.velocity.x * stepDistance; var dy = self.velocity.y * stepDistance; var nextX = self.x + dx; var nextY = self.y + dy; if (nextX < BALL_RADIUS + SHIELD_BUFFER) { nextX = BALL_RADIUS + SHIELD_BUFFER; self.velocity.x = -self.velocity.x; self.velocity.y += (Math.random() - 0.5) * 0.1; LK.getSound('bounce').play(); } else if (nextX > GAME_WIDTH - BALL_RADIUS - SHIELD_BUFFER) { nextX = GAME_WIDTH - BALL_RADIUS - SHIELD_BUFFER; self.velocity.x = -self.velocity.x; self.velocity.y += (Math.random() - 0.5) * 0.1; LK.getSound('bounce').play(); } if (nextY < BALL_RADIUS + SHIELD_BUFFER) { nextY = BALL_RADIUS + SHIELD_BUFFER; self.velocity.y = -self.velocity.y; self.velocity.x += (Math.random() - 0.5) * 0.1; LK.getSound('bounce').play(); } else if (nextY > GAME_HEIGHT - BALL_RADIUS - SHIELD_BUFFER) { nextY = GAME_HEIGHT - BALL_RADIUS - SHIELD_BUFFER; self.velocity.y = -self.velocity.y; self.velocity.x += (Math.random() - 0.5) * 0.1; LK.getSound('bounce').play(); } var ballLeft = nextX - BALL_RADIUS - SHIELD_BUFFER; var ballRight = nextX + BALL_RADIUS + SHIELD_BUFFER; var ballTop = nextY - BALL_RADIUS - SHIELD_BUFFER; var ballBottom = nextY + BALL_RADIUS + SHIELD_BUFFER; var collided = false; for (var i = bricks.length - 1; i >= 0; i--) { var brick = bricks[i]; if (brick.health <= 0) { continue; } var brickLeft = brick.x - BRICK_WIDTH / 2; var brickRight = brick.x + BRICK_WIDTH / 2; var brickTop = brick.y - BRICK_HEIGHT / 2; var brickBottom = brick.y + BRICK_HEIGHT / 2; if (ballLeft < brickRight && ballRight > brickLeft && ballTop < brickBottom && ballBottom > brickTop) { var overlapLeft = ballRight - brickLeft; var overlapRight = brickRight - ballLeft; var overlapTop = ballBottom - brickTop; var overlapBottom = brickBottom - ballTop; var minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom); if (minOverlap === overlapLeft) { nextX = brickLeft - BALL_RADIUS - SHIELD_BUFFER; self.velocity.x = -self.velocity.x; } else if (minOverlap === overlapRight) { nextX = brickRight + BALL_RADIUS + SHIELD_BUFFER; self.velocity.x = -self.velocity.x; } else if (minOverlap === overlapTop) { nextY = brickTop - BALL_RADIUS - SHIELD_BUFFER; self.velocity.y = -self.velocity.y; } else { nextY = brickBottom + BALL_RADIUS + SHIELD_BUFFER; self.velocity.y = -self.velocity.y; } self.velocity.x += (Math.random() - 0.5) * 0.2; self.velocity.y += (Math.random() - 0.5) * 0.2; LK.getSound('bounce').play(); brick.hit(self.power); ballDamage[self.type] = (ballDamage[self.type] || 0) + self.power; if (self.type === 'splash' && !splashApplied) { applySplashDamage(brick); splashApplied = true; } else if (self.type === 'scatter') { scatterOnImpact(self); self.destroy(); balls.splice(balls.indexOf(self), 1); return; } collided = true; break; } } self.x = nextX; self.y = nextY; if (collided) { break; } } var magnitude = Math.sqrt(self.velocity.x * self.velocity.x + self.velocity.y * self.velocity.y); if (magnitude > 0) { self.velocity.x /= magnitude; self.velocity.y /= magnitude; } }; }); var Brick = Container.expand(function () { var self = Container.call(this); var brickGraphics = self.attachAsset('brick', { anchorX: 0.5, anchorY: 0.5 }); self.health = 1; self.maxHealth = 1; self.healthText = new Text2(self.health.toString(), { size: 50, fill: 0x000000, fontWeight: 'bold' }); self.healthText.anchor.set(0.5, 0.5); self.addChild(self.healthText); self.updateTint = function () { var baseColors = LEVEL_COLORS; var colorCount = baseColors.length; if (self.health <= colorCount) { brickGraphics.tint = baseColors[self.health - 1]; } else { var lastDigit = self.health % 10; var colorIndex = lastDigit === 0 ? 9 : lastDigit - 1; brickGraphics.tint = baseColors[colorIndex]; } }; self.updateTint(); self.hit = function () { var damage = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; self.health -= damage; if (self.health <= 0) { LK.getSound('explosion').play(); score += self.maxHealth === 1 ? 1 : self.maxHealth; scoreTxt.setText('$' + score.toString()); storage.score = score; var brickIndex = bricks.indexOf(self); if (brickIndex !== -1) { bricks.splice(brickIndex, 1); } var explosionColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff]; var randomColor = explosionColors[Math.floor(Math.random() * explosionColors.length)]; var randomScale = Math.random() * 1.5 + 1.5; var randomDuration = Math.random() * 300 + 400; tween(self, { tint: randomColor, scaleX: randomScale, scaleY: randomScale, alpha: 0 }, { duration: randomDuration, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); } else { self.healthText.setText(self.health.toString()); self.updateTint(); } }; }); var GameTitle = Container.expand(function () { var self = Container.call(this); var titleGraphics = self.attachAsset('gametitle', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.35, scaleY: 1.5 }); var titleText = new Text2('Idle BrickBreaker', { size: 200, fill: 0x000000 }); titleText.anchor.set(0.5, 0.5); self.addChild(titleText); }); var ResetButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('resetButton', { anchorX: 0.5, anchorY: 0.5, tint: 0xff6666 }); var buttonText = new Text2('RESET', { size: 50, fill: 0x000000, fontWeight: 'bold' }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.interactive = true; self.down = function () { LK.getSound('click').play(); clearLocalStorage(); playTime = 0; storage.playTime = playTime; LK.showGameOver(); }; }); var Star = Container.expand(function () { var self = Container.call(this); var starGraphics = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5 }); self.speed = Math.random() * 2 + 1; self.update = function () { self.y += self.speed; if (self.y > GAME_HEIGHT) { self.y = 0; self.x = Math.random() * GAME_WIDTH; } }; }); var StartButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('startButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); var buttonText = new Text2('START', { size: 100, fill: 0x000000, fontWeight: 'bold' }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.interactive = true; self.down = function () { LK.getSound('click').play(); self.interactive = false; var explosionColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff]; var randomColor = explosionColors[Math.floor(Math.random() * explosionColors.length)]; LK.getSound('explosion').play(); tween(self, { tint: randomColor, scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { startTransitionSequence(); } }); }; }); var UpgradeButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('upgrade', { anchorX: 0.5, anchorY: 0.5, tint: 0x00ffff }); var buttonText = new Text2('UPGRADES', { size: 50, fill: 0x000000, fontWeight: 'bold' }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.interactive = true; self.down = function () { LK.getSound('click').play(); powerupContainer.visible = !powerupContainer.visible; }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ var lastRunStartTime = 0; var lastRunTime = 0; var ballDamage = { normal: 0, splash: 0, sniper: 0, scatter: 0, smallScatter: 0 }; function _toConsumableArray2(r) { return _arrayWithoutHoles2(r) || _iterableToArray2(r) || _unsupportedIterableToArray2(r) || _nonIterableSpread2(); } function _nonIterableSpread2() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray2(r, a) { if (r) { if ("string" == typeof r) { return _arrayLikeToArray2(r, a); } var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray2(r, a) : void 0; } } function _iterableToArray2(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) { return Array.from(r); } } function _arrayWithoutHoles2(r) { if (Array.isArray(r)) { return _arrayLikeToArray2(r); } } function _arrayLikeToArray2(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) { return _arrayLikeToArray(r, a); } var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) { return Array.from(r); } } function _arrayWithoutHoles(r) { if (Array.isArray(r)) { return _arrayLikeToArray(r); } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; } function tintEndScreenTitle() { gameTitleContainer.children.forEach(function (child) { child.tint = 0xff33cc; }); } var frameThickness = 10; var topFrame = new Container(); var topFrameGraphics = topFrame.attachAsset('frame', { anchorX: 0, anchorY: 0, width: GAME_WIDTH, height: frameThickness }); topFrame.x = 0; topFrame.y = 0; game.addChild(topFrame); function animateTopFrameTint() { tween(topFrameGraphics, { tint: 0xff33cc }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(topFrameGraphics, { tint: 0x00ff99 }, { duration: 2000, easing: tween.easeInOut, onFinish: animateTopFrameTint }); } }); } animateTopFrameTint(); var bottomFrame = new Container(); var bottomFrameGraphics = bottomFrame.attachAsset('frame', { anchorX: 0, anchorY: 0, width: GAME_WIDTH, height: frameThickness }); bottomFrame.x = 0; bottomFrame.y = 2720; game.addChild(bottomFrame); // Should be bottomFrame function animateBottomFrameTint() { tween(bottomFrameGraphics, { tint: 0xff33cc }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(bottomFrameGraphics, { tint: 0x00ff99 }, { duration: 2000, easing: tween.easeInOut, onFinish: animateBottomFrameTint }); } }); } animateBottomFrameTint(); var leftFrame = new Container(); var leftFrameGraphics = leftFrame.attachAsset('frame', { anchorX: 0, anchorY: 0, width: frameThickness, height: GAME_HEIGHT }); leftFrame.x = 0; leftFrame.y = 0; game.addChild(leftFrame); function animateLeftFrameTint() { tween(leftFrameGraphics, { tint: 0xff33cc }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(leftFrameGraphics, { tint: 0x00ff99 }, { duration: 2000, easing: tween.easeInOut, onFinish: animateLeftFrameTint }); } }); } animateLeftFrameTint(); var rightFrame = new Container(); var rightFrameGraphics = rightFrame.attachAsset('frame', { anchorX: 0, anchorY: 0, width: frameThickness, height: GAME_HEIGHT }); rightFrame.x = 2040; rightFrame.y = 0; game.addChild(rightFrame); function animateRightFrameTint() { tween(rightFrameGraphics, { tint: 0xff33cc }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(rightFrameGraphics, { tint: 0x00ff99 }, { duration: 2000, easing: tween.easeInOut, onFinish: animateRightFrameTint }); } }); } animateRightFrameTint(); var welcomeText = null; function showEndScreen() { game.isGameOver = true; hud.visible = false; powerupContainer.visible = false; upgradeButton.visible = false; balls.forEach(function (ball) { return ball.visible = true; }); bricks.forEach(function (brick) { return brick.visible = false; }); // Calculate last run time lastRunTime = Math.floor((Date.now() - lastRunStartTime) / 1000); var congratsText = new Text2('Congratulations! You broke them ALL!', { size: 100, fill: 0xffffff }); congratsText.anchor.set(0.5, 0); congratsText.x = GAME_WIDTH / 2; congratsText.y = GAME_HEIGHT / 2 - 600; // Moved up slightly game.addChild(congratsText); // Move game title up var gameTitle = new GameTitle(); gameTitle.x = GAME_WIDTH / 2; gameTitle.y = congratsText.y - 400; // Moved down by 200 pixels gameTitleContainer.addChild(gameTitle); function animateEndTitleColor() { tintEndScreenTitle(); tween(gameTitle, { tint: 0xff33cc }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(gameTitle, { tint: 0x00ff99 }, { duration: 2000, easing: tween.easeInOut, onFinish: animateEndTitleColor }); } }); } animateEndTitleColor(); var playTimeText = new Text2('Total Time Played: ' + playTime + ' seconds', { size: 60, fill: 0xffffff }); playTimeText.anchor.set(0.5, 0); playTimeText.x = GAME_WIDTH / 2; playTimeText.y = congratsText.y + 200; game.addChild(playTimeText); var lastRunText = new Text2('Last Run Time: ' + lastRunTime + ' seconds', { size: 60, fill: 0xffffff }); lastRunText.anchor.set(0.5, 0); lastRunText.x = GAME_WIDTH / 2; lastRunText.y = playTimeText.y + 200; game.addChild(lastRunText); // Add damage stats var damageText = new Text2('Damage Dealt This Run:\n' + 'Normal: ' + ballDamage.normal + '\n' + 'Splash: ' + ballDamage.splash + '\n' + 'Sniper: ' + ballDamage.sniper + '\n' + 'Scatter: ' + ballDamage.scatter + '\n' + 'Small Scatter: ' + ballDamage.smallScatter, { size: 50, fill: 0xffffff, align: 'center' }); damageText.anchor.set(0.5, 0); damageText.x = GAME_WIDTH / 2; damageText.y = lastRunText.y + 120; game.addChild(damageText); var noteText = new Text2('Start over with all your upgrades, or reset for a fresh new run! Your choice!', { size: 50, fill: 0xffffff }); noteText.anchor.set(0.5, 0); noteText.x = GAME_WIDTH / 2; noteText.y = damageText.y + 500; game.addChild(noteText); var endGameButton = new Container(); var buttonGraphics = endGameButton.attachAsset('endGameButton', { anchorX: 0.5, anchorY: 0.5, tint: 0x00ffff }); var buttonText = new Text2('RESTART!', { size: 50, fill: 0x000000, fontWeight: 'bold' }); buttonText.anchor.set(0.5, 0.5); endGameButton.addChild(buttonText); endGameButton.x = GAME_WIDTH / 2; endGameButton.y = noteText.y + 300; endGameButton.interactive = true; endGameButton.down = function () { storage.level = 1; LK.showGameOver(); }; game.addChild(endGameButton); var resetButton = new ResetButton(); resetButton.x = GAME_WIDTH / 2; resetButton.y = endGameButton.y + 260; game.addChild(resetButton); LK.clearInterval(playTimeInterval); playTimeInterval = null; } var GAME_WIDTH = 2048; var GAME_HEIGHT = 2720; var BALL_RADIUS = 50; var BRICK_WIDTH = 300; var BRICK_HEIGHT = 99; var LEVEL_COLORS = [0xff00ff, 0x00ffff, 0xffff00, 0xff0066, 0x00ff99, 0xff33cc, 0x66ff33, 0xcc00ff, 0x33ffcc, 0xff3300]; var levelConfig = { 1: { totalBricks: 28, hitpoints: 1, pattern: 'clustered' }, 2: { totalBricks: 63, hitpoints: 2, pattern: 'staggered' }, 3: { totalBricks: 63, hitpoints: 3, pattern: 'cross' }, 4: { totalBricks: 77, pattern: 'custom', customPattern: [[0, 3, 3, 0, 3, 3, 0], [3, 4, 4, 3, 4, 4, 3], [3, 4, 4, 4, 4, 4, 3], [3, 4, 4, 4, 4, 4, 3], [3, 4, 4, 4, 4, 4, 3], [3, 4, 4, 4, 4, 4, 3], [3, 4, 4, 4, 4, 4, 3], [0, 3, 4, 4, 4, 3, 0], [0, 0, 3, 4, 3, 0, 0], [0, 0, 0, 3, 0, 0, 0], [0, 0, 0, 3, 0, 0, 0]] }, 5: { totalBricks: 112, pattern: 'custom', customPattern: [[0, 0, 0, 3, 0, 0, 0], [0, 0, 3, 4, 3, 0, 0], [0, 3, 4, 5, 4, 3, 0], [3, 4, 5, 6, 5, 4, 3], [4, 5, 6, 7, 6, 5, 4], [3, 5, 6, 7, 6, 5, 3], [0, 4, 5, 6, 5, 4, 0], [0, 3, 4, 5, 4, 3, 0], [0, 0, 3, 4, 3, 0, 0], [0, 0, 2, 3, 2, 0, 0], [0, 0, 1, 2, 1, 0, 0], [0, 0, 0, 1, 0, 0, 0], [0, 0, 1, 2, 1, 0, 0], [0, 0, 1, 2, 1, 0, 0]] }, 6: { totalBricks: 60, hitpoints: 10, pattern: 'cross' }, 7: { totalBricks: 70, hitpoints: 13, pattern: 'clustered' }, 8: { totalBricks: 112, hitpoints: 15, pattern: 'clustered' }, 9: { totalBricks: 112, hitpoints: 20, pattern: 'cross' }, 10: { totalBricks: 112, hitpoints: 30, pattern: 'clustered' }, 11: { totalBricks: 112, hitpoints: 50, pattern: 'clustered' }, 12: { totalBricks: 112, hitpoints: 99, pattern: 'clustered' }, 13: { totalBricks: 140, pattern: 'custom', customPattern: [[222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [0, 222, 222, 222, 222, 222, 0], [0, 0, 222, 222, 222, 0, 0]] }, 14: { totalBricks: 140, pattern: 'custom', customPattern: [[0, 0, 333, 333, 333, 333, 333, 0, 0], [0, 0, 333, 0, 0, 0, 333, 0, 0], [0, 0, 333, 0, 0, 0, 333, 0, 0], [0, 0, 333, 0, 0, 0, 333, 0, 0], [333, 333, 333, 333, 333, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0]] }, 15: { totalBricks: 140, pattern: 'custom', customPattern: [[0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0]] }, 16: { totalBricks: 140, pattern: 'custom', customPattern: [[0, 333, 333, 333, 333, 333, 0, 0], [0, 333, 0, 0, 0, 333, 0, 0], [0, 333, 0, 0, 0, 333, 0, 0], [0, 333, 0, 0, 0, 333, 0, 0], [0, 333, 333, 333, 333, 333, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0]] } }; var upgrades = storage.upgrades || { normalSpeed: 1, normalPower: 1, splashSpeed: 1, splashPower: 2, sniperSpeed: 1, sniperPower: 1, scatterSpeed: 1, scatterPower: 1, clickDamage: 1, normalSpeedCost: 25, normalPowerCost: 50, splashSpeedCost: 75, splashPowerCost: 75, sniperSpeedCost: 100, sniperPowerCost: 100, scatterSpeedCost: 125, scatterPowerCost: 125, clickCost: 25, normalBallCost: 25, splashBallCost: 150, sniperBallCost: 500, scatterBallCost: 2000 }; var balls = []; var ballQuantities = storage.ballQuantities || { normal: 0, splash: 0, sniper: 0, scatter: 0 }; var bricks = []; var score = storage.score || 0; var level = storage.level || 1; var brickGridBounds = null; var unlockedTiers = storage.unlockedTiers || { normal: true, splash: false, sniper: false, scatter: false }; var playTime = storage.playTime || 0; var playTimeInterval = LK.setInterval(function () { if (!game.isGameOver) { playTime += 1; storage.playTime = playTime; console.log('Time Played2:', playTime, 'seconds'); } }, 1000); game.isGameOver = false; function clearLocalStorage() { storage.score = 0; storage.level = 1; storage.unlockedTiers = { normal: true, splash: false, sniper: false, scatter: false }; unlockedTiers = Object.assign({}, storage.unlockedTiers); storage.upgrades = { normalSpeed: 1, normalPower: 1, splashSpeed: 1, splashPower: 2, sniperSpeed: 1, sniperPower: 1, scatterSpeed: 1, scatterPower: 1, clickDamage: 1, normalSpeedCost: 50, normalPowerCost: 50, splashSpeedCost: 75, splashPowerCost: 75, sniperSpeedCost: 100, sniperPowerCost: 100, scatterSpeedCost: 125, scatterPowerCost: 125, clickCost: 25, normalBallCost: 25, splashBallCost: 150, sniperBallCost: 500, scatterBallCost: 2000 }; score = 0; storage.ballQuantities = { normal: 0, splash: 0, sniper: 0, scatter: 0 }; storage.firstLoad = false; ballQuantities = Object.assign({}, storage.ballQuantities); level = 1; unlockedTiers = Object.assign({}, storage.unlockedTiers); scoreTxt.setText('$' + score.toString()); levelTxt.setText('Level: ' + level); updateButtonStates(); } var hud = new Container(); LK.gui.top.addChild(hud); var scoreTxt = new Text2('$0', { size: 60, fill: 0x39ff14 }); scoreTxt.anchor.set(0.3, 0); scoreTxt.x += 570; hud.addChild(scoreTxt); var levelTxt = new Text2('Level: ' + level, { size: 50, fill: 0xffffff }); levelTxt.anchor.set(1, 0); levelTxt.x = scoreTxt.x + 100; levelTxt.y = scoreTxt.height + 10; hud.addChild(levelTxt); var ballButtons = {}; function createBallButton(type, x, cost, asset, prevTier) { var button = new Container(); var buttonGraphics = button.attachAsset('button', { anchorX: 0.5, anchorY: 0, tint: 0x1a1a2e }); button.y = 50; button.x = x + 20; var contentContainer = new Container(); button.addChild(contentContainer); var ballIcon = button.attachAsset('ball', { anchorX: 0.5, anchorY: -0.5, scaleX: 0.6, scaleY: 0.6, y: -10 }); ballIcon.tint = type === 'splash' ? 0xff0066 : type === 'sniper' ? 0x00ff99 : type === 'scatter' ? 0xffff00 : 0xffffff; contentContainer.addChild(ballIcon); var displayType = type === 'scatter' ? 'Multi' : type.charAt(0).toUpperCase() + type.slice(1); var typeText = new Text2(displayType, { size: 30, fill: 0xffffff, fontWeight: 'bold' }); typeText.anchor.set(0.5, 0); typeText.y = -50; button.addChild(typeText); var costText = new Text2('$' + upgrades[type + 'BallCost'], { size: 40, fill: 0xffffff }); costText.anchor.set(0.5, 0); costText.y = 100; button.addChild(costText); button.interactive = true; button.down = function () { if (score < upgrades[type + 'BallCost']) { return; } if (welcomeText && welcomeText.parent) { welcomeText.parent.removeChild(welcomeText); } score -= upgrades[type + 'BallCost']; scoreTxt.setText('$' + score.toString()); createBall(type); ballQuantities[type] = (ballQuantities[type] || 0) + 1; storage.ballQuantities = Object.assign({}, ballQuantities); upgrades[type + 'BallCost'] = Math.floor(upgrades[type + 'BallCost'] * 2); storage.upgrades = Object.assign({}, upgrades); costText.setText('$' + upgrades[type + 'BallCost']); if (!unlockedTiers[type]) { unlockedTiers[type] = true; storage.unlockedTiers = Object.assign({}, unlockedTiers); updateButtonStates(); } }; button.updateState = function () { var isEnabled = (prevTier ? unlockedTiers[prevTier] : true) && score >= upgrades[type + 'BallCost']; buttonGraphics.tint = isEnabled ? 0x00ffff : 0x666666; button.interactive = isEnabled; if (isEnabled) { ballIcon.tint = type === 'splash' ? 0xff0066 : type === 'sniper' ? 0x00ff99 : type === 'scatter' ? 0xffff00 : 0xffffff; typeText.fill = 0xffffff; costText.fill = 0x00ffff; } else { ballIcon.tint = 0x666666; typeText.fill = 0x666666; costText.fill = 0x666666; } }; hud.addChild(button); ballButtons[type] = button; } createBallButton('normal', -450, 25, 'ball', null); createBallButton('splash', -300, upgrades.splashBallCost, 'splashBall', 'normal'); createBallButton('sniper', -150, upgrades.sniperBallCost, 'sniperBall', 'splash'); createBallButton('scatter', 0, upgrades.scatterBallCost, 'scatterBall', 'sniper'); var clearStorageButton = LK.getAsset('button', { size: 0, fill: 0x1a1a2e, anchorX: 0.5, anchorY: 0, x: scoreTxt.width + 12000, y: 0 }); var clearStorageText = new Text2('', { size: 0, fill: 0xffffff }); clearStorageText.anchor.set(0.5, 0); clearStorageText.y = 100; clearStorageButton.addChild(clearStorageText); clearStorageButton.down = clearLocalStorage; hud.addChild(clearStorageButton); var powerupContainer = new Container(); powerupContainer.y = 1800; powerupContainer.visible = false; game.addChild(powerupContainer); var bottomHud = new Container(); bottomHud.y = GAME_HEIGHT - 200; game.addChild(bottomHud); // Should be bottomHud var upgradeButtons = {}; function createUpgradeButton(labelPrefix, x, costKey, upgradeKey, baseCost, iconType, prevTier) { var button = new Container(); var buttonGraphics = button.attachAsset('powerupbutton', { anchorX: 0.5, anchorY: 0, tint: 0x1a1a2e }); button.x = x + 60; button.y = 350; button.addChild(buttonGraphics); var contentContainer = new Container(); button.addChild(contentContainer); var icon = null; if (iconType) { icon = button.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, y: 40, tint: iconType === 'splashBall' ? 0xff0066 : iconType === 'sniperBall' ? 0x00ff99 : iconType === 'scatterBall' ? 0xffff00 : iconType === 'ball' ? 0xffffff : 0x00ffff }); contentContainer.addChild(icon); } var labelText = new Text2("".concat(labelPrefix.replace('Speed', 'SPD').replace('Power', 'DMG'), " +").concat(upgrades[upgradeKey]), { size: upgradeKey === 'clickDamage' ? 40 : 40, fill: 0x000000, fontWeight: 'bold' }); labelText.anchor.set(0.5, 0); labelText.y = 80; contentContainer.addChild(labelText); var currentCost = baseCost * Math.pow(2, upgrades[upgradeKey] - 1); var costText = new Text2("$".concat(currentCost), { size: 40, fill: 0x000000 }); costText.anchor.set(0.5, 0); costText.y = 140; contentContainer.addChild(costText); button.interactive = true; button.down = function () { if (welcomeText && welcomeText.parent) { welcomeText.parent.removeChild(welcomeText); } var cost = baseCost * Math.pow(2, upgrades[upgradeKey] - 1); var ballType = upgradeKey.split('Speed')[0].split('Power')[0]; if (upgradeKey === 'clickDamage') { if (score < cost) { return; } } else { if (!unlockedTiers[ballType] || score < cost) { return; } } score -= cost; LK.getSound('click').play(); upgrades[upgradeKey]++; storage.upgrades = Object.assign({}, upgrades); var newCost = baseCost * Math.pow(2, upgrades[upgradeKey] - 1); costText.setText("$".concat(newCost)); labelText.setText("".concat(labelPrefix, " +").concat(upgrades[upgradeKey])); scoreTxt.setText('$' + score.toString()); balls.forEach(function (b) { if (b.type === 'normal' && upgradeKey.includes('normal')) { b[upgradeKey.includes('Speed') ? 'speed' : 'power'] = upgrades[upgradeKey]; } else if (b.type === 'splash' && upgradeKey.includes('splash')) { b[upgradeKey.includes('Speed') ? 'speed' : 'power'] = upgrades[upgradeKey]; } else if (b.type === 'sniper' && upgradeKey.includes('sniper')) { b[upgradeKey.includes('Speed') ? 'speed' : 'power'] = upgrades[upgradeKey]; } else if ((b.type === 'scatter' || b.type === 'smallScatter') && upgradeKey.includes('scatter')) { b[upgradeKey.includes('Speed') ? 'speed' : 'power'] = upgrades[upgradeKey]; } }); if (upgradeKey === 'clickDamage') { upgrades.clickDamage = upgrades[upgradeKey], storage.upgrades = Object.assign({}, upgrades); } updateButtonStates(); }; button.updateState = function () { var ballType = upgradeKey.split('Speed')[0].split('Power')[0]; var currentCost = baseCost * Math.pow(2, upgrades[upgradeKey] - 1); var isEnabled = upgradeKey === 'clickDamage' ? score >= currentCost : unlockedTiers[ballType] && (prevTier ? unlockedTiers[prevTier] : true) && score >= currentCost; buttonGraphics.tint = isEnabled ? 0x00ffff : 0x666666; button.interactive = isEnabled; if (icon) { icon.tint = isEnabled ? iconType === 'splashBall' ? 0xff0066 : iconType === 'sniperBall' ? 0x00ff99 : iconType === 'scatterBall' ? 0xffff00 : iconType === 'ball' ? 0xffffff : 0x00ffff : 0x666666; } labelText.fill = isEnabled ? 0x000000 : 0x666666; costText.fill = isEnabled ? 0x000000 : 0x666666; costText.setText("$".concat(currentCost)); }; powerupContainer.addChild(button); upgradeButtons[upgradeKey] = button; } var buttonWidth = 150; var spacing = 70; var totalButtons = 9; var totalWidth = totalButtons * buttonWidth + (totalButtons - 1) * spacing; var startX = (GAME_WIDTH - totalWidth) / 2; createUpgradeButton('Speed', startX, 'normalSpeedCost', 'normalSpeed', 25, 'ball', null); createUpgradeButton('Power', startX + (buttonWidth + spacing), 'normalPowerCost', 'normalPower', 50, 'ball', null); createUpgradeButton('Speed', startX + 2 * (buttonWidth + spacing), 'splashSpeedCost', 'splashSpeed', 75, 'splashBall', 'normal'); createUpgradeButton('Power', startX + 3 * (buttonWidth + spacing), 'splashPowerCost', 'splashPower', 75, 'splashBall', 'normal'); createUpgradeButton('Speed', startX + 4 * (buttonWidth + spacing), 'sniperSpeedCost', 'sniperSpeed', 100, 'sniperBall', 'splash'); createUpgradeButton('Power', startX + 5 * (buttonWidth + spacing), 'sniperPowerCost', 'sniperPower', 100, 'sniperBall', 'splash'); createUpgradeButton('Speed', startX + 6 * (buttonWidth + spacing), 'scatterSpeedCost', 'scatterSpeed', 125, 'scatterBall', 'sniper'); createUpgradeButton('Power', startX + 7 * (buttonWidth + spacing), 'scatterPowerCost', 'scatterPower', 125, 'scatterBall', 'sniper'); createUpgradeButton('Click', startX + 8 * (buttonWidth + spacing), 'clickCost', 'clickDamage', 25, null, null); var upgradeButton = new UpgradeButton(); upgradeButton.x = GAME_WIDTH / 2; upgradeButton.y = GAME_HEIGHT - 100; upgradeButton.visible = false; game.addChild(upgradeButton); game.setChildIndex(upgradeButton, game.children.length - 1); hud.visible = false; function updateButtonStates() { for (var type in ballButtons) { ballButtons[type].updateState(); } var canPurchaseAny = false; for (var key in upgradeButtons) { upgradeButtons[key].updateState(); if (upgradeButtons[key].interactive) { canPurchaseAny = true; } } upgradeButton.tint = canPurchaseAny ? 0x00ffff : 0x666666; upgradeButton.interactive = canPurchaseAny; } function applySplashDamage(brick) { var splashDamage = Math.floor(upgrades.splashPower / 2); var horizontalMaxDistance = BRICK_WIDTH + 15; var verticalMaxDistance = BRICK_HEIGHT + 15; bricks.forEach(function (adjBrick) { if (adjBrick === brick || adjBrick.health <= 0) { return; } var dx = Math.abs(adjBrick.x - brick.x); var dy = Math.abs(adjBrick.y - brick.y); var isHorizontalAdjacent = dx <= horizontalMaxDistance && dy <= BRICK_HEIGHT / 2; var isVerticalAdjacent = dy <= verticalMaxDistance && dx <= BRICK_WIDTH / 2; if (isHorizontalAdjacent || isVerticalAdjacent) { adjBrick.hit(splashDamage); ballDamage['splash'] = (ballDamage['splash'] || 0) + splashDamage; } }); } function scatterOnImpact(ball) { var numBalls = 4; for (var i = 0; i < numBalls; i++) { var smallBall = new Ball('smallScatter'); smallBall.x = ball.x; smallBall.y = ball.y; var angle = Math.random() * 2 * Math.PI; var speedVariation = 0.8 + Math.random() * 0.4; smallBall.speed = upgrades.scatterSpeed * 0.8 * speedVariation; smallBall.velocity.x = Math.cos(angle); smallBall.velocity.y = Math.sin(angle); var magnitude = Math.sqrt(smallBall.velocity.x * smallBall.velocity.x + smallBall.velocity.y * smallBall.velocity.y); smallBall.velocity.x /= magnitude; smallBall.velocity.y /= magnitude; balls.push(smallBall); game.addChild(smallBall); // Track the initial creation damage from scatter splitting ballDamage['scatter'] = (ballDamage['scatter'] || 0) + ball.power; } } function findNearestBrick(x, y) { if (bricks.length === 0) { return null; } return bricks.reduce(function (closest, brick) { var dx = brick.x - x; var dy = brick.y - y; var distance = Math.sqrt(dx * dx + dy * dy); return !closest || distance < closest.distance ? { brick: brick, distance: distance } : closest; }, null).brick; } function createBricks() { var config = levelConfig[level] || {}; var totalBricks = config.totalBricks || 50; var baseHitpoints = config.hitpoints || 1; var pattern = config.pattern || 'grid'; var spacingX = -15; var spacingY = 0; bricks = []; var cols = 7; var rows = Math.ceil(totalBricks / cols); var totalWidth = cols * BRICK_WIDTH + (cols - 1) * spacingX; var totalHeight = rows * BRICK_HEIGHT + (rows - 1) * spacingY; var startX = (GAME_WIDTH - totalWidth) / 2 + BRICK_WIDTH / 2; var startY = (GAME_HEIGHT - totalHeight) / 2 + BRICK_HEIGHT / 2; var brickCount = 0; console.log("Creating bricks for level ".concat(level, ", pattern: ").concat(pattern, ", totalBricks: ").concat(totalBricks)); if (pattern === 'grid') { for (var i = 0; i < rows && brickCount < totalBricks; i++) { for (var j = 0; j < cols && brickCount < totalBricks; j++) { addBrick(startX + j * (BRICK_WIDTH + spacingX), startY + i * (BRICK_HEIGHT + spacingY), baseHitpoints); brickCount++; } } } else if (pattern === 'staggered') { var centerRow = Math.floor(rows / 2); var centerCol = Math.floor(cols / 2); for (var i = 0; i < rows && brickCount < totalBricks; i++) { var offsetX = 0; for (var j = 0; j < cols && brickCount < totalBricks; j++) { var x = startX + offsetX + j * (BRICK_WIDTH + spacingX); var y = startY + i * (BRICK_HEIGHT + spacingY); var rowDistance = Math.abs(i - centerRow); var colDistance = Math.abs(j - centerCol); var maxDistance = Math.max(centerRow, centerCol); var distance = Math.max(rowDistance, colDistance); var hitpoints = Math.max(1, Math.round(baseHitpoints * (1 - distance / maxDistance))); addBrick(x, y, hitpoints); brickCount++; } } } else if (pattern === 'clustered') { var centerRow = Math.floor(rows / 2); var centerCol = Math.floor(cols / 2); var maxDistance = Math.max(centerRow, centerCol); var positions = []; for (var i = 0; i < rows; i++) { for (var j = 0; j < cols; j++) { var rowDistance = Math.abs(i - centerRow); var colDistance = Math.abs(j - centerCol); var distance = Math.max(rowDistance, colDistance); positions.push({ i: i, j: j, distance: distance }); } } positions.sort(function (a, b) { return b.distance - a.distance; }); for (var k = 0; k < positions.length && brickCount < totalBricks; k++) { var pos = positions[k]; var i = pos.i; var j = pos.j; var distance = pos.distance; var x = startX + j * (BRICK_WIDTH + spacingX); var y = startY + i * (BRICK_HEIGHT + spacingY); var hitpoints = Math.max(1, Math.round(baseHitpoints * (distance / maxDistance))); addBrick(x, y, hitpoints); brickCount++; } } else if (pattern === 'cross') { var centerRow = Math.floor(rows / 2); var centerCol = Math.floor(cols / 2); for (var i = 0; i < rows && brickCount < totalBricks; i++) { for (var colOffset = -2; colOffset <= 2 && brickCount < totalBricks; colOffset++) { var col = centerCol + colOffset; if (col >= 0 && col < cols) { var x = startX + col * (BRICK_WIDTH + spacingX); var y = startY + i * (BRICK_HEIGHT + spacingY); var distanceFromCenter = Math.max(Math.abs(i - centerRow), Math.abs(colOffset)); var hitpoints = Math.max(1, baseHitpoints - distanceFromCenter); addBrick(x, y, hitpoints); brickCount++; } } } for (var j = 0; j < cols && brickCount < totalBricks; j++) { if (Math.abs(j - centerCol) > 2) { for (var rowOffset = -2; rowOffset <= 2 && brickCount < totalBricks; rowOffset++) { var row = centerRow + rowOffset; if (row >= 0 && row < rows) { var x = startX + j * (BRICK_WIDTH + spacingX); var y = startY + row * (BRICK_HEIGHT + spacingY); var distanceFromCenter = Math.max(Math.abs(j - centerCol), Math.abs(rowOffset)); var hitpoints = Math.max(1, baseHitpoints - distanceFromCenter); addBrick(x, y, hitpoints); brickCount++; } } } } for (var j = 0; j < cols && brickCount < totalBricks; j++) { if (Math.abs(j - centerCol) > 3) { for (var rowOffset = -1; rowOffset <= 1 && brickCount < totalBricks; rowOffset++) { var row = centerRow + rowOffset; if (row >= 0 && row < rows) { var x = startX + j * (BRICK_WIDTH + spacingX); var y = startY + row * (BRICK_HEIGHT + spacingY); var distanceFromCenter = Math.max(Math.abs(j - centerCol), Math.abs(rowOffset)); var hitpoints = Math.max(1, baseHitpoints - distanceFromCenter); addBrick(x, y, hitpoints); brickCount++; } } } } } else if (pattern === 'custom') { var customPattern = config.customPattern || []; var patternRows = customPattern.length; var patternCols = patternRows > 0 ? customPattern[0].length : 0; console.log("Custom pattern dimensions: ".concat(patternRows, "x").concat(patternCols, ", grid: ").concat(rows, "x").concat(cols)); rows = Math.max(rows, patternRows); totalHeight = rows * BRICK_HEIGHT + (rows - 1) * spacingY; startY = (GAME_HEIGHT - totalHeight) / 2 + BRICK_HEIGHT / 2; if (patternRows > 0 && patternCols <= cols) { var offsetX = Math.floor((cols - patternCols) / 2); var offsetY = Math.floor((rows - patternRows) / 2); for (var i = 0; i < patternRows && brickCount < totalBricks; i++) { for (var j = 0; j < patternCols && brickCount < totalBricks; j++) { var hitpoints = customPattern[i][j]; if (hitpoints > 0) { var x = startX + (j + offsetX) * (BRICK_WIDTH + spacingX); var y = startY + (i + offsetY) * (BRICK_HEIGHT + spacingY); addBrick(x, y, hitpoints); brickCount++; console.log("Added brick at (".concat(x, ", ").concat(y, ") with hitpoints: ").concat(hitpoints)); } } } } else { console.error("Custom pattern (".concat(patternRows, "x").concat(patternCols, ") invalid or exceeds grid (").concat(rows, "x").concat(cols, ")")); } } console.log("Total bricks created: ".concat(brickCount, ", bricks array length: ").concat(bricks.length)); brickGridBounds = { minX: Math.min.apply(Math, _toConsumableArray2(bricks.map(function (b) { return b.x - BRICK_WIDTH / 2; }))), maxX: Math.max.apply(Math, _toConsumableArray2(bricks.map(function (b) { return b.x + BRICK_WIDTH / 2; }))), minY: Math.min.apply(Math, _toConsumableArray2(bricks.map(function (b) { return b.y - BRICK_HEIGHT / 2; }))), maxY: Math.max.apply(Math, _toConsumableArray2(bricks.map(function (b) { return b.y + BRICK_HEIGHT / 2; }))) }; } function addBrick(x, y, hitpoints) { var brick = new Brick(); brick.x = x; brick.y = y; brick.health = hitpoints; brick.maxHealth = hitpoints; brick.healthText.setText(brick.health.toString()); brick.updateTint(); bricks.push(brick); game.addChild(brick); } function repositionBall(ball, index) { var spawnFromTop = index % 2 === 0; var safeX = GAME_WIDTH / 2 + (Math.random() * 200 - 100); var safeY = spawnFromTop ? BALL_RADIUS + 50 : GAME_HEIGHT - BALL_RADIUS - 50; var attempts = 0; var maxAttempts = 10; while (attempts < maxAttempts && isOverlappingWithBricks(safeX, safeY)) { safeX = GAME_WIDTH / 2 + (Math.random() * 200 - 100); safeY = spawnFromTop ? BALL_RADIUS + 50 + attempts * 50 : GAME_HEIGHT - BALL_RADIUS - 50 - attempts * 50; attempts++; } ball.x = safeX; ball.y = safeY; var angle = (Math.random() * 0.5 + 0.25) * Math.PI; ball.velocity.x = Math.cos(angle); ball.velocity.y = spawnFromTop ? Math.sin(angle) : -Math.sin(angle); var magnitude = Math.sqrt(ball.velocity.x * ball.velocity.x + ball.velocity.y * ball.velocity.y); ball.velocity.x /= magnitude; ball.velocity.y /= magnitude; } function isOverlappingWithBricks(x, y) { var ballLeft = x - BALL_RADIUS; var ballRight = x + BALL_RADIUS; var ballTop = y - BALL_RADIUS; var ballBottom = y + BALL_RADIUS; for (var i = 0; i < bricks.length; i++) { var brick = bricks[i]; var brickLeft = brick.x - BRICK_WIDTH / 2; var brickRight = brick.x + BRICK_WIDTH / 2; var brickTop = brick.y - BRICK_HEIGHT / 2; var brickBottom = brick.y + BRICK_HEIGHT / 2; if (ballLeft < brickRight && ballRight > brickLeft && ballTop < brickBottom && ballBottom > brickTop) { return true; } } return false; } function createBall() { var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'normal'; var ball = new Ball(type); repositionBall(ball, balls.length); balls.push(ball); game.addChild(ball); } game.update = function () { for (var i = 0; i < stars.length; i++) { stars[i].update(); } for (var i = balls.length - 1; i >= 0; i--) { var ball = balls[i]; ball.update(); if (ball.y > GAME_HEIGHT + BALL_RADIUS) { ball.destroy(); balls.splice(i, 1); } } if (bricks.length === 0 && !game.isGameOver) { console.log("Level ".concat(level, " cleared, advancing to next level")); if (level === Object.keys(levelConfig).length) { showEndScreen(); } else { level += 1; storage.level = level; levelTxt.setText('Level: ' + level); createBricks(); balls.forEach(function (ball, index) { repositionBall(ball, index); }); } } updateButtonStates(); }; game.down = function (x, y, obj) { if (!bricks || !Array.isArray(bricks)) { return; } x = Number(x); y = Number(y); for (var i = 0; i < bricks.length; i++) { var brick = bricks[i]; if (!brick.x || !brick.y || !brick.width || !brick.height) { continue; } if (x >= brick.x - brick.width / 2 && x <= brick.x + brick.width / 2 && y >= brick.y - brick.height / 2 && y <= brick.y + brick.height / 2) { brick.hit(upgrades.clickDamage); powerupContainer.visible = false; LK.getSound('click').play(); scoreTxt.setText('$' + score.toString()); storage.score = score; return; } } }; var stars = []; for (var i = 0; i < 100; i++) { var star = new Star(); star.x = Math.random() * GAME_WIDTH; star.y = Math.random() * GAME_HEIGHT; stars.push(star); game.addChildAt(star, 0); } var gameTitleContainer = new Container(); game.addChild(gameTitleContainer); var gameTitle = new GameTitle(); gameTitle.x = GAME_WIDTH / 2; gameTitle.y = GAME_HEIGHT / 2 - 1100; gameTitleContainer.addChild(gameTitle); function animateTitleColor() { tween(gameTitle, { tint: 0xff33cc }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(gameTitle, { tint: 0x00ff99 }, { duration: 2000, easing: tween.easeInOut, onFinish: animateTitleColor }); } }); } animateTitleColor(); tween(gameTitle, { y: 500 }, { duration: 1000, easing: tween.bounceOut }); var startButton = new StartButton(); startButton.x = GAME_WIDTH / 2; startButton.y = GAME_HEIGHT / 2 + 400; startButton.tint = 0x00ff99; game.addChild(startButton); function animateStartButton() { tween(startButton, { y: 1500 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(startButton, { y: startButton.y + 50 }, { duration: 1000, easing: tween.easeInOut, onFinish: animateStartButton }); } }); } animateStartButton(); var resetButton = new ResetButton(); resetButton.x = GAME_WIDTH / 2; resetButton.y = GAME_HEIGHT + 200; // Start from below the screen game.addChild(resetButton); tween(resetButton, { y: startButton.y + 800 // Tween to the desired position }, { duration: 1000, easing: tween.bounceOut, onFinish: function onFinish() { tween(resetButton, { y: resetButton.y + 20 }, { duration: 1000, easing: tween.easeInOut }); } }); LK.playMusic('backgroundmusic'); function startTransitionSequence() { tween(gameTitle, { y: -500, alpha: 0 }, { duration: 800, easing: tween.easeIn }); tween(resetButton, { y: GAME_HEIGHT + 200, alpha: 0 }, { duration: 800, easing: tween.easeIn, onFinish: function onFinish() { LK.setTimeout(function () { startGameLogic(); }, 500); } }); } function startGameLogic() { startButton.destroy(); gameTitle.destroy(); resetButton.visible = false; upgradeButton.visible = true; hud.visible = true; createBricks(); console.log("Initial bricks after startGame: " + bricks.length); createBall('normal'); if (score > 0) { scoreTxt.setText('$' + score.toString()); } // Add this line to reset damage tracking and set start time lastRunStartTime = Date.now(); for (var type in ballDamage) { ballDamage[type] = 0; } if (storage.firstLoad !== true) { welcomeText = new Text2(' Smash bricks, earn cash,\nbuy balls, and power up to auto-win!', { size: 90, fill: 0xffffff }); welcomeText.anchor.set(0.5, 0.5); welcomeText.x = GAME_WIDTH / 2; welcomeText.y = GAME_HEIGHT / 2 + 600; game.addChild(welcomeText); storage.firstLoad = true; } playTimeInterval = LK.setInterval(function () { playTime += 1; console.log('Time Played:', playTime, 'seconds'); }, 1000); for (var type in ballQuantities) { for (var i = 0; i < ballQuantities[type]; i++) { createBall(type); } } updateButtonStates(); game.update = function () { for (var i = 0; i < stars.length; i++) { stars[i].update(); } for (var i = balls.length - 1; i >= 0; i--) { var ball = balls[i]; ball.update(); if (ball.y > GAME_HEIGHT + BALL_RADIUS) { ball.destroy(); balls.splice(i, 1); } } if (bricks.length === 0 && !game.isGameOver) { console.log("Level ".concat(level, " cleared in active game loop")); if (level === Object.keys(levelConfig).length) { showEndScreen(); } else { level += 1; storage.level = level; levelTxt.setText('Level: ' + level); createBricks(); balls.forEach(function (ball, index) { repositionBall(ball, index); }); } } updateButtonStates(); }; } function startGame() {} game.update = function () { for (var i = 0; i < stars.length; i++) { stars[i].update(); } };
/****
* Plugins
****/
var storage = LK.import("@upit/storage.v1");
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'normal';
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
ballGraphics.tint = type === 'splash' ? 0xff0066 : type === 'sniper' ? 0x00ff99 : type === 'scatter' ? 0xffff00 : type === 'smallScatter' ? 0xffff00 : 0xffffff;
if (type === 'smallScatter') {
ballGraphics.scaleX = 0.5;
ballGraphics.scaleY = 0.5;
}
self.type = type;
self.speed = type === 'splash' ? upgrades.splashSpeed : type === 'sniper' ? upgrades.sniperSpeed : type === 'scatter' ? upgrades.scatterSpeed : type === 'smallScatter' ? upgrades.scatterSpeed * 1.5 : upgrades.normalSpeed;
self.power = type === 'splash' ? upgrades.splashPower : type === 'sniper' ? upgrades.sniperPower : type === 'scatter' ? upgrades.scatterPower : type === 'smallScatter' ? Math.max(1, Math.floor(upgrades.scatterPower * 0.8)) : upgrades.normalPower;
self.velocity = {
x: 1,
y: -1
};
self.sniperCooldown = 0;
self.sniperCooldownMax = 60;
self.interactive = true;
self.down = function (x, y, obj) {
var angle = Math.random() * 2 * Math.PI;
self.velocity.x = Math.cos(angle);
self.velocity.y = Math.sin(angle);
var magnitude = Math.sqrt(self.velocity.x * self.velocity.x + self.velocity.y * self.velocity.y);
self.velocity.x /= magnitude;
self.velocity.y /= magnitude;
};
self.update = function () {
var SHIELD_BUFFER = 5;
var MAX_STEP = BALL_RADIUS / 2;
var totalDistance = self.speed;
var steps = Math.ceil(totalDistance / MAX_STEP);
var stepDistance = totalDistance / steps;
var splashApplied = false;
if (self.type === 'sniper') {
self.sniperCooldown--;
if (self.sniperCooldown <= 0) {
var nearestBrick = findNearestBrick(self.x, self.y);
if (nearestBrick) {
var dx = nearestBrick.x - self.x;
var dy = nearestBrick.y - self.y;
var magnitude = Math.sqrt(dx * dx + dy * dy);
self.velocity.x = dx / magnitude;
self.velocity.y = dy / magnitude;
self.sniperCooldown = self.sniperCooldownMax;
}
}
}
for (var step = 0; step < steps; step++) {
var dx = self.velocity.x * stepDistance;
var dy = self.velocity.y * stepDistance;
var nextX = self.x + dx;
var nextY = self.y + dy;
if (nextX < BALL_RADIUS + SHIELD_BUFFER) {
nextX = BALL_RADIUS + SHIELD_BUFFER;
self.velocity.x = -self.velocity.x;
self.velocity.y += (Math.random() - 0.5) * 0.1;
LK.getSound('bounce').play();
} else if (nextX > GAME_WIDTH - BALL_RADIUS - SHIELD_BUFFER) {
nextX = GAME_WIDTH - BALL_RADIUS - SHIELD_BUFFER;
self.velocity.x = -self.velocity.x;
self.velocity.y += (Math.random() - 0.5) * 0.1;
LK.getSound('bounce').play();
}
if (nextY < BALL_RADIUS + SHIELD_BUFFER) {
nextY = BALL_RADIUS + SHIELD_BUFFER;
self.velocity.y = -self.velocity.y;
self.velocity.x += (Math.random() - 0.5) * 0.1;
LK.getSound('bounce').play();
} else if (nextY > GAME_HEIGHT - BALL_RADIUS - SHIELD_BUFFER) {
nextY = GAME_HEIGHT - BALL_RADIUS - SHIELD_BUFFER;
self.velocity.y = -self.velocity.y;
self.velocity.x += (Math.random() - 0.5) * 0.1;
LK.getSound('bounce').play();
}
var ballLeft = nextX - BALL_RADIUS - SHIELD_BUFFER;
var ballRight = nextX + BALL_RADIUS + SHIELD_BUFFER;
var ballTop = nextY - BALL_RADIUS - SHIELD_BUFFER;
var ballBottom = nextY + BALL_RADIUS + SHIELD_BUFFER;
var collided = false;
for (var i = bricks.length - 1; i >= 0; i--) {
var brick = bricks[i];
if (brick.health <= 0) {
continue;
}
var brickLeft = brick.x - BRICK_WIDTH / 2;
var brickRight = brick.x + BRICK_WIDTH / 2;
var brickTop = brick.y - BRICK_HEIGHT / 2;
var brickBottom = brick.y + BRICK_HEIGHT / 2;
if (ballLeft < brickRight && ballRight > brickLeft && ballTop < brickBottom && ballBottom > brickTop) {
var overlapLeft = ballRight - brickLeft;
var overlapRight = brickRight - ballLeft;
var overlapTop = ballBottom - brickTop;
var overlapBottom = brickBottom - ballTop;
var minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom);
if (minOverlap === overlapLeft) {
nextX = brickLeft - BALL_RADIUS - SHIELD_BUFFER;
self.velocity.x = -self.velocity.x;
} else if (minOverlap === overlapRight) {
nextX = brickRight + BALL_RADIUS + SHIELD_BUFFER;
self.velocity.x = -self.velocity.x;
} else if (minOverlap === overlapTop) {
nextY = brickTop - BALL_RADIUS - SHIELD_BUFFER;
self.velocity.y = -self.velocity.y;
} else {
nextY = brickBottom + BALL_RADIUS + SHIELD_BUFFER;
self.velocity.y = -self.velocity.y;
}
self.velocity.x += (Math.random() - 0.5) * 0.2;
self.velocity.y += (Math.random() - 0.5) * 0.2;
LK.getSound('bounce').play();
brick.hit(self.power);
ballDamage[self.type] = (ballDamage[self.type] || 0) + self.power;
if (self.type === 'splash' && !splashApplied) {
applySplashDamage(brick);
splashApplied = true;
} else if (self.type === 'scatter') {
scatterOnImpact(self);
self.destroy();
balls.splice(balls.indexOf(self), 1);
return;
}
collided = true;
break;
}
}
self.x = nextX;
self.y = nextY;
if (collided) {
break;
}
}
var magnitude = Math.sqrt(self.velocity.x * self.velocity.x + self.velocity.y * self.velocity.y);
if (magnitude > 0) {
self.velocity.x /= magnitude;
self.velocity.y /= magnitude;
}
};
});
var Brick = Container.expand(function () {
var self = Container.call(this);
var brickGraphics = self.attachAsset('brick', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.maxHealth = 1;
self.healthText = new Text2(self.health.toString(), {
size: 50,
fill: 0x000000,
fontWeight: 'bold'
});
self.healthText.anchor.set(0.5, 0.5);
self.addChild(self.healthText);
self.updateTint = function () {
var baseColors = LEVEL_COLORS;
var colorCount = baseColors.length;
if (self.health <= colorCount) {
brickGraphics.tint = baseColors[self.health - 1];
} else {
var lastDigit = self.health % 10;
var colorIndex = lastDigit === 0 ? 9 : lastDigit - 1;
brickGraphics.tint = baseColors[colorIndex];
}
};
self.updateTint();
self.hit = function () {
var damage = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
self.health -= damage;
if (self.health <= 0) {
LK.getSound('explosion').play();
score += self.maxHealth === 1 ? 1 : self.maxHealth;
scoreTxt.setText('$' + score.toString());
storage.score = score;
var brickIndex = bricks.indexOf(self);
if (brickIndex !== -1) {
bricks.splice(brickIndex, 1);
}
var explosionColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];
var randomColor = explosionColors[Math.floor(Math.random() * explosionColors.length)];
var randomScale = Math.random() * 1.5 + 1.5;
var randomDuration = Math.random() * 300 + 400;
tween(self, {
tint: randomColor,
scaleX: randomScale,
scaleY: randomScale,
alpha: 0
}, {
duration: randomDuration,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
} else {
self.healthText.setText(self.health.toString());
self.updateTint();
}
};
});
var GameTitle = Container.expand(function () {
var self = Container.call(this);
var titleGraphics = self.attachAsset('gametitle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.35,
scaleY: 1.5
});
var titleText = new Text2('Idle BrickBreaker', {
size: 200,
fill: 0x000000
});
titleText.anchor.set(0.5, 0.5);
self.addChild(titleText);
});
var ResetButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('resetButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff6666
});
var buttonText = new Text2('RESET', {
size: 50,
fill: 0x000000,
fontWeight: 'bold'
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.interactive = true;
self.down = function () {
LK.getSound('click').play();
clearLocalStorage();
playTime = 0;
storage.playTime = playTime;
LK.showGameOver();
};
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Math.random() * 2 + 1;
self.update = function () {
self.y += self.speed;
if (self.y > GAME_HEIGHT) {
self.y = 0;
self.x = Math.random() * GAME_WIDTH;
}
};
});
var StartButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
var buttonText = new Text2('START', {
size: 100,
fill: 0x000000,
fontWeight: 'bold'
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.interactive = true;
self.down = function () {
LK.getSound('click').play();
self.interactive = false;
var explosionColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];
var randomColor = explosionColors[Math.floor(Math.random() * explosionColors.length)];
LK.getSound('explosion').play();
tween(self, {
tint: randomColor,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
startTransitionSequence();
}
});
};
});
var UpgradeButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('upgrade', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x00ffff
});
var buttonText = new Text2('UPGRADES', {
size: 50,
fill: 0x000000,
fontWeight: 'bold'
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.interactive = true;
self.down = function () {
LK.getSound('click').play();
powerupContainer.visible = !powerupContainer.visible;
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
var lastRunStartTime = 0;
var lastRunTime = 0;
var ballDamage = {
normal: 0,
splash: 0,
sniper: 0,
scatter: 0,
smallScatter: 0
};
function _toConsumableArray2(r) {
return _arrayWithoutHoles2(r) || _iterableToArray2(r) || _unsupportedIterableToArray2(r) || _nonIterableSpread2();
}
function _nonIterableSpread2() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _unsupportedIterableToArray2(r, a) {
if (r) {
if ("string" == typeof r) {
return _arrayLikeToArray2(r, a);
}
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray2(r, a) : void 0;
}
}
function _iterableToArray2(r) {
if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) {
return Array.from(r);
}
}
function _arrayWithoutHoles2(r) {
if (Array.isArray(r)) {
return _arrayLikeToArray2(r);
}
}
function _arrayLikeToArray2(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) {
n[e] = r[e];
}
return n;
}
function _toConsumableArray(r) {
return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) {
return _arrayLikeToArray(r, a);
}
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
}
}
function _iterableToArray(r) {
if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) {
return Array.from(r);
}
}
function _arrayWithoutHoles(r) {
if (Array.isArray(r)) {
return _arrayLikeToArray(r);
}
}
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) {
n[e] = r[e];
}
return n;
}
function tintEndScreenTitle() {
gameTitleContainer.children.forEach(function (child) {
child.tint = 0xff33cc;
});
}
var frameThickness = 10;
var topFrame = new Container();
var topFrameGraphics = topFrame.attachAsset('frame', {
anchorX: 0,
anchorY: 0,
width: GAME_WIDTH,
height: frameThickness
});
topFrame.x = 0;
topFrame.y = 0;
game.addChild(topFrame);
function animateTopFrameTint() {
tween(topFrameGraphics, {
tint: 0xff33cc
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(topFrameGraphics, {
tint: 0x00ff99
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: animateTopFrameTint
});
}
});
}
animateTopFrameTint();
var bottomFrame = new Container();
var bottomFrameGraphics = bottomFrame.attachAsset('frame', {
anchorX: 0,
anchorY: 0,
width: GAME_WIDTH,
height: frameThickness
});
bottomFrame.x = 0;
bottomFrame.y = 2720;
game.addChild(bottomFrame); // Should be bottomFrame
function animateBottomFrameTint() {
tween(bottomFrameGraphics, {
tint: 0xff33cc
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(bottomFrameGraphics, {
tint: 0x00ff99
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: animateBottomFrameTint
});
}
});
}
animateBottomFrameTint();
var leftFrame = new Container();
var leftFrameGraphics = leftFrame.attachAsset('frame', {
anchorX: 0,
anchorY: 0,
width: frameThickness,
height: GAME_HEIGHT
});
leftFrame.x = 0;
leftFrame.y = 0;
game.addChild(leftFrame);
function animateLeftFrameTint() {
tween(leftFrameGraphics, {
tint: 0xff33cc
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(leftFrameGraphics, {
tint: 0x00ff99
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: animateLeftFrameTint
});
}
});
}
animateLeftFrameTint();
var rightFrame = new Container();
var rightFrameGraphics = rightFrame.attachAsset('frame', {
anchorX: 0,
anchorY: 0,
width: frameThickness,
height: GAME_HEIGHT
});
rightFrame.x = 2040;
rightFrame.y = 0;
game.addChild(rightFrame);
function animateRightFrameTint() {
tween(rightFrameGraphics, {
tint: 0xff33cc
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(rightFrameGraphics, {
tint: 0x00ff99
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: animateRightFrameTint
});
}
});
}
animateRightFrameTint();
var welcomeText = null;
function showEndScreen() {
game.isGameOver = true;
hud.visible = false;
powerupContainer.visible = false;
upgradeButton.visible = false;
balls.forEach(function (ball) {
return ball.visible = true;
});
bricks.forEach(function (brick) {
return brick.visible = false;
});
// Calculate last run time
lastRunTime = Math.floor((Date.now() - lastRunStartTime) / 1000);
var congratsText = new Text2('Congratulations! You broke them ALL!', {
size: 100,
fill: 0xffffff
});
congratsText.anchor.set(0.5, 0);
congratsText.x = GAME_WIDTH / 2;
congratsText.y = GAME_HEIGHT / 2 - 600; // Moved up slightly
game.addChild(congratsText);
// Move game title up
var gameTitle = new GameTitle();
gameTitle.x = GAME_WIDTH / 2;
gameTitle.y = congratsText.y - 400; // Moved down by 200 pixels
gameTitleContainer.addChild(gameTitle);
function animateEndTitleColor() {
tintEndScreenTitle();
tween(gameTitle, {
tint: 0xff33cc
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(gameTitle, {
tint: 0x00ff99
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: animateEndTitleColor
});
}
});
}
animateEndTitleColor();
var playTimeText = new Text2('Total Time Played: ' + playTime + ' seconds', {
size: 60,
fill: 0xffffff
});
playTimeText.anchor.set(0.5, 0);
playTimeText.x = GAME_WIDTH / 2;
playTimeText.y = congratsText.y + 200;
game.addChild(playTimeText);
var lastRunText = new Text2('Last Run Time: ' + lastRunTime + ' seconds', {
size: 60,
fill: 0xffffff
});
lastRunText.anchor.set(0.5, 0);
lastRunText.x = GAME_WIDTH / 2;
lastRunText.y = playTimeText.y + 200;
game.addChild(lastRunText);
// Add damage stats
var damageText = new Text2('Damage Dealt This Run:\n' + 'Normal: ' + ballDamage.normal + '\n' + 'Splash: ' + ballDamage.splash + '\n' + 'Sniper: ' + ballDamage.sniper + '\n' + 'Scatter: ' + ballDamage.scatter + '\n' + 'Small Scatter: ' + ballDamage.smallScatter, {
size: 50,
fill: 0xffffff,
align: 'center'
});
damageText.anchor.set(0.5, 0);
damageText.x = GAME_WIDTH / 2;
damageText.y = lastRunText.y + 120;
game.addChild(damageText);
var noteText = new Text2('Start over with all your upgrades, or reset for a fresh new run! Your choice!', {
size: 50,
fill: 0xffffff
});
noteText.anchor.set(0.5, 0);
noteText.x = GAME_WIDTH / 2;
noteText.y = damageText.y + 500;
game.addChild(noteText);
var endGameButton = new Container();
var buttonGraphics = endGameButton.attachAsset('endGameButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x00ffff
});
var buttonText = new Text2('RESTART!', {
size: 50,
fill: 0x000000,
fontWeight: 'bold'
});
buttonText.anchor.set(0.5, 0.5);
endGameButton.addChild(buttonText);
endGameButton.x = GAME_WIDTH / 2;
endGameButton.y = noteText.y + 300;
endGameButton.interactive = true;
endGameButton.down = function () {
storage.level = 1;
LK.showGameOver();
};
game.addChild(endGameButton);
var resetButton = new ResetButton();
resetButton.x = GAME_WIDTH / 2;
resetButton.y = endGameButton.y + 260;
game.addChild(resetButton);
LK.clearInterval(playTimeInterval);
playTimeInterval = null;
}
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2720;
var BALL_RADIUS = 50;
var BRICK_WIDTH = 300;
var BRICK_HEIGHT = 99;
var LEVEL_COLORS = [0xff00ff, 0x00ffff, 0xffff00, 0xff0066, 0x00ff99, 0xff33cc, 0x66ff33, 0xcc00ff, 0x33ffcc, 0xff3300];
var levelConfig = {
1: {
totalBricks: 28,
hitpoints: 1,
pattern: 'clustered'
},
2: {
totalBricks: 63,
hitpoints: 2,
pattern: 'staggered'
},
3: {
totalBricks: 63,
hitpoints: 3,
pattern: 'cross'
},
4: {
totalBricks: 77,
pattern: 'custom',
customPattern: [[0, 3, 3, 0, 3, 3, 0], [3, 4, 4, 3, 4, 4, 3], [3, 4, 4, 4, 4, 4, 3], [3, 4, 4, 4, 4, 4, 3], [3, 4, 4, 4, 4, 4, 3], [3, 4, 4, 4, 4, 4, 3], [3, 4, 4, 4, 4, 4, 3], [0, 3, 4, 4, 4, 3, 0], [0, 0, 3, 4, 3, 0, 0], [0, 0, 0, 3, 0, 0, 0], [0, 0, 0, 3, 0, 0, 0]]
},
5: {
totalBricks: 112,
pattern: 'custom',
customPattern: [[0, 0, 0, 3, 0, 0, 0], [0, 0, 3, 4, 3, 0, 0], [0, 3, 4, 5, 4, 3, 0], [3, 4, 5, 6, 5, 4, 3], [4, 5, 6, 7, 6, 5, 4], [3, 5, 6, 7, 6, 5, 3], [0, 4, 5, 6, 5, 4, 0], [0, 3, 4, 5, 4, 3, 0], [0, 0, 3, 4, 3, 0, 0], [0, 0, 2, 3, 2, 0, 0], [0, 0, 1, 2, 1, 0, 0], [0, 0, 0, 1, 0, 0, 0], [0, 0, 1, 2, 1, 0, 0], [0, 0, 1, 2, 1, 0, 0]]
},
6: {
totalBricks: 60,
hitpoints: 10,
pattern: 'cross'
},
7: {
totalBricks: 70,
hitpoints: 13,
pattern: 'clustered'
},
8: {
totalBricks: 112,
hitpoints: 15,
pattern: 'clustered'
},
9: {
totalBricks: 112,
hitpoints: 20,
pattern: 'cross'
},
10: {
totalBricks: 112,
hitpoints: 30,
pattern: 'clustered'
},
11: {
totalBricks: 112,
hitpoints: 50,
pattern: 'clustered'
},
12: {
totalBricks: 112,
hitpoints: 99,
pattern: 'clustered'
},
13: {
totalBricks: 140,
pattern: 'custom',
customPattern: [[222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [222, 222, 0, 0, 0, 222, 222], [0, 222, 222, 222, 222, 222, 0], [0, 0, 222, 222, 222, 0, 0]]
},
14: {
totalBricks: 140,
pattern: 'custom',
customPattern: [[0, 0, 333, 333, 333, 333, 333, 0, 0], [0, 0, 333, 0, 0, 0, 333, 0, 0], [0, 0, 333, 0, 0, 0, 333, 0, 0], [0, 0, 333, 0, 0, 0, 333, 0, 0], [333, 333, 333, 333, 333, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0], [0, 0, 333, 333, 0, 0, 0, 0, 0]]
},
15: {
totalBricks: 140,
pattern: 'custom',
customPattern: [[0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0], [0, 444, 444, 444, 0]]
},
16: {
totalBricks: 140,
pattern: 'custom',
customPattern: [[0, 333, 333, 333, 333, 333, 0, 0], [0, 333, 0, 0, 0, 333, 0, 0], [0, 333, 0, 0, 0, 333, 0, 0], [0, 333, 0, 0, 0, 333, 0, 0], [0, 333, 333, 333, 333, 333, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0], [0, 333, 333, 0, 0, 0, 0, 0]]
}
};
var upgrades = storage.upgrades || {
normalSpeed: 1,
normalPower: 1,
splashSpeed: 1,
splashPower: 2,
sniperSpeed: 1,
sniperPower: 1,
scatterSpeed: 1,
scatterPower: 1,
clickDamage: 1,
normalSpeedCost: 25,
normalPowerCost: 50,
splashSpeedCost: 75,
splashPowerCost: 75,
sniperSpeedCost: 100,
sniperPowerCost: 100,
scatterSpeedCost: 125,
scatterPowerCost: 125,
clickCost: 25,
normalBallCost: 25,
splashBallCost: 150,
sniperBallCost: 500,
scatterBallCost: 2000
};
var balls = [];
var ballQuantities = storage.ballQuantities || {
normal: 0,
splash: 0,
sniper: 0,
scatter: 0
};
var bricks = [];
var score = storage.score || 0;
var level = storage.level || 1;
var brickGridBounds = null;
var unlockedTiers = storage.unlockedTiers || {
normal: true,
splash: false,
sniper: false,
scatter: false
};
var playTime = storage.playTime || 0;
var playTimeInterval = LK.setInterval(function () {
if (!game.isGameOver) {
playTime += 1;
storage.playTime = playTime;
console.log('Time Played2:', playTime, 'seconds');
}
}, 1000);
game.isGameOver = false;
function clearLocalStorage() {
storage.score = 0;
storage.level = 1;
storage.unlockedTiers = {
normal: true,
splash: false,
sniper: false,
scatter: false
};
unlockedTiers = Object.assign({}, storage.unlockedTiers);
storage.upgrades = {
normalSpeed: 1,
normalPower: 1,
splashSpeed: 1,
splashPower: 2,
sniperSpeed: 1,
sniperPower: 1,
scatterSpeed: 1,
scatterPower: 1,
clickDamage: 1,
normalSpeedCost: 50,
normalPowerCost: 50,
splashSpeedCost: 75,
splashPowerCost: 75,
sniperSpeedCost: 100,
sniperPowerCost: 100,
scatterSpeedCost: 125,
scatterPowerCost: 125,
clickCost: 25,
normalBallCost: 25,
splashBallCost: 150,
sniperBallCost: 500,
scatterBallCost: 2000
};
score = 0;
storage.ballQuantities = {
normal: 0,
splash: 0,
sniper: 0,
scatter: 0
};
storage.firstLoad = false;
ballQuantities = Object.assign({}, storage.ballQuantities);
level = 1;
unlockedTiers = Object.assign({}, storage.unlockedTiers);
scoreTxt.setText('$' + score.toString());
levelTxt.setText('Level: ' + level);
updateButtonStates();
}
var hud = new Container();
LK.gui.top.addChild(hud);
var scoreTxt = new Text2('$0', {
size: 60,
fill: 0x39ff14
});
scoreTxt.anchor.set(0.3, 0);
scoreTxt.x += 570;
hud.addChild(scoreTxt);
var levelTxt = new Text2('Level: ' + level, {
size: 50,
fill: 0xffffff
});
levelTxt.anchor.set(1, 0);
levelTxt.x = scoreTxt.x + 100;
levelTxt.y = scoreTxt.height + 10;
hud.addChild(levelTxt);
var ballButtons = {};
function createBallButton(type, x, cost, asset, prevTier) {
var button = new Container();
var buttonGraphics = button.attachAsset('button', {
anchorX: 0.5,
anchorY: 0,
tint: 0x1a1a2e
});
button.y = 50;
button.x = x + 20;
var contentContainer = new Container();
button.addChild(contentContainer);
var ballIcon = button.attachAsset('ball', {
anchorX: 0.5,
anchorY: -0.5,
scaleX: 0.6,
scaleY: 0.6,
y: -10
});
ballIcon.tint = type === 'splash' ? 0xff0066 : type === 'sniper' ? 0x00ff99 : type === 'scatter' ? 0xffff00 : 0xffffff;
contentContainer.addChild(ballIcon);
var displayType = type === 'scatter' ? 'Multi' : type.charAt(0).toUpperCase() + type.slice(1);
var typeText = new Text2(displayType, {
size: 30,
fill: 0xffffff,
fontWeight: 'bold'
});
typeText.anchor.set(0.5, 0);
typeText.y = -50;
button.addChild(typeText);
var costText = new Text2('$' + upgrades[type + 'BallCost'], {
size: 40,
fill: 0xffffff
});
costText.anchor.set(0.5, 0);
costText.y = 100;
button.addChild(costText);
button.interactive = true;
button.down = function () {
if (score < upgrades[type + 'BallCost']) {
return;
}
if (welcomeText && welcomeText.parent) {
welcomeText.parent.removeChild(welcomeText);
}
score -= upgrades[type + 'BallCost'];
scoreTxt.setText('$' + score.toString());
createBall(type);
ballQuantities[type] = (ballQuantities[type] || 0) + 1;
storage.ballQuantities = Object.assign({}, ballQuantities);
upgrades[type + 'BallCost'] = Math.floor(upgrades[type + 'BallCost'] * 2);
storage.upgrades = Object.assign({}, upgrades);
costText.setText('$' + upgrades[type + 'BallCost']);
if (!unlockedTiers[type]) {
unlockedTiers[type] = true;
storage.unlockedTiers = Object.assign({}, unlockedTiers);
updateButtonStates();
}
};
button.updateState = function () {
var isEnabled = (prevTier ? unlockedTiers[prevTier] : true) && score >= upgrades[type + 'BallCost'];
buttonGraphics.tint = isEnabled ? 0x00ffff : 0x666666;
button.interactive = isEnabled;
if (isEnabled) {
ballIcon.tint = type === 'splash' ? 0xff0066 : type === 'sniper' ? 0x00ff99 : type === 'scatter' ? 0xffff00 : 0xffffff;
typeText.fill = 0xffffff;
costText.fill = 0x00ffff;
} else {
ballIcon.tint = 0x666666;
typeText.fill = 0x666666;
costText.fill = 0x666666;
}
};
hud.addChild(button);
ballButtons[type] = button;
}
createBallButton('normal', -450, 25, 'ball', null);
createBallButton('splash', -300, upgrades.splashBallCost, 'splashBall', 'normal');
createBallButton('sniper', -150, upgrades.sniperBallCost, 'sniperBall', 'splash');
createBallButton('scatter', 0, upgrades.scatterBallCost, 'scatterBall', 'sniper');
var clearStorageButton = LK.getAsset('button', {
size: 0,
fill: 0x1a1a2e,
anchorX: 0.5,
anchorY: 0,
x: scoreTxt.width + 12000,
y: 0
});
var clearStorageText = new Text2('', {
size: 0,
fill: 0xffffff
});
clearStorageText.anchor.set(0.5, 0);
clearStorageText.y = 100;
clearStorageButton.addChild(clearStorageText);
clearStorageButton.down = clearLocalStorage;
hud.addChild(clearStorageButton);
var powerupContainer = new Container();
powerupContainer.y = 1800;
powerupContainer.visible = false;
game.addChild(powerupContainer);
var bottomHud = new Container();
bottomHud.y = GAME_HEIGHT - 200;
game.addChild(bottomHud); // Should be bottomHud
var upgradeButtons = {};
function createUpgradeButton(labelPrefix, x, costKey, upgradeKey, baseCost, iconType, prevTier) {
var button = new Container();
var buttonGraphics = button.attachAsset('powerupbutton', {
anchorX: 0.5,
anchorY: 0,
tint: 0x1a1a2e
});
button.x = x + 60;
button.y = 350;
button.addChild(buttonGraphics);
var contentContainer = new Container();
button.addChild(contentContainer);
var icon = null;
if (iconType) {
icon = button.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
y: 40,
tint: iconType === 'splashBall' ? 0xff0066 : iconType === 'sniperBall' ? 0x00ff99 : iconType === 'scatterBall' ? 0xffff00 : iconType === 'ball' ? 0xffffff : 0x00ffff
});
contentContainer.addChild(icon);
}
var labelText = new Text2("".concat(labelPrefix.replace('Speed', 'SPD').replace('Power', 'DMG'), " +").concat(upgrades[upgradeKey]), {
size: upgradeKey === 'clickDamage' ? 40 : 40,
fill: 0x000000,
fontWeight: 'bold'
});
labelText.anchor.set(0.5, 0);
labelText.y = 80;
contentContainer.addChild(labelText);
var currentCost = baseCost * Math.pow(2, upgrades[upgradeKey] - 1);
var costText = new Text2("$".concat(currentCost), {
size: 40,
fill: 0x000000
});
costText.anchor.set(0.5, 0);
costText.y = 140;
contentContainer.addChild(costText);
button.interactive = true;
button.down = function () {
if (welcomeText && welcomeText.parent) {
welcomeText.parent.removeChild(welcomeText);
}
var cost = baseCost * Math.pow(2, upgrades[upgradeKey] - 1);
var ballType = upgradeKey.split('Speed')[0].split('Power')[0];
if (upgradeKey === 'clickDamage') {
if (score < cost) {
return;
}
} else {
if (!unlockedTiers[ballType] || score < cost) {
return;
}
}
score -= cost;
LK.getSound('click').play();
upgrades[upgradeKey]++;
storage.upgrades = Object.assign({}, upgrades);
var newCost = baseCost * Math.pow(2, upgrades[upgradeKey] - 1);
costText.setText("$".concat(newCost));
labelText.setText("".concat(labelPrefix, " +").concat(upgrades[upgradeKey]));
scoreTxt.setText('$' + score.toString());
balls.forEach(function (b) {
if (b.type === 'normal' && upgradeKey.includes('normal')) {
b[upgradeKey.includes('Speed') ? 'speed' : 'power'] = upgrades[upgradeKey];
} else if (b.type === 'splash' && upgradeKey.includes('splash')) {
b[upgradeKey.includes('Speed') ? 'speed' : 'power'] = upgrades[upgradeKey];
} else if (b.type === 'sniper' && upgradeKey.includes('sniper')) {
b[upgradeKey.includes('Speed') ? 'speed' : 'power'] = upgrades[upgradeKey];
} else if ((b.type === 'scatter' || b.type === 'smallScatter') && upgradeKey.includes('scatter')) {
b[upgradeKey.includes('Speed') ? 'speed' : 'power'] = upgrades[upgradeKey];
}
});
if (upgradeKey === 'clickDamage') {
upgrades.clickDamage = upgrades[upgradeKey], storage.upgrades = Object.assign({}, upgrades);
}
updateButtonStates();
};
button.updateState = function () {
var ballType = upgradeKey.split('Speed')[0].split('Power')[0];
var currentCost = baseCost * Math.pow(2, upgrades[upgradeKey] - 1);
var isEnabled = upgradeKey === 'clickDamage' ? score >= currentCost : unlockedTiers[ballType] && (prevTier ? unlockedTiers[prevTier] : true) && score >= currentCost;
buttonGraphics.tint = isEnabled ? 0x00ffff : 0x666666;
button.interactive = isEnabled;
if (icon) {
icon.tint = isEnabled ? iconType === 'splashBall' ? 0xff0066 : iconType === 'sniperBall' ? 0x00ff99 : iconType === 'scatterBall' ? 0xffff00 : iconType === 'ball' ? 0xffffff : 0x00ffff : 0x666666;
}
labelText.fill = isEnabled ? 0x000000 : 0x666666;
costText.fill = isEnabled ? 0x000000 : 0x666666;
costText.setText("$".concat(currentCost));
};
powerupContainer.addChild(button);
upgradeButtons[upgradeKey] = button;
}
var buttonWidth = 150;
var spacing = 70;
var totalButtons = 9;
var totalWidth = totalButtons * buttonWidth + (totalButtons - 1) * spacing;
var startX = (GAME_WIDTH - totalWidth) / 2;
createUpgradeButton('Speed', startX, 'normalSpeedCost', 'normalSpeed', 25, 'ball', null);
createUpgradeButton('Power', startX + (buttonWidth + spacing), 'normalPowerCost', 'normalPower', 50, 'ball', null);
createUpgradeButton('Speed', startX + 2 * (buttonWidth + spacing), 'splashSpeedCost', 'splashSpeed', 75, 'splashBall', 'normal');
createUpgradeButton('Power', startX + 3 * (buttonWidth + spacing), 'splashPowerCost', 'splashPower', 75, 'splashBall', 'normal');
createUpgradeButton('Speed', startX + 4 * (buttonWidth + spacing), 'sniperSpeedCost', 'sniperSpeed', 100, 'sniperBall', 'splash');
createUpgradeButton('Power', startX + 5 * (buttonWidth + spacing), 'sniperPowerCost', 'sniperPower', 100, 'sniperBall', 'splash');
createUpgradeButton('Speed', startX + 6 * (buttonWidth + spacing), 'scatterSpeedCost', 'scatterSpeed', 125, 'scatterBall', 'sniper');
createUpgradeButton('Power', startX + 7 * (buttonWidth + spacing), 'scatterPowerCost', 'scatterPower', 125, 'scatterBall', 'sniper');
createUpgradeButton('Click', startX + 8 * (buttonWidth + spacing), 'clickCost', 'clickDamage', 25, null, null);
var upgradeButton = new UpgradeButton();
upgradeButton.x = GAME_WIDTH / 2;
upgradeButton.y = GAME_HEIGHT - 100;
upgradeButton.visible = false;
game.addChild(upgradeButton);
game.setChildIndex(upgradeButton, game.children.length - 1);
hud.visible = false;
function updateButtonStates() {
for (var type in ballButtons) {
ballButtons[type].updateState();
}
var canPurchaseAny = false;
for (var key in upgradeButtons) {
upgradeButtons[key].updateState();
if (upgradeButtons[key].interactive) {
canPurchaseAny = true;
}
}
upgradeButton.tint = canPurchaseAny ? 0x00ffff : 0x666666;
upgradeButton.interactive = canPurchaseAny;
}
function applySplashDamage(brick) {
var splashDamage = Math.floor(upgrades.splashPower / 2);
var horizontalMaxDistance = BRICK_WIDTH + 15;
var verticalMaxDistance = BRICK_HEIGHT + 15;
bricks.forEach(function (adjBrick) {
if (adjBrick === brick || adjBrick.health <= 0) {
return;
}
var dx = Math.abs(adjBrick.x - brick.x);
var dy = Math.abs(adjBrick.y - brick.y);
var isHorizontalAdjacent = dx <= horizontalMaxDistance && dy <= BRICK_HEIGHT / 2;
var isVerticalAdjacent = dy <= verticalMaxDistance && dx <= BRICK_WIDTH / 2;
if (isHorizontalAdjacent || isVerticalAdjacent) {
adjBrick.hit(splashDamage);
ballDamage['splash'] = (ballDamage['splash'] || 0) + splashDamage;
}
});
}
function scatterOnImpact(ball) {
var numBalls = 4;
for (var i = 0; i < numBalls; i++) {
var smallBall = new Ball('smallScatter');
smallBall.x = ball.x;
smallBall.y = ball.y;
var angle = Math.random() * 2 * Math.PI;
var speedVariation = 0.8 + Math.random() * 0.4;
smallBall.speed = upgrades.scatterSpeed * 0.8 * speedVariation;
smallBall.velocity.x = Math.cos(angle);
smallBall.velocity.y = Math.sin(angle);
var magnitude = Math.sqrt(smallBall.velocity.x * smallBall.velocity.x + smallBall.velocity.y * smallBall.velocity.y);
smallBall.velocity.x /= magnitude;
smallBall.velocity.y /= magnitude;
balls.push(smallBall);
game.addChild(smallBall);
// Track the initial creation damage from scatter splitting
ballDamage['scatter'] = (ballDamage['scatter'] || 0) + ball.power;
}
}
function findNearestBrick(x, y) {
if (bricks.length === 0) {
return null;
}
return bricks.reduce(function (closest, brick) {
var dx = brick.x - x;
var dy = brick.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
return !closest || distance < closest.distance ? {
brick: brick,
distance: distance
} : closest;
}, null).brick;
}
function createBricks() {
var config = levelConfig[level] || {};
var totalBricks = config.totalBricks || 50;
var baseHitpoints = config.hitpoints || 1;
var pattern = config.pattern || 'grid';
var spacingX = -15;
var spacingY = 0;
bricks = [];
var cols = 7;
var rows = Math.ceil(totalBricks / cols);
var totalWidth = cols * BRICK_WIDTH + (cols - 1) * spacingX;
var totalHeight = rows * BRICK_HEIGHT + (rows - 1) * spacingY;
var startX = (GAME_WIDTH - totalWidth) / 2 + BRICK_WIDTH / 2;
var startY = (GAME_HEIGHT - totalHeight) / 2 + BRICK_HEIGHT / 2;
var brickCount = 0;
console.log("Creating bricks for level ".concat(level, ", pattern: ").concat(pattern, ", totalBricks: ").concat(totalBricks));
if (pattern === 'grid') {
for (var i = 0; i < rows && brickCount < totalBricks; i++) {
for (var j = 0; j < cols && brickCount < totalBricks; j++) {
addBrick(startX + j * (BRICK_WIDTH + spacingX), startY + i * (BRICK_HEIGHT + spacingY), baseHitpoints);
brickCount++;
}
}
} else if (pattern === 'staggered') {
var centerRow = Math.floor(rows / 2);
var centerCol = Math.floor(cols / 2);
for (var i = 0; i < rows && brickCount < totalBricks; i++) {
var offsetX = 0;
for (var j = 0; j < cols && brickCount < totalBricks; j++) {
var x = startX + offsetX + j * (BRICK_WIDTH + spacingX);
var y = startY + i * (BRICK_HEIGHT + spacingY);
var rowDistance = Math.abs(i - centerRow);
var colDistance = Math.abs(j - centerCol);
var maxDistance = Math.max(centerRow, centerCol);
var distance = Math.max(rowDistance, colDistance);
var hitpoints = Math.max(1, Math.round(baseHitpoints * (1 - distance / maxDistance)));
addBrick(x, y, hitpoints);
brickCount++;
}
}
} else if (pattern === 'clustered') {
var centerRow = Math.floor(rows / 2);
var centerCol = Math.floor(cols / 2);
var maxDistance = Math.max(centerRow, centerCol);
var positions = [];
for (var i = 0; i < rows; i++) {
for (var j = 0; j < cols; j++) {
var rowDistance = Math.abs(i - centerRow);
var colDistance = Math.abs(j - centerCol);
var distance = Math.max(rowDistance, colDistance);
positions.push({
i: i,
j: j,
distance: distance
});
}
}
positions.sort(function (a, b) {
return b.distance - a.distance;
});
for (var k = 0; k < positions.length && brickCount < totalBricks; k++) {
var pos = positions[k];
var i = pos.i;
var j = pos.j;
var distance = pos.distance;
var x = startX + j * (BRICK_WIDTH + spacingX);
var y = startY + i * (BRICK_HEIGHT + spacingY);
var hitpoints = Math.max(1, Math.round(baseHitpoints * (distance / maxDistance)));
addBrick(x, y, hitpoints);
brickCount++;
}
} else if (pattern === 'cross') {
var centerRow = Math.floor(rows / 2);
var centerCol = Math.floor(cols / 2);
for (var i = 0; i < rows && brickCount < totalBricks; i++) {
for (var colOffset = -2; colOffset <= 2 && brickCount < totalBricks; colOffset++) {
var col = centerCol + colOffset;
if (col >= 0 && col < cols) {
var x = startX + col * (BRICK_WIDTH + spacingX);
var y = startY + i * (BRICK_HEIGHT + spacingY);
var distanceFromCenter = Math.max(Math.abs(i - centerRow), Math.abs(colOffset));
var hitpoints = Math.max(1, baseHitpoints - distanceFromCenter);
addBrick(x, y, hitpoints);
brickCount++;
}
}
}
for (var j = 0; j < cols && brickCount < totalBricks; j++) {
if (Math.abs(j - centerCol) > 2) {
for (var rowOffset = -2; rowOffset <= 2 && brickCount < totalBricks; rowOffset++) {
var row = centerRow + rowOffset;
if (row >= 0 && row < rows) {
var x = startX + j * (BRICK_WIDTH + spacingX);
var y = startY + row * (BRICK_HEIGHT + spacingY);
var distanceFromCenter = Math.max(Math.abs(j - centerCol), Math.abs(rowOffset));
var hitpoints = Math.max(1, baseHitpoints - distanceFromCenter);
addBrick(x, y, hitpoints);
brickCount++;
}
}
}
}
for (var j = 0; j < cols && brickCount < totalBricks; j++) {
if (Math.abs(j - centerCol) > 3) {
for (var rowOffset = -1; rowOffset <= 1 && brickCount < totalBricks; rowOffset++) {
var row = centerRow + rowOffset;
if (row >= 0 && row < rows) {
var x = startX + j * (BRICK_WIDTH + spacingX);
var y = startY + row * (BRICK_HEIGHT + spacingY);
var distanceFromCenter = Math.max(Math.abs(j - centerCol), Math.abs(rowOffset));
var hitpoints = Math.max(1, baseHitpoints - distanceFromCenter);
addBrick(x, y, hitpoints);
brickCount++;
}
}
}
}
} else if (pattern === 'custom') {
var customPattern = config.customPattern || [];
var patternRows = customPattern.length;
var patternCols = patternRows > 0 ? customPattern[0].length : 0;
console.log("Custom pattern dimensions: ".concat(patternRows, "x").concat(patternCols, ", grid: ").concat(rows, "x").concat(cols));
rows = Math.max(rows, patternRows);
totalHeight = rows * BRICK_HEIGHT + (rows - 1) * spacingY;
startY = (GAME_HEIGHT - totalHeight) / 2 + BRICK_HEIGHT / 2;
if (patternRows > 0 && patternCols <= cols) {
var offsetX = Math.floor((cols - patternCols) / 2);
var offsetY = Math.floor((rows - patternRows) / 2);
for (var i = 0; i < patternRows && brickCount < totalBricks; i++) {
for (var j = 0; j < patternCols && brickCount < totalBricks; j++) {
var hitpoints = customPattern[i][j];
if (hitpoints > 0) {
var x = startX + (j + offsetX) * (BRICK_WIDTH + spacingX);
var y = startY + (i + offsetY) * (BRICK_HEIGHT + spacingY);
addBrick(x, y, hitpoints);
brickCount++;
console.log("Added brick at (".concat(x, ", ").concat(y, ") with hitpoints: ").concat(hitpoints));
}
}
}
} else {
console.error("Custom pattern (".concat(patternRows, "x").concat(patternCols, ") invalid or exceeds grid (").concat(rows, "x").concat(cols, ")"));
}
}
console.log("Total bricks created: ".concat(brickCount, ", bricks array length: ").concat(bricks.length));
brickGridBounds = {
minX: Math.min.apply(Math, _toConsumableArray2(bricks.map(function (b) {
return b.x - BRICK_WIDTH / 2;
}))),
maxX: Math.max.apply(Math, _toConsumableArray2(bricks.map(function (b) {
return b.x + BRICK_WIDTH / 2;
}))),
minY: Math.min.apply(Math, _toConsumableArray2(bricks.map(function (b) {
return b.y - BRICK_HEIGHT / 2;
}))),
maxY: Math.max.apply(Math, _toConsumableArray2(bricks.map(function (b) {
return b.y + BRICK_HEIGHT / 2;
})))
};
}
function addBrick(x, y, hitpoints) {
var brick = new Brick();
brick.x = x;
brick.y = y;
brick.health = hitpoints;
brick.maxHealth = hitpoints;
brick.healthText.setText(brick.health.toString());
brick.updateTint();
bricks.push(brick);
game.addChild(brick);
}
function repositionBall(ball, index) {
var spawnFromTop = index % 2 === 0;
var safeX = GAME_WIDTH / 2 + (Math.random() * 200 - 100);
var safeY = spawnFromTop ? BALL_RADIUS + 50 : GAME_HEIGHT - BALL_RADIUS - 50;
var attempts = 0;
var maxAttempts = 10;
while (attempts < maxAttempts && isOverlappingWithBricks(safeX, safeY)) {
safeX = GAME_WIDTH / 2 + (Math.random() * 200 - 100);
safeY = spawnFromTop ? BALL_RADIUS + 50 + attempts * 50 : GAME_HEIGHT - BALL_RADIUS - 50 - attempts * 50;
attempts++;
}
ball.x = safeX;
ball.y = safeY;
var angle = (Math.random() * 0.5 + 0.25) * Math.PI;
ball.velocity.x = Math.cos(angle);
ball.velocity.y = spawnFromTop ? Math.sin(angle) : -Math.sin(angle);
var magnitude = Math.sqrt(ball.velocity.x * ball.velocity.x + ball.velocity.y * ball.velocity.y);
ball.velocity.x /= magnitude;
ball.velocity.y /= magnitude;
}
function isOverlappingWithBricks(x, y) {
var ballLeft = x - BALL_RADIUS;
var ballRight = x + BALL_RADIUS;
var ballTop = y - BALL_RADIUS;
var ballBottom = y + BALL_RADIUS;
for (var i = 0; i < bricks.length; i++) {
var brick = bricks[i];
var brickLeft = brick.x - BRICK_WIDTH / 2;
var brickRight = brick.x + BRICK_WIDTH / 2;
var brickTop = brick.y - BRICK_HEIGHT / 2;
var brickBottom = brick.y + BRICK_HEIGHT / 2;
if (ballLeft < brickRight && ballRight > brickLeft && ballTop < brickBottom && ballBottom > brickTop) {
return true;
}
}
return false;
}
function createBall() {
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'normal';
var ball = new Ball(type);
repositionBall(ball, balls.length);
balls.push(ball);
game.addChild(ball);
}
game.update = function () {
for (var i = 0; i < stars.length; i++) {
stars[i].update();
}
for (var i = balls.length - 1; i >= 0; i--) {
var ball = balls[i];
ball.update();
if (ball.y > GAME_HEIGHT + BALL_RADIUS) {
ball.destroy();
balls.splice(i, 1);
}
}
if (bricks.length === 0 && !game.isGameOver) {
console.log("Level ".concat(level, " cleared, advancing to next level"));
if (level === Object.keys(levelConfig).length) {
showEndScreen();
} else {
level += 1;
storage.level = level;
levelTxt.setText('Level: ' + level);
createBricks();
balls.forEach(function (ball, index) {
repositionBall(ball, index);
});
}
}
updateButtonStates();
};
game.down = function (x, y, obj) {
if (!bricks || !Array.isArray(bricks)) {
return;
}
x = Number(x);
y = Number(y);
for (var i = 0; i < bricks.length; i++) {
var brick = bricks[i];
if (!brick.x || !brick.y || !brick.width || !brick.height) {
continue;
}
if (x >= brick.x - brick.width / 2 && x <= brick.x + brick.width / 2 && y >= brick.y - brick.height / 2 && y <= brick.y + brick.height / 2) {
brick.hit(upgrades.clickDamage);
powerupContainer.visible = false;
LK.getSound('click').play();
scoreTxt.setText('$' + score.toString());
storage.score = score;
return;
}
}
};
var stars = [];
for (var i = 0; i < 100; i++) {
var star = new Star();
star.x = Math.random() * GAME_WIDTH;
star.y = Math.random() * GAME_HEIGHT;
stars.push(star);
game.addChildAt(star, 0);
}
var gameTitleContainer = new Container();
game.addChild(gameTitleContainer);
var gameTitle = new GameTitle();
gameTitle.x = GAME_WIDTH / 2;
gameTitle.y = GAME_HEIGHT / 2 - 1100;
gameTitleContainer.addChild(gameTitle);
function animateTitleColor() {
tween(gameTitle, {
tint: 0xff33cc
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(gameTitle, {
tint: 0x00ff99
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: animateTitleColor
});
}
});
}
animateTitleColor();
tween(gameTitle, {
y: 500
}, {
duration: 1000,
easing: tween.bounceOut
});
var startButton = new StartButton();
startButton.x = GAME_WIDTH / 2;
startButton.y = GAME_HEIGHT / 2 + 400;
startButton.tint = 0x00ff99;
game.addChild(startButton);
function animateStartButton() {
tween(startButton, {
y: 1500
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startButton, {
y: startButton.y + 50
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: animateStartButton
});
}
});
}
animateStartButton();
var resetButton = new ResetButton();
resetButton.x = GAME_WIDTH / 2;
resetButton.y = GAME_HEIGHT + 200; // Start from below the screen
game.addChild(resetButton);
tween(resetButton, {
y: startButton.y + 800 // Tween to the desired position
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(resetButton, {
y: resetButton.y + 20
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
LK.playMusic('backgroundmusic');
function startTransitionSequence() {
tween(gameTitle, {
y: -500,
alpha: 0
}, {
duration: 800,
easing: tween.easeIn
});
tween(resetButton, {
y: GAME_HEIGHT + 200,
alpha: 0
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
LK.setTimeout(function () {
startGameLogic();
}, 500);
}
});
}
function startGameLogic() {
startButton.destroy();
gameTitle.destroy();
resetButton.visible = false;
upgradeButton.visible = true;
hud.visible = true;
createBricks();
console.log("Initial bricks after startGame: " + bricks.length);
createBall('normal');
if (score > 0) {
scoreTxt.setText('$' + score.toString());
}
// Add this line to reset damage tracking and set start time
lastRunStartTime = Date.now();
for (var type in ballDamage) {
ballDamage[type] = 0;
}
if (storage.firstLoad !== true) {
welcomeText = new Text2(' Smash bricks, earn cash,\nbuy balls, and power up to auto-win!', {
size: 90,
fill: 0xffffff
});
welcomeText.anchor.set(0.5, 0.5);
welcomeText.x = GAME_WIDTH / 2;
welcomeText.y = GAME_HEIGHT / 2 + 600;
game.addChild(welcomeText);
storage.firstLoad = true;
}
playTimeInterval = LK.setInterval(function () {
playTime += 1;
console.log('Time Played:', playTime, 'seconds');
}, 1000);
for (var type in ballQuantities) {
for (var i = 0; i < ballQuantities[type]; i++) {
createBall(type);
}
}
updateButtonStates();
game.update = function () {
for (var i = 0; i < stars.length; i++) {
stars[i].update();
}
for (var i = balls.length - 1; i >= 0; i--) {
var ball = balls[i];
ball.update();
if (ball.y > GAME_HEIGHT + BALL_RADIUS) {
ball.destroy();
balls.splice(i, 1);
}
}
if (bricks.length === 0 && !game.isGameOver) {
console.log("Level ".concat(level, " cleared in active game loop"));
if (level === Object.keys(levelConfig).length) {
showEndScreen();
} else {
level += 1;
storage.level = level;
levelTxt.setText('Level: ' + level);
createBricks();
balls.forEach(function (ball, index) {
repositionBall(ball, index);
});
}
}
updateButtonStates();
};
}
function startGame() {}
game.update = function () {
for (var i = 0; i < stars.length; i++) {
stars[i].update();
}
};