/****
* 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');