/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5
});
// Add floating animation
self.floatDirection = Math.random() * Math.PI * 2;
self.floatSpeed = 2.0 + Math.random() * 4.0;
self.isDestroyed = false;
self.update = function () {
if (self.isDestroyed) return;
// Bubbles no longer move - they stay in place
};
self.down = function (x, y, obj) {
if (!isGameActive || self.isDestroyed) return;
// Resume timer when bubble is hit
if (timerPaused) {
timerPaused = false;
pausedTime += Date.now() - gameStartTime;
gameStartTime = Date.now();
}
// Mark as destroyed
self.isDestroyed = true;
// Pop this bubble - check for double score
var points = doubleScoreActive ? 20 : 10;
LK.setScore(LK.getScore() + points);
scoreTxt.setText('Score: ' + LK.getScore());
// Play pop sound
LK.getSound('pop').play();
// Time no longer increases when bubbles are popped
// Increase speed multipliers
speedMultiplier += 0.2;
spawnSpeedMultiplier += 0.15;
// Remove this bubble from array
for (var i = 0; i < bubbles.length; i++) {
if (bubbles[i] === self) {
bubbles.splice(i, 1);
break;
}
}
// Destroy this bubble
self.destroy();
// Spawn 1 new bubble at distant random location, but respect the 5 bubble limit
if (bubbles.length < 5) {
spawnBubbleDistant(self.x, self.y);
}
};
return self;
});
var MouseNeedle = Container.expand(function () {
var self = Container.call(this);
var needleGraphics = self.attachAsset('needle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001122
});
/****
* Game Code
****/
// Set cursor to needle image
game.cursor;
// Create needle that follows mouse
var mouseNeedle = game.addChild(new MouseNeedle());
// Handle mouse movement to make needle follow cursor
game.move = function (x, y, obj) {
mouseNeedle.x = x;
mouseNeedle.y = y;
};
// Add background
var background = game.attachAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
// Game variables
var bubbles = [];
var gameTimer = 60000; // 1 minute in milliseconds
var gameStartTime;
var isGameActive = false; // Game starts inactive
var gameStarted = false; // Track if game has been started
var speedMultiplier = 1.0; // Speed multiplier that increases with each hit
var spawnSpeedMultiplier = 1.0; // Spawn speed multiplier
var doubleScoreActive = false;
var doubleScoreEndTime = 0;
var timeBoostUsed = false;
var doubleScoreUsed = false;
var lastShrinkTime = 0; // Track when bubbles were last shrunk
var bubbleShrinkAmount = 10; // Amount to shrink bubbles by (10cm = ~37.8 pixels at 96 DPI)
var timerPaused = true; // Timer starts paused
var pausedTime = 0; // Track how much time was spent paused
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var timerTxt = new Text2('1:00', {
size: 60,
fill: 0xFFAA00
});
timerTxt.anchor.set(0.5, 0);
timerTxt.y = 80;
LK.gui.top.addChild(timerTxt);
// Play button
var playButton = new Text2('PLAY', {
size: 200,
fill: 0x00FF00
});
playButton.anchor.set(0.5, 0.5);
playButton.x = 1024;
playButton.y = 1366;
game.addChild(playButton);
// Play button click handler
playButton.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
isGameActive = true;
gameStartTime = Date.now();
playButton.destroy();
// Initialize bubbles - bubbles will spawn when play button is clicked
}
// Game start will be triggered by play button
};
// Powerup buttons removed
// Function to spawn a bubble at random position
function spawnBubble() {
var bubble = new Bubble();
// Avoid top-left 100x100 area where pause button is located
do {
bubble.x = 50 + Math.random() * 1948;
bubble.y = 50 + Math.random() * 2632;
} while (bubble.x < 150 && bubble.y < 150);
// Apply faster spawn animation
bubble.alpha = 0;
bubble.scaleX = 0.3;
bubble.scaleY = 0.3;
tween(bubble, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: Math.max(100, 500 / spawnSpeedMultiplier),
easing: tween.easeOut
});
bubbles.push(bubble);
game.addChild(bubble);
}
// Function to spawn a bubble at distant random location from given position
function spawnBubbleDistant(fromX, fromY) {
var bubble = new Bubble();
var bestX, bestY;
var maxDistance = 0;
// Try multiple random positions and pick the one farthest away
for (var attempt = 0; attempt < 10; attempt++) {
var testX, testY;
// Avoid top-left 100x100 area where pause button is located
do {
testX = 50 + Math.random() * 1948;
testY = 50 + Math.random() * 2632;
} while (testX < 150 && testY < 150);
var distance = Math.sqrt((testX - fromX) * (testX - fromX) + (testY - fromY) * (testY - fromY));
if (distance > maxDistance) {
maxDistance = distance;
bestX = testX;
bestY = testY;
}
}
bubble.x = bestX;
bubble.y = bestY;
// Apply faster spawn animation
bubble.alpha = 0;
bubble.scaleX = 0.3;
bubble.scaleY = 0.3;
tween(bubble, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: Math.max(100, 500 / spawnSpeedMultiplier),
easing: tween.easeOut
});
bubbles.push(bubble);
game.addChild(bubble);
}
// Initialize bubbles - start with just 1 bubble
spawnBubble();
// Game start
// Main game update loop
game.update = function () {
if (!isGameActive) return;
// Update timer - only count down when not paused
var elapsed;
if (timerPaused) {
elapsed = pausedTime;
} else {
elapsed = pausedTime + (Date.now() - gameStartTime);
}
var remaining = Math.max(0, gameTimer - elapsed);
if (remaining <= 0) {
isGameActive = false;
LK.showGameOver();
return;
}
var minutes = Math.floor(remaining / 60000);
var seconds = Math.floor(remaining % 60000 / 1000);
timerTxt.setText(minutes + ':' + (seconds < 10 ? '0' : '') + seconds);
// Check if double score effect should end
if (doubleScoreActive && Date.now() > doubleScoreEndTime) {
doubleScoreActive = false;
}
// Shrink bubbles every 10 seconds - only when timer is running
if (!timerPaused && elapsed - lastShrinkTime >= 10000) {
lastShrinkTime = elapsed;
for (var i = 0; i < bubbles.length; i++) {
var bubble = bubbles[i];
if (!bubble.isDestroyed) {
var newScale = bubble.scaleX - 0.1;
// If bubble becomes smaller than 20cm (scale < 0.2), reset to normal size
if (newScale < 0.2) {
newScale = 1.0;
}
tween(bubble, {
scaleX: newScale,
scaleY: newScale
}, {
duration: 500,
easing: tween.easeOut
});
}
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5
});
// Add floating animation
self.floatDirection = Math.random() * Math.PI * 2;
self.floatSpeed = 2.0 + Math.random() * 4.0;
self.isDestroyed = false;
self.update = function () {
if (self.isDestroyed) return;
// Bubbles no longer move - they stay in place
};
self.down = function (x, y, obj) {
if (!isGameActive || self.isDestroyed) return;
// Resume timer when bubble is hit
if (timerPaused) {
timerPaused = false;
pausedTime += Date.now() - gameStartTime;
gameStartTime = Date.now();
}
// Mark as destroyed
self.isDestroyed = true;
// Pop this bubble - check for double score
var points = doubleScoreActive ? 20 : 10;
LK.setScore(LK.getScore() + points);
scoreTxt.setText('Score: ' + LK.getScore());
// Play pop sound
LK.getSound('pop').play();
// Time no longer increases when bubbles are popped
// Increase speed multipliers
speedMultiplier += 0.2;
spawnSpeedMultiplier += 0.15;
// Remove this bubble from array
for (var i = 0; i < bubbles.length; i++) {
if (bubbles[i] === self) {
bubbles.splice(i, 1);
break;
}
}
// Destroy this bubble
self.destroy();
// Spawn 1 new bubble at distant random location, but respect the 5 bubble limit
if (bubbles.length < 5) {
spawnBubbleDistant(self.x, self.y);
}
};
return self;
});
var MouseNeedle = Container.expand(function () {
var self = Container.call(this);
var needleGraphics = self.attachAsset('needle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001122
});
/****
* Game Code
****/
// Set cursor to needle image
game.cursor;
// Create needle that follows mouse
var mouseNeedle = game.addChild(new MouseNeedle());
// Handle mouse movement to make needle follow cursor
game.move = function (x, y, obj) {
mouseNeedle.x = x;
mouseNeedle.y = y;
};
// Add background
var background = game.attachAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
// Game variables
var bubbles = [];
var gameTimer = 60000; // 1 minute in milliseconds
var gameStartTime;
var isGameActive = false; // Game starts inactive
var gameStarted = false; // Track if game has been started
var speedMultiplier = 1.0; // Speed multiplier that increases with each hit
var spawnSpeedMultiplier = 1.0; // Spawn speed multiplier
var doubleScoreActive = false;
var doubleScoreEndTime = 0;
var timeBoostUsed = false;
var doubleScoreUsed = false;
var lastShrinkTime = 0; // Track when bubbles were last shrunk
var bubbleShrinkAmount = 10; // Amount to shrink bubbles by (10cm = ~37.8 pixels at 96 DPI)
var timerPaused = true; // Timer starts paused
var pausedTime = 0; // Track how much time was spent paused
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var timerTxt = new Text2('1:00', {
size: 60,
fill: 0xFFAA00
});
timerTxt.anchor.set(0.5, 0);
timerTxt.y = 80;
LK.gui.top.addChild(timerTxt);
// Play button
var playButton = new Text2('PLAY', {
size: 200,
fill: 0x00FF00
});
playButton.anchor.set(0.5, 0.5);
playButton.x = 1024;
playButton.y = 1366;
game.addChild(playButton);
// Play button click handler
playButton.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
isGameActive = true;
gameStartTime = Date.now();
playButton.destroy();
// Initialize bubbles - bubbles will spawn when play button is clicked
}
// Game start will be triggered by play button
};
// Powerup buttons removed
// Function to spawn a bubble at random position
function spawnBubble() {
var bubble = new Bubble();
// Avoid top-left 100x100 area where pause button is located
do {
bubble.x = 50 + Math.random() * 1948;
bubble.y = 50 + Math.random() * 2632;
} while (bubble.x < 150 && bubble.y < 150);
// Apply faster spawn animation
bubble.alpha = 0;
bubble.scaleX = 0.3;
bubble.scaleY = 0.3;
tween(bubble, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: Math.max(100, 500 / spawnSpeedMultiplier),
easing: tween.easeOut
});
bubbles.push(bubble);
game.addChild(bubble);
}
// Function to spawn a bubble at distant random location from given position
function spawnBubbleDistant(fromX, fromY) {
var bubble = new Bubble();
var bestX, bestY;
var maxDistance = 0;
// Try multiple random positions and pick the one farthest away
for (var attempt = 0; attempt < 10; attempt++) {
var testX, testY;
// Avoid top-left 100x100 area where pause button is located
do {
testX = 50 + Math.random() * 1948;
testY = 50 + Math.random() * 2632;
} while (testX < 150 && testY < 150);
var distance = Math.sqrt((testX - fromX) * (testX - fromX) + (testY - fromY) * (testY - fromY));
if (distance > maxDistance) {
maxDistance = distance;
bestX = testX;
bestY = testY;
}
}
bubble.x = bestX;
bubble.y = bestY;
// Apply faster spawn animation
bubble.alpha = 0;
bubble.scaleX = 0.3;
bubble.scaleY = 0.3;
tween(bubble, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: Math.max(100, 500 / spawnSpeedMultiplier),
easing: tween.easeOut
});
bubbles.push(bubble);
game.addChild(bubble);
}
// Initialize bubbles - start with just 1 bubble
spawnBubble();
// Game start
// Main game update loop
game.update = function () {
if (!isGameActive) return;
// Update timer - only count down when not paused
var elapsed;
if (timerPaused) {
elapsed = pausedTime;
} else {
elapsed = pausedTime + (Date.now() - gameStartTime);
}
var remaining = Math.max(0, gameTimer - elapsed);
if (remaining <= 0) {
isGameActive = false;
LK.showGameOver();
return;
}
var minutes = Math.floor(remaining / 60000);
var seconds = Math.floor(remaining % 60000 / 1000);
timerTxt.setText(minutes + ':' + (seconds < 10 ? '0' : '') + seconds);
// Check if double score effect should end
if (doubleScoreActive && Date.now() > doubleScoreEndTime) {
doubleScoreActive = false;
}
// Shrink bubbles every 10 seconds - only when timer is running
if (!timerPaused && elapsed - lastShrinkTime >= 10000) {
lastShrinkTime = elapsed;
for (var i = 0; i < bubbles.length; i++) {
var bubble = bubbles[i];
if (!bubble.isDestroyed) {
var newScale = bubble.scaleX - 0.1;
// If bubble becomes smaller than 20cm (scale < 0.2), reset to normal size
if (newScale < 0.2) {
newScale = 1.0;
}
tween(bubble, {
scaleX: newScale,
scaleY: newScale
}, {
duration: 500,
easing: tween.easeOut
});
}
}
}
};