Code edit (1 edits merged)
Please save this source code
User prompt
use a new asset for particle effect, not splash ball
User prompt
lets add somoe particle effect when a block is destroyed
User prompt
Import of asset
Code edit (1 edits merged)
Please save this source code
User prompt
local storage button delete sholuld be next to the points ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
add a button to delete local storage ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
add local storage module ↪💡 Consider importing and using the following plugins: @upit/storage.v1
Code edit (1 edits merged)
Please save this source code
User prompt
add a main menu screen with the game title and a game start button. game should not start until game start is touched. main menu should cover the whole screen and the game should not be displayed.
User prompt
make numbers in brick bigge
User prompt
now some pricks are out of the screen. adjust columns and rows to adapt to thenew size of each brick
User prompt
can we make bricks bigger and adjust the grid accordingly. double their size
User prompt
create a home screen with the game title and a start game button
User prompt
reset points, player should start with 0 points unless they have points in storage ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
remove hardcoding of points
User prompt
add local storage to the game ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
make background marine blue
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'splashBallCost')' in or related to this line: 'var splashCostText = new Text2('$' + upgrades.splashBallCost.toString(), {' Line Number: 229
User prompt
do not reste points, level, upgrades costs on game start
User prompt
Please fix the bug: 'storage.load is not a function' in or related to this line: 'storage.load();' Line Number: 132 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
local storage is not working
User prompt
save points, level, balls purchased, and upgrades purchased in local storage so you continue next level from where you last playerd ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Progress is not being savesd in local sgtoras. Allshoudl be stored, level, upgrades, balls, evertyhig ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
all progress of game should be stored in local storage ↪💡 Consider importing and using the following plugins: @upit/storage.v1
/**** * Plugins ****/ var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'normal'; var asset = type === 'splash' ? 'splashBall' : type === 'sniper' ? 'sniperBall' : type === 'scatter' ? 'scatterBall' : type === 'smallScatter' ? 'smallScatter' : 'ball'; var ballGraphics = self.attachAsset(asset, { anchorX: 0.5, anchorY: 0.5 }); 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 }); 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(); } }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x3b9c9c }); /**** * Game Code ****/ // Smaller scatter fragments // Yellow for Scatter // Green for Sniper // Constants 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, 0x00ffcc, 0xccff00, 0xff6600, 0x66ffff, 0xff3366, 0xffcc00, 0x9966ff, 0x33cc33, 0xff0000]; // Game Variables 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; var brickGridBounds = null; function clearLocalStorage() { storage.score = 0; storage.level = 1; score = 0; level = 1; scoreTxt.setText('$' + score.toString()); levelTxt.setText('Level: ' + level); } // HUD Setup var hud = new Container(); LK.gui.top.addChild(hud); var scoreTxt = new Text2('0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.3, 0); scoreTxt.x += 200; hud.addChild(scoreTxt); var levelTxt = new Text2('Level: ' + level, { size: 60, fill: 0xFFFFFF }); levelTxt.anchor.set(1, 0); levelTxt.x = scoreTxt.width + 20; hud.addChild(levelTxt); // Ball Purchase Buttons function createBallButton(type, x, cost, asset) { var button = LK.getAsset('BuyBall50', { size: 80, fill: 0xFFFFFF, anchorX: 0.5, anchorY: 0, y: 0, x: x }); var costText = new Text2('$' + cost, { size: 50, fill: 0xFFFFFF }); costText.anchor.set(0.5, 0); costText.y = 100; button.addChild(costText); button.addChild(button.attachAsset(asset, { anchorX: 0.5, anchorY: -0.5, scaleX: 0.5, scaleY: 0.5 })); button.down = function () { if (score >= cost) { score -= cost; scoreTxt.setText('$' + score.toString()); createBall(type); } }; hud.addChild(button); } createBallButton('normal', -400, BALL_COST, 'ball'); createBallButton('splash', -280, upgrades.splashBallCost, 'splashBall'); createBallButton('sniper', -160, upgrades.sniperBallCost, 'sniperBall'); createBallButton('scatter', -40, upgrades.scatterBallCost, 'scatterBall'); var clearStorageButton = LK.getAsset('BuyBall50', { size: 80, fill: 0xFFFFFF, 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 bottomHud = new Container(); bottomHud.y = GAME_HEIGHT - 150; game.addChild(bottomHud); function createUpgradeButton(labelPrefix, x, costKey, upgradeKey, baseCost, iconType) { var button = LK.getAsset('BuyBall50', { size: 80, fill: 0xFFFFFF, anchorX: 0.5, anchorY: 0, x: x, y: 0 }); var costText = new Text2((baseCost * upgrades[upgradeKey]).toString(), { size: 50, fill: 0xFFFFFF }); costText.anchor.set(0.5, 0); costText.y = 100; button.addChild(costText); var labelText = new Text2("".concat(labelPrefix, " x").concat(upgrades[upgradeKey]), { size: 20, fill: 0xFFFFFF }); labelText.anchor.set(0.5, -0.5); button.addChild(labelText); if (iconType) { button.addChild(button.attachAsset(iconType, { anchorX: 0.5, anchorY: -0.5, scaleX: 0.5, scaleY: 0.5 })); } button.down = function () { 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]; } 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]; } }); } }; bottomHud.addChild(button); } // Extended Upgrade Buttons createUpgradeButton('Speed', GAME_WIDTH / 2 - 600, 'normalSpeedCost', 'normalSpeed', 50, 'ball'); createUpgradeButton('Power', GAME_WIDTH / 2 - 480, 'normalPowerCost', 'normalPower', 75, 'ball'); createUpgradeButton('Speed', GAME_WIDTH / 2 - 360, 'splashSpeedCost', 'splashSpeed', 50, 'splashBall'); createUpgradeButton('Power', GAME_WIDTH / 2 - 240, 'splashPowerCost', 'splashPower', 75, 'splashBall'); createUpgradeButton('Speed', GAME_WIDTH / 2 - 120, 'sniperSpeedCost', 'sniperSpeed', 75, 'sniperBall'); createUpgradeButton('Power', GAME_WIDTH / 2, 'sniperPowerCost', 'sniperPower', 100, 'sniperBall'); createUpgradeButton('Speed', GAME_WIDTH / 2 + 120, 'scatterSpeedCost', 'scatterSpeed', 50, 'scatterBall'); createUpgradeButton('Power', GAME_WIDTH / 2 + 240, 'scatterPowerCost', 'scatterPower', 75, 'scatterBall'); createUpgradeButton('Click', GAME_WIDTH / 2 + 360, 'clickCost', 'clickDamage', 25, null); // 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)); } }); } }); } 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, _toConsumableArray(bricks.map(function (b) { return b.x - BRICK_WIDTH / 2; }))), maxX: Math.max.apply(Math, _toConsumableArray(bricks.map(function (b) { return b.x + BRICK_WIDTH / 2; }))), minY: Math.min.apply(Math, _toConsumableArray(bricks.map(function (b) { return b.y - BRICK_HEIGHT / 2; }))), maxY: Math.max.apply(Math, _toConsumableArray(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 = 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(); } } 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();
===================================================================
--- original.js
+++ change.js
@@ -8,23 +8,33 @@
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'normal';
- var asset = type === 'splash' ? 'splashBall' : 'ball';
+ var asset = type === 'splash' ? 'splashBall' : type === 'sniper' ? 'sniperBall' : type === 'scatter' ? 'scatterBall' : type === 'smallScatter' ? 'smallScatter' : '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.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;
@@ -59,8 +69,14 @@
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);
}
@@ -96,15 +112,13 @@
self.health -= damage;
if (self.health <= 0) {
score += Math.max(1, Math.floor(self.maxHealth * 0.5));
scoreTxt.setText('$' + score.toString());
- storage.score = score; // Persist score to storage
+ storage.score = score;
var brickIndex = bricks.indexOf(self);
if (brickIndex !== -1) {
bricks.splice(brickIndex, 1);
}
- // Create particle effect at the brick's position before destroying
- createParticleEffect(self.x, self.y);
self.destroy();
} else {
self.healthText.setText(self.health.toString());
self.updateTint();
@@ -121,45 +135,11 @@
/****
* Game Code
****/
-function createParticleEffect(x, y) {
- // Create a container for the particle effect
- var particleContainer = new Container();
- game.addChild(particleContainer);
- // Create particles
- for (var i = 0; i < 20; i++) {
- var particle = LK.getAsset('particleEffect', {
- anchorX: 0.5,
- anchorY: 0.5,
- scaleX: 0.2,
- scaleY: 0.2
- });
- particle.x = x;
- particle.y = y;
- particle.direction = {
- x: (Math.random() - 0.5) * 2,
- y: (Math.random() - 0.5) * 2
- };
- particle.speed = Math.random() * 5 + 2;
- particleContainer.addChild(particle);
- }
- // Update particles
- particleContainer.update = function () {
- for (var i = particleContainer.children.length - 1; i >= 0; i--) {
- var p = particleContainer.children[i];
- p.x += p.direction.x * p.speed;
- p.y += p.direction.y * p.speed;
- p.alpha -= 0.02;
- if (p.alpha <= 0) {
- particleContainer.removeChild(p);
- }
- }
- if (particleContainer.children.length === 0) {
- game.removeChild(particleContainer);
- }
- };
-}
+// Smaller scatter fragments
+// Yellow for Scatter
+// Green for Sniper
// Constants
function _toConsumableArray(r) {
return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
}
@@ -195,66 +175,73 @@
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2632;
var BALL_RADIUS = 50;
var BRICK_WIDTH = 300;
-var BRICK_HEIGHT = 99; // Adjusted to match asset definition
+var BRICK_HEIGHT = 99;
var BALL_COST = 50;
var LEVEL_COLORS = [0xff00ff, 0x00ffcc, 0xccff00, 0xff6600, 0x66ffff, 0xff3366, 0xffcc00, 0x9966ff, 0x33cc33, 0xff0000];
// Game Variables
var levelConfig = {
1: {
totalBricks: 30,
- // Fewer bricks for mobile visibility
hitpoints: 1,
gridSize: 400,
- // Larger grid for simpler collision
- pattern: 'grid' // Standard grid layout
+ pattern: 'grid'
},
2: {
totalBricks: 50,
hitpoints: 2,
gridSize: 360,
- pattern: 'staggered' // Offset rows for a "zigzag" feel
+ pattern: 'staggered'
},
3: {
totalBricks: 70,
hitpoints: 3,
gridSize: 320,
- pattern: 'clustered' // Tighter clusters of bricks
+ pattern: 'clustered'
},
4: {
totalBricks: 90,
hitpoints: 4,
gridSize: 280,
- pattern: 'diagonal' // Diagonal line pattern
+ pattern: 'diagonal'
},
5: {
totalBricks: 110,
hitpoints: 5,
gridSize: 240,
- pattern: 'sparse' // Spread out with gaps
+ 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
+ splashBallCost: 100,
+ sniperBallCost: 150,
+ scatterBallCost: 125
};
var balls = [];
var bricks = [];
var brickGrid = {};
-var score = storage.score || 0; // Retrieve score from storage or set to 0
-var level = storage.level || 1; // Retrieve level from storage or set to 1
+var score = storage.score || 0;
+var level = storage.level || 1;
var brickGridBounds = null;
-// Function to clear local storage
function clearLocalStorage() {
storage.score = 0;
storage.level = 1;
score = 0;
@@ -264,9 +251,8 @@
}
// HUD Setup
var hud = new Container();
LK.gui.top.addChild(hud);
-// Upper-Left: Score, Level, Ball Purchases
var scoreTxt = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
@@ -279,67 +265,44 @@
});
levelTxt.anchor.set(1, 0);
levelTxt.x = scoreTxt.width + 20;
hud.addChild(levelTxt);
-var buyNormalButton = LK.getAsset('BuyBall50', {
- size: 80,
- fill: 0xFFFFFF,
- anchorX: 0.5,
- anchorY: 0,
- y: 0,
- x: -400
-});
-var normalCostText = new Text2('$' + BALL_COST.toString(), {
- size: 50,
- fill: 0xFFFFFF
-});
-normalCostText.anchor.set(0.5, 0);
-normalCostText.y = 100;
-buyNormalButton.addChild(normalCostText);
-buyNormalButton.addChild(buyNormalButton.attachAsset('ball', {
- anchorX: 0.5,
- anchorY: -0.5,
- scaleX: 0.5,
- scaleY: 0.5
-}));
-buyNormalButton.down = function () {
- if (score >= BALL_COST) {
- score -= BALL_COST;
- scoreTxt.setText('$' + score.toString());
- createBall('normal');
- }
-};
-hud.addChild(buyNormalButton);
-var buySplashButton = LK.getAsset('BuyBall50', {
- size: 80,
- fill: 0xFFFFFF,
- anchorX: 0.5,
- anchorY: 0,
- y: 0,
- x: -280
-});
-var splashCostText = new Text2('$' + upgrades.splashBallCost.toString(), {
- size: 50,
- fill: 0xFFFFFF
-});
-splashCostText.anchor.set(0.5, 0);
-splashCostText.y = 100;
-buySplashButton.addChild(splashCostText);
-buySplashButton.addChild(buySplashButton.attachAsset('splashBall', {
- anchorX: 0.5,
- anchorY: -0.5,
- scaleX: 0.5,
- scaleY: 0.5
-}));
-buySplashButton.down = function () {
- if (score >= upgrades.splashBallCost) {
- score -= upgrades.splashBallCost;
- scoreTxt.setText('$' + score.toString());
- createBall('splash');
- }
-};
-hud.addChild(buySplashButton);
-// Button to clear local storage
+// Ball Purchase Buttons
+function createBallButton(type, x, cost, asset) {
+ var button = LK.getAsset('BuyBall50', {
+ size: 80,
+ fill: 0xFFFFFF,
+ anchorX: 0.5,
+ anchorY: 0,
+ y: 0,
+ x: x
+ });
+ var costText = new Text2('$' + cost, {
+ size: 50,
+ fill: 0xFFFFFF
+ });
+ costText.anchor.set(0.5, 0);
+ costText.y = 100;
+ button.addChild(costText);
+ button.addChild(button.attachAsset(asset, {
+ anchorX: 0.5,
+ anchorY: -0.5,
+ scaleX: 0.5,
+ scaleY: 0.5
+ }));
+ button.down = function () {
+ if (score >= cost) {
+ score -= cost;
+ scoreTxt.setText('$' + score.toString());
+ createBall(type);
+ }
+ };
+ hud.addChild(button);
+}
+createBallButton('normal', -400, BALL_COST, 'ball');
+createBallButton('splash', -280, upgrades.splashBallCost, 'splashBall');
+createBallButton('sniper', -160, upgrades.sniperBallCost, 'sniperBall');
+createBallButton('scatter', -40, upgrades.scatterBallCost, 'scatterBall');
var clearStorageButton = LK.getAsset('BuyBall50', {
size: 80,
fill: 0xFFFFFF,
anchorX: 0.5,
@@ -353,13 +316,10 @@
});
clearStorageText.anchor.set(0.5, 0);
clearStorageText.y = 100;
clearStorageButton.addChild(clearStorageText);
-clearStorageButton.down = function () {
- clearLocalStorage();
-};
+clearStorageButton.down = clearLocalStorage;
hud.addChild(clearStorageButton);
-// Bottom: Upgrade Buttons
var bottomHud = new Container();
bottomHud.y = GAME_HEIGHT - 150;
game.addChild(bottomHud);
function createUpgradeButton(labelPrefix, x, costKey, upgradeKey, baseCost, iconType) {
@@ -404,20 +364,28 @@
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];
}
});
}
};
bottomHud.addChild(button);
}
-// Upgrade buttons with icons for ball-specific upgrades
-createUpgradeButton('Speed', GAME_WIDTH / 2 - 480, 'normalSpeedCost', 'normalSpeed', 50, 'ball');
-createUpgradeButton('Power', GAME_WIDTH / 2 - 360, 'normalPowerCost', 'normalPower', 75, 'ball');
-createUpgradeButton('Speed', GAME_WIDTH / 2 - 240, 'splashSpeedCost', 'splashSpeed', 50, 'splashBall');
-createUpgradeButton('Power', GAME_WIDTH / 2 - 120, 'splashPowerCost', 'splashPower', 75, 'splashBall');
-createUpgradeButton('Click', GAME_WIDTH / 2, 'clickCost', 'clickDamage', 25, null); // No icon for Click
+// Extended Upgrade Buttons
+createUpgradeButton('Speed', GAME_WIDTH / 2 - 600, 'normalSpeedCost', 'normalSpeed', 50, 'ball');
+createUpgradeButton('Power', GAME_WIDTH / 2 - 480, 'normalPowerCost', 'normalPower', 75, 'ball');
+createUpgradeButton('Speed', GAME_WIDTH / 2 - 360, 'splashSpeedCost', 'splashSpeed', 50, 'splashBall');
+createUpgradeButton('Power', GAME_WIDTH / 2 - 240, 'splashPowerCost', 'splashPower', 75, 'splashBall');
+createUpgradeButton('Speed', GAME_WIDTH / 2 - 120, 'sniperSpeedCost', 'sniperSpeed', 75, 'sniperBall');
+createUpgradeButton('Power', GAME_WIDTH / 2, 'sniperPowerCost', 'sniperPower', 100, 'sniperBall');
+createUpgradeButton('Speed', GAME_WIDTH / 2 + 120, 'scatterSpeedCost', 'scatterSpeed', 50, 'scatterBall');
+createUpgradeButton('Power', GAME_WIDTH / 2 + 240, 'scatterPowerCost', 'scatterPower', 75, 'scatterBall');
+createUpgradeButton('Click', GAME_WIDTH / 2 + 360, 'clickCost', 'clickDamage', 25, null);
// Helper Functions
function handleBallBrickCollision(ball, brick) {
var relativeX = (ball.x - brick.x) / (brick.width / 2);
var relativeY = (ball.y - brick.y) / (brick.height / 2);
@@ -446,8 +414,34 @@
});
}
});
}
+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;
}
@@ -583,9 +577,9 @@
if (level === Object.keys(levelConfig).length) {
LK.showGameOver();
} else {
level += 1;
- storage.level = level; // Persist level to storage
+ storage.level = level;
levelTxt.setText('Level: ' + level);
createBricks();
}
}