/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ var Bubble = Container.expand(function (type, size, speed) { var self = Container.call(this); self.type = type || 'red'; self.size = size || 1; self.speed = speed || 2; self.points = 10; self.isSpecial = false; // Set points based on type if (self.type === 'red') { self.points = 10; } else if (self.type === 'blue') { self.points = 15; } else if (self.type === 'green') { self.points = 20; } else if (self.type === 'yellow') { self.points = 25; } else if (self.type === 'purple') { self.points = 30; } else if (self.type === 'special') { self.points = 50; self.isSpecial = true; } // Create bubble graphic self.bubbleGraphic = self.attachAsset('bubble_' + self.type, { anchorX: 0.5, anchorY: 0.5, scaleX: self.size, scaleY: self.size, alpha: 0.9 }); // Add shine effect self.shineGraphic = self.attachAsset('bubble_' + self.type + '_shine', { anchorX: 0.5, anchorY: 0.5, scaleX: self.size, scaleY: self.size, x: -self.bubbleGraphic.width * 0.2, y: -self.bubbleGraphic.height * 0.2, alpha: 0.7 }); // Add bubble rim highlight for 3D effect self.rimGraphic = self.attachAsset('bubble_ring', { anchorX: 0.5, anchorY: 0.5, scaleX: self.bubbleGraphic.width * 0.1 * self.size, scaleY: self.bubbleGraphic.height * 0.1 * self.size, alpha: 0.5 }); // If it's a special bubble, make it pulsate if (self.isSpecial) { self.pulsateDirection = 1; self.pulsateAmount = 0.1; self.pulsateSpeed = 0.02; // Add glowing effect to special bubbles // Use tween directly with repeat for looping animation tween(self.bubbleGraphic, { alpha: 0.6 }, { alpha: 1 }, { duration: 800, easing: tween.easeInOut, repeat: -1, // -1 means infinite repetition yoyo: true // Reverse the animation on each repeat }); } // Event handler for touch self.down = function (x, y, obj) { self.pop(); }; // Pop the bubble self.pop = function () { // Play pop sound if (self.isSpecial) { LK.getSound('special_pop').play(); // Apply special effect self.applySpecialEffect(); } else { LK.getSound('pop').play(); } // Add points LK.setScore(LK.getScore() + self.points * currentMultiplier); // Update score display updateScoreText(); // Create and display floating score text var scorePopup = new Text2("+" + self.points * currentMultiplier, { size: 70, fill: self.isSpecial ? 0xFFFF00 : 0xFFFFFF }); scorePopup.anchor.set(0.5, 0.5); scorePopup.x = 0; scorePopup.y = -20; self.addChild(scorePopup); // Animate score popup tween(scorePopup, { y: -100, alpha: 0 }, { duration: 800, easing: tween.easeOut }); // Generate particle effects var particleCount = self.isSpecial ? 20 : 10; var bubbleColor = self.bubbleGraphic.tint; var particleSize = self.size; // Create particles using the particle system particles.burst({ x: self.x, y: self.y, count: particleCount, minSpeed: 2, maxSpeed: 8, minScale: 0.3 * self.size, maxScale: 0.7 * self.size, minLifetime: 500, maxLifetime: 1000, gravity: 0.2, color: bubbleColor, fadeOut: true }); // Create some additional custom particles for (var i = 0; i < particleCount / 2; i++) { var particle = new BubbleParticle(bubbleColor, particleSize); particle.x = self.x; particle.y = self.y; game.addChild(particle); bubbleParticles.push(particle); } // Flash effect with bubble color tint instead of just white LK.effects.flashObject(self, bubbleColor, 300); // Increase speed for remaining bubbles when normal bubble popped if (!self.isSpecial) { clickUpgrades++; // Apply speed upgrade to all bubbles applySpeedUpgradeToBubbles(); } // Scale effect and remove with bounce effect tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { self.readyToRemove = true; } }); } }); }; // Apply special effect based on bubble type self.applySpecialEffect = function () { // Random effect var effectType = Math.floor(Math.random() * 3); if (effectType === 0) { // Slow down all bubbles gameSpeed = 0.5; LK.setTimeout(function () { gameSpeed = 1; }, 5000); showMessage("SLOW TIME!", 2000); } else if (effectType === 1) { // Score multiplier currentMultiplier = 2; LK.setTimeout(function () { currentMultiplier = 1; }, 5000); showMessage("2X POINTS!", 2000); } else { // Pop nearby bubbles popNearbyBubbles(self); showMessage("CHAIN REACTION!", 2000); } }; // Update method called by the game engine self.update = function () { // Move bubble up self.y -= self.speed * gameSpeed; // Subtle wobble effect for all bubbles var wobbleAmount = 0.5; self.x += Math.sin(LK.ticks * 0.05 + self.y * 0.01) * wobbleAmount; // Update bubble rim position to follow bubble self.rimGraphic.rotation += 0.01; // Special bubble pulsate effect if (self.isSpecial) { if (self.bubbleGraphic.scale.x > 1.2) { self.pulsateDirection = -1; } else if (self.bubbleGraphic.scale.x < 0.8) { self.pulsateDirection = 1; } self.bubbleGraphic.scale.x += self.pulsateDirection * self.pulsateSpeed; self.bubbleGraphic.scale.y += self.pulsateDirection * self.pulsateSpeed; // Make shine and rim follow the pulsation self.shineGraphic.scale.x = self.bubbleGraphic.scale.x * 0.5; self.shineGraphic.scale.y = self.bubbleGraphic.scale.y * 0.5; self.rimGraphic.scale.x = self.bubbleGraphic.scale.x * 10; self.rimGraphic.scale.y = self.bubbleGraphic.scale.y * 10; // Add occasional sparkle effect for special bubbles if (Math.random() < 0.05) { particles.emit({ x: self.x, y: self.y, count: 1, minSpeed: 0.5, maxSpeed: 1.5, minScale: 0.1, maxScale: 0.3, minLifetime: 300, maxLifetime: 600, color: 0xFFFFFF, fadeOut: true }); } } else { // Subtle scale variation for normal bubbles to make them look more organic var scaleVar = Math.sin(LK.ticks * 0.02 + self.x * 0.01) * 0.02; self.bubbleGraphic.scale.x = self.size + scaleVar; self.bubbleGraphic.scale.y = self.size + scaleVar; // Update shine position self.shineGraphic.scale.x = self.bubbleGraphic.scale.x * 0.5; self.shineGraphic.scale.y = self.bubbleGraphic.scale.y * 0.5; } }; return self; }); var BubbleParticle = Container.expand(function (color, size) { var self = Container.call(this); self.lifespan = 30 + Math.random() * 30; self.age = 0; self.speed = 1 + Math.random() * 3; self.direction = Math.random() * Math.PI * 2; self.gravity = 0.05 + Math.random() * 0.1; var particleSize = (10 + Math.random() * 15) * size; self.graphic = self.attachAsset('bubble_ring', { anchorX: 0.5, anchorY: 0.5, scaleX: particleSize, scaleY: particleSize, alpha: 0.8 }); // Set the color of the particle self.graphic.tint = color; self.update = function () { // Update position based on velocity self.x += Math.cos(self.direction) * self.speed; self.y += Math.sin(self.direction) * self.speed; // Add gravity effect self.y += self.gravity; // Age the particle self.age++; // Fade out as it ages self.alpha = 1 - self.age / self.lifespan; // Remove when dead if (self.age >= self.lifespan) { self.readyToRemove = true; } }; return self; }); var Particles = Container.expand(function () { var self = Container.call(this); self.burst = function (options) { var count = options.count || 10; var minSpeed = options.minSpeed || 1; var maxSpeed = options.maxSpeed || 5; var minScale = options.minScale || 0.1; var maxScale = options.maxScale || 0.5; var minLifetime = options.minLifetime || 300; var maxLifetime = options.maxLifetime || 800; var gravity = options.gravity || 0; var color = options.color || 0xFFFFFF; var fadeOut = options.fadeOut || true; var x = options.x || 0; var y = options.y || 0; for (var i = 0; i < count; i++) { var particle = new BubbleParticle(color, Math.random() * (maxScale - minScale) + minScale); particle.x = x; particle.y = y; particle.speed = Math.random() * (maxSpeed - minSpeed) + minSpeed; particle.gravity = gravity; particle.lifespan = Math.random() * (maxLifetime - minLifetime) + minLifetime; game.addChild(particle); bubbleParticles.push(particle); } }; self.emit = function (options) { var count = options.count || 1; var minSpeed = options.minSpeed || 0.5; var maxSpeed = options.maxSpeed || 1.5; var minScale = options.minScale || 0.1; var maxScale = options.maxScale || 0.3; var minLifetime = options.minLifetime || 300; var maxLifetime = options.maxLifetime || 600; var color = options.color || 0xFFFFFF; var fadeOut = options.fadeOut || true; var x = options.x || 0; var y = options.y || 0; for (var i = 0; i < count; i++) { var particle = new BubbleParticle(color, Math.random() * (maxScale - minScale) + minScale); particle.x = x; particle.y = y; particle.speed = Math.random() * (maxSpeed - minSpeed) + minSpeed; particle.lifespan = Math.random() * (maxLifetime - minLifetime) + minLifetime; game.addChild(particle); bubbleParticles.push(particle); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x4588d2 }); /**** * Game Code ****/ // Game variables var bubbles = []; var bubbleParticles = []; var difficulty = 1; var spawnRate = 60; // Frames between bubble spawns var gameSpeed = 1; var currentMultiplier = 1; var lastSpawn = 0; var gameRunning = true; var clickUpgrades = 0; var speedUpgrades = 0; var upgradeMultiplier = 1.2; // Speed increase per upgrade // Background bubble effect variables var backgroundBubbles = []; // Particle system var particles = new Particles(); // Score display var scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 50; // Level display var levelTxt = new Text2('Level: 1', { size: 70, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); LK.gui.topRight.addChild(levelTxt); levelTxt.x = -250; levelTxt.y = 50; // Message display (for power-ups and events) var messageTxt = new Text2('', { size: 100, fill: 0xFFFFFF }); messageTxt.anchor.set(0.5, 0.5); messageTxt.alpha = 0; LK.gui.center.addChild(messageTxt); // Function to show temporary messages function showMessage(message, duration) { messageTxt.setText(message); messageTxt.alpha = 1; // Animate message tween(messageTxt, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, easing: tween.bounceOut, onFinish: function onFinish() { tween(messageTxt, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); // Hide after duration LK.setTimeout(function () { tween(messageTxt, { alpha: 0 }, { duration: 500 }); }, duration); } // Update score display function updateScoreText() { scoreTxt.setText(LK.getScore().toString()); // Check for level up var newLevel = Math.floor(LK.getScore() / 500) + 1; if (newLevel > difficulty) { difficulty = newLevel; levelTxt.setText('Level: ' + difficulty); showMessage("LEVEL UP!", 2000); // Decrease spawn rate with level (faster spawning) spawnRate = Math.max(10, 60 - difficulty * 5); } } // Function to spawn a bubble function spawnBubble() { // Determine bubble type var types = ['red', 'blue', 'green', 'yellow', 'purple']; var type = types[Math.floor(Math.random() * types.length)]; // Special bubble chance (10% + increases slightly with difficulty) var specialChance = 0.1 + difficulty * 0.01; if (Math.random() < specialChance) { type = 'special'; } // Random size variation var size = 0.8 + Math.random() * 0.4; // Speed based on size and difficulty var speed = (2 + difficulty * 0.5) * (1 / size); // Create the bubble var bubble = new Bubble(type, size, speed); // Position randomly along bottom of screen bubble.x = 150 + Math.random() * (2048 - 300); bubble.y = 2732 + 100; // Store original speed for upgrade calculations bubble.originalSpeed = bubble.speed; // Apply current speed upgrades if (speedUpgrades > 0) { bubble.speed = bubble.originalSpeed * speedUpgrades; } // Add to game and array game.addChild(bubble); bubbles.push(bubble); } // Function to pop bubbles near a specific bubble function popNearbyBubbles(sourceBubble) { var popRadius = 300; for (var i = 0; i < bubbles.length; i++) { if (bubbles[i] !== sourceBubble && !bubbles[i].readyToRemove) { var dx = bubbles[i].x - sourceBubble.x; var dy = bubbles[i].y - sourceBubble.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < popRadius) { bubbles[i].pop(); } } } } // Game update function game.update = function () { if (!gameRunning) return; // Spawn bubbles on interval if (LK.ticks - lastSpawn > spawnRate) { spawnBubble(); lastSpawn = LK.ticks; } // Process bubbles for (var i = bubbles.length - 1; i >= 0; i--) { var bubble = bubbles[i]; // Check if bubble has gone off top of screen if (bubble.y < -150) { // Remove bubble bubble.destroy(); bubbles.splice(i, 1); // Lose life or game over if not special if (!bubble.isSpecial) { // Game over gameRunning = false; // Update high score if (LK.getScore() > storage.highScore) { storage.highScore = LK.getScore(); } // Flash screen and show game over LK.effects.flashScreen(0xff0000, 1000); LK.getSound('game_over').play(); LK.setTimeout(function () { LK.showGameOver(); }, 1000); } continue; } // Remove popped bubbles if (bubble.readyToRemove) { bubble.destroy(); bubbles.splice(i, 1); } } // Process bubble particles for (var i = bubbleParticles.length - 1; i >= 0; i--) { var particle = bubbleParticles[i]; // Update particle particle.update(); // Remove dead particles if (particle.readyToRemove) { particle.destroy(); bubbleParticles.splice(i, 1); } } // Add occasional background bubbles for visual effect if (Math.random() < 0.02) { var bgBubble = new BubbleParticle(0xFFFFFF, 2); bgBubble.x = Math.random() * 2048; bgBubble.y = 2732 + 50; bgBubble.speed = 0.5 + Math.random() * 1; bgBubble.direction = -Math.PI / 2; // Move upward bgBubble.alpha = 0.2 + Math.random() * 0.2; bgBubble.lifespan = 300 + Math.random() * 200; // Add to game and track game.addChild(bgBubble); backgroundBubbles.push(bgBubble); } // Process background bubbles for (var i = backgroundBubbles.length - 1; i >= 0; i--) { var bgBubble = backgroundBubbles[i]; // Update bubble bgBubble.update(); // Remove when offscreen or dead if (bgBubble.y < -50 || bgBubble.readyToRemove) { bgBubble.destroy(); backgroundBubbles.splice(i, 1); } } }; // Game start function startGame() { // Reset variables bubbles = []; bubbleParticles = []; backgroundBubbles = []; difficulty = 1; spawnRate = 60; gameSpeed = 1; currentMultiplier = 1; lastSpawn = 0; gameRunning = true; clickUpgrades = 0; speedUpgrades = 0; // Reset score LK.setScore(0); updateScoreText(); levelTxt.setText('Level: 1'); // Show welcome message showMessage("POP THE BUBBLES!", 2000); // Start music LK.playMusic('game_music', { fade: { start: 0, end: 0.6, duration: 1000 } }); } // Function to apply speed upgrades to all bubbles function applySpeedUpgradeToBubbles() { // Calculate new speed multiplier based on clicks speedUpgrades = 1 + clickUpgrades * 0.01; // 1% speed increase per click // Apply to all existing bubbles with visual effect for (var i = 0; i < bubbles.length; i++) { var bubble = bubbles[i]; if (!bubble.readyToRemove) { // Store original speed if not already stored if (!bubble.originalSpeed) { bubble.originalSpeed = bubble.speed; } // Calculate new speed var newSpeed = bubble.originalSpeed * speedUpgrades; // Apply new speed with visual feedback bubble.speed = newSpeed; // Visual feedback - flash the bubble briefly if (clickUpgrades % 5 === 0) { // Only show visual effect every 5 upgrades to avoid spam tween(bubble, { scaleX: bubble.size * 1.2, scaleY: bubble.size * 1.2 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(bubble, { scaleX: bubble.size, scaleY: bubble.size }, { duration: 200, easing: tween.easeIn }); } }); } } } // Show upgrade message on significant milestones if (clickUpgrades % 10 === 0) { showMessage("SPEED UP! " + Math.floor(speedUpgrades * 100) + "%", 1500); } } // Start the game startGame(); ;
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Bubble = Container.expand(function (type, size, speed) {
var self = Container.call(this);
self.type = type || 'red';
self.size = size || 1;
self.speed = speed || 2;
self.points = 10;
self.isSpecial = false;
// Set points based on type
if (self.type === 'red') {
self.points = 10;
} else if (self.type === 'blue') {
self.points = 15;
} else if (self.type === 'green') {
self.points = 20;
} else if (self.type === 'yellow') {
self.points = 25;
} else if (self.type === 'purple') {
self.points = 30;
} else if (self.type === 'special') {
self.points = 50;
self.isSpecial = true;
}
// Create bubble graphic
self.bubbleGraphic = self.attachAsset('bubble_' + self.type, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.size,
scaleY: self.size,
alpha: 0.9
});
// Add shine effect
self.shineGraphic = self.attachAsset('bubble_' + self.type + '_shine', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.size,
scaleY: self.size,
x: -self.bubbleGraphic.width * 0.2,
y: -self.bubbleGraphic.height * 0.2,
alpha: 0.7
});
// Add bubble rim highlight for 3D effect
self.rimGraphic = self.attachAsset('bubble_ring', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.bubbleGraphic.width * 0.1 * self.size,
scaleY: self.bubbleGraphic.height * 0.1 * self.size,
alpha: 0.5
});
// If it's a special bubble, make it pulsate
if (self.isSpecial) {
self.pulsateDirection = 1;
self.pulsateAmount = 0.1;
self.pulsateSpeed = 0.02;
// Add glowing effect to special bubbles
// Use tween directly with repeat for looping animation
tween(self.bubbleGraphic, {
alpha: 0.6
}, {
alpha: 1
}, {
duration: 800,
easing: tween.easeInOut,
repeat: -1,
// -1 means infinite repetition
yoyo: true // Reverse the animation on each repeat
});
}
// Event handler for touch
self.down = function (x, y, obj) {
self.pop();
};
// Pop the bubble
self.pop = function () {
// Play pop sound
if (self.isSpecial) {
LK.getSound('special_pop').play();
// Apply special effect
self.applySpecialEffect();
} else {
LK.getSound('pop').play();
}
// Add points
LK.setScore(LK.getScore() + self.points * currentMultiplier);
// Update score display
updateScoreText();
// Create and display floating score text
var scorePopup = new Text2("+" + self.points * currentMultiplier, {
size: 70,
fill: self.isSpecial ? 0xFFFF00 : 0xFFFFFF
});
scorePopup.anchor.set(0.5, 0.5);
scorePopup.x = 0;
scorePopup.y = -20;
self.addChild(scorePopup);
// Animate score popup
tween(scorePopup, {
y: -100,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut
});
// Generate particle effects
var particleCount = self.isSpecial ? 20 : 10;
var bubbleColor = self.bubbleGraphic.tint;
var particleSize = self.size;
// Create particles using the particle system
particles.burst({
x: self.x,
y: self.y,
count: particleCount,
minSpeed: 2,
maxSpeed: 8,
minScale: 0.3 * self.size,
maxScale: 0.7 * self.size,
minLifetime: 500,
maxLifetime: 1000,
gravity: 0.2,
color: bubbleColor,
fadeOut: true
});
// Create some additional custom particles
for (var i = 0; i < particleCount / 2; i++) {
var particle = new BubbleParticle(bubbleColor, particleSize);
particle.x = self.x;
particle.y = self.y;
game.addChild(particle);
bubbleParticles.push(particle);
}
// Flash effect with bubble color tint instead of just white
LK.effects.flashObject(self, bubbleColor, 300);
// Increase speed for remaining bubbles when normal bubble popped
if (!self.isSpecial) {
clickUpgrades++;
// Apply speed upgrade to all bubbles
applySpeedUpgradeToBubbles();
}
// Scale effect and remove with bounce effect
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
self.readyToRemove = true;
}
});
}
});
};
// Apply special effect based on bubble type
self.applySpecialEffect = function () {
// Random effect
var effectType = Math.floor(Math.random() * 3);
if (effectType === 0) {
// Slow down all bubbles
gameSpeed = 0.5;
LK.setTimeout(function () {
gameSpeed = 1;
}, 5000);
showMessage("SLOW TIME!", 2000);
} else if (effectType === 1) {
// Score multiplier
currentMultiplier = 2;
LK.setTimeout(function () {
currentMultiplier = 1;
}, 5000);
showMessage("2X POINTS!", 2000);
} else {
// Pop nearby bubbles
popNearbyBubbles(self);
showMessage("CHAIN REACTION!", 2000);
}
};
// Update method called by the game engine
self.update = function () {
// Move bubble up
self.y -= self.speed * gameSpeed;
// Subtle wobble effect for all bubbles
var wobbleAmount = 0.5;
self.x += Math.sin(LK.ticks * 0.05 + self.y * 0.01) * wobbleAmount;
// Update bubble rim position to follow bubble
self.rimGraphic.rotation += 0.01;
// Special bubble pulsate effect
if (self.isSpecial) {
if (self.bubbleGraphic.scale.x > 1.2) {
self.pulsateDirection = -1;
} else if (self.bubbleGraphic.scale.x < 0.8) {
self.pulsateDirection = 1;
}
self.bubbleGraphic.scale.x += self.pulsateDirection * self.pulsateSpeed;
self.bubbleGraphic.scale.y += self.pulsateDirection * self.pulsateSpeed;
// Make shine and rim follow the pulsation
self.shineGraphic.scale.x = self.bubbleGraphic.scale.x * 0.5;
self.shineGraphic.scale.y = self.bubbleGraphic.scale.y * 0.5;
self.rimGraphic.scale.x = self.bubbleGraphic.scale.x * 10;
self.rimGraphic.scale.y = self.bubbleGraphic.scale.y * 10;
// Add occasional sparkle effect for special bubbles
if (Math.random() < 0.05) {
particles.emit({
x: self.x,
y: self.y,
count: 1,
minSpeed: 0.5,
maxSpeed: 1.5,
minScale: 0.1,
maxScale: 0.3,
minLifetime: 300,
maxLifetime: 600,
color: 0xFFFFFF,
fadeOut: true
});
}
} else {
// Subtle scale variation for normal bubbles to make them look more organic
var scaleVar = Math.sin(LK.ticks * 0.02 + self.x * 0.01) * 0.02;
self.bubbleGraphic.scale.x = self.size + scaleVar;
self.bubbleGraphic.scale.y = self.size + scaleVar;
// Update shine position
self.shineGraphic.scale.x = self.bubbleGraphic.scale.x * 0.5;
self.shineGraphic.scale.y = self.bubbleGraphic.scale.y * 0.5;
}
};
return self;
});
var BubbleParticle = Container.expand(function (color, size) {
var self = Container.call(this);
self.lifespan = 30 + Math.random() * 30;
self.age = 0;
self.speed = 1 + Math.random() * 3;
self.direction = Math.random() * Math.PI * 2;
self.gravity = 0.05 + Math.random() * 0.1;
var particleSize = (10 + Math.random() * 15) * size;
self.graphic = self.attachAsset('bubble_ring', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: particleSize,
scaleY: particleSize,
alpha: 0.8
});
// Set the color of the particle
self.graphic.tint = color;
self.update = function () {
// Update position based on velocity
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
// Add gravity effect
self.y += self.gravity;
// Age the particle
self.age++;
// Fade out as it ages
self.alpha = 1 - self.age / self.lifespan;
// Remove when dead
if (self.age >= self.lifespan) {
self.readyToRemove = true;
}
};
return self;
});
var Particles = Container.expand(function () {
var self = Container.call(this);
self.burst = function (options) {
var count = options.count || 10;
var minSpeed = options.minSpeed || 1;
var maxSpeed = options.maxSpeed || 5;
var minScale = options.minScale || 0.1;
var maxScale = options.maxScale || 0.5;
var minLifetime = options.minLifetime || 300;
var maxLifetime = options.maxLifetime || 800;
var gravity = options.gravity || 0;
var color = options.color || 0xFFFFFF;
var fadeOut = options.fadeOut || true;
var x = options.x || 0;
var y = options.y || 0;
for (var i = 0; i < count; i++) {
var particle = new BubbleParticle(color, Math.random() * (maxScale - minScale) + minScale);
particle.x = x;
particle.y = y;
particle.speed = Math.random() * (maxSpeed - minSpeed) + minSpeed;
particle.gravity = gravity;
particle.lifespan = Math.random() * (maxLifetime - minLifetime) + minLifetime;
game.addChild(particle);
bubbleParticles.push(particle);
}
};
self.emit = function (options) {
var count = options.count || 1;
var minSpeed = options.minSpeed || 0.5;
var maxSpeed = options.maxSpeed || 1.5;
var minScale = options.minScale || 0.1;
var maxScale = options.maxScale || 0.3;
var minLifetime = options.minLifetime || 300;
var maxLifetime = options.maxLifetime || 600;
var color = options.color || 0xFFFFFF;
var fadeOut = options.fadeOut || true;
var x = options.x || 0;
var y = options.y || 0;
for (var i = 0; i < count; i++) {
var particle = new BubbleParticle(color, Math.random() * (maxScale - minScale) + minScale);
particle.x = x;
particle.y = y;
particle.speed = Math.random() * (maxSpeed - minSpeed) + minSpeed;
particle.lifespan = Math.random() * (maxLifetime - minLifetime) + minLifetime;
game.addChild(particle);
bubbleParticles.push(particle);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x4588d2
});
/****
* Game Code
****/
// Game variables
var bubbles = [];
var bubbleParticles = [];
var difficulty = 1;
var spawnRate = 60; // Frames between bubble spawns
var gameSpeed = 1;
var currentMultiplier = 1;
var lastSpawn = 0;
var gameRunning = true;
var clickUpgrades = 0;
var speedUpgrades = 0;
var upgradeMultiplier = 1.2; // Speed increase per upgrade
// Background bubble effect variables
var backgroundBubbles = [];
// Particle system
var particles = new Particles();
// Score display
var scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
// Level display
var levelTxt = new Text2('Level: 1', {
size: 70,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(levelTxt);
levelTxt.x = -250;
levelTxt.y = 50;
// Message display (for power-ups and events)
var messageTxt = new Text2('', {
size: 100,
fill: 0xFFFFFF
});
messageTxt.anchor.set(0.5, 0.5);
messageTxt.alpha = 0;
LK.gui.center.addChild(messageTxt);
// Function to show temporary messages
function showMessage(message, duration) {
messageTxt.setText(message);
messageTxt.alpha = 1;
// Animate message
tween(messageTxt, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(messageTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
// Hide after duration
LK.setTimeout(function () {
tween(messageTxt, {
alpha: 0
}, {
duration: 500
});
}, duration);
}
// Update score display
function updateScoreText() {
scoreTxt.setText(LK.getScore().toString());
// Check for level up
var newLevel = Math.floor(LK.getScore() / 500) + 1;
if (newLevel > difficulty) {
difficulty = newLevel;
levelTxt.setText('Level: ' + difficulty);
showMessage("LEVEL UP!", 2000);
// Decrease spawn rate with level (faster spawning)
spawnRate = Math.max(10, 60 - difficulty * 5);
}
}
// Function to spawn a bubble
function spawnBubble() {
// Determine bubble type
var types = ['red', 'blue', 'green', 'yellow', 'purple'];
var type = types[Math.floor(Math.random() * types.length)];
// Special bubble chance (10% + increases slightly with difficulty)
var specialChance = 0.1 + difficulty * 0.01;
if (Math.random() < specialChance) {
type = 'special';
}
// Random size variation
var size = 0.8 + Math.random() * 0.4;
// Speed based on size and difficulty
var speed = (2 + difficulty * 0.5) * (1 / size);
// Create the bubble
var bubble = new Bubble(type, size, speed);
// Position randomly along bottom of screen
bubble.x = 150 + Math.random() * (2048 - 300);
bubble.y = 2732 + 100;
// Store original speed for upgrade calculations
bubble.originalSpeed = bubble.speed;
// Apply current speed upgrades
if (speedUpgrades > 0) {
bubble.speed = bubble.originalSpeed * speedUpgrades;
}
// Add to game and array
game.addChild(bubble);
bubbles.push(bubble);
}
// Function to pop bubbles near a specific bubble
function popNearbyBubbles(sourceBubble) {
var popRadius = 300;
for (var i = 0; i < bubbles.length; i++) {
if (bubbles[i] !== sourceBubble && !bubbles[i].readyToRemove) {
var dx = bubbles[i].x - sourceBubble.x;
var dy = bubbles[i].y - sourceBubble.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < popRadius) {
bubbles[i].pop();
}
}
}
}
// Game update function
game.update = function () {
if (!gameRunning) return;
// Spawn bubbles on interval
if (LK.ticks - lastSpawn > spawnRate) {
spawnBubble();
lastSpawn = LK.ticks;
}
// Process bubbles
for (var i = bubbles.length - 1; i >= 0; i--) {
var bubble = bubbles[i];
// Check if bubble has gone off top of screen
if (bubble.y < -150) {
// Remove bubble
bubble.destroy();
bubbles.splice(i, 1);
// Lose life or game over if not special
if (!bubble.isSpecial) {
// Game over
gameRunning = false;
// Update high score
if (LK.getScore() > storage.highScore) {
storage.highScore = LK.getScore();
}
// Flash screen and show game over
LK.effects.flashScreen(0xff0000, 1000);
LK.getSound('game_over').play();
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
continue;
}
// Remove popped bubbles
if (bubble.readyToRemove) {
bubble.destroy();
bubbles.splice(i, 1);
}
}
// Process bubble particles
for (var i = bubbleParticles.length - 1; i >= 0; i--) {
var particle = bubbleParticles[i];
// Update particle
particle.update();
// Remove dead particles
if (particle.readyToRemove) {
particle.destroy();
bubbleParticles.splice(i, 1);
}
}
// Add occasional background bubbles for visual effect
if (Math.random() < 0.02) {
var bgBubble = new BubbleParticle(0xFFFFFF, 2);
bgBubble.x = Math.random() * 2048;
bgBubble.y = 2732 + 50;
bgBubble.speed = 0.5 + Math.random() * 1;
bgBubble.direction = -Math.PI / 2; // Move upward
bgBubble.alpha = 0.2 + Math.random() * 0.2;
bgBubble.lifespan = 300 + Math.random() * 200;
// Add to game and track
game.addChild(bgBubble);
backgroundBubbles.push(bgBubble);
}
// Process background bubbles
for (var i = backgroundBubbles.length - 1; i >= 0; i--) {
var bgBubble = backgroundBubbles[i];
// Update bubble
bgBubble.update();
// Remove when offscreen or dead
if (bgBubble.y < -50 || bgBubble.readyToRemove) {
bgBubble.destroy();
backgroundBubbles.splice(i, 1);
}
}
};
// Game start
function startGame() {
// Reset variables
bubbles = [];
bubbleParticles = [];
backgroundBubbles = [];
difficulty = 1;
spawnRate = 60;
gameSpeed = 1;
currentMultiplier = 1;
lastSpawn = 0;
gameRunning = true;
clickUpgrades = 0;
speedUpgrades = 0;
// Reset score
LK.setScore(0);
updateScoreText();
levelTxt.setText('Level: 1');
// Show welcome message
showMessage("POP THE BUBBLES!", 2000);
// Start music
LK.playMusic('game_music', {
fade: {
start: 0,
end: 0.6,
duration: 1000
}
});
}
// Function to apply speed upgrades to all bubbles
function applySpeedUpgradeToBubbles() {
// Calculate new speed multiplier based on clicks
speedUpgrades = 1 + clickUpgrades * 0.01; // 1% speed increase per click
// Apply to all existing bubbles with visual effect
for (var i = 0; i < bubbles.length; i++) {
var bubble = bubbles[i];
if (!bubble.readyToRemove) {
// Store original speed if not already stored
if (!bubble.originalSpeed) {
bubble.originalSpeed = bubble.speed;
}
// Calculate new speed
var newSpeed = bubble.originalSpeed * speedUpgrades;
// Apply new speed with visual feedback
bubble.speed = newSpeed;
// Visual feedback - flash the bubble briefly
if (clickUpgrades % 5 === 0) {
// Only show visual effect every 5 upgrades to avoid spam
tween(bubble, {
scaleX: bubble.size * 1.2,
scaleY: bubble.size * 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(bubble, {
scaleX: bubble.size,
scaleY: bubble.size
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
}
}
// Show upgrade message on significant milestones
if (clickUpgrades % 10 === 0) {
showMessage("SPEED UP! " + Math.floor(speedUpgrades * 100) + "%", 1500);
}
}
// Start the game
startGame();
;