User prompt
rename game to Idle BrickBreaker
User prompt
game should start with 0 points unless player has points in local storage ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Level 1 bricks should only give 1 point whendestoryed
User prompt
save in storage also the ball that the player has bought. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
save upgrades purchased in local storage ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
on game start I always see 0 points until I click on a brick. It should already have loaded the points in local storage ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'setText')' in or related to this line: 'scoreTxt.setText('$' + score.toString());' Line Number: 379
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'hud.addChild(scoreTxt);' Line Number: 385
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'hud.addChild(scoreTxt);' Line Number: 385
Code edit (1 edits merged)
Please save this source code
User prompt
Why is ball not spawning after bought?
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'return {' Line Number: 342
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'update')' in or related to this line: 'ball.update();' Line Number: 978
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'update')' in or related to this line: 'ball.update();' Line Number: 981
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'return {' Line Number: 342
User prompt
can you sanve upgrades bought in local storage ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
clic upgrade is not being saves ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
make sure the upgrades objects are being initialized from stogare data ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
make sure balls are being initialized from storage data ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'balls.push(ball);' Line Number: 813
User prompt
make sure balls are stored in local storage ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'balls.push(ball);' Line Number: 813
User prompt
make sure reset button also reset upgrades storage data ↪💡 Consider importing and using the following plugins: @upit/storage.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 :
// Neon Pink
type === 'sniper' ? 0x00ff99 :
// Neon Mint
type === 'scatter' ? 0xffff00 :
// Neon Yellow
type === 'smallScatter' ? 0xffff00 :
// Neon Yellow
0x00ffff; // Neon Cyan
self.type = type;
self.speed = type === 'splash' ? upgrades.splashSpeed : type === 'sniper' ? upgrades.sniperSpeed : type === 'scatter' ? upgrades.scatterSpeed : type === 'smallScatter' ? upgrades.scatterSpeed * 0.8 : 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.5)) : upgrades.normalPower;
self.direction = {
x: 1,
y: -1
};
self.update = function () {
var gridSize = levelConfig[level] ? levelConfig[level].gridSize : 200;
var stepSize = self.speed;
if (self.type === 'sniper') {
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.direction.x = dx / magnitude;
self.direction.y = dy / magnitude;
}
}
var dx = self.direction.x * stepSize;
var dy = self.direction.y * stepSize;
self.x += dx;
self.y += dy;
if (self.x <= BALL_RADIUS || self.x >= GAME_WIDTH - BALL_RADIUS) {
self.direction.x *= -1;
self.x = Math.max(BALL_RADIUS, Math.min(GAME_WIDTH - BALL_RADIUS, self.x));
}
if (self.y <= BALL_RADIUS || self.y >= GAME_HEIGHT - BALL_RADIUS) {
self.direction.y *= -1;
self.y = Math.max(BALL_RADIUS, Math.min(GAME_HEIGHT - BALL_RADIUS, self.y));
}
if (!isNearBricks(self.x, self.y)) {
return;
}
var gridXMin = Math.floor((self.x - BALL_RADIUS) / gridSize);
var gridXMax = Math.floor((self.x + BALL_RADIUS) / gridSize);
var gridYMin = Math.floor((self.y - BALL_RADIUS) / gridSize);
var gridYMax = Math.floor((self.y + BALL_RADIUS) / gridSize);
var hasCollided = false;
for (var gx = gridXMin; gx <= gridXMax && !hasCollided; gx++) {
for (var gy = gridYMin; gy <= gridYMax && !hasCollided; gy++) {
var gridKey = "".concat(gx, ",").concat(gy);
var cellBricks = brickGrid[gridKey];
if (!cellBricks || cellBricks.length === 0) {
continue;
}
for (var j = cellBricks.length - 1; j >= 0; j--) {
var brick = cellBricks[j];
if (!brick || brick.health <= 0 || !self.intersects(brick)) {
continue;
}
handleBallBrickCollision(self, brick);
brick.hit(self.power);
if (self.type === 'splash' && brick.health > 0) {
applySplashDamage(brick, gridSize);
} else if (self.type === 'scatter') {
scatterOnImpact(self);
self.destroy();
balls.splice(balls.indexOf(self), 1);
hasCollided = true;
break;
}
if (brick.health <= 0) {
cellBricks.splice(j, 1);
}
hasCollided = true;
break;
}
}
}
};
});
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: 0xffffff // White for neon contrast
});
self.healthText.anchor.set(0.5, 0.5);
self.addChild(self.healthText);
self.updateTint = function () {
var healthPercent = self.health / self.maxHealth;
var colorIndex = Math.min(Math.floor((1 - healthPercent) * LEVEL_COLORS.length), LEVEL_COLORS.length - 1);
brickGraphics.tint = LEVEL_COLORS[colorIndex];
};
self.updateTint();
self.hit = function () {
var damage = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
self.health -= damage;
if (self.health <= 0) {
score += Math.max(1, Math.floor(self.maxHealth * 0.5));
scoreTxt.setText('$' + score.toString());
storage.score = score;
var brickIndex = bricks.indexOf(self);
if (brickIndex !== -1) {
bricks.splice(brickIndex, 1);
}
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
});
var titleText = new Text2('Idle BrickBreaker', {
size: 150,
// Increased font size from 100 to 150
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 // Soft red
});
var buttonText = new Text2('RESET', {
size: 50,
fill: 0x000000
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.interactive = true;
self.down = function () {
clearLocalStorage();
};
});
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; // Random speed for each star
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
});
var buttonText = new Text2('START', {
size: 80,
fill: 0x000000
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.interactive = true;
self.down = function () {
startGame();
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e // Dark neon-friendly background
});
/****
* Game Code
****/
// Red color for reset button
// Green color for start button
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;
}
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2632;
var BALL_RADIUS = 50;
var BRICK_WIDTH = 300;
var BRICK_HEIGHT = 99;
var BALL_COST = 50;
var LEVEL_COLORS = [0xff00ff,
// Neon Magenta
0x00ffff,
// Neon Cyan
0xffff00,
// Neon Yellow
0xff0066,
// Neon Pink
0x00ff99,
// Neon Mint
0xff33cc,
// Neon Hot Pink
0x66ff33,
// Neon Lime
0xcc00ff,
// Neon Purple
0x33ffcc,
// Neon Turquoise
0xff3300 // Neon Orange
];
var levelConfig = {
1: {
totalBricks: 30,
hitpoints: 1,
gridSize: 400,
pattern: 'grid'
},
2: {
totalBricks: 50,
hitpoints: 2,
gridSize: 360,
pattern: 'staggered'
},
3: {
totalBricks: 70,
hitpoints: 3,
gridSize: 320,
pattern: 'clustered'
},
4: {
totalBricks: 90,
hitpoints: 4,
gridSize: 280,
pattern: 'diagonal'
},
5: {
totalBricks: 110,
hitpoints: 5,
gridSize: 240,
pattern: 'sparse'
}
};
var upgrades = {
normalSpeed: 1,
normalPower: 1,
splashSpeed: 1,
splashPower: 1,
sniperSpeed: 1.5,
sniperPower: 2,
scatterSpeed: 1,
scatterPower: 1,
clickDamage: 1,
normalSpeedCost: 50,
normalPowerCost: 75,
splashSpeedCost: 50,
splashPowerCost: 75,
sniperSpeedCost: 75,
sniperPowerCost: 100,
scatterSpeedCost: 50,
scatterPowerCost: 75,
clickCost: 25,
splashBallCost: 100,
sniperBallCost: 150,
scatterBallCost: 125
};
var balls = [];
var bricks = [];
var brickGrid = {};
var score = 10000;
var level = storage.level || 1;
var brickGridBounds = null;
var unlockedTiers = storage.unlockedTiers || {
normal: true,
splash: false,
sniper: false,
scatter: false
};
function clearLocalStorage() {
storage.score = 0;
storage.level = 1;
storage.unlockedTiers = {
normal: true,
splash: false,
sniper: false,
scatter: false
};
score = 0;
level = 1;
unlockedTiers = Object.assign({}, storage.unlockedTiers);
scoreTxt.setText('$' + score.toString());
levelTxt.setText('Level: ' + level);
updateButtonStates();
}
// HUD Setup
var hud = new Container();
LK.gui.top.addChild(hud);
var scoreTxt = new Text2('0', {
size: 60,
fill: 0x00ffff
}); // Neon Cyan
scoreTxt.anchor.set(0.3, 0);
scoreTxt.x += 450;
hud.addChild(scoreTxt);
var levelTxt = new Text2('Level: ' + level, {
size: 60,
fill: 0x00ffff
}); // Neon Cyan
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 = LK.getAsset('button', {
size: 80,
fill: 0x1a1a2e,
// Dark base
anchorX: 0.5,
anchorY: 0,
y: 50,
x: x
});
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,
tint: type === 'splash' ? 0xff0066 :
// Neon Pink
type === 'sniper' ? 0x00ff99 :
// Neon Mint
type === 'scatter' ? 0xffff00 :
// Neon Yellow
0x00ffff // Neon Cyan
});
contentContainer.addChild(ballIcon);
var typeText = new Text2(type.charAt(0).toUpperCase() + type.slice(1), {
size: 30,
fill: 0xffffff // White for contrast
});
typeText.anchor.set(0.5, 0);
typeText.y = -50;
button.addChild(typeText);
var costText = new Text2('$' + cost, {
size: 50,
fill: 0x00ffff // Neon Cyan
});
costText.anchor.set(0.5, 0);
costText.y = 100;
button.addChild(costText);
button.interactive = true;
button.down = function () {
if (score < cost) {
return;
}
score -= cost;
scoreTxt.setText('$' + score.toString());
createBall(type);
if (!unlockedTiers[type]) {
unlockedTiers[type] = true;
storage.unlockedTiers = Object.assign({}, unlockedTiers);
updateButtonStates();
}
};
button.updateState = function () {
var isEnabled = (prevTier ? unlockedTiers[prevTier] : true) && score >= cost;
button.tint = isEnabled ? 0x00ffff : 0x666666; // Neon Cyan when enabled
button.interactive = isEnabled;
};
hud.addChild(button);
ballButtons[type] = button;
}
createBallButton('normal', -400, BALL_COST, 'ball', null);
createBallButton('splash', -280, upgrades.splashBallCost, 'splashBall', 'normal');
createBallButton('sniper', -160, upgrades.sniperBallCost, 'sniperBall', 'splash');
createBallButton('scatter', -40, upgrades.scatterBallCost, 'scatterBall', 'sniper');
var clearStorageButton = LK.getAsset('button', {
size: 80,
fill: 0x1a1a2e,
anchorX: 0.5,
anchorY: 0,
x: scoreTxt.width + 200,
y: 0
});
var clearStorageText = new Text2('Reset', {
size: 50,
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);
var upgradeButtons = {};
function createUpgradeButton(labelPrefix, x, costKey, upgradeKey, baseCost, iconType, prevTier) {
var button = LK.getAsset('powerupbutton', {
size: 150,
fill: 0x1a1a2e,
anchorX: 0.5,
anchorY: 0,
x: x,
y: 0
});
var contentContainer = new Container();
button.addChild(contentContainer);
if (iconType) {
var 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 : 0x00ffff
});
contentContainer.addChild(icon);
}
var labelText = new Text2("".concat(labelPrefix, " x").concat(upgrades[upgradeKey]), {
size: 30,
fill: 0xffffff
});
labelText.anchor.set(0.5, 0);
labelText.y = 100;
button.addChild(labelText);
var costText = new Text2('$' + (baseCost * upgrades[upgradeKey]).toString(), {
size: 40,
fill: 0x00ffff
});
costText.anchor.set(0.5, 0);
costText.y = 140;
button.addChild(costText);
button.interactive = true;
button.down = function () {
var cost = baseCost * upgrades[upgradeKey];
var ballType = upgradeKey.split('Speed')[0].split('Power')[0];
// Special handling for clickDamage - no tier dependency
if (upgradeKey === 'clickDamage') {
if (score < cost) {
return;
}
} else {
if (!unlockedTiers[ballType] || score < cost) {
return;
}
}
score -= cost;
upgrades[upgradeKey]++;
costText.setText('$' + (baseCost * upgrades[upgradeKey]).toString());
labelText.setText("".concat(labelPrefix, " x").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];
}
};
button.updateState = function () {
var ballType = upgradeKey.split('Speed')[0].split('Power')[0];
var isEnabled = upgradeKey === 'clickDamage' ? score >= baseCost * upgrades[upgradeKey] : unlockedTiers[ballType] && (prevTier ? unlockedTiers[prevTier] : true) && score >= baseCost * upgrades[upgradeKey];
button.tint = isEnabled ? 0x00ffff : 0x666666;
button.interactive = isEnabled;
};
powerupContainer.addChild(button);
upgradeButtons[upgradeKey] = button;
}
var buttonWidth = 150;
var spacing = 50;
var totalButtons = 9;
var totalWidth = totalButtons * buttonWidth + (totalButtons - 1) * spacing;
var startX = (GAME_WIDTH - totalWidth) / 2;
createUpgradeButton('Speed', startX, 'normalSpeedCost', 'normalSpeed', 50, 'ball', null);
createUpgradeButton('Power', startX + (buttonWidth + spacing), 'normalPowerCost', 'normalPower', 75, 'ball', null);
createUpgradeButton('Speed', startX + 2 * (buttonWidth + spacing), 'splashSpeedCost', 'splashSpeed', 50, 'splashBall', 'normal');
createUpgradeButton('Power', startX + 3 * (buttonWidth + spacing), 'splashPowerCost', 'splashPower', 75, 'splashBall', 'normal');
createUpgradeButton('Speed', startX + 4 * (buttonWidth + spacing), 'sniperSpeedCost', 'sniperSpeed', 75, 'sniperBall', 'splash');
createUpgradeButton('Power', startX + 5 * (buttonWidth + spacing), 'sniperPowerCost', 'sniperPower', 100, 'sniperBall', 'splash');
createUpgradeButton('Speed', startX + 6 * (buttonWidth + spacing), 'scatterSpeedCost', 'scatterSpeed', 50, 'scatterBall', 'sniper');
createUpgradeButton('Power', startX + 7 * (buttonWidth + spacing), 'scatterPowerCost', 'scatterPower', 75, 'scatterBall', 'sniper');
createUpgradeButton('Click', startX + 8 * (buttonWidth + spacing), 'clickCost', 'clickDamage', 25, null, null);
var upgradeButton = LK.getAsset('upgrade', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH / 2,
y: GAME_HEIGHT - 100,
tint: 0x00ffff
});
var upgradeText = new Text2('UPGRADE', {
size: 50,
fill: 0xffffff
});
upgradeText.anchor.set(0.5, 0.5);
upgradeButton.addChild(upgradeText);
upgradeButton.down = function () {
powerupContainer.visible = !powerupContainer.visible;
};
upgradeButton.visible = false; // Initially hide upgrade button
game.addChild(upgradeButton);
// Initially hide top elements
hud.visible = false;
// Helper Functions
function updateButtonStates() {
for (var type in ballButtons) {
ballButtons[type].updateState();
}
for (var key in upgradeButtons) {
upgradeButtons[key].updateState();
}
}
function handleBallBrickCollision(ball, brick) {
var relativeX = (ball.x - brick.x) / (brick.width / 2);
var relativeY = (ball.y - brick.y) / (brick.height / 2);
if (Math.abs(relativeX) > Math.abs(relativeY)) {
ball.direction.x = -ball.direction.x + relativeX * 0.5;
ball.x = brick.x + (relativeX > 0 ? brick.width / 2 + BALL_RADIUS : -brick.width / 2 - BALL_RADIUS);
} else {
ball.direction.y = -ball.direction.y;
ball.y = brick.y + (relativeY > 0 ? brick.height / 2 + BALL_RADIUS : -brick.height / 2 - BALL_RADIUS);
}
ball.direction.x += (Math.random() - 0.5) * 0.1;
var magnitude = Math.sqrt(ball.direction.x * ball.direction.x + ball.direction.y * ball.direction.y);
ball.direction.x /= magnitude;
ball.direction.y /= magnitude;
}
function applySplashDamage(brick, gridSize) {
var gridX = Math.floor(brick.x / gridSize);
var gridY = Math.floor(brick.y / gridSize);
var adjacentKeys = ["".concat(gridX - 1, ",").concat(gridY), "".concat(gridX + 1, ",").concat(gridY), "".concat(gridX, ",").concat(gridY - 1), "".concat(gridX, ",").concat(gridY + 1)];
adjacentKeys.forEach(function (key) {
if (brickGrid[key]) {
brickGrid[key].forEach(function (adjBrick) {
if (adjBrick && adjBrick.health > 0) {
adjBrick.hit(Math.floor(upgrades.splashPower * 0.25));
}
});
}
});
}
function scatterOnImpact(ball) {
for (var i = 0; i < 4; i++) {
var smallBall = new Ball('smallScatter');
smallBall.x = ball.x;
smallBall.y = ball.y;
var angle = i / 4 * 2 * Math.PI;
smallBall.direction.x = Math.cos(angle);
smallBall.direction.y = Math.sin(angle);
balls.push(smallBall);
game.addChild(smallBall);
}
}
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 isNearBricks(x, y) {
if (!brickGridBounds) {
return true;
}
var buffer = BALL_RADIUS * 2;
return x >= brickGridBounds.minX - buffer && x <= brickGridBounds.maxX + buffer && y >= brickGridBounds.minY - buffer && y <= brickGridBounds.maxY + buffer;
}
function createBricks() {
var config = levelConfig[level] || {};
var totalBricks = config.totalBricks || 50;
var hitpoints = config.hitpoints || 1;
var gridSize = config.gridSize || 200;
var pattern = config.pattern || 'grid';
var spacingX = 2;
var spacingY = 2;
brickGrid = {};
bricks = [];
var cols = Math.floor(GAME_WIDTH / (BRICK_WIDTH + spacingX));
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) / 3 + BRICK_HEIGHT / 2;
var brickCount = 0;
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), hitpoints, gridSize);
brickCount++;
}
}
} else if (pattern === 'staggered') {
for (var i = 0; i < rows && brickCount < totalBricks; i++) {
var offsetX = i % 2 === 0 ? 0 : BRICK_WIDTH / 2;
for (var j = 0; j < cols && brickCount < totalBricks; j++) {
addBrick(startX + offsetX + j * (BRICK_WIDTH + spacingX), startY + i * (BRICK_HEIGHT + spacingY), hitpoints, gridSize);
brickCount++;
}
}
} else if (pattern === 'clustered') {
var clusterCols = Math.floor(cols / 2);
var clusterRows = Math.floor(rows / 2);
var clusterStartX = GAME_WIDTH / 2 - clusterCols * BRICK_WIDTH / 2;
var clusterStartY = GAME_HEIGHT / 3 - clusterRows * BRICK_HEIGHT / 2;
for (var i = 0; i < clusterRows && brickCount < totalBricks; i++) {
for (var j = 0; j < clusterCols && brickCount < totalBricks; j++) {
addBrick(clusterStartX + j * (BRICK_WIDTH + spacingX), clusterStartY + i * (BRICK_HEIGHT + spacingY), hitpoints, gridSize);
brickCount++;
}
}
} else if (pattern === 'diagonal') {
var stepX = (GAME_WIDTH - BRICK_WIDTH) / (totalBricks - 1);
var stepY = GAME_HEIGHT / 3 / (totalBricks - 1);
for (var i = 0; i < totalBricks; i++) {
addBrick(startX + i * stepX, startY + i * stepY, hitpoints, gridSize);
brickCount++;
}
} else if (pattern === 'sparse') {
while (brickCount < totalBricks) {
var x = startX + Math.floor(Math.random() * cols) * (BRICK_WIDTH + spacingX);
var y = startY + Math.floor(Math.random() * rows) * (BRICK_HEIGHT + spacingY);
if (!bricks.some(function (b) {
return b.x === x && b.y === y;
})) {
addBrick(x, y, hitpoints, gridSize);
brickCount++;
}
}
}
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, gridSize) {
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);
var gridX = Math.floor(brick.x / gridSize);
var gridY = Math.floor(brick.y / gridSize);
var gridKey = "".concat(gridX, ",").concat(gridY);
if (!brickGrid[gridKey]) {
brickGrid[gridKey] = [];
}
brickGrid[gridKey].push(brick);
}
function createBall() {
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'normal';
var ball = new Ball(type);
var gridBottom = brickGridBounds ? brickGridBounds.maxY + 150 : GAME_HEIGHT * 0.7;
ball.x = GAME_WIDTH / 2 + (Math.random() * 200 - 100);
ball.y = Math.min(gridBottom + 100, GAME_HEIGHT - BALL_RADIUS * 2);
var angle = (Math.random() * 0.5 + 0.25) * Math.PI;
ball.direction.x = Math.cos(angle);
ball.direction.y = -Math.sin(angle);
var magnitude = Math.sqrt(ball.direction.x * ball.direction.x + ball.direction.y * ball.direction.y);
ball.direction.x /= magnitude;
ball.direction.y /= magnitude;
for (var i = 0; i < bricks.length; i++) {
if (ball.intersects(bricks[i])) {
ball.y = brickGridBounds.maxY + BALL_RADIUS + 10;
break;
}
}
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) {
if (level === Object.keys(levelConfig).length) {
LK.showGameOver();
} else {
level += 1;
storage.level = level;
levelTxt.setText('Level: ' + level);
createBricks();
}
}
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);
score += upgrades.clickDamage;
scoreTxt.setText('$' + score.toString());
storage.score = score;
return;
}
}
};
// Create and add stars to the game background
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); // Add stars behind other elements
}
// Initialize game elements
var gameTitle = new GameTitle();
gameTitle.x = GAME_WIDTH / 2;
gameTitle.y = GAME_HEIGHT / 2 - 600;
game.addChild(gameTitle);
// Add color and animation to the title
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 // Recursively call to keep changing color
});
}
});
}
animateTitleColor();
tween(gameTitle, {
y: GAME_HEIGHT / 2 - 500
}, {
duration: 1000,
easing: tween.bounceOut
});
var startButton = new StartButton();
startButton.x = GAME_WIDTH / 2;
startButton.y = GAME_HEIGHT / 2 + 300; // Moved 200 pixels down
startButton.tint = 0x00ff99; // Apply green tint to match game style
game.addChild(startButton);
tween(startButton, {
y: startButton.y - 20
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startButton, {
y: startButton.y + 20
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
var resetButton = new ResetButton();
resetButton.x = GAME_WIDTH / 2;
resetButton.y = startButton.y + 900;
game.addChild(resetButton);
tween(resetButton, {
y: resetButton.y - 20
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(resetButton, {
y: resetButton.y + 20
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
function startGame() {
startButton.destroy();
gameTitle.destroy();
resetButton.visible = false;
upgradeButton.visible = true; // Show upgrade button
hud.visible = true; // Show top elements
createBricks();
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) {
if (level === Object.keys(levelConfig).length) {
LK.showGameOver();
} else {
level += 1;
storage.level = level;
levelTxt.setText('Level: ' + level);
createBricks();
}
}
updateButtonStates();
};
}
game.update = function () {
for (var i = 0; i < stars.length; i++) {
stars[i].update();
}
};