/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { volume: 0.6 }); /**** * Classes ****/ var Background = Container.expand(function () { var self = Container.call(this); var backgroundGraphics = self.attachAsset('background', { anchorX: 0, anchorY: 0 }); return self; }); var BonusNote = Container.expand(function () { var self = Container.call(this); var noteGraphics = self.attachAsset('bonusNote', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.lastY = 0; self.noteType = 'bonus'; self.update = function () { self.lastY = self.y; self.y += self.speed; // Add slight horizontal movement for bonus notes self.x += Math.sin(self.y * 0.01) * 2; }; return self; }); var FastNote = Container.expand(function () { var self = Container.call(this); var noteGraphics = self.attachAsset('fastNote', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 14; self.lastY = 0; self.noteType = 'fast'; self.update = function () { self.lastY = self.y; self.y += self.speed; }; return self; }); var Note = Container.expand(function () { var self = Container.call(this); var noteGraphics = self.attachAsset('note', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.lastY = 0; self.noteType = 'normal'; self.update = function () { self.lastY = self.y; self.y += self.speed; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var SlowNote = Container.expand(function () { var self = Container.call(this); var noteGraphics = self.attachAsset('slowNote', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.lastY = 0; self.noteType = 'slow'; self.update = function () { self.lastY = self.y; self.y += self.speed; }; return self; }); var Star = Container.expand(function () { var self = Container.call(this); var starGraphics = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5 }); self.speed = Math.random() * 2 + 1; self.twinkleSpeed = Math.random() * 0.1 + 0.05; self.opacity = Math.random() * 0.5 + 0.3; starGraphics.alpha = self.opacity; self.update = function () { self.y += self.speed; // Twinkling effect starGraphics.alpha = self.opacity + Math.sin(LK.ticks * self.twinkleSpeed) * 0.3; // Reset position when off screen if (self.y > 2732 + 20) { self.y = -20; self.x = Math.random() * 2048; } }; return self; }); var VolumeSlider = Container.expand(function () { var self = Container.call(this); // Slider background var sliderBg = self.attachAsset('volumeSliderBg', { anchorX: 0, anchorY: 0.5 }); // Slider handle var sliderHandle = self.attachAsset('volumeHandle', { anchorX: 0.5, anchorY: 0.5 }); self.isDragging = false; self.sliderWidth = 300; // Initialize handle position based on stored volume sliderHandle.x = storage.volume * self.sliderWidth; self.updateVolume = function (newVolume) { storage.volume = Math.max(0, Math.min(1, newVolume)); sliderHandle.x = storage.volume * self.sliderWidth; // Update music volume LK.stopMusic(); LK.playMusic('bgmusic', { volume: storage.volume }); }; self.down = function (x, y, obj) { self.isDragging = true; // Use the x,y coordinates directly as they are already in the correct coordinate space var newVolume = Math.max(0, Math.min(1, x / self.sliderWidth)); self.updateVolume(newVolume); }; self.move = function (x, y, obj) { if (self.isDragging) { // Use the x,y coordinates directly as they are already in the correct coordinate space var newVolume = Math.max(0, Math.min(1, x / self.sliderWidth)); self.updateVolume(newVolume); } }; self.up = function (x, y, obj) { self.isDragging = false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2C3E50 }); /**** * Game Code ****/ var notes = []; var noteSpawnTimer = 0; var noteSpawnInterval = 60; // Spawn every 60 ticks (1 second at 60fps) var gameStarted = false; var songEnded = false; var missedNotes = 0; var maxMisses = 3; // Game ends after 3 missed notes var rhythmPatterns = [{ type: 'normal', weight: 50 }, { type: 'fast', weight: 25 }, { type: 'slow', weight: 20 }, { type: 'bonus', weight: 5 }]; var patternTimer = 0; var currentPattern = 0; // Score display var scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Missed notes display var missesTxt = new Text2('Misses: 0/3', { size: 60, fill: 0xFF6B6B }); missesTxt.anchor.set(1, 0); LK.gui.topRight.addChild(missesTxt); // Instructions var instructionsTxt = new Text2('Drag to move and catch the notes!', { size: 60, fill: 0xFFFFFF }); instructionsTxt.anchor.set(0.5, 0.5); instructionsTxt.x = 2048 / 2; instructionsTxt.y = 2732 / 2 - 200; game.addChild(instructionsTxt); // Volume control UI (positioned below misses counter) var volumeIcon = LK.getAsset('volumeIcon', { anchorX: 0, anchorY: 0.5 }); LK.gui.topRight.addChild(volumeIcon); volumeIcon.x = -350; volumeIcon.y = 80; var volumeSlider = LK.gui.topRight.addChild(new VolumeSlider()); volumeSlider.x = -300; volumeSlider.y = 80; var volumeLabel = new Text2('Volume: ' + Math.round(storage.volume * 100) + '%', { size: 40, fill: 0xFFFFFF }); volumeLabel.anchor.set(0, 0.5); LK.gui.topRight.addChild(volumeLabel); volumeLabel.x = 20; volumeLabel.y = 80; // Update volume label function function updateVolumeLabel() { volumeLabel.setText('Volume: ' + Math.round(storage.volume * 100) + '%'); } var dragActive = false; // Background image var background = game.addChild(new Background()); background.x = 0; background.y = 0; // Player (added after background to layer on top) var player = game.addChild(new Player()); player.x = 2048 / 2; player.y = 2732 - 150; function updateScore() { scoreTxt.setText('Score: ' + LK.getScore()); } function updateMisses() { missesTxt.setText('Misses: ' + missedNotes + '/' + maxMisses); } function spawnNote() { var noteType = getRandomNoteType(); var note; switch (noteType) { case 'fast': note = new FastNote(); break; case 'slow': note = new SlowNote(); break; case 'bonus': note = new BonusNote(); break; default: note = new Note(); break; } note.x = Math.random() * (2048 - 160) + 80; // Keep notes within screen bounds note.y = -50; note.lastY = note.y; notes.push(note); game.addChild(note); } function getRandomNoteType() { var totalWeight = 0; for (var i = 0; i < rhythmPatterns.length; i++) { totalWeight += rhythmPatterns[i].weight; } var random = Math.random() * totalWeight; var currentWeight = 0; for (var i = 0; i < rhythmPatterns.length; i++) { currentWeight += rhythmPatterns[i].weight; if (random <= currentWeight) { return rhythmPatterns[i].type; } } return 'normal'; } function startGame() { if (!gameStarted) { gameStarted = true; LK.playMusic('bgmusic', { volume: storage.volume }); // Remove instructions if (instructionsTxt.parent) { instructionsTxt.parent.removeChild(instructionsTxt); } // Start spawning notes noteSpawnTimer = 0; } } // Touch controls game.down = function (x, y, obj) { dragActive = true; player.x = Math.max(60, Math.min(2048 - 60, x)); if (!gameStarted) { startGame(); } }; game.move = function (x, y, obj) { if (dragActive) { player.x = Math.max(60, Math.min(2048 - 60, x)); } // Handle volume slider interaction if (volumeSlider.isDragging) { updateVolumeLabel(); } }; game.up = function (x, y, obj) { dragActive = false; if (volumeSlider.isDragging) { updateVolumeLabel(); } }; game.update = function () { if (!gameStarted || songEnded) return; // Update rhythm patterns over time patternTimer++; if (patternTimer >= 900) { // Every 15 seconds (900 ticks) patternTimer = 0; currentPattern = (currentPattern + 1) % 3; // Adjust rhythm patterns based on game progression switch (currentPattern) { case 0: // Normal mix rhythmPatterns = [{ type: 'normal', weight: 50 }, { type: 'fast', weight: 25 }, { type: 'slow', weight: 20 }, { type: 'bonus', weight: 5 }]; break; case 1: // Fast-heavy pattern rhythmPatterns = [{ type: 'normal', weight: 30 }, { type: 'fast', weight: 50 }, { type: 'slow', weight: 10 }, { type: 'bonus', weight: 10 }]; break; case 2: // Chaotic pattern rhythmPatterns = [{ type: 'normal', weight: 25 }, { type: 'fast', weight: 30 }, { type: 'slow', weight: 30 }, { type: 'bonus', weight: 15 }]; break; } } // Spawn notes noteSpawnTimer++; if (noteSpawnTimer >= noteSpawnInterval) { spawnNote(); noteSpawnTimer = 0; // Gradually increase spawn rate if (noteSpawnInterval > 30) { noteSpawnInterval -= 0.5; } } // Update notes for (var i = notes.length - 1; i >= 0; i--) { var note = notes[i]; // Check if note went off screen if (note.lastY <= 2732 + 50 && note.y > 2732 + 50) { missedNotes++; updateMisses(); note.destroy(); notes.splice(i, 1); // Check if max misses reached if (missedNotes >= maxMisses) { songEnded = true; // Show game over message var gameOverTxt = new Text2('Game Over!\nYou missed too many notes!\nFinal Score: ' + LK.getScore() + '\nTap to try again', { size: 80, fill: 0xFF6B6B }); gameOverTxt.anchor.set(0.5, 0.5); gameOverTxt.x = 2048 / 2; gameOverTxt.y = 2732 / 2; game.addChild(gameOverTxt); // Clear remaining notes for (var j = 0; j < notes.length; j++) { if (notes[j].parent) { notes[j].destroy(); } } notes = []; // Allow restart game.down = function (x, y, obj) { LK.showGameOver(); }; return; } continue; } // Check collision with player if (note.intersects(player)) { var points = 1; var flashColor = 0xFFFFFF; // Different points based on note type switch (note.noteType) { case 'fast': points = 3; flashColor = 0xe74c3c; break; case 'slow': points = 2; flashColor = 0x9b59b6; break; case 'bonus': points = 5; flashColor = 0x2ecc71; break; default: points = 1; flashColor = 0xf5a623; break; } LK.setScore(LK.getScore() + points); updateScore(); LK.getSound('catch').play(); // Flash effect based on note type LK.effects.flashObject(player, flashColor, 300); // Visual feedback tween(note, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200, onFinish: function onFinish() { if (note.parent) { note.destroy(); } } }); notes.splice(i, 1); continue; } } // Check if music ended (approximate timing) if (LK.ticks > 3600 && !songEnded) { // 60 seconds at 60fps songEnded = true; // Show final score var finalScoreTxt = new Text2('Final Score: ' + LK.getScore() + '\nTap to play again', { size: 100, fill: 0xFFFFFF }); finalScoreTxt.anchor.set(0.5, 0.5); finalScoreTxt.x = 2048 / 2; finalScoreTxt.y = 2732 / 2; game.addChild(finalScoreTxt); // Clear remaining notes for (var j = 0; j < notes.length; j++) { if (notes[j].parent) { notes[j].destroy(); } } notes = []; // Allow restart game.down = function (x, y, obj) { LK.showGameOver(); }; } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
volume: 0.6
});
/****
* Classes
****/
var Background = Container.expand(function () {
var self = Container.call(this);
var backgroundGraphics = self.attachAsset('background', {
anchorX: 0,
anchorY: 0
});
return self;
});
var BonusNote = Container.expand(function () {
var self = Container.call(this);
var noteGraphics = self.attachAsset('bonusNote', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.lastY = 0;
self.noteType = 'bonus';
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
// Add slight horizontal movement for bonus notes
self.x += Math.sin(self.y * 0.01) * 2;
};
return self;
});
var FastNote = Container.expand(function () {
var self = Container.call(this);
var noteGraphics = self.attachAsset('fastNote', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 14;
self.lastY = 0;
self.noteType = 'fast';
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
};
return self;
});
var Note = Container.expand(function () {
var self = Container.call(this);
var noteGraphics = self.attachAsset('note', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.lastY = 0;
self.noteType = 'normal';
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var SlowNote = Container.expand(function () {
var self = Container.call(this);
var noteGraphics = self.attachAsset('slowNote', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.lastY = 0;
self.noteType = 'slow';
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Math.random() * 2 + 1;
self.twinkleSpeed = Math.random() * 0.1 + 0.05;
self.opacity = Math.random() * 0.5 + 0.3;
starGraphics.alpha = self.opacity;
self.update = function () {
self.y += self.speed;
// Twinkling effect
starGraphics.alpha = self.opacity + Math.sin(LK.ticks * self.twinkleSpeed) * 0.3;
// Reset position when off screen
if (self.y > 2732 + 20) {
self.y = -20;
self.x = Math.random() * 2048;
}
};
return self;
});
var VolumeSlider = Container.expand(function () {
var self = Container.call(this);
// Slider background
var sliderBg = self.attachAsset('volumeSliderBg', {
anchorX: 0,
anchorY: 0.5
});
// Slider handle
var sliderHandle = self.attachAsset('volumeHandle', {
anchorX: 0.5,
anchorY: 0.5
});
self.isDragging = false;
self.sliderWidth = 300;
// Initialize handle position based on stored volume
sliderHandle.x = storage.volume * self.sliderWidth;
self.updateVolume = function (newVolume) {
storage.volume = Math.max(0, Math.min(1, newVolume));
sliderHandle.x = storage.volume * self.sliderWidth;
// Update music volume
LK.stopMusic();
LK.playMusic('bgmusic', {
volume: storage.volume
});
};
self.down = function (x, y, obj) {
self.isDragging = true;
// Use the x,y coordinates directly as they are already in the correct coordinate space
var newVolume = Math.max(0, Math.min(1, x / self.sliderWidth));
self.updateVolume(newVolume);
};
self.move = function (x, y, obj) {
if (self.isDragging) {
// Use the x,y coordinates directly as they are already in the correct coordinate space
var newVolume = Math.max(0, Math.min(1, x / self.sliderWidth));
self.updateVolume(newVolume);
}
};
self.up = function (x, y, obj) {
self.isDragging = false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2C3E50
});
/****
* Game Code
****/
var notes = [];
var noteSpawnTimer = 0;
var noteSpawnInterval = 60; // Spawn every 60 ticks (1 second at 60fps)
var gameStarted = false;
var songEnded = false;
var missedNotes = 0;
var maxMisses = 3; // Game ends after 3 missed notes
var rhythmPatterns = [{
type: 'normal',
weight: 50
}, {
type: 'fast',
weight: 25
}, {
type: 'slow',
weight: 20
}, {
type: 'bonus',
weight: 5
}];
var patternTimer = 0;
var currentPattern = 0;
// Score display
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Missed notes display
var missesTxt = new Text2('Misses: 0/3', {
size: 60,
fill: 0xFF6B6B
});
missesTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(missesTxt);
// Instructions
var instructionsTxt = new Text2('Drag to move and catch the notes!', {
size: 60,
fill: 0xFFFFFF
});
instructionsTxt.anchor.set(0.5, 0.5);
instructionsTxt.x = 2048 / 2;
instructionsTxt.y = 2732 / 2 - 200;
game.addChild(instructionsTxt);
// Volume control UI (positioned below misses counter)
var volumeIcon = LK.getAsset('volumeIcon', {
anchorX: 0,
anchorY: 0.5
});
LK.gui.topRight.addChild(volumeIcon);
volumeIcon.x = -350;
volumeIcon.y = 80;
var volumeSlider = LK.gui.topRight.addChild(new VolumeSlider());
volumeSlider.x = -300;
volumeSlider.y = 80;
var volumeLabel = new Text2('Volume: ' + Math.round(storage.volume * 100) + '%', {
size: 40,
fill: 0xFFFFFF
});
volumeLabel.anchor.set(0, 0.5);
LK.gui.topRight.addChild(volumeLabel);
volumeLabel.x = 20;
volumeLabel.y = 80;
// Update volume label function
function updateVolumeLabel() {
volumeLabel.setText('Volume: ' + Math.round(storage.volume * 100) + '%');
}
var dragActive = false;
// Background image
var background = game.addChild(new Background());
background.x = 0;
background.y = 0;
// Player (added after background to layer on top)
var player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 - 150;
function updateScore() {
scoreTxt.setText('Score: ' + LK.getScore());
}
function updateMisses() {
missesTxt.setText('Misses: ' + missedNotes + '/' + maxMisses);
}
function spawnNote() {
var noteType = getRandomNoteType();
var note;
switch (noteType) {
case 'fast':
note = new FastNote();
break;
case 'slow':
note = new SlowNote();
break;
case 'bonus':
note = new BonusNote();
break;
default:
note = new Note();
break;
}
note.x = Math.random() * (2048 - 160) + 80; // Keep notes within screen bounds
note.y = -50;
note.lastY = note.y;
notes.push(note);
game.addChild(note);
}
function getRandomNoteType() {
var totalWeight = 0;
for (var i = 0; i < rhythmPatterns.length; i++) {
totalWeight += rhythmPatterns[i].weight;
}
var random = Math.random() * totalWeight;
var currentWeight = 0;
for (var i = 0; i < rhythmPatterns.length; i++) {
currentWeight += rhythmPatterns[i].weight;
if (random <= currentWeight) {
return rhythmPatterns[i].type;
}
}
return 'normal';
}
function startGame() {
if (!gameStarted) {
gameStarted = true;
LK.playMusic('bgmusic', {
volume: storage.volume
});
// Remove instructions
if (instructionsTxt.parent) {
instructionsTxt.parent.removeChild(instructionsTxt);
}
// Start spawning notes
noteSpawnTimer = 0;
}
}
// Touch controls
game.down = function (x, y, obj) {
dragActive = true;
player.x = Math.max(60, Math.min(2048 - 60, x));
if (!gameStarted) {
startGame();
}
};
game.move = function (x, y, obj) {
if (dragActive) {
player.x = Math.max(60, Math.min(2048 - 60, x));
}
// Handle volume slider interaction
if (volumeSlider.isDragging) {
updateVolumeLabel();
}
};
game.up = function (x, y, obj) {
dragActive = false;
if (volumeSlider.isDragging) {
updateVolumeLabel();
}
};
game.update = function () {
if (!gameStarted || songEnded) return;
// Update rhythm patterns over time
patternTimer++;
if (patternTimer >= 900) {
// Every 15 seconds (900 ticks)
patternTimer = 0;
currentPattern = (currentPattern + 1) % 3;
// Adjust rhythm patterns based on game progression
switch (currentPattern) {
case 0:
// Normal mix
rhythmPatterns = [{
type: 'normal',
weight: 50
}, {
type: 'fast',
weight: 25
}, {
type: 'slow',
weight: 20
}, {
type: 'bonus',
weight: 5
}];
break;
case 1:
// Fast-heavy pattern
rhythmPatterns = [{
type: 'normal',
weight: 30
}, {
type: 'fast',
weight: 50
}, {
type: 'slow',
weight: 10
}, {
type: 'bonus',
weight: 10
}];
break;
case 2:
// Chaotic pattern
rhythmPatterns = [{
type: 'normal',
weight: 25
}, {
type: 'fast',
weight: 30
}, {
type: 'slow',
weight: 30
}, {
type: 'bonus',
weight: 15
}];
break;
}
}
// Spawn notes
noteSpawnTimer++;
if (noteSpawnTimer >= noteSpawnInterval) {
spawnNote();
noteSpawnTimer = 0;
// Gradually increase spawn rate
if (noteSpawnInterval > 30) {
noteSpawnInterval -= 0.5;
}
}
// Update notes
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
// Check if note went off screen
if (note.lastY <= 2732 + 50 && note.y > 2732 + 50) {
missedNotes++;
updateMisses();
note.destroy();
notes.splice(i, 1);
// Check if max misses reached
if (missedNotes >= maxMisses) {
songEnded = true;
// Show game over message
var gameOverTxt = new Text2('Game Over!\nYou missed too many notes!\nFinal Score: ' + LK.getScore() + '\nTap to try again', {
size: 80,
fill: 0xFF6B6B
});
gameOverTxt.anchor.set(0.5, 0.5);
gameOverTxt.x = 2048 / 2;
gameOverTxt.y = 2732 / 2;
game.addChild(gameOverTxt);
// Clear remaining notes
for (var j = 0; j < notes.length; j++) {
if (notes[j].parent) {
notes[j].destroy();
}
}
notes = [];
// Allow restart
game.down = function (x, y, obj) {
LK.showGameOver();
};
return;
}
continue;
}
// Check collision with player
if (note.intersects(player)) {
var points = 1;
var flashColor = 0xFFFFFF;
// Different points based on note type
switch (note.noteType) {
case 'fast':
points = 3;
flashColor = 0xe74c3c;
break;
case 'slow':
points = 2;
flashColor = 0x9b59b6;
break;
case 'bonus':
points = 5;
flashColor = 0x2ecc71;
break;
default:
points = 1;
flashColor = 0xf5a623;
break;
}
LK.setScore(LK.getScore() + points);
updateScore();
LK.getSound('catch').play();
// Flash effect based on note type
LK.effects.flashObject(player, flashColor, 300);
// Visual feedback
tween(note, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
if (note.parent) {
note.destroy();
}
}
});
notes.splice(i, 1);
continue;
}
}
// Check if music ended (approximate timing)
if (LK.ticks > 3600 && !songEnded) {
// 60 seconds at 60fps
songEnded = true;
// Show final score
var finalScoreTxt = new Text2('Final Score: ' + LK.getScore() + '\nTap to play again', {
size: 100,
fill: 0xFFFFFF
});
finalScoreTxt.anchor.set(0.5, 0.5);
finalScoreTxt.x = 2048 / 2;
finalScoreTxt.y = 2732 / 2;
game.addChild(finalScoreTxt);
// Clear remaining notes
for (var j = 0; j < notes.length; j++) {
if (notes[j].parent) {
notes[j].destroy();
}
}
notes = [];
// Allow restart
game.down = function (x, y, obj) {
LK.showGameOver();
};
}
};
top view piano. In-Game asset. 2d. High contrast. No shadows
red note. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
green note. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
blue note. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
note but without the right end and purple. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat