User prompt
If bubble7 is selected, make hintbubble navy blue
User prompt
remove 9 colours
User prompt
If bubble6 is selected, make hintbubble orange
User prompt
If bubble5 is selected, make hint bubble cyan
User prompt
If bubble4 is selected, make hintbubble purple
User prompt
If bubble3 is selected, make hintbubble yellow
User prompt
Remove 8 colour and 9 colour
User prompt
Iron bubbles must fall when there is no connection with any bubbles like normal bubbles fall and give score like normal bubbles give score
User prompt
Put iron bubbles like normal bubbles if yes
User prompt
If player say yes to iron bubbles. The whole score must be %30 higher
User prompt
After selecting colors, menu must ask whether player wants iron bubbles or not
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'toString')' in or related to this line: 'var label = new Text2(score, {' Line Number: 839
Code edit (2 edits merged)
Please save this source code
User prompt
Gameoverjingle don't play fully. The sound must play full length
User prompt
But when game over jingle is not playing
User prompt
gameoverjingle must be played when game over
User prompt
We can switch between next ball by pressing the icon that showing next ball
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'toString')' in or related to this line: 'var label = new Text2(score, {' Line Number: 790
Code edit (4 edits merged)
Please save this source code
User prompt
There should be a score multiplier ball numbers after 3 colors. This multiplier should increase at higher numbers
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
The view of the menu is another background from the gameplay screen
User prompt
We musn't be able to play game before selecting the choice
User prompt
Menu must be at the center of the screen
/**** * Classes ****/ var Barrier = Container.expand(function () { var self = Container.call(this); var barrierGraphics = self.attachAsset('barrier', { anchorX: .5, anchorY: .5 }); }); var BonusUX = Container.expand(function () { var self = Container.call(this); //Insert label here var barHeight = 50; var bonusLabel = self.addChild(new Text2('Streak Bonus', { size: 90, fill: 0xF4F5FF, font: "Impact" })); var bonusAmountLabel = self.addChild(new Text2('1x', { size: 170, fill: 0xF4F5FF, font: "Impact" })); bonusLabel.anchor.set(1, 1); bonusLabel.y = barHeight / 2; var rightMargin = -10; bonusLabel.x = rightMargin; bonusAmountLabel.anchor.set(.5, .5); bonusAmountLabel.x = 100; var bonusBarWidth = bonusLabel.width; var bonusBarStart = self.attachAsset('bonusend', { y: 30, x: -bonusBarWidth + rightMargin }); var bonuseBarEnd = self.attachAsset('bonusend', { y: 30, x: -bonusBarWidth + rightMargin }); var bonusBarMiddle = self.attachAsset('bonusbarmiddle', { y: 30, x: -bonusBarWidth + rightMargin + barHeight / 2, width: 0 }); self.x = game.width - 270; self.y = game.height - 145; var bonusBarStepSize = (bonusBarWidth - barHeight) / 5; var targetWidth = 0; var currentWidth = 0; var jumpToAtEnd = 0; self.bonusAmount = 1; self.streakCount = 0; var maxLevel = 40; self.setStreakCount = function (level) { self.streakCount = Math.min(level, maxLevel); var newBonus = Math.floor(self.streakCount / 5) + 1; if (newBonus != self.bonusAmount) { for (var a = 0; a < scoreMultipliers.length; a++) { scoreMultipliers[a].setMultiplier(newBonus); } } self.bonusAmount = newBonus; bonusAmountLabel.setText(self.bonusAmount + 'x'); var newbarpos = level >= maxLevel ? 5 : level % 5; targetWidth = newbarpos * bonusBarStepSize; jumpToAtEnd = targetWidth; if (newbarpos == 0 && level > 0) { targetWidth = 5 * bonusBarStepSize; jumpToAtEnd = 0; } }; self.update = function () { var delta = targetWidth - currentWidth; if (delta < 1) { targetWidth = currentWidth = jumpToAtEnd; } else { currentWidth += delta / 8; } bonuseBarEnd.x = -bonusBarWidth + currentWidth + rightMargin; bonusBarMiddle.width = currentWidth; }; // bonuseBarEnd.x = -bonusLabel.width; }); var Bubble = Container.expand(function (max_types, isFireBall, type) { var self = Container.call(this); self.isFireBall = isFireBall; var state = 0; self.isAttached = true; self.isFreeBubble = false; var speedX = 0; var speedY = 0; self.targetX = 0; self.targetY = 0; self.setPos = function (x, y) { self.x = self.targetX = x; self.y = self.targetY = y; }; if (type !== undefined) { this.type = type; } else { max_types = max_types || 3; if (max_types > 4) { self.type = Math.floor(Math.random() * (.8 + Math.random() * .2) * max_types); } else { self.type = Math.floor(Math.random() * max_types); } } if (isFireBall) { var bubbleGraphics = self.attachAsset('fireball', { anchorX: 0.5, anchorY: 0.5 }); bubbleGraphics.width = 150; bubbleGraphics.height = 150; } else { var bubbleGraphics = self.attachAsset('bubble' + self.type, { anchorX: 0.5, anchorY: 0.5 }); } /*if (!isFireBall && self.type > 1) { bubbleGraphics.tint = bubbleColors[self.type]; }*/ self.detach = function () { freeBubbleLayer.addChild(self); LK.getSound('detachCircle').play(); self.y += grid.y; self.isAttached = false; speedX = Math.random() * 40 - 20; speedY = -Math.random() * 30; self.down = undefined; }; var spawnMod = 0; self.update = function () { if (self.isFreeBubble) { if (isFireBall) { if (++spawnMod % 2 == 0 && self.parent) { // Spawn fire particles every 5 ticks var angle = Math.random() * Math.PI * 2; var fireParticle = self.parent.addChild(new FireParticle(angle)); fireParticle.x = self.x + Math.cos(angle) * self.width / 4; fireParticle.y = self.y + Math.sin(angle) * self.width / 4; } } return; } if (self.isAttached) { if (self.x != self.targetX) { self.x += (self.targetX - self.x) / 10; } if (self.y != self.targetY) { self.y += (self.targetY - self.y) / 10; } } else { self.x += speedX; self.y += speedY; speedY += 1.5; if (self.x < bubbleSize / 2 && speedX < 0 || self.x > game.width - bubbleSize / 2 && speedX > 0) { speedX = -speedX; LK.getSound('circleBounce').play(); } // Check for collision with barriers for (var i = 0; i < barriers.length; i++) { var barrier = barriers[i]; var dx = self.x - barrier.x; var dy = self.y - barrier.y; var distance = Math.sqrt(dx * dx + dy * dy); var minDist = bubbleSize / 2 + barrier.width / 2; if (distance < minDist) { // Calculate the angle of the collision var angle = Math.atan2(dy, dx); // Calculate the new speed based on the angle of collision, treating the barrier as a static billiard ball var newSpeed = Math.sqrt(speedX * speedX + speedY * speedY); speedX = Math.cos(angle) * newSpeed * .7; speedY = Math.sin(angle) * newSpeed * .7; // Move the bubble back to the point where it just touches the barrier var overlap = minDist - distance; self.x += overlap * Math.cos(angle); self.y += overlap * Math.sin(angle); LK.getSound('circleBounce').play(); } } // Remove unattached bubbles that fall below 2732 - 500 if (self.y > 2732 - 400) { self.destroy(); scoreMultipliers[Math.floor(self.x / (2048 / 5))].applyBubble(self); LK.getSound('scoreCollected').play(); } } }; }); var BubbleRemoveParticle = Container.expand(function () { var self = Container.call(this); var particle = self.attachAsset('removebubbleeffect', { anchorX: 0.5, anchorY: 0.5 }); particle.blendMode = 1; self.scale.set(.33, .33); var cscale = .5; self.update = function () { cscale += .02; self.scale.set(cscale, cscale); self.alpha = 1 - (cscale - .5) * 1.5; if (self.alpha < 0) { self.destroy(); } }; }); var FireBallPowerupOverlay = Container.expand(function () { var self = Container.call(this); var bubbleGraphics = self.attachAsset('fireball', { anchorX: 0.5, anchorY: 0.5 }); self.y = game.height - 140; self.x = 200; var countBG = self.attachAsset('countbg', { anchorX: 0.5, anchorY: 0.5 }); countBG.x = 90; countBG.y = 50; self.fireballsLeft = 1; var label = self.addChild(new Text2(self.fireballsLeft, { size: 70, fill: 0xFFFFFF, font: "Impact", stroke: 0x000000, strokeThickness: 13 })); label.anchor.set(.5, .5); label.x = 90; label.y = 50; self.down = function () { if (self.fireballsLeft > 0 && !launcher.isFireBall()) { self.fireballsLeft--; label.setText(self.fireballsLeft); launcher.triggerFireBall(); if (self.fireballsLeft == 0) { self.alpha = .5; } } }; }); var FireParticle = Container.expand(function (angle) { var self = Container.call(this); var particleGraphics = self.attachAsset('fireparticle', { anchorX: 0.5, anchorY: 0.5 }); particleGraphics.blendMode = 1; var speedX = Math.cos(angle) * 1; var speedY = Math.sin(angle) * 1; var rotationSpeed = Math.random() * 0.1 - 0.05; self.update = function () { self.x += speedX * self.alpha; self.y += speedY * self.alpha; particleGraphics.rotation += rotationSpeed; self.alpha -= 0.01; if (self.alpha <= 0) { self.destroy(); } }; }); var Grid = Container.expand(function () { var self = Container.call(this); var rows = []; self.container = self.addChild(new Container()); var rowCount = 0; function insertRow() { var row = []; var rowWidth = rowCount % 2 == 0 ? 13 : 12; for (var a = 0; a < rowWidth; a++) { var bubble; // If iron bubbles are enabled, randomly place iron bubbles with a certain probability (e.g., 1 in 7) if (typeof ironBubblesEnabled !== "undefined" && ironBubblesEnabled && Math.random() < 1 / 7) { // Create an iron bubble using the ironbubble asset bubble = new Container(); var ironBubbleGraphics = bubble.attachAsset('ironbubble', { anchorX: 0.5, anchorY: 0.5 }); // Mark as iron bubble for game logic bubble.isIronBubble = true; // Set position bubble.setPos = function (x, y) { bubble.x = bubble.targetX = x; bubble.y = bubble.targetY = y; }; bubble.setPos((2048 - bubbleSize * rowWidth) / 2 + bubbleSize * a + bubbleSize / 2, -rowCount * (1.7320508076 * bubbleSize) / 2); // Iron bubbles are not fireballs and have no type bubble.isFireBall = false; bubble.type = -1; // For compatibility with grid logic bubble.isAttached = true; bubble.isFreeBubble = false; // Dummy detach for iron bubbles bubble.detach = function () { freeBubbleLayer.addChild(bubble); bubble.y += grid.y; bubble.isAttached = false; }; // Dummy update for iron bubbles bubble.update = function () {}; } else { bubble = new Bubble(getMaxTypes()); bubble.setPos((2048 - bubbleSize * rowWidth) / 2 + bubbleSize * a + bubbleSize / 2, -rowCount * (1.7320508076 * bubbleSize) / 2); } self.container.addChild(bubble); row.push(bubble); /*bubble.down = function () { var bubbles = self.getConnectedBubbles(this); self.removeBubbles(bubbles); var disconnected = self.getDetachedBubbles(); self.removeBubbles(disconnected); };*/ } rows.push(row); rowCount++; } //Method that removes an array of bubbles from the rows array. self.removeBubbles = function (bubbles) { for (var i = 0; i < bubbles.length; i++) { var bubble = bubbles[i]; if (bubble) { var bubbleIndex = this.findBubbleIndex(bubble); if (bubbleIndex) { rows[bubbleIndex.row][bubbleIndex.col] = null; bubble.detach(); } } } }; self.getConnectedBubbles = function (bubble, ignoreType) { var connectedBubbles = []; var queue = [bubble]; var visited = []; while (queue.length > 0) { var currentBubble = queue.shift(); if (visited.indexOf(currentBubble) === -1) { visited.push(currentBubble); connectedBubbles.push(currentBubble); var neighbors = self.getNeighbors(currentBubble); for (var i = 0; i < neighbors.length; i++) { var neighbor = neighbors[i]; if (neighbor && (neighbor.type === bubble.type || ignoreType)) { queue.push(neighbor); } } } } return connectedBubbles; }; //Get a list of bubbles that are not connected to the top row, or to a chain of bubbles connected to the top row. self.getDetachedBubbles = function () { var detachedBubbles = []; var connectedToTop = []; // Mark all bubbles connected to the bottom row var lastRowIndex = rows.length - 1; for (var i = 0; i < rows[lastRowIndex].length; i++) { if (rows[lastRowIndex][i] !== null) { var bottomConnected = self.getConnectedBubbles(rows[lastRowIndex][i], true); connectedToTop = connectedToTop.concat(bottomConnected); } } // Mark all bubbles as visited or not var visited = connectedToTop.filter(function (bubble) { return bubble != null; }); // Find all bubbles that are not visited and not connected to the top for (var row = 0; row < rows.length - 1; row++) { for (var col = 0; col < rows[row].length; col++) { var bubble = rows[row][col]; if (bubble !== null && visited.indexOf(bubble) == -1) { detachedBubbles.push(bubble); } } } return detachedBubbles; }; self.getNeighbors = function (bubble) { var neighbors = []; var bubbleIndex = this.findBubbleIndex(bubble); if (!bubbleIndex) { return []; } var directions = [[-1, 0], [1, 0], // left and right [0, -1], [0, 1], // above and below [-1, -1], [1, -1] // diagonals for even rows ]; if (bubbleIndex && rows[bubbleIndex.row] && rows[bubbleIndex.row].length == 12) { // Adjust diagonals for odd rows directions[4] = [-1, 1]; directions[5] = [1, 1]; } for (var i = 0; i < directions.length; i++) { var dir = directions[i]; if (bubbleIndex && rows[bubbleIndex.row]) { var newRow = bubbleIndex.row + dir[0]; } var newCol = bubbleIndex.col + dir[1]; if (newRow >= 0 && newRow < rows.length && newCol >= 0 && newCol < rows[newRow].length) { neighbors.push(rows[newRow][newCol]); } } return neighbors; }; self.findBubbleIndex = function (bubble) { for (var row = 0; row < rows.length; row++) { var col = rows[row].indexOf(bubble); if (col !== -1) { return { row: row, col: col }; } } return null; }; self.printRowsToConsole = function () { var gridString = ''; for (var i = rows.length - 1; i >= 0; i--) { var rowString = ': ' + (rows[i].length == 13 ? '' : ' '); for (var j = 0; j < rows[i].length; j++) { var bubble = rows[i][j]; rowString += bubble ? '[' + bubble.type + ']' : '[_]'; } gridString += rowString + '\n'; } console.log(gridString); }; // Method to calculate path of movement based on angle and starting point //TODO: MAKE THIS MUCH FASTER! self.bubbleIntersectsGrid = function (nextX, nextY) { outer: for (var row = 0; row < rows.length; row++) { for (var col = 0; col < rows[row].length; col++) { var bubble = rows[row][col]; if (bubble) { var dist = nextY - bubble.y - self.y; //Quick exit if we are nowhere near the row if (dist > 145 || dist < -145) { continue outer; } var dx = nextX - bubble.x - self.x; var dy = nextY - bubble.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < (bubbleSize - 70) / 2 + bubbleSize / 2) { return bubble; } } } } return false; }; self.calculatePath = function (startPoint, angle) { var path = []; var currentPoint = { x: startPoint.x, y: startPoint.y }; var radians = angle; var stepSize = 4; var hitBubble = false; while (currentPoint.y > 0 && !hitBubble) { // Calculate next point var nextX = currentPoint.x + stepSize * Math.cos(radians); var nextY = currentPoint.y + stepSize * Math.sin(radians); // Check for wall collisions if (nextX < 150 / 2 || nextX > 2048 - 150 / 2) { radians = Math.PI - radians; // Reflect angle nextX = currentPoint.x + stepSize * Math.cos(radians); // Recalculate nextX after reflection } hitBubble = self.bubbleIntersectsGrid(nextX, nextY); // Add point to path and update currentPoint path.push({ x: nextX, y: nextY }); currentPoint.x = nextX; currentPoint.y = nextY; } if (hitBubble) { //Only increase avilable bubble type when we have actually pointed as such a bubble if (hitBubble.type + 1 > maxSelectableBubble) { maxSelectableBubble = hitBubble.type + 1; } ; } return path; }; var bubblesInFlight = []; self.fireBubble = function (bubble, angle) { self.addChild(bubble); bubble.x = launcher.x; bubble.y += launcher.y - self.y; bubblesInFlight.push({ bubble: bubble, angle: angle }); }; self.calculateWarningScoreList = function () { var warningScores = []; for (var i = 0; i < 13; i++) { warningScores.push(0); // Initialize all scores to 0 } // Calculate the distance from the bottom for each bubble and increment the warning score based on proximity for (var row = 0; row < rows.length; row++) { for (var col = 0; col < rows[row].length; col++) { var bubble = rows[row][col]; if (bubble) { var distanceFromBottom = 2732 - (bubble.y + self.y); if (distanceFromBottom < 2000) { // If a bubble is within 500px from the bottom var columnIndex = Math.floor(bubble.x / (2048 / 13)); warningScores[columnIndex] += (2000 - distanceFromBottom) / 2000; // Increment the warning score for the column } } } } return warningScores; }; self.update = function () { outer: for (var a = 0; a < bubblesInFlight.length; a++) { var current = bubblesInFlight[a]; var bubble = current.bubble; var nextX = bubble.x; var nextY = bubble.y + gridSpeed; var prevX = bubble.x; var prevY = bubble.y; for (var rep = 0; rep < 25; rep++) { prevX = nextX; prevY = nextY; nextX += Math.cos(current.angle) * 4; nextY += Math.sin(current.angle) * 4; if (nextX < 150 / 2 || nextX > 2048 - 150 / 2) { current.angle = Math.PI - current.angle; // Reflect angle nextX = Math.min(Math.max(nextX, 150 / 2), 2048 - 150 / 2); LK.getSound('circleBounce').play(); } var intersectedBubble = self.bubbleIntersectsGrid(nextX + self.x, nextY + self.y); if (intersectedBubble) { gameIsStarted = true; if (bubble.isFireBall) { self.removeBubbles([intersectedBubble]); var disconnected = self.getDetachedBubbles(); self.removeBubbles(disconnected); } else { var intersectedBubblePos = self.findBubbleIndex(intersectedBubble); var colOffset = rows[intersectedBubblePos.row].length == 13 ? 0 : 1; var offsetPositions = [{ x: intersectedBubble.targetX - bubbleSize / 2, y: intersectedBubble.targetY - 1.7320508076 * bubbleSize / 2, ro: intersectedBubblePos.row + 1, co: intersectedBubblePos.col - 1 + colOffset }, { x: intersectedBubble.targetX + bubbleSize / 2, y: intersectedBubble.targetY - 1.7320508076 * bubbleSize / 2, ro: intersectedBubblePos.row + 1, co: intersectedBubblePos.col + colOffset }, { x: intersectedBubble.targetX + bubbleSize, y: intersectedBubble.targetY, ro: intersectedBubblePos.row, co: intersectedBubblePos.col + 1 }, { x: intersectedBubble.targetX + bubbleSize / 2, y: intersectedBubble.targetY + 1.7320508076 * bubbleSize / 2, ro: intersectedBubblePos.row - 1, co: intersectedBubblePos.col + colOffset }, { x: intersectedBubble.targetX - bubbleSize / 2, y: intersectedBubble.targetY + 1.7320508076 * bubbleSize / 2, ro: intersectedBubblePos.row - 1, co: intersectedBubblePos.col - 1 + colOffset }, { x: intersectedBubble.targetX - bubbleSize, y: intersectedBubble.targetY, ro: intersectedBubblePos.row, co: intersectedBubblePos.col - 1 }]; var closestPosition = 0; var closestDistance = Math.sqrt(Math.pow(offsetPositions[0].x - bubble.x, 2) + Math.pow(offsetPositions[0].y - bubble.y, 2)); for (var i = 1; i < offsetPositions.length; i++) { var currentPosition = offsetPositions[i]; var currentDistance = Math.sqrt(Math.pow(currentPosition.x - bubble.x, 2) + Math.pow(currentPosition.y - bubble.y, 2)); if (currentDistance < closestDistance) { var row = rows[currentPosition.ro]; if (currentPosition.co < 0) { continue; } if (row) { if (row[currentPosition.co]) { continue; } if (currentPosition.co >= row.length) { continue; } } else { var newRowLength = rows[intersectedBubblePos.row].length == 13 ? 12 : 13; if (currentPosition.co >= newRowLength) { continue; } } closestDistance = currentDistance; closestPosition = i; } } // Attach bubble to the closest position var currentMatch = offsetPositions[closestPosition]; bubble.x = prevX; bubble.y = prevY; bubble.targetX = currentMatch.x; bubble.targetY = currentMatch.y; bubble.isFreeBubble = false; var row = rows[offsetPositions[closestPosition].ro]; if (!row) { if (rows[intersectedBubblePos.row].length == 13) { row = [null, null, null, null, null, null, null, null, null, null, null, null]; } else { row = [null, null, null, null, null, null, null, null, null, null, null, null, null]; } rows.unshift(row); } row[offsetPositions[closestPosition].co] = bubble; bubblesInFlight.splice(a--, 1); refreshHintLine(); var bubbles = self.getConnectedBubbles(bubble); if (bubbles.length > 2) { self.removeBubbles(bubbles); var disconnected = self.getDetachedBubbles(); self.removeBubbles(disconnected); bonusUX.setStreakCount(bonusUX.streakCount + 1); } else { bonusUX.setStreakCount(0); LK.getSound('attachCircle').play(); } //Add a grid movement effect when you don't do a match var neighbors = self.getNeighbors(bubble); var touched = []; var neighbors2 = []; for (var i = 0; i < neighbors.length; i++) { var neighbor = neighbors[i]; if (neighbor) { touched.push(neighbor); neighbors2 = neighbors2.concat(self.getNeighbors(neighbor)); var ox = neighbor.x - bubble.x; var oy = neighbor.y - bubble.y; var angle = Math.atan2(oy, ox); neighbor.x += Math.cos(angle) * 20; neighbor.y += Math.sin(angle) * 20; } } //One more layer for (var i = 0; i < neighbors2.length; i++) { var neighbor = neighbors2[i]; if (neighbor && touched.indexOf(neighbor) == -1) { touched.push(neighbor); var ox = neighbor.x - bubble.x; var oy = neighbor.y - bubble.y; var angle = Math.atan2(oy, ox); neighbor.x += Math.cos(angle) * 10; neighbor.y += Math.sin(angle) * 10; } } //self.printRowsToConsole(); continue outer; } } } bubble.x = nextX; bubble.y = nextY; if (bubble.y + self.y < -1000) { //Destory bubbles that somehow manages to escape at the top bubblesInFlight.splice(a--, 1); bubble.destroy(); } } if (gameIsStarted) { self.y += gridSpeed; } var zeroRow = rows[rows.length - 1]; if (zeroRow) { for (var a = 0; a < zeroRow.length; a++) { var bubble = zeroRow[a]; if (bubble) { if (bubble.y + self.y > 0) { insertRow(); } break; } } } else { insertRow(); } for (var row = rows.length - 1; row >= 0; row--) { if (rows[row].every(function (bubble) { return !bubble; })) { rows.splice(row, 1); } } var lastRow = rows[0]; /*if(LK.ticks % 10 == 0){ self.printRowsToConsole() }*/ if (lastRow) { for (var a = 0; a < zeroRow.length; a++) { var bubble = lastRow[a]; if (bubble) { if (bubble.y + self.y > 2200) { LK.effects.flashScreen(0xff0000, 3000); if (!self._gameOverTriggered) { self._gameOverTriggered = true; var jingle = LK.getSound('gameOverJingle'); jingle.stop(); // Ensure not overlapping jingle.play(); // Play game over only after jingle finishes (duration = end - start) // The jingle is defined with start:0, end:1 (full length), so we need to know the actual duration in ms. // If not available, default to 2000ms (safe fallback for most short jingles) var duration = jingle.duration && typeof jingle.duration === "number" ? jingle.duration * 1000 : 2000; LK.setTimeout(function () { LK.showGameOver(); }, duration); } return; // Prevent further processing after game over } if (gameIsStarted) { var targetSpeed = Math.pow(Math.pow((2200 - (bubble.y + self.y)) / 2200, 2), 2) * 4 + 0.5; if (bubble.y + self.y > 2000) { targetSpeed = .2; } gridSpeed += (targetSpeed - gridSpeed) / 20; if (LK.ticks % 10 == 0) { //console.log(gridSpeed) } } break; } } } }; for (var a = 0; a < 8; a++) { insertRow(); } }); var HintBubble = Container.expand(function () { var self = Container.call(this); var bubble = self.attachAsset('hintbubble', { anchorX: 0.5, anchorY: 0.5 }); self.setTint = function (tint) { bubble.tint = tint; }; self.getTint = function (tint) { return bubble.tint; }; }); var Launcher = Container.expand(function () { var self = Container.call(this); var bubble = self.addChild(new Bubble(getMaxTypes(), false)); bubble.isFreeBubble = true; var previewBubble; var lastTypes = [undefined, bubble.type]; function createPreviewBubble() { var nextType; do { nextType = Math.floor(Math.random() * maxSelectableBubble); } while (nextType == lastTypes[0] && nextType == lastTypes[1]); lastTypes.shift(); lastTypes.push(nextType); previewBubble = self.addChildAt(new Bubble(maxSelectableBubble, false, nextType), 0); previewBubble.scale.set(.7, .7); previewBubble.x = -90; previewBubble.y = 20; previewBubble.isFreeBubble = true; // Add down event to allow switching with current bubble previewBubble.interactive = true; previewBubble.buttonMode = true; previewBubble.down = function (x, y, obj) { // Swap types between previewBubble and bubble if (bubble && previewBubble) { // Only allow swap if both are not fireballs if (!bubble.isFireBall && !previewBubble.isFireBall) { var tmpType = bubble.type; bubble.type = previewBubble.type; previewBubble.type = tmpType; // Update graphics for both bubbles if (bubble.children && bubble.children.length > 0) { var old = bubble.children[0]; bubble.removeChild(old); var newAsset = bubble.attachAsset('bubble' + bubble.type, { anchorX: 0.5, anchorY: 0.5 }); } if (previewBubble.children && previewBubble.children.length > 0) { var oldPrev = previewBubble.children[0]; previewBubble.removeChild(oldPrev); var newPrevAsset = previewBubble.attachAsset('bubble' + previewBubble.type, { anchorX: 0.5, anchorY: 0.5 }); newPrevAsset.width = previewBubble.width; newPrevAsset.height = previewBubble.height; } refreshHintLine && refreshHintLine(); } } }; } createPreviewBubble(); self.fire = function () { bulletsFired++; LK.getSound('fireBubble').play(); // Play sound when the ball is fired grid.fireBubble(bubble, self.angle); bubble = previewBubble; previewBubble.x = previewBubble.y = 0; previewBubble.scale.set(1, 1); createPreviewBubble(); }; self.angle = -Math.PI / 2; self.getBubble = function () { return bubble; }; self.isFireBall = function () { return bubble.isFireBall; }; self.triggerFireBall = function () { bubble.destroy(); bubble = self.addChild(new Bubble(getMaxTypes(), true)); bubble.isFreeBubble = true; }; }); var ScoreIndicatorLabel = Container.expand(function (score, type) { var self = Container.call(this); // Ensure score is always a string for Text2 var label = new Text2(score !== undefined ? score.toString() : "0", { size: 100, fill: "#" + (bubbleColors[type] !== undefined ? bubbleColors[type].toString(16).padStart(6, '0') : "ffffff"), font: "Impact" }); label.anchor.set(0.5, 0); self.addChild(label); self.update = function () { self.y -= 7; self.alpha -= .05; if (self.alpha <= 0) { self.destroy(); increaseScore(score); } }; }); var ScoreMultipliers = Container.expand(function (baseValue) { var self = Container.call(this); // Create a score label text string for ScoreMultipliers var scoreMultiplierLabel = new Text2(baseValue, { size: 100, fill: 0x3954FF, font: "Impact" }); scoreMultiplierLabel.anchor.set(0.5, 0); self.addChild(scoreMultiplierLabel); var currentMultiplier = 1; self.applyBubble = function (bubble) { var scoreIndicator = game.addChild(new ScoreIndicatorLabel(baseValue * currentMultiplier, bubble.type)); scoreIndicator.x = self.x; scoreIndicator.y = self.y; var particle = particlesLayer.addChild(new BubbleRemoveParticle()); particle.x = bubble.x; particle.y = self.y + 150; }; self.setMultiplier = function (multiplier) { currentMultiplier = multiplier; scoreMultiplierLabel.setText(baseValue * currentMultiplier); }; }); var WarningLine = Container.expand(function () { var self = Container.call(this); var warning = self.attachAsset('warningstripe', { anchorX: .5, anchorY: .5 }); var warningOffset = Math.random() * 100; var speed = Math.random() * 1 + 1; self.update = function () { warningOffset += speed; warning.alpha = (Math.cos(warningOffset / 50) + 1) / 2 * 0.3 + .7; }; warning.blendMode = 1; warning.rotation = .79; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0c0d25 }); /**** * Game Code ****/ var gridSpeed = .5; var colorBallCount = 3; // Default, will be set by menu // Iron bubbles option flag and score multiplier var ironBubblesEnabled = false; var ironScoreMultiplier = 1.0; // Show menu to select number of color balls using LK.gui var menuOverlay = new Container(); var menuBG = LK.getAsset('uxoverlay', { anchorX: 0, anchorY: 0 }); menuBG.width = 1200; menuBG.height = 1200; menuOverlay.addChild(menuBG); // Center the menu overlay vertically and horizontally menuBG.x = -600; menuBG.y = -600; var menuTitle = new Text2("Bubble Shooter", { size: 120, fill: 0xffffff, font: "Impact" }); menuTitle.anchor.set(0.5, 0); menuTitle.x = menuBG.x / 2 + 300; menuTitle.y = menuBG.y + 50; menuOverlay.addChild(menuTitle); var menuDesc = new Text2("How many different color balls?", { size: 70, fill: 0xffffff, font: "Impact" }); menuDesc.anchor.set(0.5, 0); menuDesc.x = menuBG.x / 2 + 300; menuDesc.y = menuBG.y + 200; menuOverlay.addChild(menuDesc); var colorOptions = [{ label: "3 Colors", value: 3 }, { label: "4 Colors", value: 4 }, { label: "5 Colors", value: 5 }, { label: "6 Colors", value: 6 }, { label: "7 Colors", value: 7 }, { label: "8 Colors", value: 8 }]; var menuButtons = []; // Vertically center the menu buttons below the menu description var buttonSpacing = 120; var totalButtonHeight = colorOptions.length * buttonSpacing; var buttonStartY = menuBG.y + 300; function onMenuSelect(option) { colorBallCount = option.value; maxSelectableBubble = colorBallCount; menuActive = false; if (menuOverlay.parent) { menuOverlay.parent.removeChild(menuOverlay); } // Show iron bubble selection menu showIronBubbleMenu(); } function showIronBubbleMenu() { menuActive = true; var ironMenuOverlay = new Container(); var ironMenuBG = LK.getAsset('uxoverlay2', { anchorX: 0, anchorY: 0 }); ironMenuBG.width = 900; ironMenuBG.height = 700; ironMenuOverlay.addChild(ironMenuBG); ironMenuBG.x = -450; ironMenuBG.y = -350; var ironMenuTitle = new Text2("Iron Bubbles?", { size: 100, fill: 0xffffff, font: "Impact" }); ironMenuTitle.anchor.set(0.5, 0); ironMenuTitle.x = ironMenuBG.x / 2 + 225; ironMenuTitle.y = ironMenuBG.y + 60; ironMenuOverlay.addChild(ironMenuTitle); var ironMenuDesc = new Text2("Do you want to include iron bubbles?", { size: 60, fill: 0xffffff, font: "Impact" }); ironMenuDesc.anchor.set(0.5, 0); ironMenuDesc.x = ironMenuBG.x / 2 + 225; ironMenuDesc.y = ironMenuBG.y + 200; ironMenuOverlay.addChild(ironMenuDesc); var yesBtn = new Text2("Yes", { size: 90, fill: 0x3954FF, font: "Impact", stroke: 0xffffff, strokeThickness: 8 }); yesBtn.anchor.set(0.5, 0); yesBtn.x = ironMenuBG.x / 2 + 225; yesBtn.y = ironMenuBG.y + 350; yesBtn.interactive = true; yesBtn.buttonMode = true; yesBtn.down = function (x, y, obj) { ironBubblesEnabled = true; if (ironMenuOverlay.parent) { ironMenuOverlay.parent.removeChild(ironMenuOverlay); } menuActive = false; // Reset scoreMultipliers and baseScores based on new colorBallCount setupScoreMultipliers(); }; ironMenuOverlay.addChild(yesBtn); var noBtn = new Text2("No", { size: 90, fill: 0x3954FF, font: "Impact", stroke: 0xffffff, strokeThickness: 8 }); noBtn.anchor.set(0.5, 0); noBtn.x = ironMenuBG.x / 2 + 225; noBtn.y = ironMenuBG.y + 500; noBtn.interactive = true; noBtn.buttonMode = true; noBtn.down = function (x, y, obj) { ironBubblesEnabled = false; if (ironMenuOverlay.parent) { ironMenuOverlay.parent.removeChild(ironMenuOverlay); } menuActive = false; // Reset scoreMultipliers and baseScores based on new colorBallCount setupScoreMultipliers(); }; ironMenuOverlay.addChild(noBtn); LK.gui.center.addChild(ironMenuOverlay); } // Helper to reset scoreMultipliers and baseScores after menu function setupScoreMultipliers() { for (var i = 0; i < scoreMultipliers.length; i++) { if (scoreMultipliers[i].parent) { scoreMultipliers[i].parent.removeChild(scoreMultipliers[i]); } } scoreMultipliers = []; // Set ironScoreMultiplier based on ironBubblesEnabled ironScoreMultiplier = ironBubblesEnabled ? 1.3 : 1.0; if (colorBallCount <= 3) { baseScores = [100, 250, 500, 250, 100]; } else if (colorBallCount == 4) { baseScores = [120, 300, 600, 300, 120]; } else if (colorBallCount == 5) { baseScores = [150, 375, 750, 375, 150]; } else if (colorBallCount == 6) { baseScores = [200, 500, 1000, 500, 200]; } else if (colorBallCount == 7) { baseScores = [250, 625, 1250, 625, 250]; } else if (colorBallCount == 8) { baseScores = [300, 750, 1500, 750, 300]; } else { baseScores = [100, 250, 500, 250, 100]; } for (var a = 0; a < 5; a++) { var sm = new ScoreMultipliers(Math.round(baseScores[a] * ironScoreMultiplier)); sm.x = 2048 / 5 * a + 2048 / 10; sm.y = 2300; scoreMultipliers.push(sm); game.addChild(sm); } } for (var i = 0; i < colorOptions.length; i++) { (function (idx) { var opt = colorOptions[idx]; var btn = new Text2(opt.label, { size: 90, fill: 0x3954FF, font: "Impact", stroke: 0xffffff, strokeThickness: 8 }); btn.anchor.set(0.5, 0); btn.x = menuBG.x / 2 + 300; btn.y = buttonStartY + idx * buttonSpacing; btn.interactive = true; btn.buttonMode = true; btn.down = function (x, y, obj) { onMenuSelect(opt); }; menuOverlay.addChild(btn); menuButtons.push(btn); })(i); } LK.gui.center.addChild(menuOverlay); function increaseScore(amount) { var currentScore = LK.getScore(); var newScore = currentScore + amount; LK.setScore(newScore); // Update the game score using LK method scoreLabel.setText(newScore.toString()); // Update the score label with the new score } //Game size 2048x2732 /* Todo: [X] Make sure we GC nodes that drop of screen [ ] Make preview line fade out at the end */ var bulletsFired = 0; //3*30+1 var bubbleSize = 150; var gameIsStarted = false; var bubbleColors = [0xff2853, 0x44d31f, 0x5252ff, 0xcb2bff, 0x28f2f0, 0xffc411]; var barriers = []; var maxSelectableBubble = colorBallCount; var warningLines = []; for (var a = 0; a < 13; a++) { var wl = game.addChild(new WarningLine()); wl.x = 2048 / 13 * (a + .5); wl.y = 2200; wl.alpha = 0; warningLines.push(wl); wl.scale.set(16, 40); } var warningOverlay = game.attachAsset('dangeroverlay', {}); warningOverlay.y = 2280; var uxoverlay = game.attachAsset('uxoverlay', {}); uxoverlay.y = 2440; var uxoverlay2 = game.attachAsset('uxoverlay2', {}); uxoverlay2.y = 2460; for (var a = 0; a < 4; a++) { for (var b = 0; b < 3; b++) { var barrier = game.addChild(new Barrier()); barrier.y = 2732 - 450 + b * 70; barrier.x = 2048 / 5 * a + 2048 / 5; barriers.push(barrier); } var barrierBlock = game.attachAsset('barrierblock', {}); barrierBlock.x = 2048 / 5 * a + 2048 / 5; barrierBlock.y = 2732 - 450; barrierBlock.anchor.x = .5; } // Create a score label var scoreLabel = new Text2('0', { size: 120, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 15, font: "Impact" }); scoreLabel.anchor.set(0.5, 0); LK.gui.top.addChild(scoreLabel); var scoreMultipliers = []; // Score multiplier logic based on colorBallCount var baseScores; if (colorBallCount <= 3) { baseScores = [100, 250, 500, 250, 100]; } else if (colorBallCount == 4) { baseScores = [120, 300, 600, 300, 120]; } else if (colorBallCount == 5) { baseScores = [150, 375,, 750, 375, 150]; } else if (colorBallCount == 6) { baseScores = [200, 500, 1000, 500, 200]; } else if (colorBallCount == 7) { baseScores = [250, 625, 1250, 625, 250]; } else if (colorBallCount == 8) { baseScores = [350, 875, 1750, 875, 350]; } else { baseScores = [100, 250, 500, 250, 100]; } for (var a = 0; a < 5; a++) { var sm = new ScoreMultipliers(Math.round(baseScores[a] * ironScoreMultiplier)); sm.x = 2048 / 5 * a + 2048 / 10; sm.y = 2300; scoreMultipliers.push(sm); game.addChild(sm); } var bonusUX = game.addChild(new BonusUX()); var fireBallPowerupOverlay = game.addChild(new FireBallPowerupOverlay()); var particlesLayer = game.addChild(new Container()); var grid = game.addChild(new Grid()); grid.y = 1000; var freeBubbleLayer = game.addChild(new Container()); var hintBubblePlayer = game.addChild(new Container()); var launcher = game.addChild(new Launcher()); launcher.x = game.width / 2; launcher.y = game.height - 138; var hintBubbleCache = []; var hintBubbles = []; var isValid = false; var path = []; var bubbleAlpha = 1; var hintTargetX = game.width / 2; var hintTargetY = 0; // Prevent game interaction before menu selection var menuActive = true; game.move = function (x, y, obj) { if (menuActive) { return; } hintTargetX = x; hintTargetY = y; refreshHintLine(); // } }; game.down = function (x, y, obj) { if (menuActive) { return; } game.move(x, y, obj); }; function getMaxTypes() { return colorBallCount; } function refreshHintLine() { var ox = hintTargetX - launcher.x; var oy = hintTargetY - launcher.y; var angle = Math.atan2(oy, ox); launcher.angle = angle; isValid = angle < -.2 && angle > -Math.PI + .2; if (isValid) { path = grid.calculatePath(launcher, angle); //This allows updated faster than 60fps, making everyting feel better. } renderHintBubbels(); } var hintOffset = 0; var distanceBetweenHintbubbles = 100; function renderHintBubbels() { if (isValid) { hintOffset = hintOffset % distanceBetweenHintbubbles; var distanceSinceLastDot = -hintOffset + 100; var hintBubbleOffset = 0; var lastPoint = path[0]; var bubble = launcher.getBubble(); var tint; if (bubble.isFireBall) { tint = 0xff9c00; } else if (bubble.type === 3) { tint = 0xffff00; // yellow } else if (bubble.type === 4) { tint = 0xcb2bff; // purple } else if (bubble.type === 5) { tint = 0x28f2f0; // cyan } else if (bubble.type === 6) { tint = 0xff9c00; // orange } else if (bubble.type === 7) { tint = 0x001f4d; // navy blue } else { tint = bubbleColors[bubble.type]; } var updateTint = true; for (var a = 1; a < path.length; a++) { var p2 = path[a]; var ox = p2.x - lastPoint.x; var oy = p2.y - lastPoint.y; var dist = Math.sqrt(ox * ox + oy * oy); distanceSinceLastDot += dist; if (distanceSinceLastDot >= distanceBetweenHintbubbles) { var amountOver = distanceSinceLastDot - distanceBetweenHintbubbles; var angle = Math.atan2(oy, ox); var currentBubble = hintBubbles[hintBubbleOffset]; if (!currentBubble) { currentBubble = hintBubbles[hintBubbleOffset] = new HintBubble(); hintBubblePlayer.addChild(currentBubble); } currentBubble.alpha = bubbleAlpha; currentBubble.visible = true; var currentTint = currentBubble.getTint(); if (hintBubbleOffset == 0) { currentBubble.setTint(tint); } else if (updateTint && currentTint != tint || currentTint == 0xffffff) { currentBubble.setTint(tint); updateTint = false; } currentBubble.x = lastPoint.x - Math.cos(angle) * amountOver; currentBubble.y = lastPoint.y - Math.sin(angle) * amountOver; hintBubbleOffset++; distanceSinceLastDot = 0; lastPoint = currentBubble; } else { lastPoint = p2; } } for (var a = hintBubbleOffset; a < hintBubbles.length; a++) { hintBubbles[a].visible = false; } } else { for (var a = 0; a < hintBubbles.length; a++) { hintBubbles[a].alpha = bubbleAlpha; } } } game.update = function () { if (menuActive) { return; } hintOffset += 5; if (isValid) { bubbleAlpha = Math.min(bubbleAlpha + .05, 1); } else { bubbleAlpha = Math.max(bubbleAlpha - .05, 0); } refreshHintLine(); var alphaList = grid.calculateWarningScoreList(); for (var a = 0; a < warningLines.length; a++) { var value = alphaList[a] / 3; warningLines[a].alpha += (Math.min(value, .6) - warningLines[a].alpha) / 100; warningLines[a].scale.y += (value * 60 - warningLines[a].scale.y) / 100; } }; game.up = function () { if (menuActive) { return; } if (isValid) { launcher.fire(); } }; ; ; ; ; ; ; ; ; ; ;
===================================================================
--- original.js
+++ change.js
@@ -1253,8 +1253,10 @@
} else if (bubble.type === 5) {
tint = 0x28f2f0; // cyan
} else if (bubble.type === 6) {
tint = 0xff9c00; // orange
+ } else if (bubble.type === 7) {
+ tint = 0x001f4d; // navy blue
} else {
tint = bubbleColors[bubble.type];
}
var updateTint = true;
Circular white gradient circle on black background. Gradient from white on the center to black on the outer edge all around.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Soft straight Long red paint on black background. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Fire ball. Bubble shooter game. Thin black outline.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
green notification bubble. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.