/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var HitEffect = Container.expand(function () {
var self = Container.call(this);
var effectGraphics = self.attachAsset('hitEffect', {
anchorX: 0.5,
anchorY: 0.5
});
effectGraphics.alpha = 0.8;
tween(self, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
return self;
});
var Note = Container.expand(function () {
var self = Container.call(this);
var noteGraphics = self.attachAsset('note', {
anchorX: 0.5,
anchorY: 0.5
});
self.startDepth = 0.1;
self.targetDepth = 1.0;
self.currentDepth = self.startDepth;
self.speed = 0.008;
self.lane = 0;
self.hit = false;
self.startX = 0;
self.startY = 0;
self.update = function () {
if (self.hit) return;
self.currentDepth += self.speed;
// Calculate scale based on depth (closer = larger)
var scale = self.currentDepth * 2;
self.scaleX = scale;
self.scaleY = scale;
// Calculate position based on depth and lane
var progress = self.currentDepth / self.targetDepth;
var targetX = 1024 + self.lane * 300 - 450; // Center with lane offset
var targetY = 2000;
self.x = self.startX + (targetX - self.startX) * progress;
self.y = self.startY + (targetY - self.startY) * progress;
// Adjust alpha based on depth
self.alpha = Math.min(1, self.currentDepth * 3);
// Rotation for 3D effect
noteGraphics.rotation += 0.05;
};
self.down = function (x, y, obj) {
if (self.hit) return;
var hitZoneStart = 0.85;
var hitZoneEnd = 1.1;
if (self.currentDepth >= hitZoneStart && self.currentDepth <= hitZoneEnd) {
self.hit = true;
// Calculate hit accuracy
var optimal = 0.98;
var accuracy = 1 - Math.abs(self.currentDepth - optimal) / 0.15;
accuracy = Math.max(0, Math.min(1, accuracy));
var points = Math.floor(accuracy * 100);
LK.setScore(LK.getScore() + points);
// Update combo
combo++;
if (combo > 5) {
var bonusPoints = Math.floor(points * (combo / 10));
LK.setScore(LK.getScore() + bonusPoints);
}
// Visual feedback
createHitEffect(self.x, self.y);
// Sound feedback
LK.getSound('hit').play();
// Scale effect
tween(self, {
scaleX: self.scaleX * 1.5,
scaleY: self.scaleY * 1.5,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.destroy();
}
});
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a2e
});
/****
* Game Code
****/
var notes = [];
var combo = 0;
var lastMissTime = 0;
var spawnTimer = 0;
var spawnInterval = 90; // Spawn every 1.5 seconds at 60fps
var lanes = [-1, 0, 1]; // Three lanes
// Target zone in center
var targetZone = game.addChild(LK.getAsset('targetZone', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2000,
alpha: 0.3
}));
// Score display
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Combo display
var comboText = new Text2('', {
size: 60,
fill: 0xFFFF00
});
comboText.anchor.set(0.5, 0);
comboText.y = 100;
LK.gui.top.addChild(comboText);
function createHitEffect(x, y) {
var effect = game.addChild(new HitEffect());
effect.x = x;
effect.y = y;
}
function spawnNote() {
var note = game.addChild(new Note());
// Random lane
var laneIndex = Math.floor(Math.random() * lanes.length);
note.lane = lanes[laneIndex];
// Starting position (far away)
note.startX = 1024 + note.lane * 100; // Slight lane offset at start
note.startY = 1000;
note.x = note.startX;
note.y = note.startY;
// Random speed variation
note.speed = 0.006 + Math.random() * 0.004;
notes.push(note);
}
game.update = function () {
// Update score display
scoreText.setText('Score: ' + LK.getScore());
// Update combo display
if (combo > 3) {
comboText.setText('Combo: ' + combo + 'x');
} else {
comboText.setText('');
}
// Spawn notes
spawnTimer++;
if (spawnTimer >= spawnInterval) {
spawnNote();
spawnTimer = 0;
// Gradually increase difficulty
if (spawnInterval > 45) {
spawnInterval -= 0.5;
}
}
// Check for missed notes and cleanup
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
// Note missed (went too far)
if (!note.hit && note.currentDepth > 1.2) {
combo = 0; // Reset combo on miss
LK.getSound('miss').play();
// Flash effect for miss
LK.effects.flashScreen(0xff0000, 200);
note.destroy();
notes.splice(i, 1);
continue;
}
// Remove hit notes that finished animating
if (note.hit && (note.alpha <= 0 || !note.parent)) {
notes.splice(i, 1);
continue;
}
}
// Pulsating target zone effect
var pulse = Math.sin(LK.ticks * 0.1) * 0.1 + 1;
targetZone.scaleX = pulse;
targetZone.scaleY = pulse;
};
// Handle taps anywhere on screen
game.down = function (x, y, obj) {
var hitAny = false;
// Check if any note was hit
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
if (!note.hit && note.down && note.down(x, y, obj)) {
hitAny = true;
break;
}
}
// If no note was hit, reset combo
if (!hitAny) {
combo = 0;
LK.effects.flashScreen(0x444444, 100);
}
};
// Start background music
LK.setTimeout(function () {
LK.playMusic('bgmusic');
}, 500); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var HitEffect = Container.expand(function () {
var self = Container.call(this);
var effectGraphics = self.attachAsset('hitEffect', {
anchorX: 0.5,
anchorY: 0.5
});
effectGraphics.alpha = 0.8;
tween(self, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
return self;
});
var Note = Container.expand(function () {
var self = Container.call(this);
var noteGraphics = self.attachAsset('note', {
anchorX: 0.5,
anchorY: 0.5
});
self.startDepth = 0.1;
self.targetDepth = 1.0;
self.currentDepth = self.startDepth;
self.speed = 0.008;
self.lane = 0;
self.hit = false;
self.startX = 0;
self.startY = 0;
self.update = function () {
if (self.hit) return;
self.currentDepth += self.speed;
// Calculate scale based on depth (closer = larger)
var scale = self.currentDepth * 2;
self.scaleX = scale;
self.scaleY = scale;
// Calculate position based on depth and lane
var progress = self.currentDepth / self.targetDepth;
var targetX = 1024 + self.lane * 300 - 450; // Center with lane offset
var targetY = 2000;
self.x = self.startX + (targetX - self.startX) * progress;
self.y = self.startY + (targetY - self.startY) * progress;
// Adjust alpha based on depth
self.alpha = Math.min(1, self.currentDepth * 3);
// Rotation for 3D effect
noteGraphics.rotation += 0.05;
};
self.down = function (x, y, obj) {
if (self.hit) return;
var hitZoneStart = 0.85;
var hitZoneEnd = 1.1;
if (self.currentDepth >= hitZoneStart && self.currentDepth <= hitZoneEnd) {
self.hit = true;
// Calculate hit accuracy
var optimal = 0.98;
var accuracy = 1 - Math.abs(self.currentDepth - optimal) / 0.15;
accuracy = Math.max(0, Math.min(1, accuracy));
var points = Math.floor(accuracy * 100);
LK.setScore(LK.getScore() + points);
// Update combo
combo++;
if (combo > 5) {
var bonusPoints = Math.floor(points * (combo / 10));
LK.setScore(LK.getScore() + bonusPoints);
}
// Visual feedback
createHitEffect(self.x, self.y);
// Sound feedback
LK.getSound('hit').play();
// Scale effect
tween(self, {
scaleX: self.scaleX * 1.5,
scaleY: self.scaleY * 1.5,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.destroy();
}
});
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a2e
});
/****
* Game Code
****/
var notes = [];
var combo = 0;
var lastMissTime = 0;
var spawnTimer = 0;
var spawnInterval = 90; // Spawn every 1.5 seconds at 60fps
var lanes = [-1, 0, 1]; // Three lanes
// Target zone in center
var targetZone = game.addChild(LK.getAsset('targetZone', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2000,
alpha: 0.3
}));
// Score display
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Combo display
var comboText = new Text2('', {
size: 60,
fill: 0xFFFF00
});
comboText.anchor.set(0.5, 0);
comboText.y = 100;
LK.gui.top.addChild(comboText);
function createHitEffect(x, y) {
var effect = game.addChild(new HitEffect());
effect.x = x;
effect.y = y;
}
function spawnNote() {
var note = game.addChild(new Note());
// Random lane
var laneIndex = Math.floor(Math.random() * lanes.length);
note.lane = lanes[laneIndex];
// Starting position (far away)
note.startX = 1024 + note.lane * 100; // Slight lane offset at start
note.startY = 1000;
note.x = note.startX;
note.y = note.startY;
// Random speed variation
note.speed = 0.006 + Math.random() * 0.004;
notes.push(note);
}
game.update = function () {
// Update score display
scoreText.setText('Score: ' + LK.getScore());
// Update combo display
if (combo > 3) {
comboText.setText('Combo: ' + combo + 'x');
} else {
comboText.setText('');
}
// Spawn notes
spawnTimer++;
if (spawnTimer >= spawnInterval) {
spawnNote();
spawnTimer = 0;
// Gradually increase difficulty
if (spawnInterval > 45) {
spawnInterval -= 0.5;
}
}
// Check for missed notes and cleanup
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
// Note missed (went too far)
if (!note.hit && note.currentDepth > 1.2) {
combo = 0; // Reset combo on miss
LK.getSound('miss').play();
// Flash effect for miss
LK.effects.flashScreen(0xff0000, 200);
note.destroy();
notes.splice(i, 1);
continue;
}
// Remove hit notes that finished animating
if (note.hit && (note.alpha <= 0 || !note.parent)) {
notes.splice(i, 1);
continue;
}
}
// Pulsating target zone effect
var pulse = Math.sin(LK.ticks * 0.1) * 0.1 + 1;
targetZone.scaleX = pulse;
targetZone.scaleY = pulse;
};
// Handle taps anywhere on screen
game.down = function (x, y, obj) {
var hitAny = false;
// Check if any note was hit
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
if (!note.hit && note.down && note.down(x, y, obj)) {
hitAny = true;
break;
}
}
// If no note was hit, reset combo
if (!hitAny) {
combo = 0;
LK.effects.flashScreen(0x444444, 100);
}
};
// Start background music
LK.setTimeout(function () {
LK.playMusic('bgmusic');
}, 500);