/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, totalPlays: 0 }); /**** * Classes ****/ var HitEffect = Container.expand(function (rating) { var self = Container.call(this); // Create effect circle var effect = self.attachAsset('hitEffect', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); // Create rating text var text = new Text2(rating, { size: 60, fill: 0xFFFFFF }); text.anchor.set(0.5, 0.5); self.addChild(text); // Set initial scale self.scale.set(0.8); // Animate and destroy tween(self, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); return self; }); var MissEffect = Container.expand(function () { var self = Container.call(this); // Create miss effect var effect = self.attachAsset('missEffect', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); // Create X text var text = new Text2("MISS", { size: 60, fill: 0xFFFFFF }); text.anchor.set(0.5, 0.5); self.addChild(text); // Set initial scale self.scale.set(0.8); // Animate and destroy tween(self, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); return self; }); var Note = Container.expand(function (timing, lane) { var self = Container.call(this); self.timing = timing; self.lane = lane; self.active = true; self.hit = false; self.approaching = false; // Create outer ring var ring = self.attachAsset('targetRing', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); // Create inner circle var circle = self.attachAsset('targetCircle', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); // Set initial scale for approach animation self.scale.set(0.1); // Define tap/click interaction self.down = function (x, y, obj) { if (!self.active || !self.approaching) { return; } // Check timing var currentTime = gameTime; var timeDiff = Math.abs(currentTime - self.timing); if (timeDiff <= PERFECT_TIMING) { hitNote(self, "PERFECT", 100); } else if (timeDiff <= GREAT_TIMING) { hitNote(self, "GREAT", 75); } else if (timeDiff <= GOOD_TIMING) { hitNote(self, "GOOD", 50); } else if (timeDiff <= OK_TIMING) { hitNote(self, "OK", 25); } else { // Too early or too late missNote(self); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ // Constants var PERFECT_TIMING = 100; // ms var GREAT_TIMING = 150; // ms var GOOD_TIMING = 200; // ms var OK_TIMING = 250; // ms var APPROACH_TIME = 1500; // ms var START_DELAY = 3000; // ms // Game state variables var gameTime = 0; var isPlaying = false; var currentCombo = 0; var maxCombo = 0; var perfectCount = 0; var greatCount = 0; var goodCount = 0; var okCount = 0; var missCount = 0; // Notes and patterns var notes = []; var noteLanes = [{ x: 2048 * 0.2, y: 2732 * 0.5 }, { x: 2048 * 0.4, y: 2732 * 0.4 }, { x: 2048 * 0.6, y: 2732 * 0.4 }, { x: 2048 * 0.8, y: 2732 * 0.5 }]; // UI Elements var comboText = new Text2("", { size: 120, fill: 0xFFFFFF }); comboText.anchor.set(0.5, 0.5); comboText.position.set(2048 / 2, 400); game.addChild(comboText); var scoreText = new Text2("SCORE: 0", { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(1.0, 0); scoreText.position.set(2048 - 50, 50); game.addChild(scoreText); var progressBarBackground = LK.getAsset('progressBar', { anchorX: 0.5, anchorY: 0.5, tint: 0x34495e, scaleX: 1, scaleY: 1, x: 2048 / 2, y: 100 }); game.addChild(progressBarBackground); var progressBarFill = LK.getAsset('progressBar', { anchorX: 0, anchorY: 0.5, tint: 0x9b59b6, scaleX: 0, scaleY: 1, x: (2048 - 1800) / 2, y: 100 }); game.addChild(progressBarFill); // Generate a sample beat pattern function generateBeatPattern() { var pattern = []; var songLength = 30000; // 30 seconds var beatInterval = 500; // 500ms between beats for (var time = START_DELAY; time < songLength; time += beatInterval) { // Simple pattern: alternate between lanes var lane = Math.floor(Math.random() * noteLanes.length); pattern.push({ timing: time, lane: lane }); // Occasionally add a double note if (Math.random() < 0.2) { var secondLane = (lane + 1 + Math.floor(Math.random() * (noteLanes.length - 1))) % noteLanes.length; pattern.push({ timing: time, lane: secondLane }); } } return pattern; } // Initialize game function initGame() { gameTime = 0; isPlaying = true; currentCombo = 0; maxCombo = 0; perfectCount = 0; greatCount = 0; goodCount = 0; okCount = 0; missCount = 0; // Clear previous notes for (var i = 0; i < notes.length; i++) { if (notes[i].parent) { notes[i].parent.removeChild(notes[i]); } } notes = []; // Reset score LK.setScore(0); scoreText.setText("SCORE: 0"); comboText.setText(""); progressBarFill.scaleX = 0; // Generate beat pattern var pattern = generateBeatPattern(); for (var j = 0; j < pattern.length; j++) { var noteInfo = pattern[j]; var note = new Note(noteInfo.timing, noteInfo.lane); note.position.set(noteLanes[noteInfo.lane].x, noteLanes[noteInfo.lane].y); notes.push(note); } // Start music after countdown LK.setTimeout(function () { LK.playMusic('gameMusic', { loop: false }); }, START_DELAY); } // Hit a note successfully function hitNote(note, rating, points) { if (!note.active || note.hit) { return; } note.active = false; note.hit = true; // Update combo currentCombo++; if (currentCombo > maxCombo) { maxCombo = currentCombo; } // Update stats switch (rating) { case "PERFECT": perfectCount++; break; case "GREAT": greatCount++; break; case "GOOD": goodCount++; break; case "OK": okCount++; break; } // Calculate score with combo multiplier var comboMultiplier = Math.min(4, 1 + Math.floor(currentCombo / 10) * 0.1); var finalPoints = Math.floor(points * comboMultiplier); // Update score LK.setScore(LK.getScore() + finalPoints); scoreText.setText("SCORE: " + LK.getScore()); // Update combo display comboText.setText("COMBO " + currentCombo); tween(comboText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(comboText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeIn }); } }); // Play hit sound LK.getSound('hitSound').play(); // Special effects for higher combos if (currentCombo % 10 === 0) { LK.getSound('comboSound').play(); LK.effects.flashScreen(0x9b59b6, 300); } // Create hit effect var effect = new HitEffect(rating); effect.position.set(note.x, note.y); game.addChild(effect); // Remove the note if (note.parent) { note.parent.removeChild(note); } } // Miss a note function missNote(note) { if (!note.active || note.hit) { return; } note.active = false; note.hit = true; // Reset combo currentCombo = 0; missCount++; // Play miss sound LK.getSound('missSound').play(); // Update combo display comboText.setText(""); // Create miss effect var effect = new MissEffect(); effect.position.set(note.x, note.y); game.addChild(effect); // Remove the note if (note.parent) { note.parent.removeChild(note); } } // Check for auto-miss (when a note passes without being tapped) function checkMissedNotes() { for (var i = 0; i < notes.length; i++) { var note = notes[i]; if (note.active && note.approaching && gameTime > note.timing + OK_TIMING) { missNote(note); } } } // Update progress bar function updateProgressBar() { var songLength = 30000; // 30 seconds var progress = Math.min(1, gameTime / songLength); progressBarFill.scaleX = progress; if (progress >= 1 && isPlaying) { endGame(); } } // End the game function endGame() { isPlaying = false; // Update high score if (LK.getScore() > storage.highScore) { storage.highScore = LK.getScore(); } // Update total plays storage.totalPlays = (storage.totalPlays || 0) + 1; // Show game over LK.setTimeout(function () { LK.showGameOver(); }, 1000); } // Initialize the game initGame(); // Game loop game.update = function () { if (!isPlaying) { return; } // Update game time gameTime += 1000 / 60; // Approximate ms per frame at 60fps // Update notes for (var i = 0; i < notes.length; i++) { var note = notes[i]; // Check if note should start approaching if (note.active && !note.approaching && gameTime >= note.timing - APPROACH_TIME) { note.approaching = true; game.addChild(note); // Animate note approaching tween(note, { scaleX: 1, scaleY: 1 }, { duration: APPROACH_TIME, easing: tween.linear }); } } // Check for auto-missed notes checkMissedNotes(); // Update progress bar updateProgressBar(); }; // Touch controls game.down = function (x, y, obj) { // Check if any note was directly tapped // Note: The Note class's down method will handle the hit logic }; // Handle direct taps on the game area that aren't on notes game.move = function (x, y, obj) { // Not needed for this game }; game.up = function (x, y, obj) { // Not needed for this game };
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,422 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ highScore: 0,
+ totalPlays: 0
+});
+
+/****
+* Classes
+****/
+var HitEffect = Container.expand(function (rating) {
+ var self = Container.call(this);
+ // Create effect circle
+ var effect = self.attachAsset('hitEffect', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.7
+ });
+ // Create rating text
+ var text = new Text2(rating, {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ text.anchor.set(0.5, 0.5);
+ self.addChild(text);
+ // Set initial scale
+ self.scale.set(0.8);
+ // Animate and destroy
+ tween(self, {
+ alpha: 0,
+ scaleX: 1.5,
+ scaleY: 1.5
+ }, {
+ duration: 500,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ self.destroy();
+ }
+ });
+ return self;
+});
+var MissEffect = Container.expand(function () {
+ var self = Container.call(this);
+ // Create miss effect
+ var effect = self.attachAsset('missEffect', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.7
+ });
+ // Create X text
+ var text = new Text2("MISS", {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ text.anchor.set(0.5, 0.5);
+ self.addChild(text);
+ // Set initial scale
+ self.scale.set(0.8);
+ // Animate and destroy
+ tween(self, {
+ alpha: 0,
+ scaleX: 1.5,
+ scaleY: 1.5
+ }, {
+ duration: 500,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ self.destroy();
+ }
+ });
+ return self;
+});
+var Note = Container.expand(function (timing, lane) {
+ var self = Container.call(this);
+ self.timing = timing;
+ self.lane = lane;
+ self.active = true;
+ self.hit = false;
+ self.approaching = false;
+ // Create outer ring
+ var ring = self.attachAsset('targetRing', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.7
+ });
+ // Create inner circle
+ var circle = self.attachAsset('targetCircle', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8
+ });
+ // Set initial scale for approach animation
+ self.scale.set(0.1);
+ // Define tap/click interaction
+ self.down = function (x, y, obj) {
+ if (!self.active || !self.approaching) {
+ return;
+ }
+ // Check timing
+ var currentTime = gameTime;
+ var timeDiff = Math.abs(currentTime - self.timing);
+ if (timeDiff <= PERFECT_TIMING) {
+ hitNote(self, "PERFECT", 100);
+ } else if (timeDiff <= GREAT_TIMING) {
+ hitNote(self, "GREAT", 75);
+ } else if (timeDiff <= GOOD_TIMING) {
+ hitNote(self, "GOOD", 50);
+ } else if (timeDiff <= OK_TIMING) {
+ hitNote(self, "OK", 25);
+ } else {
+ // Too early or too late
+ missNote(self);
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x2c3e50
+});
+
+/****
+* Game Code
+****/
+// Constants
+var PERFECT_TIMING = 100; // ms
+var GREAT_TIMING = 150; // ms
+var GOOD_TIMING = 200; // ms
+var OK_TIMING = 250; // ms
+var APPROACH_TIME = 1500; // ms
+var START_DELAY = 3000; // ms
+// Game state variables
+var gameTime = 0;
+var isPlaying = false;
+var currentCombo = 0;
+var maxCombo = 0;
+var perfectCount = 0;
+var greatCount = 0;
+var goodCount = 0;
+var okCount = 0;
+var missCount = 0;
+// Notes and patterns
+var notes = [];
+var noteLanes = [{
+ x: 2048 * 0.2,
+ y: 2732 * 0.5
+}, {
+ x: 2048 * 0.4,
+ y: 2732 * 0.4
+}, {
+ x: 2048 * 0.6,
+ y: 2732 * 0.4
+}, {
+ x: 2048 * 0.8,
+ y: 2732 * 0.5
+}];
+// UI Elements
+var comboText = new Text2("", {
+ size: 120,
+ fill: 0xFFFFFF
+});
+comboText.anchor.set(0.5, 0.5);
+comboText.position.set(2048 / 2, 400);
+game.addChild(comboText);
+var scoreText = new Text2("SCORE: 0", {
+ size: 80,
+ fill: 0xFFFFFF
+});
+scoreText.anchor.set(1.0, 0);
+scoreText.position.set(2048 - 50, 50);
+game.addChild(scoreText);
+var progressBarBackground = LK.getAsset('progressBar', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ tint: 0x34495e,
+ scaleX: 1,
+ scaleY: 1,
+ x: 2048 / 2,
+ y: 100
+});
+game.addChild(progressBarBackground);
+var progressBarFill = LK.getAsset('progressBar', {
+ anchorX: 0,
+ anchorY: 0.5,
+ tint: 0x9b59b6,
+ scaleX: 0,
+ scaleY: 1,
+ x: (2048 - 1800) / 2,
+ y: 100
+});
+game.addChild(progressBarFill);
+// Generate a sample beat pattern
+function generateBeatPattern() {
+ var pattern = [];
+ var songLength = 30000; // 30 seconds
+ var beatInterval = 500; // 500ms between beats
+ for (var time = START_DELAY; time < songLength; time += beatInterval) {
+ // Simple pattern: alternate between lanes
+ var lane = Math.floor(Math.random() * noteLanes.length);
+ pattern.push({
+ timing: time,
+ lane: lane
+ });
+ // Occasionally add a double note
+ if (Math.random() < 0.2) {
+ var secondLane = (lane + 1 + Math.floor(Math.random() * (noteLanes.length - 1))) % noteLanes.length;
+ pattern.push({
+ timing: time,
+ lane: secondLane
+ });
+ }
+ }
+ return pattern;
+}
+// Initialize game
+function initGame() {
+ gameTime = 0;
+ isPlaying = true;
+ currentCombo = 0;
+ maxCombo = 0;
+ perfectCount = 0;
+ greatCount = 0;
+ goodCount = 0;
+ okCount = 0;
+ missCount = 0;
+ // Clear previous notes
+ for (var i = 0; i < notes.length; i++) {
+ if (notes[i].parent) {
+ notes[i].parent.removeChild(notes[i]);
+ }
+ }
+ notes = [];
+ // Reset score
+ LK.setScore(0);
+ scoreText.setText("SCORE: 0");
+ comboText.setText("");
+ progressBarFill.scaleX = 0;
+ // Generate beat pattern
+ var pattern = generateBeatPattern();
+ for (var j = 0; j < pattern.length; j++) {
+ var noteInfo = pattern[j];
+ var note = new Note(noteInfo.timing, noteInfo.lane);
+ note.position.set(noteLanes[noteInfo.lane].x, noteLanes[noteInfo.lane].y);
+ notes.push(note);
+ }
+ // Start music after countdown
+ LK.setTimeout(function () {
+ LK.playMusic('gameMusic', {
+ loop: false
+ });
+ }, START_DELAY);
+}
+// Hit a note successfully
+function hitNote(note, rating, points) {
+ if (!note.active || note.hit) {
+ return;
+ }
+ note.active = false;
+ note.hit = true;
+ // Update combo
+ currentCombo++;
+ if (currentCombo > maxCombo) {
+ maxCombo = currentCombo;
+ }
+ // Update stats
+ switch (rating) {
+ case "PERFECT":
+ perfectCount++;
+ break;
+ case "GREAT":
+ greatCount++;
+ break;
+ case "GOOD":
+ goodCount++;
+ break;
+ case "OK":
+ okCount++;
+ break;
+ }
+ // Calculate score with combo multiplier
+ var comboMultiplier = Math.min(4, 1 + Math.floor(currentCombo / 10) * 0.1);
+ var finalPoints = Math.floor(points * comboMultiplier);
+ // Update score
+ LK.setScore(LK.getScore() + finalPoints);
+ scoreText.setText("SCORE: " + LK.getScore());
+ // Update combo display
+ comboText.setText("COMBO " + currentCombo);
+ tween(comboText, {
+ scaleX: 1.2,
+ scaleY: 1.2
+ }, {
+ duration: 100,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(comboText, {
+ scaleX: 1.0,
+ scaleY: 1.0
+ }, {
+ duration: 100,
+ easing: tween.easeIn
+ });
+ }
+ });
+ // Play hit sound
+ LK.getSound('hitSound').play();
+ // Special effects for higher combos
+ if (currentCombo % 10 === 0) {
+ LK.getSound('comboSound').play();
+ LK.effects.flashScreen(0x9b59b6, 300);
+ }
+ // Create hit effect
+ var effect = new HitEffect(rating);
+ effect.position.set(note.x, note.y);
+ game.addChild(effect);
+ // Remove the note
+ if (note.parent) {
+ note.parent.removeChild(note);
+ }
+}
+// Miss a note
+function missNote(note) {
+ if (!note.active || note.hit) {
+ return;
+ }
+ note.active = false;
+ note.hit = true;
+ // Reset combo
+ currentCombo = 0;
+ missCount++;
+ // Play miss sound
+ LK.getSound('missSound').play();
+ // Update combo display
+ comboText.setText("");
+ // Create miss effect
+ var effect = new MissEffect();
+ effect.position.set(note.x, note.y);
+ game.addChild(effect);
+ // Remove the note
+ if (note.parent) {
+ note.parent.removeChild(note);
+ }
+}
+// Check for auto-miss (when a note passes without being tapped)
+function checkMissedNotes() {
+ for (var i = 0; i < notes.length; i++) {
+ var note = notes[i];
+ if (note.active && note.approaching && gameTime > note.timing + OK_TIMING) {
+ missNote(note);
+ }
+ }
+}
+// Update progress bar
+function updateProgressBar() {
+ var songLength = 30000; // 30 seconds
+ var progress = Math.min(1, gameTime / songLength);
+ progressBarFill.scaleX = progress;
+ if (progress >= 1 && isPlaying) {
+ endGame();
+ }
+}
+// End the game
+function endGame() {
+ isPlaying = false;
+ // Update high score
+ if (LK.getScore() > storage.highScore) {
+ storage.highScore = LK.getScore();
+ }
+ // Update total plays
+ storage.totalPlays = (storage.totalPlays || 0) + 1;
+ // Show game over
+ LK.setTimeout(function () {
+ LK.showGameOver();
+ }, 1000);
+}
+// Initialize the game
+initGame();
+// Game loop
+game.update = function () {
+ if (!isPlaying) {
+ return;
+ }
+ // Update game time
+ gameTime += 1000 / 60; // Approximate ms per frame at 60fps
+ // Update notes
+ for (var i = 0; i < notes.length; i++) {
+ var note = notes[i];
+ // Check if note should start approaching
+ if (note.active && !note.approaching && gameTime >= note.timing - APPROACH_TIME) {
+ note.approaching = true;
+ game.addChild(note);
+ // Animate note approaching
+ tween(note, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: APPROACH_TIME,
+ easing: tween.linear
+ });
+ }
+ }
+ // Check for auto-missed notes
+ checkMissedNotes();
+ // Update progress bar
+ updateProgressBar();
+};
+// Touch controls
+game.down = function (x, y, obj) {
+ // Check if any note was directly tapped
+ // Note: The Note class's down method will handle the hit logic
+};
+// Handle direct taps on the game area that aren't on notes
+game.move = function (x, y, obj) {
+ // Not needed for this game
+};
+game.up = function (x, y, obj) {
+ // Not needed for this game
+};
\ No newline at end of file