User prompt
Make sure bricks can be touched in any part of their surface
User prompt
sometimes balls bounce close to a brick butu do not touch it and nor destroy it, can you fix that
User prompt
add a level sctructurue, level two should have more bricks and some should have 2 hitpints
User prompt
add levels to the game. once all bricks are destroyed, move to next level. show current level on screen in the top
User prompt
Imptove game perfoomance to handel many balls simultaneously
User prompt
create a config file were we can say home may bricks each level will have
User prompt
game is getting stuck when there are many bricks and balls. can we optimize the code to allow many balls and bricks in the screen at the same time
User prompt
can ou optimize it more. feels like the problems is with the bricks
User prompt
Please fix the bug: 'gridSize is not defined' in or related to this line: 'var gridX = Math.floor(brick.x / gridSize);' Line Number: 170
User prompt
Lets make level config a little more specific, and allow player to define groups of blocks for each level, and also set how many hitpoins those blocks will have
User prompt
theregrid size will be different per level
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'undefined')' in or related to this line: 'var gridSize = levelConfig[level].gridSize || 200; // Define grid size per level, default to 200 if not specified' Line Number: 96
Code edit (8 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: setTimeout is not a function' in or related to this line: 'setTimeout(function () {' Line Number: 475
User prompt
remove power ups from game
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: setTimeout is not a function' in or related to this line: 'setTimeout(function () {' Line Number: 473
User prompt
Fix level 2 not loading and showing game over
Code edit (4 edits merged)
Please save this source code
User prompt
Please fix the bug: 'GAME_WIDTH is not defined' in or related to this line: 'levelTxt.x = GAME_WIDTH / 2 - levelTxt.width / 2;' Line Number: 54
User prompt
Please fix the bug: 'BALL_COST is not defined' in or related to this line: 'var normalCostText = new Text2(BALL_COST.toString(), {' Line Number: 71
Code edit (3 edits merged)
Please save this source code
User prompt
can we put the current level in the center of the top of the screen
User prompt
can you adjust the hud
User prompt
actually put it in the center please
===================================================================
--- original.js
+++ change.js
@@ -1,74 +1,213 @@
/****
* Classes
****/
-/**** * Classes
-****/
var Ball = Container.expand(function () {
var self = Container.call(this);
-} // ... (Ball class code remains the same) ...
-);
+ var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'normal';
+ var asset = type === 'splash' ? 'splashBall' : 'ball';
+ var ballGraphics = self.attachAsset(asset, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.type = type;
+ self.speed = type === 'splash' ? upgrades.splashSpeed : upgrades.normalSpeed;
+ self.power = type === 'splash' ? upgrades.splashPower : upgrades.normalPower;
+ self.direction = {
+ x: 1,
+ y: -1
+ };
+ self.update = function () {
+ var gridSize = levelConfig[level] ? levelConfig[level].gridSize : 200;
+ var stepSize = self.speed;
+ 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);
+ }
+ if (brick.health <= 0) {
+ cellBricks.splice(j, 1);
+ }
+ hasCollided = true;
+ break;
+ }
+ }
+ }
+ };
+});
var Brick = Container.expand(function () {
var self = Container.call(this);
-} // ... (Brick class code remains the same) ...
-);
+ 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: 30,
+ fill: 0xFFFFFF
+ });
+ 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());
+ var brickIndex = bricks.indexOf(self);
+ if (brickIndex !== -1) {
+ bricks.splice(brickIndex, 1);
+ }
+ self.destroy();
+ } else {
+ self.healthText.setText(self.health.toString());
+ self.updateTint();
+ }
+ };
+});
/****
* Initialize Game
****/
-/**** * Initialize Game
-****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
-/**** * Game Code
-****/
-// Define GAME_WIDTH constant
-var GAME_WIDTH = 2048; // Assuming the virtual resolution width
-// Define BALL_COST constant
-var BALL_COST = 50; // Assuming a default cost for a normal ball
-// ... (Constants and Game Variables remain the same) ...
+// Constants
+var GAME_WIDTH = 2048;
+var GAME_HEIGHT = 2632;
+var BALL_RADIUS = 50;
+var BRICK_WIDTH = 150;
+var BRICK_HEIGHT = 50;
+var BALL_COST = 50;
+var LEVEL_COLORS = [0xff00ff, 0x00ffcc, 0xccff00, 0xff6600, 0x66ffff, 0xff3366, 0xffcc00, 0x9966ff, 0x33cc33, 0xff0000];
+// Responsive Scaling
+var BASE_FONT_SIZE = GAME_WIDTH / 40; // ~51px at 2048 width
+var BUTTON_SIZE = GAME_WIDTH / 20; // ~102px at 2048 width
+var BUTTON_SPACING = GAME_WIDTH / 15; // ~136px at 2048 width
+// Game Variables
+var levelConfig = {
+ 1: {
+ totalBricks: 50,
+ hitpoints: 1,
+ gridSize: 200
+ },
+ 2: {
+ totalBricks: 100,
+ hitpoints: 2,
+ gridSize: 180
+ },
+ 3: {
+ totalBricks: 150,
+ hitpoints: 3,
+ gridSize: 160
+ },
+ 4: {
+ totalBricks: 200,
+ hitpoints: 4,
+ gridSize: 140
+ },
+ 5: {
+ totalBricks: 250,
+ hitpoints: 5,
+ gridSize: 120
+ }
+};
+var upgrades = {
+ normalSpeed: 1,
+ normalPower: 1,
+ splashSpeed: 1,
+ splashPower: 1,
+ clickDamage: 1,
+ normalSpeedCost: 50,
+ normalPowerCost: 75,
+ splashSpeedCost: 50,
+ splashPowerCost: 75,
+ clickCost: 25,
+ splashBallCost: 100
+};
+var balls = [];
+var bricks = [];
+var brickGrid = {};
+var score = 10000;
+var level = 1;
+var brickGridBounds = null;
// HUD Setup
-var topHud = new Container();
-LK.gui.top.addChild(topHud);
-var scoreTxt = new Text2('Score: 0', {
- size: 60,
+var hud = new Container();
+LK.gui.topRight.addChild(hud);
+// Upper-Right: Score, Level, Ball Purchases (Vertical Stack)
+var scoreTxt = new Text2('0', {
+ size: BASE_FONT_SIZE * 0.8,
fill: 0xFFFFFF
-});
-scoreTxt.anchor.set(0, 0);
-scoreTxt.x = 20;
-scoreTxt.y = 20;
-topHud.addChild(scoreTxt);
-var levelTxt = new Text2('Level: 1', {
- size: 60,
+}); // Smaller than before
+scoreTxt.anchor.set(1, 0);
+scoreTxt.x = 0;
+scoreTxt.y = 10;
+hud.addChild(scoreTxt);
+var levelTxt = new Text2('Level: ' + level, {
+ size: BASE_FONT_SIZE * 0.8,
fill: 0xFFFFFF
});
-levelTxt.anchor.set(0.5, 0);
-levelTxt.x = GAME_WIDTH / 2 - levelTxt.width / 2;
-levelTxt.y = 20;
-topHud.addChild(levelTxt);
-// Bottom HUD for Upgrades and Ball Purchases
-var bottomHud = new Container();
-LK.gui.bottom.addChild(bottomHud);
-// Buy Normal Ball Button
+levelTxt.anchor.set(1, 0);
+levelTxt.x = 0;
+levelTxt.y = scoreTxt.y + BASE_FONT_SIZE * 1.2;
+hud.addChild(levelTxt);
var buyNormalButton = LK.getAsset('BuyBall50', {
- size: 80,
+ size: BUTTON_SIZE,
fill: 0xFFFFFF,
anchorX: 0.5,
- anchorY: 1,
- y: -20,
- x: -GAME_WIDTH / 2 + 150
+ anchorY: 0,
+ x: -BUTTON_SPACING,
+ y: levelTxt.y + BUTTON_SIZE
});
var normalCostText = new Text2(BALL_COST.toString(), {
- size: 50,
+ size: BASE_FONT_SIZE * 0.6,
fill: 0xFFFFFF
});
normalCostText.anchor.set(0.5, 0);
-normalCostText.y = 100;
+normalCostText.y = BUTTON_SIZE * 0.8;
buyNormalButton.addChild(normalCostText);
buyNormalButton.addChild(buyNormalButton.attachAsset('ball', {
anchorX: 0.5,
anchorY: -0.5,
@@ -77,28 +216,27 @@
}));
buyNormalButton.down = function () {
if (score >= BALL_COST) {
score -= BALL_COST;
- scoreTxt.setText('Score: ' + score.toString());
+ scoreTxt.setText(score.toString());
createBall('normal');
}
};
-bottomHud.addChild(buyNormalButton);
-// Buy Splash Ball Button
+hud.addChild(buyNormalButton);
var buySplashButton = LK.getAsset('BuyBall50', {
- size: 80,
+ size: BUTTON_SIZE,
fill: 0xFFFFFF,
anchorX: 0.5,
- anchorY: 1,
- y: -20,
- x: -GAME_WIDTH / 2 + 300
+ anchorY: 0,
+ x: BUTTON_SPACING,
+ y: levelTxt.y + BUTTON_SIZE
});
var splashCostText = new Text2(upgrades.splashBallCost.toString(), {
- size: 50,
+ size: BASE_FONT_SIZE * 0.6,
fill: 0xFFFFFF
});
splashCostText.anchor.set(0.5, 0);
-splashCostText.y = 100;
+splashCostText.y = BUTTON_SIZE * 0.8;
buySplashButton.addChild(splashCostText);
buySplashButton.addChild(buySplashButton.attachAsset('splashBall', {
anchorX: 0.5,
anchorY: -0.5,
@@ -107,77 +245,209 @@
}));
buySplashButton.down = function () {
if (score >= upgrades.splashBallCost) {
score -= upgrades.splashBallCost;
- scoreTxt.setText('Score: ' + score.toString());
+ scoreTxt.setText(score.toString());
createBall('splash');
}
};
-bottomHud.addChild(buySplashButton);
-// Upgrade Buttons
-function createUpgradeButton(label, x, costKey, upgradeKey, increment, updateFn) {
+hud.addChild(buySplashButton);
+// Bottom: Upgrade Buttons
+var bottomHud = new Container();
+bottomHud.y = GAME_HEIGHT - BUTTON_SIZE * 1.5;
+game.addChild(bottomHud);
+// Upgrade Button Factory
+function createUpgradeButton(labelPrefix, x, costKey, upgradeKey, baseCost) {
var button = LK.getAsset('BuyBall50', {
- size: 80,
+ size: BUTTON_SIZE,
fill: 0xFFFFFF,
anchorX: 0.5,
- anchorY: 1,
- y: -20,
- x: x
+ anchorY: 0,
+ x: x,
+ y: 0
});
- var costText = new Text2(upgrades[costKey].toString(), {
- size: 50,
+ var costText = new Text2((baseCost * upgrades[upgradeKey]).toString(), {
+ size: BASE_FONT_SIZE * 0.6,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0);
- costText.y = 100;
+ costText.y = BUTTON_SIZE * 0.8;
button.addChild(costText);
- var labelText = new Text2(label, {
- size: 20,
+ var labelText = new Text2("".concat(labelPrefix, " x").concat(upgrades[upgradeKey]), {
+ size: BASE_FONT_SIZE * 0.4,
fill: 0xFFFFFF
});
labelText.anchor.set(0.5, -0.5);
button.addChild(labelText);
button.down = function () {
- if (score >= upgrades[costKey]) {
- score -= upgrades[costKey];
- upgrades[upgradeKey] += increment;
- upgrades[costKey] *= 1.1; // Cost increases by 10%
- costText.setText(Math.floor(upgrades[costKey]).toString());
- scoreTxt.setText('Score: ' + score.toString());
- updateFn();
+ var cost = baseCost * upgrades[upgradeKey];
+ if (score >= cost) {
+ 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];
+ }
+ });
}
};
bottomHud.addChild(button);
}
-createUpgradeButton('Spd N', -GAME_WIDTH / 2 + 450, 'speedCost', 'normalSpeed', 0.5, function () {
- return balls.forEach(function (b) {
- if (b.type === 'normal') {
- b.speed = upgrades.normalSpeed;
+createUpgradeButton('Speed', GAME_WIDTH / 2 - BUTTON_SPACING * 2, 'normalSpeedCost', 'normalSpeed', 50);
+createUpgradeButton('Power', GAME_WIDTH / 2 - BUTTON_SPACING, 'normalPowerCost', 'normalPower', 75);
+createUpgradeButton('Speed', GAME_WIDTH / 2, 'splashSpeedCost', 'splashSpeed', 50);
+createUpgradeButton('Power', GAME_WIDTH / 2 + BUTTON_SPACING, 'splashPowerCost', 'splashPower', 75);
+createUpgradeButton('Click', GAME_WIDTH / 2 + BUTTON_SPACING * 2, 'clickCost', 'clickDamage', 25);
+// Helper Functions
+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));
+ }
+ });
}
});
-});
-createUpgradeButton('Pwr N', -GAME_WIDTH / 2 + 600, 'powerCost', 'normalPower', 1, function () {
- return balls.forEach(function (b) {
- if (b.type === 'normal') {
- b.power = upgrades.normalPower;
+}
+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 spacingX = 2;
+ var spacingY = 2;
+ var cols = 10;
+ 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;
+ brickGrid = {};
+ bricks = [];
+ for (var i = 0; i < rows; i++) {
+ for (var j = 0; j < cols && i * cols + j < totalBricks; j++) {
+ var brick = new Brick();
+ brick.x = startX + j * (BRICK_WIDTH + spacingX);
+ brick.y = startY + i * (BRICK_HEIGHT + spacingY);
+ 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);
}
- });
-});
-createUpgradeButton('Spd S', -GAME_WIDTH / 2 + 750, 'speedCost', 'splashSpeed', 0.5, function () {
- return balls.forEach(function (b) {
- if (b.type === 'splash') {
- b.speed = upgrades.splashSpeed;
+ }
+ brickGridBounds = {
+ minX: startX - BRICK_WIDTH / 2,
+ maxX: startX + totalWidth - BRICK_WIDTH / 2,
+ minY: startY - BRICK_HEIGHT / 2,
+ maxY: startY + totalHeight - BRICK_HEIGHT / 2
+ };
+}
+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;
}
- });
-});
-createUpgradeButton('Pwr S', -GAME_WIDTH / 2 + 900, 'powerCost', 'splashPower', 1, function () {
- return balls.forEach(function (b) {
- if (b.type === 'splash') {
- b.power = upgrades.splashPower;
+ }
+ balls.push(ball);
+ game.addChild(ball);
+}
+game.update = function () {
+ 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);
}
- });
-});
-createUpgradeButton('Tap', -GAME_WIDTH / 2 + 1050, 'tapCost', 'tapDamage', 1, function () {});
-// ... (Helper Functions and Game Logic remain the same) ...
+ }
+ if (bricks.length === 0) {
+ for (var i = balls.length - 1; i >= 0; i--) {
+ balls[i].destroy();
+ balls.splice(i, 1);
+ }
+ if (level === Object.keys(levelConfig).length) {
+ LK.showGameOver();
+ } else {
+ level += 1;
+ levelTxt.setText('Level: ' + level);
+ createBricks();
+ createBall();
+ }
+ }
+ if (balls.length === 0 && score >= BALL_COST) {
+ score -= BALL_COST;
+ scoreTxt.setText(score.toString());
+ createBall();
+ }
+};
+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);
+ return;
+ }
+ }
+};
// Initialize game elements
createBricks();
createBall();
\ No newline at end of file