/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var PerfectEffect = Container.expand(function (x, y) {
var self = Container.call(this);
var effectGraphics = self.attachAsset('perfectEffect', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
self.alpha = 1;
self.scale.set(0.5, 0.5);
tween(self, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
var index = perfectEffects.indexOf(self);
if (index > -1) {
perfectEffects.splice(index, 1);
}
}
});
return self;
});
var PianoKey = Container.expand(function (lane) {
var self = Container.call(this);
var keyGraphics = self.attachAsset('pianoKey', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = lane;
self.pressed = false;
self.pressTimer = 0;
self.update = function () {
if (self.pressed) {
self.pressTimer--;
if (self.pressTimer <= 0) {
self.setUnpressed();
}
}
};
self.setPressed = function () {
if (!self.pressed) {
self.pressed = true;
self.pressTimer = 10;
keyGraphics.removeChild(keyGraphics.children[0]);
var pressedGraphics = keyGraphics.attachAsset('pianoKeyPressed', {
anchorX: 0.5,
anchorY: 0.5
});
// Add bouncy press animation to match upbeat music
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.elasticOut
});
}
});
}
};
self.setUnpressed = function () {
if (self.pressed) {
self.pressed = false;
keyGraphics.removeChild(keyGraphics.children[0]);
var normalGraphics = keyGraphics.attachAsset('pianoKey', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
self.down = function (x, y, obj) {
handleKeyPress(self.lane);
};
return self;
});
var PianoTile = Container.expand(function (lane, noteIndex) {
var self = Container.call(this);
var tileGraphics = self.attachAsset('pianoTile', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = lane;
self.noteIndex = noteIndex;
self.speed = gameSpeed;
self.tapped = false;
self.lastY = self.y;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
var gameSpeed = 8;
var speedIncrement = 0.5;
var maxSpeed = 20;
var combo = 0;
var gameRunning = true;
var spawnRate = 90;
var spawnCounter = 0;
var lanes = 4;
var laneWidth = 400;
var keyboardY = 2400;
var hitZoneY = 2300;
var hitZoneHeight = 200;
var tiles = [];
var pianoKeys = [];
var perfectEffects = [];
var notes = ['note1', 'note2', 'note3', 'note4'];
var songs = ['song1', 'song2', 'song3'];
var currentSongIndex = 0;
var songStarted = false;
// Create piano keyboard with pulsing animation
for (var i = 0; i < lanes; i++) {
var key = new PianoKey(i);
key.x = i * laneWidth + laneWidth / 2 + 224;
key.y = keyboardY;
pianoKeys.push(key);
game.addChild(key);
// Add subtle pulsing animation to match upbeat music
tween(key, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(key, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Create infinite loop by calling the pulse again
if (gameRunning) {
tween(key, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: arguments.callee.caller
});
}
}
});
}
});
}
// Create score display
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Create combo display
var comboText = new Text2('', {
size: 60,
fill: 0xFFD700
});
comboText.anchor.set(0.5, 0);
comboText.y = 100;
LK.gui.top.addChild(comboText);
function updateScore() {
scoreText.setText('Score: ' + LK.getScore());
if (combo > 5) {
comboText.setText('Combo: ' + combo);
} else {
comboText.setText('');
}
}
function spawnTile() {
if (!gameRunning) return;
// Start music on first tile spawn
if (!songStarted) {
LK.playMusic('upbeat', {
loop: true
});
songStarted = true;
}
var lane = Math.floor(Math.random() * lanes);
var tile = new PianoTile(lane, notes[lane]);
tile.x = lane * laneWidth + laneWidth / 2 + 224;
tile.y = -50;
tile.lastY = tile.y;
// Add bouncy spawn animation to match upbeat music
tile.scaleX = 0.3;
tile.scaleY = 0.3;
tween(tile, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.bounceOut
});
tiles.push(tile);
game.addChild(tile);
}
function handleKeyPress(lane) {
if (!gameRunning) return;
var hitTile = null;
var bestDistance = Infinity;
// Find the closest tile in the hit zone for this lane
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (tile.lane === lane && !tile.tapped) {
var distance = Math.abs(tile.y - hitZoneY);
if (distance < hitZoneHeight && distance < bestDistance) {
hitTile = tile;
bestDistance = distance;
}
}
}
if (hitTile) {
hitTile.tapped = true;
pianoKeys[lane].setPressed();
// Play note
LK.getSound(notes[lane]).play();
// Calculate score based on timing
var timingScore = Math.max(1, Math.floor((hitZoneHeight - bestDistance) / hitZoneHeight * 100));
LK.setScore(LK.getScore() + timingScore + combo * 2);
combo++;
// Perfect hit effect
if (bestDistance < 30) {
LK.getSound('perfect').play();
var effect = new PerfectEffect(hitTile.x, hitTile.y);
perfectEffects.push(effect);
game.addChild(effect);
// Add screen shake for perfect hits to match upbeat energy
var originalX = game.x;
var originalY = game.y;
tween(game, {
x: originalX + 10,
y: originalY + 5
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX - 10,
y: originalY - 5
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX,
y: originalY
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
}
// Increase speed gradually
if (gameSpeed < maxSpeed) {
gameSpeed += speedIncrement / 100;
}
updateScore();
// Flash tile before removing
tween(hitTile, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
hitTile.destroy();
var index = tiles.indexOf(hitTile);
if (index > -1) {
tiles.splice(index, 1);
}
}
});
}
}
game.update = function () {
if (!gameRunning) return;
// Add background pulsing effect every beat to match upbeat music
if (LK.ticks % 30 === 0) {
var currentBg = game.backgroundColor;
tween(game, {
backgroundColor: 0x3a4f5f
}, {
duration: 150,
onFinish: function onFinish() {
tween(game, {
backgroundColor: currentBg
}, {
duration: 150
});
}
});
}
// Spawn tiles
spawnCounter++;
if (spawnCounter >= spawnRate) {
spawnTile();
spawnCounter = 0;
// Gradually increase spawn rate
if (spawnRate > 30) {
spawnRate = Math.max(30, spawnRate - 0.2);
}
}
// Update tiles and check for misses
for (var i = tiles.length - 1; i >= 0; i--) {
var tile = tiles[i];
// Check if tile passed the hit zone without being tapped
if (!tile.tapped && tile.lastY < hitZoneY + hitZoneHeight && tile.y >= hitZoneY + hitZoneHeight) {
// Missed tile - game over
LK.getSound('miss').play();
LK.effects.flashScreen(0xff0000, 1000);
gameRunning = false;
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
return;
}
// Remove tiles that are off screen
if (tile.y > 2800) {
tile.destroy();
tiles.splice(i, 1);
continue;
}
tile.lastY = tile.y;
}
// Song progression based on score
if (LK.getScore() >= 1000 && currentSongIndex === 0) {
currentSongIndex = 1;
LK.playMusic(songs[currentSongIndex], {
loop: true,
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
} else if (LK.getScore() >= 3000 && currentSongIndex === 1) {
currentSongIndex = 2;
LK.playMusic(songs[currentSongIndex], {
loop: true,
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
}
// Check for winning condition (high score achievement)
if (LK.getScore() >= 5000) {
gameRunning = false;
LK.setTimeout(function () {
LK.showYouWin();
}, 500);
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var PerfectEffect = Container.expand(function (x, y) {
var self = Container.call(this);
var effectGraphics = self.attachAsset('perfectEffect', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
self.alpha = 1;
self.scale.set(0.5, 0.5);
tween(self, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
var index = perfectEffects.indexOf(self);
if (index > -1) {
perfectEffects.splice(index, 1);
}
}
});
return self;
});
var PianoKey = Container.expand(function (lane) {
var self = Container.call(this);
var keyGraphics = self.attachAsset('pianoKey', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = lane;
self.pressed = false;
self.pressTimer = 0;
self.update = function () {
if (self.pressed) {
self.pressTimer--;
if (self.pressTimer <= 0) {
self.setUnpressed();
}
}
};
self.setPressed = function () {
if (!self.pressed) {
self.pressed = true;
self.pressTimer = 10;
keyGraphics.removeChild(keyGraphics.children[0]);
var pressedGraphics = keyGraphics.attachAsset('pianoKeyPressed', {
anchorX: 0.5,
anchorY: 0.5
});
// Add bouncy press animation to match upbeat music
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.elasticOut
});
}
});
}
};
self.setUnpressed = function () {
if (self.pressed) {
self.pressed = false;
keyGraphics.removeChild(keyGraphics.children[0]);
var normalGraphics = keyGraphics.attachAsset('pianoKey', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
self.down = function (x, y, obj) {
handleKeyPress(self.lane);
};
return self;
});
var PianoTile = Container.expand(function (lane, noteIndex) {
var self = Container.call(this);
var tileGraphics = self.attachAsset('pianoTile', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = lane;
self.noteIndex = noteIndex;
self.speed = gameSpeed;
self.tapped = false;
self.lastY = self.y;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
var gameSpeed = 8;
var speedIncrement = 0.5;
var maxSpeed = 20;
var combo = 0;
var gameRunning = true;
var spawnRate = 90;
var spawnCounter = 0;
var lanes = 4;
var laneWidth = 400;
var keyboardY = 2400;
var hitZoneY = 2300;
var hitZoneHeight = 200;
var tiles = [];
var pianoKeys = [];
var perfectEffects = [];
var notes = ['note1', 'note2', 'note3', 'note4'];
var songs = ['song1', 'song2', 'song3'];
var currentSongIndex = 0;
var songStarted = false;
// Create piano keyboard with pulsing animation
for (var i = 0; i < lanes; i++) {
var key = new PianoKey(i);
key.x = i * laneWidth + laneWidth / 2 + 224;
key.y = keyboardY;
pianoKeys.push(key);
game.addChild(key);
// Add subtle pulsing animation to match upbeat music
tween(key, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(key, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Create infinite loop by calling the pulse again
if (gameRunning) {
tween(key, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: arguments.callee.caller
});
}
}
});
}
});
}
// Create score display
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Create combo display
var comboText = new Text2('', {
size: 60,
fill: 0xFFD700
});
comboText.anchor.set(0.5, 0);
comboText.y = 100;
LK.gui.top.addChild(comboText);
function updateScore() {
scoreText.setText('Score: ' + LK.getScore());
if (combo > 5) {
comboText.setText('Combo: ' + combo);
} else {
comboText.setText('');
}
}
function spawnTile() {
if (!gameRunning) return;
// Start music on first tile spawn
if (!songStarted) {
LK.playMusic('upbeat', {
loop: true
});
songStarted = true;
}
var lane = Math.floor(Math.random() * lanes);
var tile = new PianoTile(lane, notes[lane]);
tile.x = lane * laneWidth + laneWidth / 2 + 224;
tile.y = -50;
tile.lastY = tile.y;
// Add bouncy spawn animation to match upbeat music
tile.scaleX = 0.3;
tile.scaleY = 0.3;
tween(tile, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.bounceOut
});
tiles.push(tile);
game.addChild(tile);
}
function handleKeyPress(lane) {
if (!gameRunning) return;
var hitTile = null;
var bestDistance = Infinity;
// Find the closest tile in the hit zone for this lane
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (tile.lane === lane && !tile.tapped) {
var distance = Math.abs(tile.y - hitZoneY);
if (distance < hitZoneHeight && distance < bestDistance) {
hitTile = tile;
bestDistance = distance;
}
}
}
if (hitTile) {
hitTile.tapped = true;
pianoKeys[lane].setPressed();
// Play note
LK.getSound(notes[lane]).play();
// Calculate score based on timing
var timingScore = Math.max(1, Math.floor((hitZoneHeight - bestDistance) / hitZoneHeight * 100));
LK.setScore(LK.getScore() + timingScore + combo * 2);
combo++;
// Perfect hit effect
if (bestDistance < 30) {
LK.getSound('perfect').play();
var effect = new PerfectEffect(hitTile.x, hitTile.y);
perfectEffects.push(effect);
game.addChild(effect);
// Add screen shake for perfect hits to match upbeat energy
var originalX = game.x;
var originalY = game.y;
tween(game, {
x: originalX + 10,
y: originalY + 5
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX - 10,
y: originalY - 5
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX,
y: originalY
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
}
// Increase speed gradually
if (gameSpeed < maxSpeed) {
gameSpeed += speedIncrement / 100;
}
updateScore();
// Flash tile before removing
tween(hitTile, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
hitTile.destroy();
var index = tiles.indexOf(hitTile);
if (index > -1) {
tiles.splice(index, 1);
}
}
});
}
}
game.update = function () {
if (!gameRunning) return;
// Add background pulsing effect every beat to match upbeat music
if (LK.ticks % 30 === 0) {
var currentBg = game.backgroundColor;
tween(game, {
backgroundColor: 0x3a4f5f
}, {
duration: 150,
onFinish: function onFinish() {
tween(game, {
backgroundColor: currentBg
}, {
duration: 150
});
}
});
}
// Spawn tiles
spawnCounter++;
if (spawnCounter >= spawnRate) {
spawnTile();
spawnCounter = 0;
// Gradually increase spawn rate
if (spawnRate > 30) {
spawnRate = Math.max(30, spawnRate - 0.2);
}
}
// Update tiles and check for misses
for (var i = tiles.length - 1; i >= 0; i--) {
var tile = tiles[i];
// Check if tile passed the hit zone without being tapped
if (!tile.tapped && tile.lastY < hitZoneY + hitZoneHeight && tile.y >= hitZoneY + hitZoneHeight) {
// Missed tile - game over
LK.getSound('miss').play();
LK.effects.flashScreen(0xff0000, 1000);
gameRunning = false;
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
return;
}
// Remove tiles that are off screen
if (tile.y > 2800) {
tile.destroy();
tiles.splice(i, 1);
continue;
}
tile.lastY = tile.y;
}
// Song progression based on score
if (LK.getScore() >= 1000 && currentSongIndex === 0) {
currentSongIndex = 1;
LK.playMusic(songs[currentSongIndex], {
loop: true,
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
} else if (LK.getScore() >= 3000 && currentSongIndex === 1) {
currentSongIndex = 2;
LK.playMusic(songs[currentSongIndex], {
loop: true,
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
}
// Check for winning condition (high score achievement)
if (LK.getScore() >= 5000) {
gameRunning = false;
LK.setTimeout(function () {
LK.showYouWin();
}, 500);
}
};