/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Game starts in menu state var MenuButton = Container.expand(function (text, onClickCallback) { var self = Container.call(this); // Create button background var buttonBg = self.attachAsset('notePad', { anchorX: 0.5, anchorY: 0.5, scaleX: 3.0, scaleY: 2.4 }); buttonBg.tint = 0xffffff; // Create button text var buttonText = new Text2(text, { size: 120, fill: 0x000000 }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.onClickCallback = onClickCallback; self.down = function (x, y, obj) { buttonBg.tint = 0xcccccc; if (self.onClickCallback) { self.onClickCallback(); } }; self.up = function (x, y, obj) { buttonBg.tint = 0xffffff; }; return self; }); var Note = Container.expand(function (lane, isRedMode) { var self = Container.call(this); var noteGraphics = self.attachAsset('note', { anchorX: 0.5, anchorY: 0.5 }); self.lane = lane; // 0 = left, 1 = center, 2 = right self.speed = Note.prototype.speed || 8; self.hasBeenHit = false; self.isRedMode = isRedMode || false; self.startX = 0; // Track starting X position for swipe detection self.hasStartedDrag = false; // Make red notes visually distinct if (self.isRedMode) { noteGraphics.tint = 0xff0000; // Red color } self.update = function () { self.y += self.speed; }; self.down = function (x, y, obj) { if (!self.hasBeenHit) { if (self.isRedMode) { // For red notes, track starting position for swipe detection self.startX = x; self.hasStartedDrag = true; } else { // Normal note behavior self.hasBeenHit = true; gameScore += 5; gameCombo += 1; // Combo system logic combo += 1; if (combo >= 10 && !feverMode) { feverMode = true; LK.effects.flashScreen(0xFFD700, 200); game.setBackgroundColor(0xFFD700); // Gold LK.setTimeout(function () { feverMode = false; game.setBackgroundColor(0x1a1a2e); combo = 0; }, 5000); } comboDisplayText.setText("Perfect!"); comboDisplayText.visible = true; LK.setTimeout(function () { comboDisplayText.visible = false; }, 500); // Create explosion effect createExplosionEffect(self.x, self.y); // Change background color effect var colors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0x96ceb4, 0xfeca57, 0xff9ff3, 0x54a0ff]; var randomColor = colors[Math.floor(Math.random() * colors.length)]; game.setBackgroundColor(randomColor); // Visual effect tween(self, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 200, onFinish: function onFinish() { removeNote(self); } }); LK.getSound('success').play(); updateUI(); } } }; self.up = function (x, y, obj) { if (self.isRedMode && self.hasStartedDrag && !self.hasBeenHit) { // Check if user swiped left (moved at least 100 pixels to the left) var swipeDistance = self.startX - x; if (swipeDistance > 100) { // Successful left swipe on red note self.hasBeenHit = true; gameScore += 10; // Red notes give 10 points gameCombo += 1; // Combo system logic combo += 1; if (combo >= 10 && !feverMode) { feverMode = true; LK.effects.flashScreen(0xFFD700, 200); game.setBackgroundColor(0xFFD700); // Gold LK.setTimeout(function () { feverMode = false; game.setBackgroundColor(0x1a1a2e); combo = 0; }, 5000); } comboDisplayText.setText("Perfect!"); comboDisplayText.visible = true; LK.setTimeout(function () { comboDisplayText.visible = false; }, 500); // Create explosion effect createExplosionEffect(self.x, self.y); // Change background color effect var colors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0x96ceb4, 0xfeca57, 0xff9ff3, 0x54a0ff]; var randomColor = colors[Math.floor(Math.random() * colors.length)]; game.setBackgroundColor(randomColor); // Visual effect tween(self, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 200, onFinish: function onFinish() { removeNote(self); } }); LK.getSound('success').play(); updateUI(); } } self.hasStartedDrag = false; }; return self; }); var NotePad = Container.expand(function (lane) { var self = Container.call(this); var padGraphics = self.attachAsset('notePad', { anchorX: 0.5, anchorY: 0.5 }); var perfectZone = self.attachAsset('perfectZone', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); self.lane = lane; self.isPressed = false; self.down = function (x, y, obj) { self.isPressed = true; checkNoteHit(self.lane); }; self.up = function (x, y, obj) { self.isPressed = false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ // Create background var background = LK.getAsset('Background', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(background); var notes = []; var gameScore = 0; var gameCombo = 0; var spawnTimer = 0; var spawnInterval = 45; // 0.75 seconds at 60fps var perfectZoneY = 2400; var perfectTolerance = 100; var noteCounter = 0; // Track total notes spawned for red mode var combo = 0; var feverMode = false; var comboDisplayText; var scoreDisplayText; // Game state var gameState = 'menu'; // 'menu', 'difficulty', or 'playing' var selectedDifficulty = 'normal'; var mainMenu = new Container(); var difficultyMenu = new Container(); var howToPlayMenu = new Container(); var gameContainer = new Container(); // Main Menu Elements var titleText = new Text2('Rhythm Tap Challenge', { size: 80, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; mainMenu.addChild(titleText); var startButton = new MenuButton('START', function () { showDifficultyMenu(); }); startButton.x = 1024; startButton.y = 1200; mainMenu.addChild(startButton); var howToPlayButton = new MenuButton('HOW TO PLAY', function () { showHowToPlayMenu(); }); // Enlarge the green area behind the How To Play button howToPlayButton.children[0].scaleX = 5.0; howToPlayButton.children[0].scaleY = 4.0; howToPlayButton.x = 1024; howToPlayButton.y = 1500; mainMenu.addChild(howToPlayButton); // Difficulty Menu Elements var difficultyTitle = new Text2('Select Difficulty', { size: 70, fill: 0xFFFFFF }); difficultyTitle.anchor.set(0.5, 0.5); difficultyTitle.x = 1024; difficultyTitle.y = 800; difficultyMenu.addChild(difficultyTitle); var easyButton = new MenuButton('EASY', function () { selectedDifficulty = 'easy'; startGame(); }); easyButton.x = 1024; easyButton.y = 1000; difficultyMenu.addChild(easyButton); var normalButton = new MenuButton('NORMAL', function () { selectedDifficulty = 'normal'; startGame(); }); normalButton.x = 1024; normalButton.y = 1150; difficultyMenu.addChild(normalButton); var hardButton = new MenuButton('HARD', function () { selectedDifficulty = 'hard'; startGame(); }); hardButton.x = 1024; hardButton.y = 1300; difficultyMenu.addChild(hardButton); var backButton = new MenuButton('BACK', function () { showMainMenu(); }); backButton.x = 1024; backButton.y = 1500; difficultyMenu.addChild(backButton); // How To Play Menu Elements var howToPlayTitle = new Text2('How To Play', { size: 70, fill: 0xFFFFFF }); howToPlayTitle.anchor.set(0.5, 0.5); howToPlayTitle.x = 1024; howToPlayTitle.y = 600; howToPlayMenu.addChild(howToPlayTitle); var instructionsText1 = new Text2('Notes fall from 3 different points', { size: 50, fill: 0xFFFFFF }); instructionsText1.anchor.set(0.5, 0.5); instructionsText1.x = 1024; instructionsText1.y = 900; howToPlayMenu.addChild(instructionsText1); var instructionsText2 = new Text2('from top to bottom.', { size: 50, fill: 0xFFFFFF }); instructionsText2.anchor.set(0.5, 0.5); instructionsText2.x = 1024; instructionsText2.y = 970; howToPlayMenu.addChild(instructionsText2); var instructionsText3 = new Text2('Touch the notes before they disappear', { size: 50, fill: 0xFFFFFF }); instructionsText3.anchor.set(0.5, 0.5); instructionsText3.x = 1024; instructionsText3.y = 1040; howToPlayMenu.addChild(instructionsText3); var instructionsText4 = new Text2('and earn 5 points.', { size: 50, fill: 0xFFFFFF }); instructionsText4.anchor.set(0.5, 0.5); instructionsText4.x = 1024; instructionsText4.y = 1110; howToPlayMenu.addChild(instructionsText4); var instructionsText5 = new Text2('If you cannot touch them in time,', { size: 50, fill: 0xFFFFFF }); instructionsText5.anchor.set(0.5, 0.5); instructionsText5.x = 1024; instructionsText5.y = 1180; howToPlayMenu.addChild(instructionsText5); var instructionsText6 = new Text2('your 5 points will decrease and', { size: 50, fill: 0xFFFFFF }); instructionsText6.anchor.set(0.5, 0.5); instructionsText6.x = 1024; instructionsText6.y = 1250; howToPlayMenu.addChild(instructionsText6); var instructionsText7 = new Text2('the game will end at -50 points', { size: 50, fill: 0xFFFFFF }); instructionsText7.anchor.set(0.5, 0.5); instructionsText7.x = 1024; instructionsText7.y = 1320; howToPlayMenu.addChild(instructionsText7); var instructionsText8 = new Text2('We must move the red note that comes every 25 notes', { size: 50, fill: 0xFFFFFF }); instructionsText8.anchor.set(0.5, 0.5); instructionsText8.x = 1024; instructionsText8.y = 1390; howToPlayMenu.addChild(instructionsText8); var instructionsText9 = new Text2('to the left. If we move it, we gain 20 points.', { size: 50, fill: 0xFFFFFF }); instructionsText9.anchor.set(0.5, 0.5); instructionsText9.x = 1024; instructionsText9.y = 1460; howToPlayMenu.addChild(instructionsText9); var instructionsText10 = new Text2('If we cannot, our 20 points will be deducted', { size: 50, fill: 0xFFFFFF }); instructionsText10.anchor.set(0.5, 0.5); instructionsText10.x = 1024; instructionsText10.y = 1530; howToPlayMenu.addChild(instructionsText10); var backFromHowToPlayButton = new MenuButton('BACK', function () { showMainMenu(); }); backFromHowToPlayButton.x = 1024; backFromHowToPlayButton.y = 1650; howToPlayMenu.addChild(backFromHowToPlayButton); game.addChild(mainMenu); game.addChild(difficultyMenu); game.addChild(howToPlayMenu); difficultyMenu.visible = false; howToPlayMenu.visible = false; // UI Elements var scoreText = new Text2('0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); scoreText.x = 0; scoreText.y = 50; LK.gui.top.addChild(scoreText); var comboText = new Text2('Combo: 0', { size: 50, fill: 0xFFFF00 }); comboText.anchor.set(1, 0); comboText.x = -50; comboText.y = 130; LK.gui.topRight.addChild(comboText); var highScoreText = new Text2('High Score: ' + (storage.highScore || 0), { size: 40, fill: 0xFFFFFF }); highScoreText.anchor.set(1, 0); highScoreText.x = -50; highScoreText.y = 200; LK.gui.topRight.addChild(highScoreText); // Hide UI initially scoreText.visible = false; comboText.visible = false; highScoreText.visible = false; // Create restart button for game screen var restartButton = new MenuButton('āŗ', function () { // Reset game state gameScore = 0; gameCombo = 0; spawnTimer = 0; noteCounter = 0; // Reset note counter for red mode // Clear all notes for (var i = notes.length - 1; i >= 0; i--) { removeNote(notes[i]); } updateUI(); }); restartButton.x = 924; restartButton.y = 50; restartButton.scaleX = 0.42; restartButton.scaleY = 0.42; gameContainer.addChild(restartButton); // Create return to main menu button for game screen var returnMenuButton = new MenuButton('š ', function () { // Stop game music and start menu music LK.stopMusic(); LK.playMusic('menumusic', { loop: true }); gameState = 'menu'; gameContainer.visible = false; scoreText.visible = false; comboText.visible = false; highScoreText.visible = false; // Clear all notes for (var i = notes.length - 1; i >= 0; i--) { removeNote(notes[i]); } // Reset game variables gameScore = 0; gameCombo = 0; spawnTimer = 0; noteCounter = 0; // Reset note counter for red mode updateUI(); // Show main menu showMainMenu(); }); returnMenuButton.x = 1124; returnMenuButton.y = 50; returnMenuButton.scaleX = 0.42; returnMenuButton.scaleY = 0.42; gameContainer.addChild(returnMenuButton); // Create note pads var padPositions = [512, 1024, 1536]; // Left, center, right positions game.addChild(gameContainer); gameContainer.visible = false; // Create intro text var introText = new Text2('lighten the darkness with music', { size: 80, fill: 0xFFFFFF }); introText.anchor.set(0.5, 0.5); introText.x = 1024; introText.y = 1366; introText.alpha = 1; game.addChild(introText); // Create black overlay for screen blackout effect var blackOverlay = LK.getAsset('notePad', { anchorX: 0, anchorY: 0, scaleX: 10, scaleY: 35, x: 0, y: 0 }); blackOverlay.tint = 0x000000; blackOverlay.alpha = 0.8; game.addChild(blackOverlay); // Initialize combo and score display text comboDisplayText = new Text2("", { size: 64, fill: 0xFFFFFF }); comboDisplayText.anchor.set(0.5, 0.5); comboDisplayText.x = 360; comboDisplayText.y = 300; comboDisplayText.visible = false; game.addChild(comboDisplayText); scoreDisplayText = new Text2("", { size: 24, fill: 0xFFFFFF }); scoreDisplayText.anchor.set(0.5, 0.5); scoreDisplayText.x = 360; scoreDisplayText.y = 50; game.addChild(scoreDisplayText); // Show intro text with fade in effect and black screen - starting 4.5 seconds earlier LK.setTimeout(function () { // Hold for 2 seconds then fade out LK.setTimeout(function () { tween(introText, { alpha: 0 }, { duration: 1500, onFinish: function onFinish() { game.removeChild(introText); } }); // Fade black overlay out tween(blackOverlay, { alpha: 0 }, { duration: 1500, onFinish: function onFinish() { game.removeChild(blackOverlay); } }); }, 2000); }, 0); // Start 4.5 seconds earlier (reduced from 500ms to 0ms) // Start menu music LK.playMusic('menumusic', { loop: true }); function showDifficultyMenu() { gameState = 'difficulty'; mainMenu.visible = false; difficultyMenu.visible = true; } function showHowToPlayMenu() { gameState = 'howtoplay'; mainMenu.visible = false; howToPlayMenu.visible = true; } function showMainMenu() { gameState = 'menu'; mainMenu.visible = true; difficultyMenu.visible = false; howToPlayMenu.visible = false; } function startGame() { gameState = 'playing'; mainMenu.visible = false; difficultyMenu.visible = false; gameContainer.visible = true; scoreText.visible = true; comboText.visible = true; highScoreText.visible = true; // Reset game state gameScore = 0; gameCombo = 0; spawnTimer = 0; noteCounter = 0; // Reset note counter for red mode // Set note speed based on difficulty var noteSpeed = 8; // normal speed if (selectedDifficulty === 'easy') { noteSpeed = 12; // 1.5 times faster than normal (8 * 1.5) } else if (selectedDifficulty === 'normal') { noteSpeed = 28; // 3.5 times faster than normal (8 * 3.5) } else if (selectedDifficulty === 'hard') { noteSpeed = 32; // 4 times faster than normal (8 * 4) } // Update all note pads with new speed Note.prototype.speed = noteSpeed; // Clear any existing notes for (var i = notes.length - 1; i >= 0; i--) { removeNote(notes[i]); } // Stop menu music and start game music LK.stopMusic(); LK.playMusic('bgmusic', { loop: true }); updateUI(); // Update high score display for selected difficulty var highScoreKey = 'highScore_' + selectedDifficulty; highScoreText.setText('Best (' + selectedDifficulty.toUpperCase() + '): ' + (storage[highScoreKey] || 0)); } function spawnNote() { var randomLane = Math.floor(Math.random() * 3); noteCounter++; // Create red note every 25 notes var isRedMode = noteCounter % 25 === 0; var note = new Note(randomLane, isRedMode); note.x = padPositions[randomLane]; note.y = -50; notes.push(note); gameContainer.addChild(note); } function checkNoteHit(lane) { var hitNote = null; var bestDistance = Infinity; // Find the closest note in the perfect zone for this lane for (var i = 0; i < notes.length; i++) { var note = notes[i]; if (note.lane === lane && !note.hasBeenHit) { var distance = Math.abs(note.y - perfectZoneY); if (distance < perfectTolerance && distance < bestDistance) { hitNote = note; bestDistance = distance; } } } if (hitNote) { // Perfect hit hitNote.hasBeenHit = true; gameScore += 5; gameCombo += 1; // Create explosion effect createExplosionEffect(hitNote.x, hitNote.y); // Change background color effect var colors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0x96ceb4, 0xfeca57, 0xff9ff3, 0x54a0ff]; var randomColor = colors[Math.floor(Math.random() * colors.length)]; game.setBackgroundColor(randomColor); // Visual effect tween(hitNote, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 200, onFinish: function onFinish() { removeNote(hitNote); } }); LK.getSound('success').play(); updateUI(); } else { // Wrong timing gameScore -= 5; gameCombo = 0; LK.effects.flashScreen(0xff0000, 200); updateUI(); } } function createExplosionEffect(x, y) { // Create multiple explosion particles for (var i = 0; i < 8; i++) { var particle = LK.getAsset('note', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3 }); particle.x = x; particle.y = y; particle.tint = 0xFFFF00; // Yellow explosion color gameContainer.addChild(particle); // Random direction for each particle var angle = i / 8 * Math.PI * 2; var speed = 100 + Math.random() * 50; var targetX = x + Math.cos(angle) * speed; var targetY = y + Math.sin(angle) * speed; // Animate particle outward and fade tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { gameContainer.removeChild(particle); } }); } } function showComboEffect(x, y) { var comboEffect = new Text2('COMBO!', { size: 80, fill: 0xFFFF00 }); comboEffect.anchor.set(0.5, 0.5); comboEffect.x = x; comboEffect.y = y; gameContainer.addChild(comboEffect); tween(comboEffect, { y: y - 100, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { gameContainer.removeChild(comboEffect); } }); } function removeNote(note) { var index = notes.indexOf(note); if (index > -1) { notes.splice(index, 1); gameContainer.removeChild(note); } } function updateUI() { scoreText.setText(gameScore); comboText.setText('Combo: ' + gameCombo); LK.setScore(gameScore); // Update high score if current score is higher var highScoreKey = 'highScore_' + selectedDifficulty; var currentHighScore = storage[highScoreKey] || 0; if (gameScore > currentHighScore) { storage[highScoreKey] = gameScore; } highScoreText.setText('Best (' + selectedDifficulty.toUpperCase() + '): ' + (storage[highScoreKey] || 0)); // Check for game over at -50 points if (gameScore <= -50) { LK.showGameOver(); } } // Add pause menu functionality var pauseMenu = new Container(); var pauseTitle = new Text2('Game Paused', { size: 70, fill: 0xFFFFFF }); pauseTitle.anchor.set(0.5, 0.5); pauseTitle.x = 1024; pauseTitle.y = 1000; pauseMenu.addChild(pauseTitle); var resumeButton = new MenuButton('RESUME', function () { pauseMenu.visible = false; }); resumeButton.x = 1024; resumeButton.y = 1200; pauseMenu.addChild(resumeButton); var mainMenuButton = new MenuButton('MAIN MENU', function () { // Stop game music and start menu music LK.stopMusic(); LK.playMusic('menumusic', { loop: true }); gameState = 'menu'; pauseMenu.visible = false; gameContainer.visible = false; scoreText.visible = false; comboText.visible = false; highScoreText.visible = false; // Clear all notes for (var i = notes.length - 1; i >= 0; i--) { removeNote(notes[i]); } // Reset game variables gameScore = 0; gameCombo = 0; spawnTimer = 0; noteCounter = 0; // Reset note counter for red mode updateUI(); // Show main menu showMainMenu(); }); mainMenuButton.x = 1024; mainMenuButton.y = 1350; pauseMenu.addChild(mainMenuButton); game.addChild(pauseMenu); pauseMenu.visible = false; game.update = function () { if (gameState !== 'playing') { return; } // Spawn notes spawnTimer++; if (spawnTimer >= spawnInterval) { spawnNote(); spawnTimer = 0; } // Update and check notes for (var i = notes.length - 1; i >= 0; i--) { var note = notes[i]; // Check if note reached bottom (missed) if (note.y > 2800 && !note.hasBeenHit) { if (note.isRedMode) { gameScore -= 20; // Red notes penalty is -20 points } else { gameScore -= 5; // Normal notes penalty is -5 points } gameCombo = 0; // Combo system reset on miss combo = 0; comboDisplayText.setText("Miss!"); comboDisplayText.visible = true; LK.setTimeout(function () { comboDisplayText.visible = false; }, 500); LK.getSound('fail').play(); updateUI(); removeNote(note); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Game starts in menu state
var MenuButton = Container.expand(function (text, onClickCallback) {
var self = Container.call(this);
// Create button background
var buttonBg = self.attachAsset('notePad', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.0,
scaleY: 2.4
});
buttonBg.tint = 0xffffff;
// Create button text
var buttonText = new Text2(text, {
size: 120,
fill: 0x000000
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.onClickCallback = onClickCallback;
self.down = function (x, y, obj) {
buttonBg.tint = 0xcccccc;
if (self.onClickCallback) {
self.onClickCallback();
}
};
self.up = function (x, y, obj) {
buttonBg.tint = 0xffffff;
};
return self;
});
var Note = Container.expand(function (lane, isRedMode) {
var self = Container.call(this);
var noteGraphics = self.attachAsset('note', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = lane; // 0 = left, 1 = center, 2 = right
self.speed = Note.prototype.speed || 8;
self.hasBeenHit = false;
self.isRedMode = isRedMode || false;
self.startX = 0; // Track starting X position for swipe detection
self.hasStartedDrag = false;
// Make red notes visually distinct
if (self.isRedMode) {
noteGraphics.tint = 0xff0000; // Red color
}
self.update = function () {
self.y += self.speed;
};
self.down = function (x, y, obj) {
if (!self.hasBeenHit) {
if (self.isRedMode) {
// For red notes, track starting position for swipe detection
self.startX = x;
self.hasStartedDrag = true;
} else {
// Normal note behavior
self.hasBeenHit = true;
gameScore += 5;
gameCombo += 1;
// Combo system logic
combo += 1;
if (combo >= 10 && !feverMode) {
feverMode = true;
LK.effects.flashScreen(0xFFD700, 200);
game.setBackgroundColor(0xFFD700); // Gold
LK.setTimeout(function () {
feverMode = false;
game.setBackgroundColor(0x1a1a2e);
combo = 0;
}, 5000);
}
comboDisplayText.setText("Perfect!");
comboDisplayText.visible = true;
LK.setTimeout(function () {
comboDisplayText.visible = false;
}, 500);
// Create explosion effect
createExplosionEffect(self.x, self.y);
// Change background color effect
var colors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0x96ceb4, 0xfeca57, 0xff9ff3, 0x54a0ff];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
game.setBackgroundColor(randomColor);
// Visual effect
tween(self, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 200,
onFinish: function onFinish() {
removeNote(self);
}
});
LK.getSound('success').play();
updateUI();
}
}
};
self.up = function (x, y, obj) {
if (self.isRedMode && self.hasStartedDrag && !self.hasBeenHit) {
// Check if user swiped left (moved at least 100 pixels to the left)
var swipeDistance = self.startX - x;
if (swipeDistance > 100) {
// Successful left swipe on red note
self.hasBeenHit = true;
gameScore += 10; // Red notes give 10 points
gameCombo += 1;
// Combo system logic
combo += 1;
if (combo >= 10 && !feverMode) {
feverMode = true;
LK.effects.flashScreen(0xFFD700, 200);
game.setBackgroundColor(0xFFD700); // Gold
LK.setTimeout(function () {
feverMode = false;
game.setBackgroundColor(0x1a1a2e);
combo = 0;
}, 5000);
}
comboDisplayText.setText("Perfect!");
comboDisplayText.visible = true;
LK.setTimeout(function () {
comboDisplayText.visible = false;
}, 500);
// Create explosion effect
createExplosionEffect(self.x, self.y);
// Change background color effect
var colors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0x96ceb4, 0xfeca57, 0xff9ff3, 0x54a0ff];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
game.setBackgroundColor(randomColor);
// Visual effect
tween(self, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 200,
onFinish: function onFinish() {
removeNote(self);
}
});
LK.getSound('success').play();
updateUI();
}
}
self.hasStartedDrag = false;
};
return self;
});
var NotePad = Container.expand(function (lane) {
var self = Container.call(this);
var padGraphics = self.attachAsset('notePad', {
anchorX: 0.5,
anchorY: 0.5
});
var perfectZone = self.attachAsset('perfectZone', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
self.lane = lane;
self.isPressed = false;
self.down = function (x, y, obj) {
self.isPressed = true;
checkNoteHit(self.lane);
};
self.up = function (x, y, obj) {
self.isPressed = false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Create background
var background = LK.getAsset('Background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(background);
var notes = [];
var gameScore = 0;
var gameCombo = 0;
var spawnTimer = 0;
var spawnInterval = 45; // 0.75 seconds at 60fps
var perfectZoneY = 2400;
var perfectTolerance = 100;
var noteCounter = 0; // Track total notes spawned for red mode
var combo = 0;
var feverMode = false;
var comboDisplayText;
var scoreDisplayText;
// Game state
var gameState = 'menu'; // 'menu', 'difficulty', or 'playing'
var selectedDifficulty = 'normal';
var mainMenu = new Container();
var difficultyMenu = new Container();
var howToPlayMenu = new Container();
var gameContainer = new Container();
// Main Menu Elements
var titleText = new Text2('Rhythm Tap Challenge', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
mainMenu.addChild(titleText);
var startButton = new MenuButton('START', function () {
showDifficultyMenu();
});
startButton.x = 1024;
startButton.y = 1200;
mainMenu.addChild(startButton);
var howToPlayButton = new MenuButton('HOW TO PLAY', function () {
showHowToPlayMenu();
});
// Enlarge the green area behind the How To Play button
howToPlayButton.children[0].scaleX = 5.0;
howToPlayButton.children[0].scaleY = 4.0;
howToPlayButton.x = 1024;
howToPlayButton.y = 1500;
mainMenu.addChild(howToPlayButton);
// Difficulty Menu Elements
var difficultyTitle = new Text2('Select Difficulty', {
size: 70,
fill: 0xFFFFFF
});
difficultyTitle.anchor.set(0.5, 0.5);
difficultyTitle.x = 1024;
difficultyTitle.y = 800;
difficultyMenu.addChild(difficultyTitle);
var easyButton = new MenuButton('EASY', function () {
selectedDifficulty = 'easy';
startGame();
});
easyButton.x = 1024;
easyButton.y = 1000;
difficultyMenu.addChild(easyButton);
var normalButton = new MenuButton('NORMAL', function () {
selectedDifficulty = 'normal';
startGame();
});
normalButton.x = 1024;
normalButton.y = 1150;
difficultyMenu.addChild(normalButton);
var hardButton = new MenuButton('HARD', function () {
selectedDifficulty = 'hard';
startGame();
});
hardButton.x = 1024;
hardButton.y = 1300;
difficultyMenu.addChild(hardButton);
var backButton = new MenuButton('BACK', function () {
showMainMenu();
});
backButton.x = 1024;
backButton.y = 1500;
difficultyMenu.addChild(backButton);
// How To Play Menu Elements
var howToPlayTitle = new Text2('How To Play', {
size: 70,
fill: 0xFFFFFF
});
howToPlayTitle.anchor.set(0.5, 0.5);
howToPlayTitle.x = 1024;
howToPlayTitle.y = 600;
howToPlayMenu.addChild(howToPlayTitle);
var instructionsText1 = new Text2('Notes fall from 3 different points', {
size: 50,
fill: 0xFFFFFF
});
instructionsText1.anchor.set(0.5, 0.5);
instructionsText1.x = 1024;
instructionsText1.y = 900;
howToPlayMenu.addChild(instructionsText1);
var instructionsText2 = new Text2('from top to bottom.', {
size: 50,
fill: 0xFFFFFF
});
instructionsText2.anchor.set(0.5, 0.5);
instructionsText2.x = 1024;
instructionsText2.y = 970;
howToPlayMenu.addChild(instructionsText2);
var instructionsText3 = new Text2('Touch the notes before they disappear', {
size: 50,
fill: 0xFFFFFF
});
instructionsText3.anchor.set(0.5, 0.5);
instructionsText3.x = 1024;
instructionsText3.y = 1040;
howToPlayMenu.addChild(instructionsText3);
var instructionsText4 = new Text2('and earn 5 points.', {
size: 50,
fill: 0xFFFFFF
});
instructionsText4.anchor.set(0.5, 0.5);
instructionsText4.x = 1024;
instructionsText4.y = 1110;
howToPlayMenu.addChild(instructionsText4);
var instructionsText5 = new Text2('If you cannot touch them in time,', {
size: 50,
fill: 0xFFFFFF
});
instructionsText5.anchor.set(0.5, 0.5);
instructionsText5.x = 1024;
instructionsText5.y = 1180;
howToPlayMenu.addChild(instructionsText5);
var instructionsText6 = new Text2('your 5 points will decrease and', {
size: 50,
fill: 0xFFFFFF
});
instructionsText6.anchor.set(0.5, 0.5);
instructionsText6.x = 1024;
instructionsText6.y = 1250;
howToPlayMenu.addChild(instructionsText6);
var instructionsText7 = new Text2('the game will end at -50 points', {
size: 50,
fill: 0xFFFFFF
});
instructionsText7.anchor.set(0.5, 0.5);
instructionsText7.x = 1024;
instructionsText7.y = 1320;
howToPlayMenu.addChild(instructionsText7);
var instructionsText8 = new Text2('We must move the red note that comes every 25 notes', {
size: 50,
fill: 0xFFFFFF
});
instructionsText8.anchor.set(0.5, 0.5);
instructionsText8.x = 1024;
instructionsText8.y = 1390;
howToPlayMenu.addChild(instructionsText8);
var instructionsText9 = new Text2('to the left. If we move it, we gain 20 points.', {
size: 50,
fill: 0xFFFFFF
});
instructionsText9.anchor.set(0.5, 0.5);
instructionsText9.x = 1024;
instructionsText9.y = 1460;
howToPlayMenu.addChild(instructionsText9);
var instructionsText10 = new Text2('If we cannot, our 20 points will be deducted', {
size: 50,
fill: 0xFFFFFF
});
instructionsText10.anchor.set(0.5, 0.5);
instructionsText10.x = 1024;
instructionsText10.y = 1530;
howToPlayMenu.addChild(instructionsText10);
var backFromHowToPlayButton = new MenuButton('BACK', function () {
showMainMenu();
});
backFromHowToPlayButton.x = 1024;
backFromHowToPlayButton.y = 1650;
howToPlayMenu.addChild(backFromHowToPlayButton);
game.addChild(mainMenu);
game.addChild(difficultyMenu);
game.addChild(howToPlayMenu);
difficultyMenu.visible = false;
howToPlayMenu.visible = false;
// UI Elements
var scoreText = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 0;
scoreText.y = 50;
LK.gui.top.addChild(scoreText);
var comboText = new Text2('Combo: 0', {
size: 50,
fill: 0xFFFF00
});
comboText.anchor.set(1, 0);
comboText.x = -50;
comboText.y = 130;
LK.gui.topRight.addChild(comboText);
var highScoreText = new Text2('High Score: ' + (storage.highScore || 0), {
size: 40,
fill: 0xFFFFFF
});
highScoreText.anchor.set(1, 0);
highScoreText.x = -50;
highScoreText.y = 200;
LK.gui.topRight.addChild(highScoreText);
// Hide UI initially
scoreText.visible = false;
comboText.visible = false;
highScoreText.visible = false;
// Create restart button for game screen
var restartButton = new MenuButton('āŗ', function () {
// Reset game state
gameScore = 0;
gameCombo = 0;
spawnTimer = 0;
noteCounter = 0; // Reset note counter for red mode
// Clear all notes
for (var i = notes.length - 1; i >= 0; i--) {
removeNote(notes[i]);
}
updateUI();
});
restartButton.x = 924;
restartButton.y = 50;
restartButton.scaleX = 0.42;
restartButton.scaleY = 0.42;
gameContainer.addChild(restartButton);
// Create return to main menu button for game screen
var returnMenuButton = new MenuButton('š ', function () {
// Stop game music and start menu music
LK.stopMusic();
LK.playMusic('menumusic', {
loop: true
});
gameState = 'menu';
gameContainer.visible = false;
scoreText.visible = false;
comboText.visible = false;
highScoreText.visible = false;
// Clear all notes
for (var i = notes.length - 1; i >= 0; i--) {
removeNote(notes[i]);
}
// Reset game variables
gameScore = 0;
gameCombo = 0;
spawnTimer = 0;
noteCounter = 0; // Reset note counter for red mode
updateUI();
// Show main menu
showMainMenu();
});
returnMenuButton.x = 1124;
returnMenuButton.y = 50;
returnMenuButton.scaleX = 0.42;
returnMenuButton.scaleY = 0.42;
gameContainer.addChild(returnMenuButton);
// Create note pads
var padPositions = [512, 1024, 1536]; // Left, center, right positions
game.addChild(gameContainer);
gameContainer.visible = false;
// Create intro text
var introText = new Text2('lighten the darkness with music', {
size: 80,
fill: 0xFFFFFF
});
introText.anchor.set(0.5, 0.5);
introText.x = 1024;
introText.y = 1366;
introText.alpha = 1;
game.addChild(introText);
// Create black overlay for screen blackout effect
var blackOverlay = LK.getAsset('notePad', {
anchorX: 0,
anchorY: 0,
scaleX: 10,
scaleY: 35,
x: 0,
y: 0
});
blackOverlay.tint = 0x000000;
blackOverlay.alpha = 0.8;
game.addChild(blackOverlay);
// Initialize combo and score display text
comboDisplayText = new Text2("", {
size: 64,
fill: 0xFFFFFF
});
comboDisplayText.anchor.set(0.5, 0.5);
comboDisplayText.x = 360;
comboDisplayText.y = 300;
comboDisplayText.visible = false;
game.addChild(comboDisplayText);
scoreDisplayText = new Text2("", {
size: 24,
fill: 0xFFFFFF
});
scoreDisplayText.anchor.set(0.5, 0.5);
scoreDisplayText.x = 360;
scoreDisplayText.y = 50;
game.addChild(scoreDisplayText);
// Show intro text with fade in effect and black screen - starting 4.5 seconds earlier
LK.setTimeout(function () {
// Hold for 2 seconds then fade out
LK.setTimeout(function () {
tween(introText, {
alpha: 0
}, {
duration: 1500,
onFinish: function onFinish() {
game.removeChild(introText);
}
});
// Fade black overlay out
tween(blackOverlay, {
alpha: 0
}, {
duration: 1500,
onFinish: function onFinish() {
game.removeChild(blackOverlay);
}
});
}, 2000);
}, 0); // Start 4.5 seconds earlier (reduced from 500ms to 0ms)
// Start menu music
LK.playMusic('menumusic', {
loop: true
});
function showDifficultyMenu() {
gameState = 'difficulty';
mainMenu.visible = false;
difficultyMenu.visible = true;
}
function showHowToPlayMenu() {
gameState = 'howtoplay';
mainMenu.visible = false;
howToPlayMenu.visible = true;
}
function showMainMenu() {
gameState = 'menu';
mainMenu.visible = true;
difficultyMenu.visible = false;
howToPlayMenu.visible = false;
}
function startGame() {
gameState = 'playing';
mainMenu.visible = false;
difficultyMenu.visible = false;
gameContainer.visible = true;
scoreText.visible = true;
comboText.visible = true;
highScoreText.visible = true;
// Reset game state
gameScore = 0;
gameCombo = 0;
spawnTimer = 0;
noteCounter = 0; // Reset note counter for red mode
// Set note speed based on difficulty
var noteSpeed = 8; // normal speed
if (selectedDifficulty === 'easy') {
noteSpeed = 12; // 1.5 times faster than normal (8 * 1.5)
} else if (selectedDifficulty === 'normal') {
noteSpeed = 28; // 3.5 times faster than normal (8 * 3.5)
} else if (selectedDifficulty === 'hard') {
noteSpeed = 32; // 4 times faster than normal (8 * 4)
}
// Update all note pads with new speed
Note.prototype.speed = noteSpeed;
// Clear any existing notes
for (var i = notes.length - 1; i >= 0; i--) {
removeNote(notes[i]);
}
// Stop menu music and start game music
LK.stopMusic();
LK.playMusic('bgmusic', {
loop: true
});
updateUI();
// Update high score display for selected difficulty
var highScoreKey = 'highScore_' + selectedDifficulty;
highScoreText.setText('Best (' + selectedDifficulty.toUpperCase() + '): ' + (storage[highScoreKey] || 0));
}
function spawnNote() {
var randomLane = Math.floor(Math.random() * 3);
noteCounter++;
// Create red note every 25 notes
var isRedMode = noteCounter % 25 === 0;
var note = new Note(randomLane, isRedMode);
note.x = padPositions[randomLane];
note.y = -50;
notes.push(note);
gameContainer.addChild(note);
}
function checkNoteHit(lane) {
var hitNote = null;
var bestDistance = Infinity;
// Find the closest note in the perfect zone for this lane
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
if (note.lane === lane && !note.hasBeenHit) {
var distance = Math.abs(note.y - perfectZoneY);
if (distance < perfectTolerance && distance < bestDistance) {
hitNote = note;
bestDistance = distance;
}
}
}
if (hitNote) {
// Perfect hit
hitNote.hasBeenHit = true;
gameScore += 5;
gameCombo += 1;
// Create explosion effect
createExplosionEffect(hitNote.x, hitNote.y);
// Change background color effect
var colors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0x96ceb4, 0xfeca57, 0xff9ff3, 0x54a0ff];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
game.setBackgroundColor(randomColor);
// Visual effect
tween(hitNote, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 200,
onFinish: function onFinish() {
removeNote(hitNote);
}
});
LK.getSound('success').play();
updateUI();
} else {
// Wrong timing
gameScore -= 5;
gameCombo = 0;
LK.effects.flashScreen(0xff0000, 200);
updateUI();
}
}
function createExplosionEffect(x, y) {
// Create multiple explosion particles
for (var i = 0; i < 8; i++) {
var particle = LK.getAsset('note', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
particle.x = x;
particle.y = y;
particle.tint = 0xFFFF00; // Yellow explosion color
gameContainer.addChild(particle);
// Random direction for each particle
var angle = i / 8 * Math.PI * 2;
var speed = 100 + Math.random() * 50;
var targetX = x + Math.cos(angle) * speed;
var targetY = y + Math.sin(angle) * speed;
// Animate particle outward and fade
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
gameContainer.removeChild(particle);
}
});
}
}
function showComboEffect(x, y) {
var comboEffect = new Text2('COMBO!', {
size: 80,
fill: 0xFFFF00
});
comboEffect.anchor.set(0.5, 0.5);
comboEffect.x = x;
comboEffect.y = y;
gameContainer.addChild(comboEffect);
tween(comboEffect, {
y: y - 100,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
gameContainer.removeChild(comboEffect);
}
});
}
function removeNote(note) {
var index = notes.indexOf(note);
if (index > -1) {
notes.splice(index, 1);
gameContainer.removeChild(note);
}
}
function updateUI() {
scoreText.setText(gameScore);
comboText.setText('Combo: ' + gameCombo);
LK.setScore(gameScore);
// Update high score if current score is higher
var highScoreKey = 'highScore_' + selectedDifficulty;
var currentHighScore = storage[highScoreKey] || 0;
if (gameScore > currentHighScore) {
storage[highScoreKey] = gameScore;
}
highScoreText.setText('Best (' + selectedDifficulty.toUpperCase() + '): ' + (storage[highScoreKey] || 0));
// Check for game over at -50 points
if (gameScore <= -50) {
LK.showGameOver();
}
}
// Add pause menu functionality
var pauseMenu = new Container();
var pauseTitle = new Text2('Game Paused', {
size: 70,
fill: 0xFFFFFF
});
pauseTitle.anchor.set(0.5, 0.5);
pauseTitle.x = 1024;
pauseTitle.y = 1000;
pauseMenu.addChild(pauseTitle);
var resumeButton = new MenuButton('RESUME', function () {
pauseMenu.visible = false;
});
resumeButton.x = 1024;
resumeButton.y = 1200;
pauseMenu.addChild(resumeButton);
var mainMenuButton = new MenuButton('MAIN MENU', function () {
// Stop game music and start menu music
LK.stopMusic();
LK.playMusic('menumusic', {
loop: true
});
gameState = 'menu';
pauseMenu.visible = false;
gameContainer.visible = false;
scoreText.visible = false;
comboText.visible = false;
highScoreText.visible = false;
// Clear all notes
for (var i = notes.length - 1; i >= 0; i--) {
removeNote(notes[i]);
}
// Reset game variables
gameScore = 0;
gameCombo = 0;
spawnTimer = 0;
noteCounter = 0; // Reset note counter for red mode
updateUI();
// Show main menu
showMainMenu();
});
mainMenuButton.x = 1024;
mainMenuButton.y = 1350;
pauseMenu.addChild(mainMenuButton);
game.addChild(pauseMenu);
pauseMenu.visible = false;
game.update = function () {
if (gameState !== 'playing') {
return;
}
// Spawn notes
spawnTimer++;
if (spawnTimer >= spawnInterval) {
spawnNote();
spawnTimer = 0;
}
// Update and check notes
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
// Check if note reached bottom (missed)
if (note.y > 2800 && !note.hasBeenHit) {
if (note.isRedMode) {
gameScore -= 20; // Red notes penalty is -20 points
} else {
gameScore -= 5; // Normal notes penalty is -5 points
}
gameCombo = 0;
// Combo system reset on miss
combo = 0;
comboDisplayText.setText("Miss!");
comboDisplayText.visible = true;
LK.setTimeout(function () {
comboDisplayText.visible = false;
}, 500);
LK.getSound('fail').play();
updateUI();
removeNote(note);
}
}
};