/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BTSMember = Container.expand(function (memberNumber, xPos) { var self = Container.call(this); self.memberNumber = memberNumber; self.isPerforming = false; self.animationState = 'idle'; var memberGraphics = self.attachAsset('member' + memberNumber, { anchorX: 0.5, anchorY: 1.0 }); var hitZone = self.attachAsset('hitZone', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); self.x = xPos; self.y = 2200; hitZone.y = -200; self.performAnimation = function () { self.isPerforming = true; self.animationState = 'performing'; tween(memberGraphics, { scaleX: 1.1, scaleY: 1.1 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(memberGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.easeIn }); } }); tween(memberGraphics, { tint: 0xffffff }, { duration: 300, onFinish: function onFinish() { tween(memberGraphics, { tint: 0xffffff }, { duration: 200 }); } }); }; self.idleAnimation = function () { self.isPerforming = false; self.animationState = 'idle'; tween(memberGraphics, { scaleX: 0.9, scaleY: 0.9 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(memberGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 500, easing: tween.easeInOut }); } }); }; self.getHitZoneY = function () { return self.y + hitZone.y; }; return self; }); var Note = Container.expand(function (lane, type) { var self = Container.call(this); self.lane = lane; self.type = type || 'normal'; self.speed = 8; self.isActive = true; self.hitTiming = 0; var noteGraphics = self.attachAsset(self.type === 'hold' ? 'holdNote' : 'note', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { if (self.isActive) { self.y += self.speed; } }; self.checkHit = function (hitY) { var distance = Math.abs(self.y - hitY); if (distance < 50) { return 'perfect'; } else if (distance < 80) { return 'good'; } else if (distance < 120) { return 'ok'; } return 'miss'; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0a0a0a }); /**** * Game Code ****/ // Sound effects // UI elements // Note types // BTS character representations // Stage and background elements // Game state variables var gameState = 'playing'; var score = 0; var combo = 0; var maxCombo = 0; var performanceLevel = 100; var difficulty = 1; var songPosition = 0; var nextNoteTime = 0; // Member positions (7 members spread across stage) var memberPositions = [200, 400, 600, 800, 1000, 1200, 1400, 1600]; // Create stage var stage = game.attachAsset('stage', { anchorX: 0.5, anchorY: 1.0, x: 1024, y: 2200 }); // Create BTS members var members = []; for (var i = 0; i < 7; i++) { var member = new BTSMember(i + 1, memberPositions[i]); members.push(member); game.addChild(member); } // Create notes array var notes = []; // Create UI elements var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); var comboText = new Text2('Combo: 0', { size: 50, fill: 0xFFFF00 }); comboText.anchor.set(0.5, 0); comboText.y = 80; LK.gui.top.addChild(comboText); // Performance meter var performanceMeterBg = LK.gui.bottom.attachAsset('performanceMeter', { anchorX: 0.5, anchorY: 1.0, x: 0, y: -100 }); var performanceBar = LK.gui.bottom.attachAsset('performanceBar', { anchorX: 0.0, anchorY: 1.0, x: -150, y: -100 }); // Note patterns for different difficulty levels var notePatterns = { 1: [{ lane: 0, time: 60 }, { lane: 2, time: 120 }, { lane: 4, time: 180 }, { lane: 6, time: 240 }, { lane: 1, time: 300 }, { lane: 3, time: 360 }, { lane: 5, time: 420 }, { lane: 0, time: 480 }], 2: [{ lane: 0, time: 30 }, { lane: 2, time: 60 }, { lane: 4, time: 90 }, { lane: 6, time: 120 }, { lane: 1, time: 150 }, { lane: 3, time: 180 }, { lane: 5, time: 210 }, { lane: 0, time: 240 }] }; var currentPattern = notePatterns[difficulty]; var patternIndex = 0; // Function to spawn notes function spawnNote(lane, type) { if (lane < 0 || lane >= members.length) return; var note = new Note(lane, type); note.x = members[lane].x; note.y = 200; notes.push(note); game.addChild(note); } // Function to update performance meter function updatePerformanceMeter() { var percentage = performanceLevel / 100; performanceBar.scaleX = Math.max(0, percentage); if (performanceLevel > 70) { performanceBar.tint = 0x00ff00; } else if (performanceLevel > 40) { performanceBar.tint = 0xffff00; } else { performanceBar.tint = 0xff0000; } } // Function to handle note hit function hitNote(note, accuracy) { var points = 0; switch (accuracy) { case 'perfect': points = 100; combo++; performanceLevel = Math.min(100, performanceLevel + 3); break; case 'good': points = 80; combo++; performanceLevel = Math.min(100, performanceLevel + 2); break; case 'ok': points = 60; combo++; performanceLevel = Math.min(100, performanceLevel + 1); break; default: combo = 0; performanceLevel = Math.max(0, performanceLevel - 5); break; } score += points * (1 + combo * 0.1); maxCombo = Math.max(maxCombo, combo); // Update member animation if (accuracy !== 'miss') { members[note.lane].performAnimation(); LK.getSound('noteHit').play(); } else { LK.getSound('noteMiss').play(); } // Update UI scoreText.setText('Score: ' + Math.floor(score)); comboText.setText('Combo: ' + combo); updatePerformanceMeter(); // Set LK score for leaderboard LK.setScore(Math.floor(score)); } // Touch/click handling var touchedLanes = []; game.down = function (x, y, obj) { // Find which member was touched for (var i = 0; i < members.length; i++) { var member = members[i]; var distance = Math.abs(x - member.x); if (distance < 100) { touchedLanes.push(i); // Check for notes in this lane var hitZoneY = member.getHitZoneY(); var bestNote = null; var bestDistance = Infinity; for (var j = 0; j < notes.length; j++) { var note = notes[j]; if (note.lane === i && note.isActive) { var noteDistance = Math.abs(note.y - hitZoneY); if (noteDistance < bestDistance) { bestDistance = noteDistance; bestNote = note; } } } if (bestNote) { var accuracy = bestNote.checkHit(hitZoneY); hitNote(bestNote, accuracy); bestNote.isActive = false; bestNote.destroy(); // Remove from notes array var noteIndex = notes.indexOf(bestNote); if (noteIndex > -1) { notes.splice(noteIndex, 1); } } break; } } }; game.up = function (x, y, obj) { touchedLanes = []; }; // Main game update loop game.update = function () { songPosition++; // Spawn notes based on pattern if (patternIndex < currentPattern.length) { if (songPosition >= currentPattern[patternIndex].time) { spawnNote(currentPattern[patternIndex].lane, 'normal'); patternIndex++; // Loop pattern if (patternIndex >= currentPattern.length) { patternIndex = 0; songPosition = 0; } } } // Update notes for (var i = notes.length - 1; i >= 0; i--) { var note = notes[i]; // Remove notes that are off screen if (note.y > 2800) { // Miss penalty if (note.isActive) { combo = 0; performanceLevel = Math.max(0, performanceLevel - 8); updatePerformanceMeter(); LK.getSound('noteMiss').play(); } note.destroy(); notes.splice(i, 1); } } // Update member idle animations for (var i = 0; i < members.length; i++) { if (!members[i].isPerforming && LK.ticks % 180 === i * 20) { members[i].idleAnimation(); } } // Check game over condition if (performanceLevel <= 0) { gameState = 'gameOver'; LK.showGameOver(); } // Check win condition (high score threshold) if (score >= 5000) { gameState = 'win'; LK.showYouWin(); } // Increase difficulty over time if (LK.ticks % 1800 === 0 && difficulty < 2) { difficulty++; currentPattern = notePatterns[difficulty]; patternIndex = 0; songPosition = 0; // Increase note speed for (var i = 0; i < notes.length; i++) { notes[i].speed = 8 + difficulty * 2; } } }; // Start background music LK.playMusic('btsSong'); // Initial performance meter update updatePerformanceMeter();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BTSMember = Container.expand(function (memberNumber, xPos) {
var self = Container.call(this);
self.memberNumber = memberNumber;
self.isPerforming = false;
self.animationState = 'idle';
var memberGraphics = self.attachAsset('member' + memberNumber, {
anchorX: 0.5,
anchorY: 1.0
});
var hitZone = self.attachAsset('hitZone', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
self.x = xPos;
self.y = 2200;
hitZone.y = -200;
self.performAnimation = function () {
self.isPerforming = true;
self.animationState = 'performing';
tween(memberGraphics, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(memberGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
tween(memberGraphics, {
tint: 0xffffff
}, {
duration: 300,
onFinish: function onFinish() {
tween(memberGraphics, {
tint: 0xffffff
}, {
duration: 200
});
}
});
};
self.idleAnimation = function () {
self.isPerforming = false;
self.animationState = 'idle';
tween(memberGraphics, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(memberGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
};
self.getHitZoneY = function () {
return self.y + hitZone.y;
};
return self;
});
var Note = Container.expand(function (lane, type) {
var self = Container.call(this);
self.lane = lane;
self.type = type || 'normal';
self.speed = 8;
self.isActive = true;
self.hitTiming = 0;
var noteGraphics = self.attachAsset(self.type === 'hold' ? 'holdNote' : 'note', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (self.isActive) {
self.y += self.speed;
}
};
self.checkHit = function (hitY) {
var distance = Math.abs(self.y - hitY);
if (distance < 50) {
return 'perfect';
} else if (distance < 80) {
return 'good';
} else if (distance < 120) {
return 'ok';
}
return 'miss';
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a0a
});
/****
* Game Code
****/
// Sound effects
// UI elements
// Note types
// BTS character representations
// Stage and background elements
// Game state variables
var gameState = 'playing';
var score = 0;
var combo = 0;
var maxCombo = 0;
var performanceLevel = 100;
var difficulty = 1;
var songPosition = 0;
var nextNoteTime = 0;
// Member positions (7 members spread across stage)
var memberPositions = [200, 400, 600, 800, 1000, 1200, 1400, 1600];
// Create stage
var stage = game.attachAsset('stage', {
anchorX: 0.5,
anchorY: 1.0,
x: 1024,
y: 2200
});
// Create BTS members
var members = [];
for (var i = 0; i < 7; i++) {
var member = new BTSMember(i + 1, memberPositions[i]);
members.push(member);
game.addChild(member);
}
// Create notes array
var notes = [];
// Create UI elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var comboText = new Text2('Combo: 0', {
size: 50,
fill: 0xFFFF00
});
comboText.anchor.set(0.5, 0);
comboText.y = 80;
LK.gui.top.addChild(comboText);
// Performance meter
var performanceMeterBg = LK.gui.bottom.attachAsset('performanceMeter', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: -100
});
var performanceBar = LK.gui.bottom.attachAsset('performanceBar', {
anchorX: 0.0,
anchorY: 1.0,
x: -150,
y: -100
});
// Note patterns for different difficulty levels
var notePatterns = {
1: [{
lane: 0,
time: 60
}, {
lane: 2,
time: 120
}, {
lane: 4,
time: 180
}, {
lane: 6,
time: 240
}, {
lane: 1,
time: 300
}, {
lane: 3,
time: 360
}, {
lane: 5,
time: 420
}, {
lane: 0,
time: 480
}],
2: [{
lane: 0,
time: 30
}, {
lane: 2,
time: 60
}, {
lane: 4,
time: 90
}, {
lane: 6,
time: 120
}, {
lane: 1,
time: 150
}, {
lane: 3,
time: 180
}, {
lane: 5,
time: 210
}, {
lane: 0,
time: 240
}]
};
var currentPattern = notePatterns[difficulty];
var patternIndex = 0;
// Function to spawn notes
function spawnNote(lane, type) {
if (lane < 0 || lane >= members.length) return;
var note = new Note(lane, type);
note.x = members[lane].x;
note.y = 200;
notes.push(note);
game.addChild(note);
}
// Function to update performance meter
function updatePerformanceMeter() {
var percentage = performanceLevel / 100;
performanceBar.scaleX = Math.max(0, percentage);
if (performanceLevel > 70) {
performanceBar.tint = 0x00ff00;
} else if (performanceLevel > 40) {
performanceBar.tint = 0xffff00;
} else {
performanceBar.tint = 0xff0000;
}
}
// Function to handle note hit
function hitNote(note, accuracy) {
var points = 0;
switch (accuracy) {
case 'perfect':
points = 100;
combo++;
performanceLevel = Math.min(100, performanceLevel + 3);
break;
case 'good':
points = 80;
combo++;
performanceLevel = Math.min(100, performanceLevel + 2);
break;
case 'ok':
points = 60;
combo++;
performanceLevel = Math.min(100, performanceLevel + 1);
break;
default:
combo = 0;
performanceLevel = Math.max(0, performanceLevel - 5);
break;
}
score += points * (1 + combo * 0.1);
maxCombo = Math.max(maxCombo, combo);
// Update member animation
if (accuracy !== 'miss') {
members[note.lane].performAnimation();
LK.getSound('noteHit').play();
} else {
LK.getSound('noteMiss').play();
}
// Update UI
scoreText.setText('Score: ' + Math.floor(score));
comboText.setText('Combo: ' + combo);
updatePerformanceMeter();
// Set LK score for leaderboard
LK.setScore(Math.floor(score));
}
// Touch/click handling
var touchedLanes = [];
game.down = function (x, y, obj) {
// Find which member was touched
for (var i = 0; i < members.length; i++) {
var member = members[i];
var distance = Math.abs(x - member.x);
if (distance < 100) {
touchedLanes.push(i);
// Check for notes in this lane
var hitZoneY = member.getHitZoneY();
var bestNote = null;
var bestDistance = Infinity;
for (var j = 0; j < notes.length; j++) {
var note = notes[j];
if (note.lane === i && note.isActive) {
var noteDistance = Math.abs(note.y - hitZoneY);
if (noteDistance < bestDistance) {
bestDistance = noteDistance;
bestNote = note;
}
}
}
if (bestNote) {
var accuracy = bestNote.checkHit(hitZoneY);
hitNote(bestNote, accuracy);
bestNote.isActive = false;
bestNote.destroy();
// Remove from notes array
var noteIndex = notes.indexOf(bestNote);
if (noteIndex > -1) {
notes.splice(noteIndex, 1);
}
}
break;
}
}
};
game.up = function (x, y, obj) {
touchedLanes = [];
};
// Main game update loop
game.update = function () {
songPosition++;
// Spawn notes based on pattern
if (patternIndex < currentPattern.length) {
if (songPosition >= currentPattern[patternIndex].time) {
spawnNote(currentPattern[patternIndex].lane, 'normal');
patternIndex++;
// Loop pattern
if (patternIndex >= currentPattern.length) {
patternIndex = 0;
songPosition = 0;
}
}
}
// Update notes
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
// Remove notes that are off screen
if (note.y > 2800) {
// Miss penalty
if (note.isActive) {
combo = 0;
performanceLevel = Math.max(0, performanceLevel - 8);
updatePerformanceMeter();
LK.getSound('noteMiss').play();
}
note.destroy();
notes.splice(i, 1);
}
}
// Update member idle animations
for (var i = 0; i < members.length; i++) {
if (!members[i].isPerforming && LK.ticks % 180 === i * 20) {
members[i].idleAnimation();
}
}
// Check game over condition
if (performanceLevel <= 0) {
gameState = 'gameOver';
LK.showGameOver();
}
// Check win condition (high score threshold)
if (score >= 5000) {
gameState = 'win';
LK.showYouWin();
}
// Increase difficulty over time
if (LK.ticks % 1800 === 0 && difficulty < 2) {
difficulty++;
currentPattern = notePatterns[difficulty];
patternIndex = 0;
songPosition = 0;
// Increase note speed
for (var i = 0; i < notes.length; i++) {
notes[i].speed = 8 + difficulty * 2;
}
}
};
// Start background music
LK.playMusic('btsSong');
// Initial performance meter update
updatePerformanceMeter();