User prompt
storage poins should be loaded as soon as game starts ↪💡 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: 381
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'hud.addChild(scoreTxt);' Line Number: 387
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'hud.addChild(scoreTxt);' Line Number: 387
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'hud.addChild(scoreTxt);' Line Number: 387
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'hud.addChild(scoreTxt);' Line Number: 387
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'setText')' in or related to this line: 'levelTxt.setText('Level: ' + level);' Line Number: 390
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'hud.addChild(levelTxt);' Line Number: 397
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'hud.addChild(levelTxt);' Line Number: 397
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'hud.addChild(levelTxt);' Line Number: 397
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'hud.addChild(levelTxt);' Line Number: 397
User prompt
move in game reste button under the start button and do not hide it on game load
User prompt
unify reset buttons into the on that is below the start butotn
User prompt
remove hardcoded points for player on start, that was just for development
User prompt
save points in local storage ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
blocks score should be the ammount of points it had when they were created
User prompt
remove text for reset button that is next to level
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught ReferenceError: score is not defined' in or related to this line: 'var isEnabled = (prevTier ? unlockedTiers[prevTier] : true) && score >= cost;' Line Number: 477
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'balls.push(ball);' Line Number: 789
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'balls.push(ball);' Line Number: 789
User prompt
please fix issue when trying to create the first ball
User prompt
try a different way to fix the first ball onto being created an giving an error
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;
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 Breakout', {
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
****/
// Green color for start button
// Red color for reset 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 = storage.score || 0;
var level = storage.level || 1;
scoreTxt.setText('$' + score.toString());
levelTxt.setText('Level: ' + level);
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();
// Clear local storage
}
// 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;
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;
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;
clearStorageButton.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();
}
};