/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Balloon class
var Balloon = Container.expand(function () {
var self = Container.call(this);
// Balloon color options
var colors = [0xff4d4d, 0x4db8ff, 0x4dff88, 0xffe14d, 0xff4df2, 0x9d4dff];
// Random color
var color = colors[Math.floor(Math.random() * colors.length)];
// Random size
var minSize = 120;
var maxSize = 220;
var size = minSize + Math.floor(Math.random() * (maxSize - minSize));
// Attach balloon shape (ellipse)
var balloonShape = self.attachAsset('balloon', {
width: size,
height: size * 1.2,
color: color,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
// Is this a special balloon?
self.isSpecial = false;
self.specialType = null;
// 10% chance to be a special balloon
if (Math.random() < 0.1) {
self.isSpecial = true;
// Randomly choose special type: 'score' or 'slow'
self.specialType = Math.random() < 0.5 ? 'score' : 'slow';
// Add a visual indicator (star or S)
var specialTxt = new Text2(self.specialType === 'score' ? '★' : 'S', {
size: size * 0.7,
fill: self.specialType === 'score' ? "#fff700" : "#00eaff"
});
specialTxt.anchor.set(0.5, 0.5);
self.addChild(specialTxt);
}
// Set initial speed (pixels per frame)
self.baseSpeed = 6 + Math.random() * 3;
self.speed = self.baseSpeed;
// For touch detection
self.interactive = true;
// For popping animation
self.isPopping = false;
// Pop balloon
self.pop = function () {
if (self.isPopping) return;
self.isPopping = true;
// Animate: scale up and fade out
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 250,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
// Update method called every tick
self.update = function () {
if (self.isPopping) return;
self.y -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Game variables
var balloons = [];
var spawnInterval = 36; // frames between spawns (~0.6s at 60fps)
var lastSpawnTick = 0;
var gameDuration = 30 * 60; // 30 seconds * 60fps
var timeLeft = gameDuration;
var score = 0;
var slowEffectTicks = 0;
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Timer text
var timerTxt = new Text2('30', {
size: 90,
fill: 0xFFFFFF
});
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
timerTxt.y = 120;
// Helper: spawn a balloon at random x
function spawnBalloon() {
var balloon = new Balloon();
// Random x, avoid leftmost 100px (menu) and rightmost 100px
var margin = 140;
var x = margin + Math.random() * (2048 - 2 * margin);
balloon.x = x;
// Start just below the bottom
balloon.y = 2732 + balloon.height / 2;
// Randomize z-order a bit
game.addChild(balloon);
balloons.push(balloon);
}
// Helper: handle popping a balloon
function handlePop(balloon) {
if (balloon.isPopping) return;
// Score
var addScore = 1;
if (balloon.isSpecial) {
if (balloon.specialType === 'score') {
addScore = 5;
LK.effects.flashObject(balloon, 0xfff700, 400);
} else if (balloon.specialType === 'slow') {
slowEffectTicks = 180; // 3 seconds slow
LK.effects.flashScreen(0x00eaff, 300);
}
}
score += addScore;
LK.setScore(score);
scoreTxt.setText(score);
balloon.pop();
}
// Touch/drag handling
var dragBalloon = null;
function getBalloonAt(x, y) {
for (var i = balloons.length - 1; i >= 0; i--) {
var b = balloons[i];
if (b.isPopping) continue;
// Simple hit test: distance to center < radius
var dx = x - b.x;
var dy = y - b.y;
var rx = b.width / 2;
var ry = b.height / 2;
if (dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1) {
return b;
}
}
return null;
}
// Touch down: pop balloon if touched
game.down = function (x, y, obj) {
var b = getBalloonAt(x, y);
if (b) {
handlePop(b);
dragBalloon = b;
}
};
// Touch move: allow dragging finger to pop more balloons
game.move = function (x, y, obj) {
var b = getBalloonAt(x, y);
if (b && b !== dragBalloon) {
handlePop(b);
dragBalloon = b;
}
};
// Touch up: reset drag
game.up = function (x, y, obj) {
dragBalloon = null;
};
// Main update loop
game.update = function () {
// Spawn balloons
if (LK.ticks - lastSpawnTick >= spawnInterval) {
spawnBalloon();
lastSpawnTick = LK.ticks;
}
// Update slow effect
var speedFactor = 1;
if (slowEffectTicks > 0) {
speedFactor = 0.4;
slowEffectTicks--;
}
// Update balloons
for (var i = balloons.length - 1; i >= 0; i--) {
var b = balloons[i];
if (b.isPopping) continue;
b.speed = b.baseSpeed * speedFactor;
b.update();
// Remove if off top
if (b.y + b.height / 2 < 0) {
b.pop();
balloons.splice(i, 1);
}
}
// Remove destroyed balloons from array
for (var i = balloons.length - 1; i >= 0; i--) {
if (balloons[i].destroyed) {
balloons.splice(i, 1);
}
}
// Update timer
timeLeft--;
var seconds = Math.ceil(timeLeft / 60);
timerTxt.setText(seconds);
// End game if time is up
if (timeLeft <= 0) {
LK.showGameOver();
}
};
// Initialize score and timer
score = 0;
LK.setScore(score);
scoreTxt.setText(score);
timerTxt.setText(Math.ceil(gameDuration / 60)); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Balloon class
var Balloon = Container.expand(function () {
var self = Container.call(this);
// Balloon color options
var colors = [0xff4d4d, 0x4db8ff, 0x4dff88, 0xffe14d, 0xff4df2, 0x9d4dff];
// Random color
var color = colors[Math.floor(Math.random() * colors.length)];
// Random size
var minSize = 120;
var maxSize = 220;
var size = minSize + Math.floor(Math.random() * (maxSize - minSize));
// Attach balloon shape (ellipse)
var balloonShape = self.attachAsset('balloon', {
width: size,
height: size * 1.2,
color: color,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
// Is this a special balloon?
self.isSpecial = false;
self.specialType = null;
// 10% chance to be a special balloon
if (Math.random() < 0.1) {
self.isSpecial = true;
// Randomly choose special type: 'score' or 'slow'
self.specialType = Math.random() < 0.5 ? 'score' : 'slow';
// Add a visual indicator (star or S)
var specialTxt = new Text2(self.specialType === 'score' ? '★' : 'S', {
size: size * 0.7,
fill: self.specialType === 'score' ? "#fff700" : "#00eaff"
});
specialTxt.anchor.set(0.5, 0.5);
self.addChild(specialTxt);
}
// Set initial speed (pixels per frame)
self.baseSpeed = 6 + Math.random() * 3;
self.speed = self.baseSpeed;
// For touch detection
self.interactive = true;
// For popping animation
self.isPopping = false;
// Pop balloon
self.pop = function () {
if (self.isPopping) return;
self.isPopping = true;
// Animate: scale up and fade out
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 250,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
// Update method called every tick
self.update = function () {
if (self.isPopping) return;
self.y -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Game variables
var balloons = [];
var spawnInterval = 36; // frames between spawns (~0.6s at 60fps)
var lastSpawnTick = 0;
var gameDuration = 30 * 60; // 30 seconds * 60fps
var timeLeft = gameDuration;
var score = 0;
var slowEffectTicks = 0;
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Timer text
var timerTxt = new Text2('30', {
size: 90,
fill: 0xFFFFFF
});
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
timerTxt.y = 120;
// Helper: spawn a balloon at random x
function spawnBalloon() {
var balloon = new Balloon();
// Random x, avoid leftmost 100px (menu) and rightmost 100px
var margin = 140;
var x = margin + Math.random() * (2048 - 2 * margin);
balloon.x = x;
// Start just below the bottom
balloon.y = 2732 + balloon.height / 2;
// Randomize z-order a bit
game.addChild(balloon);
balloons.push(balloon);
}
// Helper: handle popping a balloon
function handlePop(balloon) {
if (balloon.isPopping) return;
// Score
var addScore = 1;
if (balloon.isSpecial) {
if (balloon.specialType === 'score') {
addScore = 5;
LK.effects.flashObject(balloon, 0xfff700, 400);
} else if (balloon.specialType === 'slow') {
slowEffectTicks = 180; // 3 seconds slow
LK.effects.flashScreen(0x00eaff, 300);
}
}
score += addScore;
LK.setScore(score);
scoreTxt.setText(score);
balloon.pop();
}
// Touch/drag handling
var dragBalloon = null;
function getBalloonAt(x, y) {
for (var i = balloons.length - 1; i >= 0; i--) {
var b = balloons[i];
if (b.isPopping) continue;
// Simple hit test: distance to center < radius
var dx = x - b.x;
var dy = y - b.y;
var rx = b.width / 2;
var ry = b.height / 2;
if (dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1) {
return b;
}
}
return null;
}
// Touch down: pop balloon if touched
game.down = function (x, y, obj) {
var b = getBalloonAt(x, y);
if (b) {
handlePop(b);
dragBalloon = b;
}
};
// Touch move: allow dragging finger to pop more balloons
game.move = function (x, y, obj) {
var b = getBalloonAt(x, y);
if (b && b !== dragBalloon) {
handlePop(b);
dragBalloon = b;
}
};
// Touch up: reset drag
game.up = function (x, y, obj) {
dragBalloon = null;
};
// Main update loop
game.update = function () {
// Spawn balloons
if (LK.ticks - lastSpawnTick >= spawnInterval) {
spawnBalloon();
lastSpawnTick = LK.ticks;
}
// Update slow effect
var speedFactor = 1;
if (slowEffectTicks > 0) {
speedFactor = 0.4;
slowEffectTicks--;
}
// Update balloons
for (var i = balloons.length - 1; i >= 0; i--) {
var b = balloons[i];
if (b.isPopping) continue;
b.speed = b.baseSpeed * speedFactor;
b.update();
// Remove if off top
if (b.y + b.height / 2 < 0) {
b.pop();
balloons.splice(i, 1);
}
}
// Remove destroyed balloons from array
for (var i = balloons.length - 1; i >= 0; i--) {
if (balloons[i].destroyed) {
balloons.splice(i, 1);
}
}
// Update timer
timeLeft--;
var seconds = Math.ceil(timeLeft / 60);
timerTxt.setText(seconds);
// End game if time is up
if (timeLeft <= 0) {
LK.showGameOver();
}
};
// Initialize score and timer
score = 0;
LK.setScore(score);
scoreTxt.setText(score);
timerTxt.setText(Math.ceil(gameDuration / 60));