User prompt
can you adjust the hud
User prompt
can we put the current level in the center of the top of the screen
Code edit (4 edits merged)
Please save this source code
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
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
Code edit (1 edits merged)
Please save this source code
User prompt
Fix level 2 not loading and showing game over
User prompt
Please fix the bug: 'TypeError: setTimeout is not a function' in or related to this line: 'setTimeout(function () {' Line Number: 473
Code edit (8 edits merged)
Please save this source code
User prompt
remove power ups from game
User prompt
Please fix the bug: 'TypeError: setTimeout is not a function' in or related to this line: 'setTimeout(function () {' Line Number: 475
Code edit (1 edits merged)
Please save this source code
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
User prompt
theregrid size will be different per level
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
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
can ou optimize it more. feels like the problems is with the bricks
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
create a config file were we can say home may bricks each level will have
User prompt
Imptove game perfoomance to handel many balls simultaneously
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
add a level sctructurue, level two should have more bricks and some should have 2 hitpints
User prompt
sometimes balls bounce close to a brick butu do not touch it and nor destroy it, can you fix that
User prompt
Make sure bricks can be touched in any part of their surface
User prompt
Please fix the bug: 'Graphics is not a constructor' in or related to this line: 'var hitbox = new Graphics();' Line Number: 47
/**** * Classes ****/ // Ball class representing the ball that breaks bricks var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.direction = { x: 1, y: -1 }; self.update = function () { var _ref = levelConfig[level] || { gridSize: 200 }, gridSize = _ref.gridSize; var stepSize = self.speed; var dx = self.direction.x * stepSize; var dy = self.direction.y * stepSize; self.x += dx; self.y += dy; // Bounce off walls 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)); } // Only check collisions near actual bricks (performance optimization) if (!isNearBricks(self.x, self.y)) { return; } // Check collisions with bricks using grid-based collision detection 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; } // Handle collision handleBallBrickCollision(self, brick); brick.hit(); // Remove brick from grid if destroyed if (brick.health <= 0) { cellBricks.splice(j, 1); } hasCollided = true; break; } } } }; }); // Brick class representing the bricks to be broken 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: 30, fill: 0xFFFFFF }); self.healthText.anchor.set(0.5, 0.5); self.addChild(self.healthText); self.updateTint = function () { var healthRatio = self.health / self.maxHealth; var colorIndex = Math.min(Math.floor((1 - healthRatio) * LEVEL_COLORS.length), LEVEL_COLORS.length - 1); brickGraphics.tint = LEVEL_COLORS[colorIndex]; }; self.hit = function () { self.health -= 1; if (self.health <= 0) { // Award points score += Math.max(1, Math.floor(self.maxHealth * 0.5)); scoreTxt.setText(score.toString()); // Remove from active bricks array var brickIndex = bricks.indexOf(self); if (brickIndex !== -1) { bricks.splice(brickIndex, 1); } // Destroy the brick self.destroy(); // Random power-up chance (10%) if (Math.random() < 0.1) { spawnPowerUp(self.x, self.y); } } else { // Update display self.healthText.setText(self.health.toString()); self.updateTint(); } }; }); // New PowerUp class var PowerUp = Container.expand(function (type) { var self = Container.call(this); // Set type and appearance self.type = type || 'speed'; // Default to speed boost // Create visual representation var powerUpGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.4 }); // Color based on type switch (self.type) { case 'speed': powerUpGraphics.tint = 0x00FF00; // Green break; case 'extraBall': powerUpGraphics.tint = 0xFF00FF; // Magenta break; case 'points': powerUpGraphics.tint = 0xFFFF00; // Yellow break; } // Add label var label = new Text2(self.type.charAt(0).toUpperCase(), { size: 20, fill: 0xFFFFFF }); label.anchor.set(0.5, 0.5); self.addChild(label); // Movement and behavior self.speed = 3; self.update = function () { self.y += self.speed; // Check if out of bounds if (self.y > GAME_HEIGHT) { self.destroy(); var index = powerUps.indexOf(self); if (index !== -1) { powerUps.splice(index, 1); } return; } // Check collision with any ball for (var i = 0; i < balls.length; i++) { if (self.intersects(balls[i])) { applyPowerUp(self.type); self.destroy(); var index = powerUps.indexOf(self); if (index !== -1) { powerUps.splice(index, 1); } return; } } }; }); /**** * Initialize Game ****/ /**** * Helper Functions ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ /**** * Constants ****/ /**** * Game Configuration ****/ 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, // Neon magenta 0x00ffcc, // Neon cyan 0xccff00 // Neon lime ]; /**** * Helper Functions ****/ function handleBallBrickCollision(ball, brick) { // Calculate relative position for better physics var relativeX = (ball.x - brick.x) / (brick.width / 2); var relativeY = (ball.y - brick.y) / (brick.height / 2); // Determine collision side and apply proper bounce if (Math.abs(relativeX) > Math.abs(relativeY)) { // Horizontal collision ball.direction.x = -ball.direction.x; // Push ball out of brick horizontally ball.x = brick.x + (relativeX > 0 ? brick.width / 2 + BALL_RADIUS : -brick.width / 2 - BALL_RADIUS); } else { // Vertical collision ball.direction.y = -ball.direction.y; // Push ball out vertically ball.y = brick.y + (relativeY > 0 ? brick.height / 2 + BALL_RADIUS : -brick.height / 2 - BALL_RADIUS); } // Add slight randomness to prevent looping patterns ball.direction.x += (Math.random() - 0.5) * 0.1; // Normalize vector to maintain consistent speed 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 isNearBricks(x, y) { if (!brickGridBounds) { return true; } // Add a buffer around the brick area var buffer = BALL_RADIUS * 2; return x >= brickGridBounds.minX - buffer && x <= brickGridBounds.maxX + buffer && y >= brickGridBounds.minY - buffer && y <= brickGridBounds.maxY + buffer; } function spawnPowerUp(x, y) { var types = ['speed', 'extraBall', 'points']; var randomType = types[Math.floor(Math.random() * types.length)]; var powerUp = new PowerUp(randomType); powerUp.x = x; powerUp.y = y; powerUps.push(powerUp); game.addChild(powerUp); } function applyPowerUp(type) { switch (type) { case 'speed': // Increase ball speed temporarily balls.forEach(function (ball) { ball.speed += 1; // Reset speed after 10 seconds LK.setTimeout(function () { ball.speed = Math.max(6, ball.speed - 1); }, 10000); }); break; case 'extraBall': // Create an extra ball createBall(); break; case 'points': // Bonus points score += 50; scoreTxt.setText(score.toString()); break; } } 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 } }; /**** * Game Variables ****/ var balls = []; var bricks = []; var powerUps = []; var brickGrid = {}; var score = 100; var level = 1; var brickGridBounds = null; /**** * HUD Setup ****/ var hud = new Container(); LK.gui.topRight.addChild(hud); // Score display var scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(1, 0); hud.addChild(scoreTxt); scoreTxt.setText(score.toString()); // Level display var levelTxt = new Text2('Level: ' + level, { size: 100, fill: 0xFFFFFF }); levelTxt.anchor.set(1, 0); levelTxt.y = 120; hud.addChild(levelTxt); // Buy ball button var buyBallButton = LK.getAsset('BuyBall50', { size: 80, fill: 0xFFFFFF, anchorX: 0.5, anchorY: 0, y: 0, x: -300 }); var costText = new Text2(BALL_COST.toString(), { size: 50, fill: 0xFFFFFF }); costText.anchor.set(0.5, 0); costText.y = 100; buyBallButton.addChild(costText); var ballIcon = buyBallButton.attachAsset('ball', { anchorX: 0.5, anchorY: -0.5, scaleX: 0.5, scaleY: 0.5 }); buyBallButton.down = function () { if (score >= BALL_COST) { score -= BALL_COST; scoreTxt.setText(score.toString()); createBall(); } }; hud.addChild(buyBallButton); /**** * Game Functions ****/ // Create and position bricks function createBricks() { var _ref2 = levelConfig[level] || {}, _ref2$totalBricks = _ref2.totalBricks, totalBricks = _ref2$totalBricks === void 0 ? 50 : _ref2$totalBricks, _ref2$hitpoints = _ref2.hitpoints, hitpoints = _ref2$hitpoints === void 0 ? 1 : _ref2$hitpoints, _ref2$gridSize = _ref2.gridSize, gridSize = _ref2$gridSize === void 0 ? 200 : _ref2$gridSize; 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; // Move bricks higher // Clear existing brick grid 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); // Add to spatial grid for optimized collision detection 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); } } // Store boundaries for optimization brickGridBounds = { minX: startX - BRICK_WIDTH / 2, maxX: startX + totalWidth - BRICK_WIDTH / 2, minY: startY - BRICK_HEIGHT / 2, maxY: startY + totalHeight - BRICK_HEIGHT / 2 }; } // Create a new ball with improved positioning function createBall() { var ball = new Ball(); // Position ball safely var gridBottom = brickGridBounds ? brickGridBounds.maxY + 150 : GAME_HEIGHT * 0.7; ball.x = GAME_WIDTH / 2 + (Math.random() * 200 - 100); // Slight randomization ball.y = Math.min(gridBottom + 100, GAME_HEIGHT - BALL_RADIUS * 2); // Random direction within a cone pointing upward var angle = (Math.random() * 0.5 + 0.25) * Math.PI; ball.direction.x = Math.cos(angle); ball.direction.y = -Math.sin(angle); // Normalize direction vector var magnitude = Math.sqrt(ball.direction.x * ball.direction.x + ball.direction.y * ball.direction.y); ball.direction.x /= magnitude; ball.direction.y /= magnitude; balls.push(ball); game.addChild(ball); } // Handle game completion function handleLevelComplete() { // Clean up existing objects clearLevel(); if (level === Object.keys(levelConfig).length) { // Game completed var gameOverText = new Text2('Game Completed!', { size: 150, fill: 0xFFFFFF }); gameOverText.anchor.set(0.5, 0.5); gameOverText.x = GAME_WIDTH / 2; gameOverText.y = GAME_HEIGHT / 2; game.addChild(gameOverText); var finalScoreText = new Text2('Final Score: ' + score, { size: 100, fill: 0xFFFFFF }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = GAME_WIDTH / 2; finalScoreText.y = GAME_HEIGHT / 2 + 150; game.addChild(finalScoreText); LK.setTimeout(function () { LK.showGameOver(); }, 3000); } else { // Next level level += 1; levelTxt.setText('Level: ' + level); // Level transition effect/message var levelText = new Text2('Level ' + level, { size: 150, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0.5); levelText.x = GAME_WIDTH / 2; levelText.y = GAME_HEIGHT / 2; game.addChild(levelText); // Remove level text after 2 seconds and start new level LK.setTimeout(function () { levelText.destroy(); createBricks(); createBall(); }, 2000); } } // Clear level objects function clearLevel() { // Remove all balls for (var i = balls.length - 1; i >= 0; i--) { balls[i].destroy(); } balls = []; // Remove all power-ups for (var i = powerUps.length - 1; i >= 0; i--) { powerUps[i].destroy(); } powerUps = []; // Remove any remaining bricks for (var i = bricks.length - 1; i >= 0; i--) { bricks[i].destroy(); } bricks = []; brickGrid = {}; } /**** * Game Update Loop ****/ game.update = function () { // Update all balls for (var i = balls.length - 1; i >= 0; i--) { var ball = balls[i]; ball.update(); // Remove balls that fall below the screen if (ball.y > GAME_HEIGHT + BALL_RADIUS) { ball.destroy(); balls.splice(i, 1); } } // Update all power-ups for (var i = powerUps.length - 1; i >= 0; i--) { powerUps[i].update(); } // Level completion check if (bricks.length === 0) { handleLevelComplete(); } // Auto-create ball if all balls are lost if (balls.length === 0) { if (score >= BALL_COST) { score -= Math.min(score, BALL_COST); scoreTxt.setText(score.toString()); createBall(); } else { // Game over clearLevel(); LK.showGameOver(); } } }; /**** * Input Handling ****/ game.down = function (x, y, obj) { // Manually hit bricks on click if (!bricks || !Array.isArray(bricks)) { return; } x = Number(x); y = Number(y); // Check if player clicked near the launch area to control ball direction var controlAreaY = GAME_HEIGHT * 0.8; if (y > controlAreaY) { // Direct balls toward click point for (var i = 0; i < balls.length; i++) { var ball = balls[i]; // Only redirect balls below a certain Y position if (ball.y > controlAreaY) { // Calculate direction to click point var dx = x - ball.x; var dy = y - ball.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { ball.direction.x = dx / dist; ball.direction.y = dy / dist; // Force upward direction if (ball.direction.y > 0) { ball.direction.y *= -1; // Re-normalize var magnitude = Math.sqrt(ball.direction.x * ball.direction.x + ball.direction.y * ball.direction.y); ball.direction.x /= magnitude; ball.direction.y /= magnitude; } } } } return; } // Check for brick hits (cheat/debug feature) for (var i = 0; i < bricks.length; i++) { var brick = bricks[i]; if (!brick.x || !brick.y || !brick.width || !brick.height) { continue; } // Simple AABB collision check 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(); return; } } }; // Initialize game elements createBricks(); createBall();
===================================================================
--- original.js
+++ change.js
@@ -7,54 +7,64 @@
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
- self.speed = 5;
+ self.speed = 6;
self.direction = {
x: 1,
y: -1
};
self.update = function () {
- self.x += self.speed * self.direction.x;
- self.y += self.speed * self.direction.y;
+ var _ref = levelConfig[level] || {
+ gridSize: 200
+ },
+ gridSize = _ref.gridSize;
+ var stepSize = self.speed;
+ var dx = self.direction.x * stepSize;
+ var dy = self.direction.y * stepSize;
+ self.x += dx;
+ self.y += dy;
// Bounce off walls
- if (self.x <= 0 || self.x >= 2048) {
+ if (self.x <= BALL_RADIUS || self.x >= GAME_WIDTH - BALL_RADIUS) {
self.direction.x *= -1;
- self.x = Math.max(0, Math.min(2048, self.x)); // Clamp position
+ self.x = Math.max(BALL_RADIUS, Math.min(GAME_WIDTH - BALL_RADIUS, self.x));
}
- if (self.y <= 0 || self.y >= 2632) {
+ if (self.y <= BALL_RADIUS || self.y >= GAME_HEIGHT - BALL_RADIUS) {
self.direction.y *= -1;
- self.y = Math.max(0, Math.min(2632, self.y)); // Clamp position
+ self.y = Math.max(BALL_RADIUS, Math.min(GAME_HEIGHT - BALL_RADIUS, self.y));
}
- // Check for collisions with bricks using spatial grid
- var gridSize = levelConfig[level] && levelConfig[level].gridSize || 200; // Use level-specific grid size
- var gridX = Math.floor(self.x / gridSize);
- var gridY = Math.floor(self.y / gridSize);
- var gridKey = gridX + ',' + gridY;
- if (brickGrid[gridKey]) {
- for (var j = brickGrid[gridKey].length - 1; j >= 0; j--) {
- var brick = brickGrid[gridKey][j];
- // Skip if brick is destroyed or invalid
- if (!brick || brick.health <= 0 || !self.intersects(brick)) {
+ // Only check collisions near actual bricks (performance optimization)
+ if (!isNearBricks(self.x, self.y)) {
+ return;
+ }
+ // Check collisions with bricks using grid-based collision detection
+ 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;
}
- // Collision detected
- brick.hit();
- // Calculate bounce direction based on hit position
- var hitPosition = (self.x - brick.x) / brick.width;
- self.direction.x = hitPosition > 0.5 ? 1 : -1; // Simplified bounce
- self.direction.y *= -1;
- // Normalize direction vector to maintain consistent speed
- var magnitude = Math.sqrt(self.direction.x * self.direction.x + self.direction.y * self.direction.y);
- self.direction.x /= magnitude;
- self.direction.y /= magnitude;
- // Remove brick from grid and bricks array
- brickGrid[gridKey].splice(j, 1);
- var brickIndex = bricks.indexOf(brick);
- if (brickIndex !== -1) {
- bricks.splice(brickIndex, 1);
+ for (var j = cellBricks.length - 1; j >= 0; j--) {
+ var brick = cellBricks[j];
+ if (!brick || brick.health <= 0 || !self.intersects(brick)) {
+ continue;
+ }
+ // Handle collision
+ handleBallBrickCollision(self, brick);
+ brick.hit();
+ // Remove brick from grid if destroyed
+ if (brick.health <= 0) {
+ cellBricks.splice(j, 1);
+ }
+ hasCollided = true;
+ break;
}
- break; // Handle only one collision per frame
}
}
};
});
@@ -65,48 +75,200 @@
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
- // Create a text object to display the brick's health
+ self.maxHealth = 1;
self.healthText = new Text2(self.health.toString(), {
- size: 50,
+ size: 30,
fill: 0xFFFFFF
});
self.healthText.anchor.set(0.5, 0.5);
self.addChild(self.healthText);
+ self.updateTint = function () {
+ var healthRatio = self.health / self.maxHealth;
+ var colorIndex = Math.min(Math.floor((1 - healthRatio) * LEVEL_COLORS.length), LEVEL_COLORS.length - 1);
+ brickGraphics.tint = LEVEL_COLORS[colorIndex];
+ };
self.hit = function () {
self.health -= 1;
- self.healthText.setText(self.health.toString());
if (self.health <= 0) {
- score += 1;
+ // Award points
+ score += Math.max(1, Math.floor(self.maxHealth * 0.5));
scoreTxt.setText(score.toString());
+ // Remove from active bricks array
+ var brickIndex = bricks.indexOf(self);
+ if (brickIndex !== -1) {
+ bricks.splice(brickIndex, 1);
+ }
+ // Destroy the brick
self.destroy();
- // Ensure brick is removed from spatial grid
- var gridSize = levelConfig[level] && levelConfig[level].gridSize || 200;
- var gridX = Math.floor(self.x / gridSize);
- var gridY = Math.floor(self.y / gridSize);
- var gridKey = gridX + ',' + gridY;
- if (brickGrid[gridKey]) {
- var index = brickGrid[gridKey].indexOf(self);
+ // Random power-up chance (10%)
+ if (Math.random() < 0.1) {
+ spawnPowerUp(self.x, self.y);
+ }
+ } else {
+ // Update display
+ self.healthText.setText(self.health.toString());
+ self.updateTint();
+ }
+ };
+});
+// New PowerUp class
+var PowerUp = Container.expand(function (type) {
+ var self = Container.call(this);
+ // Set type and appearance
+ self.type = type || 'speed'; // Default to speed boost
+ // Create visual representation
+ var powerUpGraphics = self.attachAsset('ball', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.4,
+ scaleY: 0.4
+ });
+ // Color based on type
+ switch (self.type) {
+ case 'speed':
+ powerUpGraphics.tint = 0x00FF00; // Green
+ break;
+ case 'extraBall':
+ powerUpGraphics.tint = 0xFF00FF; // Magenta
+ break;
+ case 'points':
+ powerUpGraphics.tint = 0xFFFF00; // Yellow
+ break;
+ }
+ // Add label
+ var label = new Text2(self.type.charAt(0).toUpperCase(), {
+ size: 20,
+ fill: 0xFFFFFF
+ });
+ label.anchor.set(0.5, 0.5);
+ self.addChild(label);
+ // Movement and behavior
+ self.speed = 3;
+ self.update = function () {
+ self.y += self.speed;
+ // Check if out of bounds
+ if (self.y > GAME_HEIGHT) {
+ self.destroy();
+ var index = powerUps.indexOf(self);
+ if (index !== -1) {
+ powerUps.splice(index, 1);
+ }
+ return;
+ }
+ // Check collision with any ball
+ for (var i = 0; i < balls.length; i++) {
+ if (self.intersects(balls[i])) {
+ applyPowerUp(self.type);
+ self.destroy();
+ var index = powerUps.indexOf(self);
if (index !== -1) {
- brickGrid[gridKey].splice(index, 1);
+ powerUps.splice(index, 1);
}
+ return;
}
}
};
});
/****
* Initialize Game
****/
+/****
+* Helper Functions
+****/
var game = new LK.Game({
- backgroundColor: 0x000000 // Init game with black background
+ backgroundColor: 0x000000
});
/****
* Game Code
****/
-// Initialize game variables
+/****
+* Constants
+****/
+/****
+* Game Configuration
+****/
+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,
+// Neon magenta
+0x00ffcc,
+// Neon cyan
+0xccff00 // Neon lime
+];
+/****
+* Helper Functions
+****/
+function handleBallBrickCollision(ball, brick) {
+ // Calculate relative position for better physics
+ var relativeX = (ball.x - brick.x) / (brick.width / 2);
+ var relativeY = (ball.y - brick.y) / (brick.height / 2);
+ // Determine collision side and apply proper bounce
+ if (Math.abs(relativeX) > Math.abs(relativeY)) {
+ // Horizontal collision
+ ball.direction.x = -ball.direction.x;
+ // Push ball out of brick horizontally
+ ball.x = brick.x + (relativeX > 0 ? brick.width / 2 + BALL_RADIUS : -brick.width / 2 - BALL_RADIUS);
+ } else {
+ // Vertical collision
+ ball.direction.y = -ball.direction.y;
+ // Push ball out vertically
+ ball.y = brick.y + (relativeY > 0 ? brick.height / 2 + BALL_RADIUS : -brick.height / 2 - BALL_RADIUS);
+ }
+ // Add slight randomness to prevent looping patterns
+ ball.direction.x += (Math.random() - 0.5) * 0.1;
+ // Normalize vector to maintain consistent speed
+ 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 isNearBricks(x, y) {
+ if (!brickGridBounds) {
+ return true;
+ }
+ // Add a buffer around the brick area
+ var buffer = BALL_RADIUS * 2;
+ return x >= brickGridBounds.minX - buffer && x <= brickGridBounds.maxX + buffer && y >= brickGridBounds.minY - buffer && y <= brickGridBounds.maxY + buffer;
+}
+function spawnPowerUp(x, y) {
+ var types = ['speed', 'extraBall', 'points'];
+ var randomType = types[Math.floor(Math.random() * types.length)];
+ var powerUp = new PowerUp(randomType);
+ powerUp.x = x;
+ powerUp.y = y;
+ powerUps.push(powerUp);
+ game.addChild(powerUp);
+}
+function applyPowerUp(type) {
+ switch (type) {
+ case 'speed':
+ // Increase ball speed temporarily
+ balls.forEach(function (ball) {
+ ball.speed += 1;
+ // Reset speed after 10 seconds
+ LK.setTimeout(function () {
+ ball.speed = Math.max(6, ball.speed - 1);
+ }, 10000);
+ });
+ break;
+ case 'extraBall':
+ // Create an extra ball
+ createBall();
+ break;
+ case 'points':
+ // Bonus points
+ score += 50;
+ scoreTxt.setText(score.toString());
+ break;
+ }
+}
var levelConfig = {
1: {
totalBricks: 50,
hitpoints: 1,
@@ -132,37 +294,49 @@
hitpoints: 5,
gridSize: 120
}
};
-// Create a HUD to display the points and the buy button
+/****
+* Game Variables
+****/
+var balls = [];
+var bricks = [];
+var powerUps = [];
+var brickGrid = {};
+var score = 100;
+var level = 1;
+var brickGridBounds = null;
+/****
+* HUD Setup
+****/
var hud = new Container();
LK.gui.topRight.addChild(hud);
-// Display the points
+// Score display
var scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
-scoreTxt.anchor.set(1, 0); // Anchor to the top-right corner
+scoreTxt.anchor.set(1, 0);
hud.addChild(scoreTxt);
-// Initialize level variable and display it
-var level = 1;
+scoreTxt.setText(score.toString());
+// Level display
var levelTxt = new Text2('Level: ' + level, {
size: 100,
fill: 0xFFFFFF
});
-levelTxt.anchor.set(1, 0); // Anchor to the top-right corner
-levelTxt.y = 120; // Position below the score
+levelTxt.anchor.set(1, 0);
+levelTxt.y = 120;
hud.addChild(levelTxt);
-// Create a button to buy extra balls
+// Buy ball button
var buyBallButton = LK.getAsset('BuyBall50', {
size: 80,
fill: 0xFFFFFF,
anchorX: 0.5,
anchorY: 0,
y: 0,
x: -300
});
-var costText = new Text2('50', {
+var costText = new Text2(BALL_COST.toString(), {
size: 50,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0);
@@ -174,127 +348,235 @@
scaleX: 0.5,
scaleY: 0.5
});
buyBallButton.down = function () {
- if (score >= 50) {
- score -= 50; // Deduct points
- scoreTxt.setText(score.toString()); // Update score display
- createBall(); // Add a new ball
+ if (score >= BALL_COST) {
+ score -= BALL_COST;
+ scoreTxt.setText(score.toString());
+ createBall();
}
};
hud.addChild(buyBallButton);
-var balls = [];
-var bricks = [];
-var brickGrid = {}; // Spatial grid for bricks
-var score = 10000;
+/****
+* Game Functions
+****/
// Create and position bricks
function createBricks() {
- var _levelConfig$level, _levelConfig$level2;
- var totalBricks = ((_levelConfig$level = levelConfig[level]) === null || _levelConfig$level === void 0 ? void 0 : _levelConfig$level.totalBricks) || 50; // Default to 50 bricks
- var hitpoints = ((_levelConfig$level2 = levelConfig[level]) === null || _levelConfig$level2 === void 0 ? void 0 : _levelConfig$level2.hitpoints) || 1; // Default to 1 hitpoint
- var rows = Math.ceil(totalBricks / 10);
- var startX = 2048 / 2 - 10 * 160 / 2;
- var startY = 2632 / 2 - 5 * 120 / 2; // Adjusted to match game height (2632)
- brickGrid = {}; // Reset spatial grid
+ var _ref2 = levelConfig[level] || {},
+ _ref2$totalBricks = _ref2.totalBricks,
+ totalBricks = _ref2$totalBricks === void 0 ? 50 : _ref2$totalBricks,
+ _ref2$hitpoints = _ref2.hitpoints,
+ hitpoints = _ref2$hitpoints === void 0 ? 1 : _ref2$hitpoints,
+ _ref2$gridSize = _ref2.gridSize,
+ gridSize = _ref2$gridSize === void 0 ? 200 : _ref2$gridSize;
+ 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; // Move bricks higher
+ // Clear existing brick grid
+ brickGrid = {};
+ bricks = [];
for (var i = 0; i < rows; i++) {
- for (var j = 0; j < 10; j++) {
+ for (var j = 0; j < cols && i * cols + j < totalBricks; j++) {
var brick = new Brick();
- brick.x = startX + j * 160; // Center bricks horizontally
- brick.y = startY + i * 120; // Center bricks vertically
- brick.health = hitpoints; // Set brick health based on level
- brick.healthText.setText(brick.health.toString()); // Update health text
+ 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);
- // Add brick to spatial grid
- var gridSize = levelConfig[level] && levelConfig[level].gridSize || 200;
+ // Add to spatial grid for optimized collision detection
var gridX = Math.floor(brick.x / gridSize);
var gridY = Math.floor(brick.y / gridSize);
- var gridKey = gridX + ',' + gridY;
+ var gridKey = "".concat(gridX, ",").concat(gridY);
if (!brickGrid[gridKey]) {
brickGrid[gridKey] = [];
}
brickGrid[gridKey].push(brick);
}
}
+ // Store boundaries for optimization
+ brickGridBounds = {
+ minX: startX - BRICK_WIDTH / 2,
+ maxX: startX + totalWidth - BRICK_WIDTH / 2,
+ minY: startY - BRICK_HEIGHT / 2,
+ maxY: startY + totalHeight - BRICK_HEIGHT / 2
+ };
}
-// Create a new ball
+// Create a new ball with improved positioning
function createBall() {
var ball = new Ball();
- ball.x = 1024;
- ball.y = 2000;
- // Assign a random direction to the ball
- ball.direction.x = Math.random() < 0.5 ? -1 : 1;
- ball.direction.y = Math.random() < 0.5 ? -1 : 1;
+ // Position ball safely
+ var gridBottom = brickGridBounds ? brickGridBounds.maxY + 150 : GAME_HEIGHT * 0.7;
+ ball.x = GAME_WIDTH / 2 + (Math.random() * 200 - 100); // Slight randomization
+ ball.y = Math.min(gridBottom + 100, GAME_HEIGHT - BALL_RADIUS * 2);
+ // Random direction within a cone pointing upward
+ var angle = (Math.random() * 0.5 + 0.25) * Math.PI;
+ ball.direction.x = Math.cos(angle);
+ ball.direction.y = -Math.sin(angle);
+ // Normalize direction vector
+ var magnitude = Math.sqrt(ball.direction.x * ball.direction.x + ball.direction.y * ball.direction.y);
+ ball.direction.x /= magnitude;
+ ball.direction.y /= magnitude;
balls.push(ball);
game.addChild(ball);
}
-// Handle game updates
+// Handle game completion
+function handleLevelComplete() {
+ // Clean up existing objects
+ clearLevel();
+ if (level === Object.keys(levelConfig).length) {
+ // Game completed
+ var gameOverText = new Text2('Game Completed!', {
+ size: 150,
+ fill: 0xFFFFFF
+ });
+ gameOverText.anchor.set(0.5, 0.5);
+ gameOverText.x = GAME_WIDTH / 2;
+ gameOverText.y = GAME_HEIGHT / 2;
+ game.addChild(gameOverText);
+ var finalScoreText = new Text2('Final Score: ' + score, {
+ size: 100,
+ fill: 0xFFFFFF
+ });
+ finalScoreText.anchor.set(0.5, 0.5);
+ finalScoreText.x = GAME_WIDTH / 2;
+ finalScoreText.y = GAME_HEIGHT / 2 + 150;
+ game.addChild(finalScoreText);
+ LK.setTimeout(function () {
+ LK.showGameOver();
+ }, 3000);
+ } else {
+ // Next level
+ level += 1;
+ levelTxt.setText('Level: ' + level);
+ // Level transition effect/message
+ var levelText = new Text2('Level ' + level, {
+ size: 150,
+ fill: 0xFFFFFF
+ });
+ levelText.anchor.set(0.5, 0.5);
+ levelText.x = GAME_WIDTH / 2;
+ levelText.y = GAME_HEIGHT / 2;
+ game.addChild(levelText);
+ // Remove level text after 2 seconds and start new level
+ LK.setTimeout(function () {
+ levelText.destroy();
+ createBricks();
+ createBall();
+ }, 2000);
+ }
+}
+// Clear level objects
+function clearLevel() {
+ // Remove all balls
+ for (var i = balls.length - 1; i >= 0; i--) {
+ balls[i].destroy();
+ }
+ balls = [];
+ // Remove all power-ups
+ for (var i = powerUps.length - 1; i >= 0; i--) {
+ powerUps[i].destroy();
+ }
+ powerUps = [];
+ // Remove any remaining bricks
+ for (var i = bricks.length - 1; i >= 0; i--) {
+ bricks[i].destroy();
+ }
+ bricks = [];
+ brickGrid = {};
+}
+/****
+* Game Update Loop
+****/
game.update = function () {
- // Update balls
+ // Update all balls
for (var i = balls.length - 1; i >= 0; i--) {
var ball = balls[i];
ball.update();
- // Remove ball if it goes off screen
- if (ball.y > 2632) {
+ // Remove balls that fall below the screen
+ if (ball.y > GAME_HEIGHT + BALL_RADIUS) {
ball.destroy();
balls.splice(i, 1);
}
}
- // Check if all bricks are destroyed
+ // Update all power-ups
+ for (var i = powerUps.length - 1; i >= 0; i--) {
+ powerUps[i].update();
+ }
+ // Level completion check
if (bricks.length === 0) {
- // Check if it's the last level
- if (level === Object.keys(levelConfig).length) {
- LK.showGameOver(); // Show game over and reset game state
+ handleLevelComplete();
+ }
+ // Auto-create ball if all balls are lost
+ if (balls.length === 0) {
+ if (score >= BALL_COST) {
+ score -= Math.min(score, BALL_COST);
+ scoreTxt.setText(score.toString());
+ createBall();
} else {
- // Increase level
- level += 1;
- levelTxt.setText('Level: ' + level);
- createBricks(); // Create new bricks for the next level
+ // Game over
+ clearLevel();
+ LK.showGameOver();
}
}
- // Check for game over (spawn a new ball if none exist)
- if (balls.length === 0) {
- createBall();
- }
};
+/****
+* Input Handling
+****/
game.down = function (x, y, obj) {
- console.log("Player tapped the screen at coordinates: ", x, y);
- // Verify bricks array exists
+ // Manually hit bricks on click
if (!bricks || !Array.isArray(bricks)) {
- console.error("Bricks array is invalid");
return;
}
- // Define intersection check function
- function checkIntersection(brick, rect) {
- return brick.x < rect.x + rect.width && brick.x + brick.width > rect.x && brick.y < rect.y + rect.height && brick.y + brick.height > rect.y;
+ x = Number(x);
+ y = Number(y);
+ // Check if player clicked near the launch area to control ball direction
+ var controlAreaY = GAME_HEIGHT * 0.8;
+ if (y > controlAreaY) {
+ // Direct balls toward click point
+ for (var i = 0; i < balls.length; i++) {
+ var ball = balls[i];
+ // Only redirect balls below a certain Y position
+ if (ball.y > controlAreaY) {
+ // Calculate direction to click point
+ var dx = x - ball.x;
+ var dy = y - ball.y;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist > 0) {
+ ball.direction.x = dx / dist;
+ ball.direction.y = dy / dist;
+ // Force upward direction
+ if (ball.direction.y > 0) {
+ ball.direction.y *= -1;
+ // Re-normalize
+ var magnitude = Math.sqrt(ball.direction.x * ball.direction.x + ball.direction.y * ball.direction.y);
+ ball.direction.x /= magnitude;
+ ball.direction.y /= magnitude;
+ }
+ }
+ }
+ }
+ return;
}
- // Check if a brick was tapped
+ // Check for brick hits (cheat/debug feature)
for (var i = 0; i < bricks.length; i++) {
var brick = bricks[i];
- // Verify brick has required properties
if (!brick.x || !brick.y || !brick.width || !brick.height) {
- console.error("Brick missing required properties at index:", i);
continue;
}
- // Debug logging
- console.log("Checking brick:", i);
- console.log("Brick position:", brick.x, brick.y);
- console.log("Brick size:", brick.width, brick.height);
- // Convert coordinates to numbers and check collision
- x = Number(x);
- y = Number(y);
- if (checkIntersection(brick, {
- x: x,
- y: y,
- width: brick.width,
- height: brick.height
- })) {
- console.log("Player tapped brick at:", brick.x, brick.y);
- brick.hit(); // Trigger the hit function on the brick
- return; // Return after the first brick is hit
+ // Simple AABB collision check
+ 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();
+ return;
}
}
- console.log("No brick collision detected");
};
// Initialize game elements
createBricks();
createBall();
\ No newline at end of file