/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Explosion = Container.expand(function () {
var self = Container.call(this);
self.init = function (x, y, color) {
self.x = x;
self.y = y;
// Create explosion particles
var particleCount = 8;
for (var i = 0; i < particleCount; i++) {
var particle = LK.getAsset('Party', {
anchorX: 0.5,
anchorY: 0.5,
tint: color,
alpha: 0.8,
scaleX: 0.5,
scaleY: 0.5
});
// Calculate angle for radial spread
var angle = Math.PI * 2 / particleCount * i;
var vx = Math.cos(angle) * 8;
var vy = Math.sin(angle) * 8;
// Store velocity on particle
particle.vx = vx;
particle.vy = vy;
particle.life = 30;
self.addChild(particle);
}
};
self.update = function () {
for (var i = self.children.length - 1; i >= 0; i--) {
var particle = self.children[i];
if (particle) {
particle.x += particle.vx;
particle.y += particle.vy;
particle.life--;
particle.alpha = particle.life / 30 * 0.8;
if (particle.life <= 0) {
particle.destroy();
}
}
}
// Destroy explosion container when all particles are gone
if (self.children.length === 0) {
self.destroy();
}
};
return self;
});
var Firework = Container.expand(function () {
var self = Container.call(this);
var colors = ['firework', 'fireworkBlue', 'fireworkGreen', 'fireworkYellow', 'fireworkPurple'];
var colorTints = [0xFFD700, 0x00BFFF, 0x00FF00, 0xFFFF00, 0xDA70D6];
var randomIndex = Math.floor(Math.random() * colors.length);
var randomColor = colors[randomIndex];
self.explosionColor = colorTints[randomIndex];
var fireworkGraphics = self.attachAsset(randomColor, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.collected = false;
self.lastX = 0;
self.update = function () {
if (!self.collected) {
self.x += self.speed;
self.lastX = self.x;
}
};
self.down = function (x, y, obj) {
if (!self.collected) {
self.collected = true;
LK.getSound('tap').play();
// Create explosion effect with firework's color
var explosion = new Explosion();
explosion.init(self.x, self.y, self.explosionColor);
self.parent.addChild(explosion);
tween(self, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
var SongMenu = Container.expand(function () {
var self = Container.call(this);
self.selectedSong = null;
var titleTxt = new Text2('Choose a Song', {
size: 150,
fill: 0xFFFFFF
});
titleTxt.anchor.set(0.5, 0);
titleTxt.x = 1024;
titleTxt.y = 400;
self.addChild(titleTxt);
var songNames = ['Song 1', 'Song 2', 'Song 3'];
var songIds = ['song1', 'song2', 'song3'];
var buttons = [];
for (var i = 0; i < 3; i++) {
var buttonContainer = new Container();
buttonContainer.x = 300 + i * 600;
buttonContainer.y = 1200;
var buttonBg = LK.getAsset('Party', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x4A5568,
scaleX: 2,
scaleY: 1.5
});
buttonContainer.addChild(buttonBg);
var songTxt = new Text2(songNames[i], {
size: 80,
fill: 0xFFFFFF
});
songTxt.anchor.set(0.5, 0.5);
buttonContainer.addChild(songTxt);
buttonContainer.songId = songIds[i];
buttonContainer.interactive = true;
(function (btn) {
btn.down = function (x, y, obj) {
self.selectedSong = btn.songId;
self.destroy();
startGame(self.selectedSong);
};
})(buttonContainer);
buttons.push(buttonContainer);
self.addChild(buttonContainer);
}
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0F0F1E
});
/****
* Game Code
****/
// Game variables
var score = 0;
var missCount = 0;
var fireworks = [];
var gameActive = true;
var beatTiming = 0;
// Rhythm settings - 120 BPM = 2 beats per second = 30 ticks per beat at 60 FPS
var bpm = 120;
var ticksPerBeat = Math.round(3600 / bpm); // 3600 ticks per minute at 60 FPS
var beatCounter = 0;
var nextBeatTick = 0;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var missTxt = new Text2('Misses: 0/3', {
size: 100,
fill: 0xFF6B9D
});
missTxt.anchor.set(0.5, 0);
missTxt.y = 140;
LK.gui.top.addChild(missTxt);
// Update score display
function updateScore() {
scoreTxt.setText('Score: ' + score);
}
// Update miss display
function updateMisses() {
missTxt.setText('Misses: ' + missCount + '/3');
if (missCount >= 3) {
gameActive = false;
LK.showGameOver();
}
}
// Game update loop
game.update = function () {
if (!gameActive) return;
beatTiming++;
// Spawn fireworks on rhythm beats
if (LK.ticks >= nextBeatTick) {
var newFirework = new Firework();
newFirework.x = -100;
newFirework.y = Math.random() * (2732 - 240) + 120;
newFirework.lastX = newFirework.x;
fireworks.push(newFirework);
game.addChild(newFirework);
beatCounter++;
// Move to next beat
nextBeatTick = LK.ticks + ticksPerBeat;
// Gradually increase difficulty by reducing ticksPerBeat (faster spawns)
if (ticksPerBeat > 10) {
ticksPerBeat -= 0.15;
nextBeatTick = LK.ticks + ticksPerBeat;
}
}
// Update fireworks and check for missed ones
for (var a = fireworks.length - 1; a >= 0; a--) {
var firework = fireworks[a];
if (firework.lastX === undefined) {
firework.lastX = firework.x;
}
// Check if firework went off-screen (missed) - only count if not already collected
if (firework.x > 2048 && !firework.collected) {
missCount++;
updateMisses();
firework.destroy();
fireworks.splice(a, 1);
continue;
}
// Clean up collected fireworks
if (firework.collected && firework.alpha === 0) {
score++;
updateScore();
firework.destroy();
fireworks.splice(a, 1);
continue;
}
firework.lastX = firework.x;
}
};
// Handle tap on fireworks
game.down = function (x, y, obj) {
// Event is handled by individual firework classes via their down methods
};
// Show song selection menu on game start
var songMenu = game.addChild(new SongMenu());
songMenu.x = 0;
songMenu.y = 0;
// High score tracking
var highScore = storage.highScore || 0;
// Store high score when game ends
LK.on('showGameOver', function () {
if (score > highScore) {
storage.highScore = score;
}
});
var selectedMusicTrack = 'song1';
function startGame(musicTrack) {
selectedMusicTrack = musicTrack;
score = 0;
missCount = 0;
fireworks = [];
gameActive = true;
beatCounter = 0;
nextBeatTick = 0;
updateScore();
updateMisses();
LK.playMusic(selectedMusicTrack, {
loop: true
});
} /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Explosion = Container.expand(function () {
var self = Container.call(this);
self.init = function (x, y, color) {
self.x = x;
self.y = y;
// Create explosion particles
var particleCount = 8;
for (var i = 0; i < particleCount; i++) {
var particle = LK.getAsset('Party', {
anchorX: 0.5,
anchorY: 0.5,
tint: color,
alpha: 0.8,
scaleX: 0.5,
scaleY: 0.5
});
// Calculate angle for radial spread
var angle = Math.PI * 2 / particleCount * i;
var vx = Math.cos(angle) * 8;
var vy = Math.sin(angle) * 8;
// Store velocity on particle
particle.vx = vx;
particle.vy = vy;
particle.life = 30;
self.addChild(particle);
}
};
self.update = function () {
for (var i = self.children.length - 1; i >= 0; i--) {
var particle = self.children[i];
if (particle) {
particle.x += particle.vx;
particle.y += particle.vy;
particle.life--;
particle.alpha = particle.life / 30 * 0.8;
if (particle.life <= 0) {
particle.destroy();
}
}
}
// Destroy explosion container when all particles are gone
if (self.children.length === 0) {
self.destroy();
}
};
return self;
});
var Firework = Container.expand(function () {
var self = Container.call(this);
var colors = ['firework', 'fireworkBlue', 'fireworkGreen', 'fireworkYellow', 'fireworkPurple'];
var colorTints = [0xFFD700, 0x00BFFF, 0x00FF00, 0xFFFF00, 0xDA70D6];
var randomIndex = Math.floor(Math.random() * colors.length);
var randomColor = colors[randomIndex];
self.explosionColor = colorTints[randomIndex];
var fireworkGraphics = self.attachAsset(randomColor, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.collected = false;
self.lastX = 0;
self.update = function () {
if (!self.collected) {
self.x += self.speed;
self.lastX = self.x;
}
};
self.down = function (x, y, obj) {
if (!self.collected) {
self.collected = true;
LK.getSound('tap').play();
// Create explosion effect with firework's color
var explosion = new Explosion();
explosion.init(self.x, self.y, self.explosionColor);
self.parent.addChild(explosion);
tween(self, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
var SongMenu = Container.expand(function () {
var self = Container.call(this);
self.selectedSong = null;
var titleTxt = new Text2('Choose a Song', {
size: 150,
fill: 0xFFFFFF
});
titleTxt.anchor.set(0.5, 0);
titleTxt.x = 1024;
titleTxt.y = 400;
self.addChild(titleTxt);
var songNames = ['Song 1', 'Song 2', 'Song 3'];
var songIds = ['song1', 'song2', 'song3'];
var buttons = [];
for (var i = 0; i < 3; i++) {
var buttonContainer = new Container();
buttonContainer.x = 300 + i * 600;
buttonContainer.y = 1200;
var buttonBg = LK.getAsset('Party', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x4A5568,
scaleX: 2,
scaleY: 1.5
});
buttonContainer.addChild(buttonBg);
var songTxt = new Text2(songNames[i], {
size: 80,
fill: 0xFFFFFF
});
songTxt.anchor.set(0.5, 0.5);
buttonContainer.addChild(songTxt);
buttonContainer.songId = songIds[i];
buttonContainer.interactive = true;
(function (btn) {
btn.down = function (x, y, obj) {
self.selectedSong = btn.songId;
self.destroy();
startGame(self.selectedSong);
};
})(buttonContainer);
buttons.push(buttonContainer);
self.addChild(buttonContainer);
}
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0F0F1E
});
/****
* Game Code
****/
// Game variables
var score = 0;
var missCount = 0;
var fireworks = [];
var gameActive = true;
var beatTiming = 0;
// Rhythm settings - 120 BPM = 2 beats per second = 30 ticks per beat at 60 FPS
var bpm = 120;
var ticksPerBeat = Math.round(3600 / bpm); // 3600 ticks per minute at 60 FPS
var beatCounter = 0;
var nextBeatTick = 0;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var missTxt = new Text2('Misses: 0/3', {
size: 100,
fill: 0xFF6B9D
});
missTxt.anchor.set(0.5, 0);
missTxt.y = 140;
LK.gui.top.addChild(missTxt);
// Update score display
function updateScore() {
scoreTxt.setText('Score: ' + score);
}
// Update miss display
function updateMisses() {
missTxt.setText('Misses: ' + missCount + '/3');
if (missCount >= 3) {
gameActive = false;
LK.showGameOver();
}
}
// Game update loop
game.update = function () {
if (!gameActive) return;
beatTiming++;
// Spawn fireworks on rhythm beats
if (LK.ticks >= nextBeatTick) {
var newFirework = new Firework();
newFirework.x = -100;
newFirework.y = Math.random() * (2732 - 240) + 120;
newFirework.lastX = newFirework.x;
fireworks.push(newFirework);
game.addChild(newFirework);
beatCounter++;
// Move to next beat
nextBeatTick = LK.ticks + ticksPerBeat;
// Gradually increase difficulty by reducing ticksPerBeat (faster spawns)
if (ticksPerBeat > 10) {
ticksPerBeat -= 0.15;
nextBeatTick = LK.ticks + ticksPerBeat;
}
}
// Update fireworks and check for missed ones
for (var a = fireworks.length - 1; a >= 0; a--) {
var firework = fireworks[a];
if (firework.lastX === undefined) {
firework.lastX = firework.x;
}
// Check if firework went off-screen (missed) - only count if not already collected
if (firework.x > 2048 && !firework.collected) {
missCount++;
updateMisses();
firework.destroy();
fireworks.splice(a, 1);
continue;
}
// Clean up collected fireworks
if (firework.collected && firework.alpha === 0) {
score++;
updateScore();
firework.destroy();
fireworks.splice(a, 1);
continue;
}
firework.lastX = firework.x;
}
};
// Handle tap on fireworks
game.down = function (x, y, obj) {
// Event is handled by individual firework classes via their down methods
};
// Show song selection menu on game start
var songMenu = game.addChild(new SongMenu());
songMenu.x = 0;
songMenu.y = 0;
// High score tracking
var highScore = storage.highScore || 0;
// Store high score when game ends
LK.on('showGameOver', function () {
if (score > highScore) {
storage.highScore = score;
}
});
var selectedMusicTrack = 'song1';
function startGame(musicTrack) {
selectedMusicTrack = musicTrack;
score = 0;
missCount = 0;
fireworks = [];
gameActive = true;
beatCounter = 0;
nextBeatTick = 0;
updateScore();
updateMisses();
LK.playMusic(selectedMusicTrack, {
loop: true
});
}