/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ 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.lane = 0; self.isHit = false; self.targetY = 2300; self.update = function () { if (!self.isHit) { self.y += self.speed; } }; self.hit = function () { self.isHit = true; var hitEffect = game.addChild(LK.getAsset('hitEffect', { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y, alpha: 0.8 })); tween(hitEffect, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 300, onFinish: function onFinish() { hitEffect.destroy(); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ // Game variables var notes = []; var lanes = []; var lanePositions = [400, 650, 900, 1150]; var targetLineY = 2300; var health = 100; var combo = 0; var maxCombo = 0; var noteSpawnTimer = 0; var noteSpeed = 8; var gameSpeed = 1; // UI elements var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); scoreText.x = 100; scoreText.y = 100; game.addChild(scoreText); var comboText = new Text2('Combo: 0', { size: 50, fill: 0xF1C40F }); comboText.anchor.set(0, 0); comboText.x = 100; comboText.y = 180; game.addChild(comboText); var healthText = new Text2('Health: 100', { size: 50, fill: 0xE74C3C }); healthText.anchor.set(1, 0); healthText.x = 1948; healthText.y = 100; game.addChild(healthText); var accuracyText = new Text2('', { size: 80, fill: 0x2ECC71 }); accuracyText.anchor.set(0.5, 0.5); accuracyText.x = 1024; accuracyText.y = 1366; game.addChild(accuracyText); // Create lanes for (var i = 0; i < 4; i++) { var lane = game.addChild(LK.getAsset('lane', { anchorX: 0.5, anchorY: 0, x: lanePositions[i], y: 0, alpha: 0.3 })); lanes.push(lane); } // Create target line var targetLine = game.addChild(LK.getAsset('targetLine', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: targetLineY })); // Game functions function spawnNote() { var note = new Note(); var randomLane = Math.floor(Math.random() * 4); note.x = lanePositions[randomLane]; note.y = -50; note.lane = randomLane; note.speed = noteSpeed * gameSpeed; notes.push(note); game.addChild(note); } function checkNoteHit(x, y) { var hitNote = null; var bestDistance = Infinity; var laneIndex = -1; // Determine which lane was tapped for (var i = 0; i < lanePositions.length; i++) { if (Math.abs(x - lanePositions[i]) < 100) { laneIndex = i; break; } } if (laneIndex === -1) return; // Find the closest note in that lane near the target line for (var i = 0; i < notes.length; i++) { var note = notes[i]; if (note.lane === laneIndex && !note.isHit) { var distance = Math.abs(note.y - targetLineY); if (distance < bestDistance && distance < 150) { bestDistance = distance; hitNote = note; } } } if (hitNote) { hitNote.hit(); var accuracy = ''; var points = 0; if (bestDistance < 30) { accuracy = 'PERFECT!'; points = 100; combo++; } else if (bestDistance < 80) { accuracy = 'GOOD!'; points = 50; combo++; } else { accuracy = 'OK'; points = 25; combo++; } LK.setScore(LK.getScore() + points * Math.max(1, Math.floor(combo / 10))); if (combo > maxCombo) { maxCombo = combo; } // Show accuracy feedback accuracyText.setText(accuracy); accuracyText.alpha = 1; tween(accuracyText, { alpha: 0 }, { duration: 800 }); LK.getSound('hitSound').play(); // Remove hit note for (var j = notes.length - 1; j >= 0; j--) { if (notes[j] === hitNote) { notes.splice(j, 1); break; } } LK.setTimeout(function () { hitNote.destroy(); }, 300); } } function updateUI() { scoreText.setText('Score: ' + LK.getScore()); comboText.setText('Combo: ' + combo); healthText.setText('Health: ' + health); } // Event handlers game.down = function (x, y, obj) { checkNoteHit(x, y); }; // Main game loop game.update = function () { // Spawn notes noteSpawnTimer++; if (noteSpawnTimer >= Math.max(30, 90 - Math.floor(LK.getScore() / 500))) { spawnNote(); noteSpawnTimer = 0; } // Update game speed based on score gameSpeed = 1 + LK.getScore() / 2000; noteSpeed = 8 * gameSpeed; // Check for missed notes and update notes for (var i = notes.length - 1; i >= 0; i--) { var note = notes[i]; // Check if note passed target line (missed) if (!note.isHit && note.y > targetLineY + 200) { health -= 10; combo = 0; accuracyText.setText('MISS!'); accuracyText.alpha = 1; tween(accuracyText, { alpha: 0 }, { duration: 800 }); LK.getSound('missSound').play(); note.destroy(); notes.splice(i, 1); continue; } // Remove notes that are off screen if (note.y > 2800) { note.destroy(); notes.splice(i, 1); } } // Check game over condition if (health <= 0) { LK.stopMusic(); LK.showGameOver(); } // Check win condition (high score achievement) if (LK.getScore() >= 10000) { LK.stopMusic(); LK.showYouWin(); } updateUI(); }; // Start background music LK.playMusic('bgMusic');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
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.lane = 0;
self.isHit = false;
self.targetY = 2300;
self.update = function () {
if (!self.isHit) {
self.y += self.speed;
}
};
self.hit = function () {
self.isHit = true;
var hitEffect = game.addChild(LK.getAsset('hitEffect', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
alpha: 0.8
}));
tween(hitEffect, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
onFinish: function onFinish() {
hitEffect.destroy();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game variables
var notes = [];
var lanes = [];
var lanePositions = [400, 650, 900, 1150];
var targetLineY = 2300;
var health = 100;
var combo = 0;
var maxCombo = 0;
var noteSpawnTimer = 0;
var noteSpeed = 8;
var gameSpeed = 1;
// UI elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 100;
scoreText.y = 100;
game.addChild(scoreText);
var comboText = new Text2('Combo: 0', {
size: 50,
fill: 0xF1C40F
});
comboText.anchor.set(0, 0);
comboText.x = 100;
comboText.y = 180;
game.addChild(comboText);
var healthText = new Text2('Health: 100', {
size: 50,
fill: 0xE74C3C
});
healthText.anchor.set(1, 0);
healthText.x = 1948;
healthText.y = 100;
game.addChild(healthText);
var accuracyText = new Text2('', {
size: 80,
fill: 0x2ECC71
});
accuracyText.anchor.set(0.5, 0.5);
accuracyText.x = 1024;
accuracyText.y = 1366;
game.addChild(accuracyText);
// Create lanes
for (var i = 0; i < 4; i++) {
var lane = game.addChild(LK.getAsset('lane', {
anchorX: 0.5,
anchorY: 0,
x: lanePositions[i],
y: 0,
alpha: 0.3
}));
lanes.push(lane);
}
// Create target line
var targetLine = game.addChild(LK.getAsset('targetLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: targetLineY
}));
// Game functions
function spawnNote() {
var note = new Note();
var randomLane = Math.floor(Math.random() * 4);
note.x = lanePositions[randomLane];
note.y = -50;
note.lane = randomLane;
note.speed = noteSpeed * gameSpeed;
notes.push(note);
game.addChild(note);
}
function checkNoteHit(x, y) {
var hitNote = null;
var bestDistance = Infinity;
var laneIndex = -1;
// Determine which lane was tapped
for (var i = 0; i < lanePositions.length; i++) {
if (Math.abs(x - lanePositions[i]) < 100) {
laneIndex = i;
break;
}
}
if (laneIndex === -1) return;
// Find the closest note in that lane near the target line
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
if (note.lane === laneIndex && !note.isHit) {
var distance = Math.abs(note.y - targetLineY);
if (distance < bestDistance && distance < 150) {
bestDistance = distance;
hitNote = note;
}
}
}
if (hitNote) {
hitNote.hit();
var accuracy = '';
var points = 0;
if (bestDistance < 30) {
accuracy = 'PERFECT!';
points = 100;
combo++;
} else if (bestDistance < 80) {
accuracy = 'GOOD!';
points = 50;
combo++;
} else {
accuracy = 'OK';
points = 25;
combo++;
}
LK.setScore(LK.getScore() + points * Math.max(1, Math.floor(combo / 10)));
if (combo > maxCombo) {
maxCombo = combo;
}
// Show accuracy feedback
accuracyText.setText(accuracy);
accuracyText.alpha = 1;
tween(accuracyText, {
alpha: 0
}, {
duration: 800
});
LK.getSound('hitSound').play();
// Remove hit note
for (var j = notes.length - 1; j >= 0; j--) {
if (notes[j] === hitNote) {
notes.splice(j, 1);
break;
}
}
LK.setTimeout(function () {
hitNote.destroy();
}, 300);
}
}
function updateUI() {
scoreText.setText('Score: ' + LK.getScore());
comboText.setText('Combo: ' + combo);
healthText.setText('Health: ' + health);
}
// Event handlers
game.down = function (x, y, obj) {
checkNoteHit(x, y);
};
// Main game loop
game.update = function () {
// Spawn notes
noteSpawnTimer++;
if (noteSpawnTimer >= Math.max(30, 90 - Math.floor(LK.getScore() / 500))) {
spawnNote();
noteSpawnTimer = 0;
}
// Update game speed based on score
gameSpeed = 1 + LK.getScore() / 2000;
noteSpeed = 8 * gameSpeed;
// Check for missed notes and update notes
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
// Check if note passed target line (missed)
if (!note.isHit && note.y > targetLineY + 200) {
health -= 10;
combo = 0;
accuracyText.setText('MISS!');
accuracyText.alpha = 1;
tween(accuracyText, {
alpha: 0
}, {
duration: 800
});
LK.getSound('missSound').play();
note.destroy();
notes.splice(i, 1);
continue;
}
// Remove notes that are off screen
if (note.y > 2800) {
note.destroy();
notes.splice(i, 1);
}
}
// Check game over condition
if (health <= 0) {
LK.stopMusic();
LK.showGameOver();
}
// Check win condition (high score achievement)
if (LK.getScore() >= 10000) {
LK.stopMusic();
LK.showYouWin();
}
updateUI();
};
// Start background music
LK.playMusic('bgMusic');