User prompt
Increase the size for all of the assets in the song story showcase section after a song is selected, and positioning all of them at the centre of the screen, and all of the elements like song cover, story description and difficulty levels are within the SongStorybox asset, songCover1 for Sky Journey, songCover2 for Night Pulse and songCover3 for Sunrise Waltz
User prompt
Still didn't appear all of the elements of SongStorybox
User prompt
Songstorybox with song cover, story and difficulty buttons didn't appear after a song is selected
User prompt
Add asset SongStorybox after a song is selected, all of the song cover, song storyline and difficulty levels are within the SongStoryBox, songcover 1 for Sky Journey, songcover 2 for Night Pulse and songcover3 for Sunrise Waltz
User prompt
Add touch asset as the touch sound for all touchable buttons
User prompt
Add KaleidoscopeMusicRhythm as background music for opening screen and homepage
User prompt
All homepage elements (title and song selection cards) shifted downwards so that the title is comfortably within the background and all song selection cards are fully visible and well aligned below the title, with adequate spacing from the top and between elements
User prompt
Remove song sover at the homepage, and move all the song selection downwards so that all of them are below Select a Song title without out of the screen, all of the words of song selection are within Selector U
User prompt
Move the song selection downwards so that all of them are within the background and replace UI with selectorUI asset
User prompt
Add Sky Journey, Night Pulse and Sunrise Waltz as song selection within SelectorUI
Code edit (1 edits merged)
Please save this source code
User prompt
Make sure that Select a Song title is visible within the background of homepage
User prompt
I'm still cannot see the title, check whether its a font color problems or the positioning problems
User prompt
Still cannot see select a song after changing the code according to your advice
Code edit (4 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught TypeError: Math.floor(...) is not a function' in or related to this line: 'return t || (t = e.slice(0)), Object.freeze(Object.defineProperties(e, {' Line Number: 135
Code edit (1 edits merged)
Please save this source code
User prompt
Cannot see select a song
User prompt
Place Select a Song for homepage title at 23% of screen height, centered horizontally, and ensure it's not above y=80
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
Add Select a Song as the title of homepage
User prompt
Same errors keep on occurring
User prompt
Same errors keep on occurring
User prompt
Backgroundhomepage only can be seen 1/4 at the right corner of homepage, unlike the openingscreen that can be successfully seen in the full screen
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { language: "en" }); /**** * Classes ****/ // Note types: 'tap', 'hold', 'swipe' var Note = Container.expand(function () { var self = Container.call(this); self.type = 'tap'; // tap, hold, swipe self.lane = 0; // 0-3 self.time = 0; // ms, when the note should be hit self.duration = 0; // for hold notes, ms self.hit = false; self.active = true; self.swipeDir = null; // 'left', 'right', 'up', 'down' for swipe notes // Visuals self.noteAsset = null; self.trailAsset = null; self.init = function (type, lane, time, duration, swipeDir) { self.type = type; self.lane = lane; self.time = time; self.duration = duration || 0; self.swipeDir = swipeDir || null; self.hit = false; self.active = true; if (self.noteAsset) { self.removeChild(self.noteAsset); } if (self.trailAsset) { self.removeChild(self.trailAsset); } if (type === 'tap') { self.noteAsset = self.attachAsset('tapNote', { anchorX: 0.5, anchorY: 0.5 }); } else if (type === 'hold') { self.noteAsset = self.attachAsset('holdNote', { anchorX: 0.5, anchorY: 0.5 }); } else if (type === 'swipe') { self.noteAsset = self.attachAsset('swipeNote', { anchorX: 0.5, anchorY: 0.5 }); } }; self.flash = function () { if (self.noteAsset) { tween(self.noteAsset, { alpha: 0.2 }, { duration: 80, onFinish: function onFinish() { tween(self.noteAsset, { alpha: 1 }, { duration: 80 }); } }); } }; self.update = function () { // Position is handled by main game loop }; return self; }); // Song selection card var SongCard = Container.expand(function () { var self = Container.call(this); self.songId = ''; self.cover = null; self.init = function (songId, colorAsset) { self.songId = songId; if (self.cover) { self.removeChild(self.cover); } if (colorAsset) { self.cover = self.attachAsset(colorAsset, { anchorX: 0.5, anchorY: 0.5 }); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c20 }); /**** * Game Code ****/ // Sounds and music (placeholders, actual music not implemented here) // Example note assets: // We'll use shapes for notes, and images for backgrounds and song covers as needed. // Note: Assets are auto-initialized by LK based on usage below. // --- GLOBALS --- var _templateObject; function _taggedTemplateLiteral(e, t) { return t || (t = e.slice(0)), Object.freeze(Object.defineProperties(e, { raw: { value: Object.freeze(t) } })); } var GAME_STATE = 'LANGUAGE'; // LANGUAGE, HOME, STORY, DIFFICULTY, PLAY, RESULT var selectedLanguage = storage.language || 'en'; var selectedSong = null; var selectedDifficulty = null; var currentSongData = null; var currentNotes = []; var noteIndex = 0; var startTime = 0; var score = 0; var combo = 0; var maxCombo = 0; var accuracy = 0; var totalNotes = 0; var hitNotes = 0; var missNotes = 0; var holdActive = null; var swipeStart = null; var swipeNote = null; var isPlaying = false; var resultTimeout = null; // Lanes: 4 lanes, evenly spaced var LANE_COUNT = 4; var LANE_WIDTH = 400; var LANE_MARGIN = 40; var LANE_START_X = (2048 - (LANE_COUNT * LANE_WIDTH + (LANE_COUNT - 1) * LANE_MARGIN)) / 2; var HIT_LINE_Y = 2200; // Where notes should be hit // --- SONG DATA (MVP: 3 songs, 3 difficulties, simple patterns) --- var SONGS = [{ id: 'sky_journey', title: 'Sky Journey', cover: 'songCover1', story: { en: "You soar above the clouds, chasing the horizon. The sky is endless, and your journey has just begun.", zh: "你在云端翱翔,追逐地平线。天空无垠,你的旅程才刚刚开始。" }, difficulties: ['Easy', 'Medium', 'Hard'], notes: { Easy: [ // [type, lane, time(ms), duration(ms), swipeDir] ['tap', 0, 1000], ['tap', 1, 1800], ['tap', 2, 2600], ['tap', 3, 3400], ['hold', 1, 4200, 1200], ['tap', 0, 6000], ['swipe', 2, 7000, 0, 'right'], ['tap', 3, 8000]], Medium: [['tap', 0, 800], ['tap', 1, 1400], ['tap', 2, 2000], ['tap', 3, 2600], ['hold', 0, 3200, 1000], ['tap', 1, 4400], ['swipe', 2, 5200, 0, 'left'], ['tap', 3, 6000], ['tap', 2, 6600], ['hold', 1, 7200, 1200], ['tap', 0, 9000]], Hard: [['tap', 0, 600], ['tap', 1, 1000], ['tap', 2, 1400], ['tap', 3, 1800], ['hold', 0, 2200, 1000], ['tap', 1, 3400], ['swipe', 2, 3800, 0, 'up'], ['tap', 3, 4200], ['tap', 2, 4600], ['hold', 1, 5000, 1200], ['tap', 0, 6400], ['swipe', 3, 7000, 0, 'down'], ['tap', 1, 7600], ['tap', 2, 8200], ['tap', 3, 8800]] } }, { id: 'night_pulse', title: 'Night Pulse', cover: 'songCover2', story: { en: "The city lights flicker in rhythm with your heartbeat. Tonight, the music guides your every move.", zh: "城市的灯光随着你的心跳闪烁。今夜,音乐引领你的每一步。" }, difficulties: ['Easy', 'Medium', 'Hard'], notes: { Easy: [['tap', 2, 1000], ['tap', 1, 1800], ['hold', 0, 2600, 1000], ['tap', 3, 4000], ['swipe', 2, 5000, 0, 'left'], ['tap', 1, 6000]], Medium: [['tap', 2, 800], ['tap', 1, 1400], ['hold', 0, 2000, 1000], ['tap', 3, 3200], ['swipe', 2, 4000, 0, 'right'], ['tap', 1, 4800], ['tap', 0, 5400], ['hold', 3, 6000, 1200]], Hard: [['tap', 2, 600], ['tap', 1, 1000], ['hold', 0, 1400, 1000], ['tap', 3, 2600], ['swipe', 2, 3200, 0, 'up'], ['tap', 1, 3800], ['tap', 0, 4200], ['hold', 3, 4600, 1200], ['tap', 2, 6000], ['swipe', 1, 6600, 0, 'down']] } }, { id: 'sunrise_waltz', title: 'Sunrise Waltz', cover: 'songCover3', story: { en: "As dawn breaks, melodies dance in the golden light. Every note is a step in your waltz with the sun.", zh: "黎明破晓,旋律在金色的光芒中舞动。每一个音符都是你与太阳华尔兹的步伐。" }, difficulties: ['Easy', 'Medium', 'Hard'], notes: { Easy: [['tap', 1, 1000], ['tap', 2, 1800], ['hold', 3, 2600, 1000], ['tap', 0, 4000], ['swipe', 1, 5000, 0, 'up'], ['tap', 2, 6000]], Medium: [['tap', 1, 800], ['tap', 2, 1400], ['hold', 3, 2000, 1000], ['tap', 0, 3200], ['swipe', 1, 4000, 0, 'down'], ['tap', 2, 4800], ['tap', 3, 5400], ['hold', 0, 6000, 1200]], Hard: [['tap', 1, 600], ['tap', 2, 1000], ['hold', 3, 1400, 1000], ['tap', 0, 2600], ['swipe', 1, 3200, 0, 'left'], ['tap', 2, 3800], ['tap', 3, 4200], ['hold', 0, 4600, 1200], ['tap', 1, 6000], ['swipe', 2, 6600, 0, 'right']] } }]; // --- GUI ELEMENTS --- var gui = LK.gui; var languageButtons = []; var startButton = null; var songCards = []; var storyText = null; var continueButton = null; var difficultyButtons = []; var scoreText = null; var comboText = null; var accuracyText = null; var resultText = null; var homeButton = null; // --- GAME ELEMENTS --- var lanes = []; var laneDividers = []; var hitLine = null; // --- UTILS --- function clearGUI() { // Remove all children from gui overlays, but only if they exist if (gui.top && gui.top.removeChildren) { gui.top.removeChildren(); } if (gui.topRight && gui.topRight.removeChildren) { gui.topRight.removeChildren(); } if (gui.topLeft && gui.topLeft.removeChildren) { gui.topLeft.removeChildren(); } if (gui.left && gui.left.removeChildren) { gui.left.removeChildren(); } if (gui.right && gui.right.removeChildren) { gui.right.removeChildren(); } if (gui.bottom && gui.bottom.removeChildren) { gui.bottom.removeChildren(); } if (gui.bottomLeft && gui.bottomLeft.removeChildren) { gui.bottomLeft.removeChildren(); } if (gui.bottomRight && gui.bottomRight.removeChildren) { gui.bottomRight.removeChildren(); } if (gui.center && gui.center.removeChildren) { gui.center.removeChildren(); } // Reset GUI-related global state languageButtons = []; startButton = null; songCards = []; storyText = null; continueButton = null; difficultyButtons = []; scoreText = null; comboText = null; accuracyText = null; resultText = null; homeButton = null; } function clearGameObjects() { // Remove all notes, lanes, etc. for (var i = 0; i < lanes.length; ++i) { if (lanes[i] && lanes[i].parent) { lanes[i].parent.removeChild(lanes[i]); } } for (var i = 0; i < laneDividers.length; ++i) { if (laneDividers[i] && laneDividers[i].parent) { laneDividers[i].parent.removeChild(laneDividers[i]); } } if (hitLine && hitLine.parent) { hitLine.parent.removeChild(hitLine); } for (var i = 0; i < currentNotes.length; ++i) { if (currentNotes[i] && currentNotes[i].parent) { currentNotes[i].parent.removeChild(currentNotes[i]); } } lanes = []; laneDividers = []; hitLine = null; currentNotes = []; noteIndex = 0; holdActive = null; swipeStart = null; swipeNote = null; isPlaying = false; } function setGameState(state) { GAME_STATE = state; clearGUI(); clearGameObjects(); // Reset global state for each screen dragLane = null; dragY = null; dragNote = null; dragStartX = null; dragStartY = null; dragStartTime = null; if (state === 'LANGUAGE') { showLanguageSelector(); } else if (state === 'HOME') { selectedSong = null; selectedDifficulty = null; showHome(); } else if (state === 'STORY') { showStory(); } else if (state === 'DIFFICULTY') { showDifficulty(); } else if (state === 'PLAY') { startGameplay(); } else if (state === 'RESULT') { showResult(); } } // --- LANGUAGE SELECTOR --- function showLanguageSelector() { languageButtons = []; // Get current screen size from LK var screenWidth = LK.width || 2048; var screenHeight = LK.height || 2732; // Create opening screen container (with background) var openingScreen = new Container(); // Add background asset, centered var bgAsset = LK.getAsset('Openingscreen', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); openingScreen.addChild(bgAsset); // Add three SelectorUI assets as backgrounds for English, 中文, and play button // Calculate button positions and sizes to fit text var langBtnYStart = Math.floor(screenHeight * 0.45) - screenHeight / 2; var langBtnSpacing = Math.floor(screenHeight * 0.08); // English SelectorUI var selectorBgEn = LK.getAsset('SelectorUI', { anchorX: 0.5, anchorY: 0.5, x: 0, y: langBtnYStart, scaleX: 3.2, scaleY: 1.3 }); openingScreen.addChild(selectorBgEn); // 中文 SelectorUI var selectorBgZh = LK.getAsset('SelectorUI', { anchorX: 0.5, anchorY: 0.5, x: 0, y: langBtnYStart + langBtnSpacing, scaleX: 2.2, scaleY: 1.3 }); openingScreen.addChild(selectorBgZh); // Play button SelectorUI var playBtnY = Math.floor(screenHeight * 0.70) - screenHeight / 2; var selectorBgPlay = LK.getAsset('SelectorUI', { anchorX: 0.5, anchorY: 0.5, x: 0, y: playBtnY, scaleX: 3.2, scaleY: 1.5 }); openingScreen.addChild(selectorBgPlay); // Center all elements inside the openingScreen container // Title var titleText = new Text2("Kaleidoscope of Music Rhythm", { size: 80, fill: "#fff" }); titleText.anchor.set(0.5, 0.5); // Place title at 23% of screen height, centered horizontally, and ensure it's not above y=80 titleText.x = 0; titleText.y = Math.max(80 - screenHeight / 2, Math.floor(screenHeight * 0.23) - screenHeight / 2); openingScreen.addChild(titleText); // Language selector var langs = [{ code: 'en', label: 'English' }, { code: 'zh', label: '中文' }]; // Place language buttons at 45% and 53% of screen height, centered horizontally var langBtnYStart = Math.floor(screenHeight * 0.45) - screenHeight / 2; var langBtnSpacing = Math.floor(screenHeight * 0.08); for (var i = 0; i < langs.length; ++i) { (function (idx) { var btn = new Text2(langs[idx].label, { size: 64, fill: "#fff" }); btn.anchor.set(0.5, 0.5); btn.x = 0; // centered in container btn.y = langBtnYStart + idx * langBtnSpacing; btn.interactive = true; btn.down = function (x, y, obj) { LK.getSound('Touch').play(); selectedLanguage = langs[idx].code; storage.language = selectedLanguage; // Do not advance to HOME yet, just set language clearGUI(); showLanguageSelector(); }; openingScreen.addChild(btn); languageButtons.push(btn); })(i); } // Start button startButton = new Text2(selectedLanguage === 'zh' ? "开始" : "Start", { size: 90, fill: "#fff" }); startButton.anchor.set(0.5, 0.5); // Place start button at 70% of screen height, centered horizontally startButton.x = 0; startButton.y = Math.floor(screenHeight * 0.70) - screenHeight / 2; startButton.interactive = true; startButton.down = function (x, y, obj) { LK.getSound('Touch').play(); setGameState('HOME'); }; openingScreen.addChild(startButton); // Add the opening screen container to gui.center gui.center.addChild(openingScreen); // Play background music for opening screen LK.playMusic('KaleidoscopeMusicRhythm'); } // --- HOME / SONG SELECTION --- function showHome() { clearGUI(); clearGameObjects(); songCards = []; var screenWidth = LK.width || 2048; var screenHeight = LK.height || 2732; // Create homeScreen container before adding children var homeScreen = new Container(); // Add Backgroundhomepage asset as background, fully fit to screen var bgAsset = LK.getAsset('Backgroundhomepage', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0, scaleX: screenWidth / 2048, scaleY: screenHeight / 2732 }); homeScreen.addChild(bgAsset); bgAsset.width = screenWidth; bgAsset.height = screenHeight; // Title: "Select a Song", in white with proper positioning var title = new Text2(selectedLanguage === 'zh' ? "选择歌曲" : "Select a Song", { size: 90, fill: "#fff", // White text for contrast font: "Arial Black" }); title.anchor.set(0.5, 0); // Place title at 15% of screen height, centered horizontally, and ensure it's not above y=120 // For gui.center containers, (0,0) is the center, so offset from center title.x = 0; title.y = -screenHeight / 2 + Math.max(120, Math.floor(screenHeight * 0.15)); homeScreen.addChild(title); // Card layout - vertical stacking with proper spacing var cardCount = SONGS.length; var cardHeight = 200; var cardSpacing = 80; var titleSpacing = 100; // Place the title at 15% of screen height, and cards start at 25% of screen height // We want all cards to be below the title and fully within SelectorUI // Calculate the starting Y so that the first card is just below the title, and all cards fit on screen var cardsStartY = title.y + title.height + titleSpacing; // 100px gap below title for (var i = 0; i < SONGS.length; i++) { (function (index) { var song = SONGS[index]; // Card Y position var cardY = cardsStartY + index * (cardHeight + cardSpacing); // Create SelectorUI background for song card var cardBg = LK.getAsset('SelectorUI', { anchorX: 0.5, anchorY: 0.5, x: 0, y: cardY, scaleX: 4.0, scaleY: 2.0 }); homeScreen.addChild(cardBg); // Make card interactive cardBg.interactive = true; cardBg.down = function (x, y, obj) { LK.getSound('Touch').play(); selectedSong = song; setGameState('STORY'); }; // Add song title (centered within SelectorUI) var songNameText = new Text2(song.title, { size: 64, fill: "#fff", font: "Arial" }); songNameText.anchor.set(0.5, 0.5); songNameText.x = 0; songNameText.y = cardY - 30; homeScreen.addChild(songNameText); // Add subtitle (optional: show "Sky Journey", "Night Pulse", "Sunrise Waltz") var subtitleText = new Text2(selectedLanguage === 'zh' && song.title === "Sky Journey" ? "天空之旅" : selectedLanguage === 'zh' && song.title === "Night Pulse" ? "夜之律动" : selectedLanguage === 'zh' && song.title === "Sunrise Waltz" ? "日出圆舞曲" : "", { size: 40, fill: 0xE0E0E0, font: "Arial" }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 0; subtitleText.y = cardY + 30; homeScreen.addChild(subtitleText); songCards.push(cardBg); })(i); } // Add homeScreen to GUI, centered homeScreen.x = 0; homeScreen.y = 0; if (gui.center && gui.center.addChild) { gui.center.addChild(homeScreen); } // Play background music for homepage LK.playMusic('KaleidoscopeMusicRhythm'); } // --- STORY INTRO --- function showStory() { clearGUI(); var story = selectedSong.story[selectedLanguage] || selectedSong.story['en']; var screenWidth = LK.width || 2048; var screenHeight = LK.height || 2732; // Create SongStorybox container var storyBox = new Container(); // Add SongStorybox asset as background, centered and scaled up for showcase var boxAsset = LK.getAsset('SongStorybox', { anchorX: 0.5, anchorY: 0.5, x: screenWidth / 2, y: screenHeight / 2, scaleX: 13, // Increased for larger showcase scaleY: 11 }); storyBox.addChild(boxAsset); // Calculate box bounds for layout var boxW = boxAsset.width * boxAsset.scaleX; var boxH = boxAsset.height * boxAsset.scaleY; var boxCenterX = screenWidth / 2; var boxTopY = screenHeight / 2 - boxH / 2; // Add song cover image, centered horizontally, near top of box, scaled up var coverAsset = LK.getAsset(selectedSong.cover, { anchorX: 0.5, anchorY: 0, x: boxCenterX, y: boxTopY + boxH * 0.07, // 7% from top of box scaleX: 2.2, // Larger cover scaleY: 2.2 }); storyBox.addChild(coverAsset); // Add story text, centered, below cover, larger and with more width storyText = new Text2(story, { size: 70, fill: "#fff", wordWrap: true, wordWrapWidth: boxW - 320 // More margin for large box }); storyText.anchor.set(0.5, 0); storyText.x = boxCenterX; storyText.y = coverAsset.y + coverAsset.height * coverAsset.scaleY + 60; storyBox.addChild(storyText); // Add difficulty buttons, spaced below story text, all inside the box, larger and centered var diffYStart = storyText.y + storyText.height + 120; var diffSpacing = 180; difficultyButtons = []; for (var i = 0; i < selectedSong.difficulties.length; ++i) { (function (idx) { var label = selectedSong.difficulties[idx]; var btn = new Text2(label, { size: 130, fill: "#fff" }); btn.anchor.set(0.5, 0.5); btn.x = boxCenterX; btn.y = diffYStart + idx * diffSpacing; btn.interactive = true; btn.down = function (x, y, obj) { LK.getSound('Touch').play(); selectedDifficulty = label; setGameState('PLAY'); }; storyBox.addChild(btn); difficultyButtons.push(btn); })(i); } // Add storyBox to gui.center, centered on screen storyBox.x = 0; storyBox.y = 0; gui.center.addChild(storyBox); } // --- DIFFICULTY SELECT --- function showDifficulty() { difficultyButtons = []; var screenWidth = LK.width || 2048; var screenHeight = LK.height || 2732; var title = new Text2(selectedLanguage === 'zh' ? "选择难度" : "Select Difficulty", { size: 100, fill: "#fff" }); title.anchor.set(0.5, 0); title.x = screenWidth / 2; title.y = Math.max(100, Math.floor(screenHeight * 0.08)); gui.top.addChild(title); var btnYStart = Math.floor(screenHeight * 0.40); var btnSpacing = Math.floor(screenHeight * 0.13); for (var i = 0; i < selectedSong.difficulties.length; ++i) { (function (idx) { var label = selectedSong.difficulties[idx]; var btn = new Text2(label, { size: 90, fill: "#fff" }); btn.anchor.set(0.5, 0.5); btn.x = screenWidth / 2; btn.y = btnYStart + idx * btnSpacing; btn.interactive = true; btn.down = function (x, y, obj) { LK.getSound('Touch').play(); selectedDifficulty = label; setGameState('PLAY'); }; gui.center.addChild(btn); difficultyButtons.push(btn); })(i); } } // --- GAMEPLAY --- function startGameplay() { // Setup lanes lanes = []; laneDividers = []; for (var i = 0; i < LANE_COUNT; ++i) { var lane = LK.getAsset('lane', { anchorX: 0, anchorY: 0 }); lane.x = LANE_START_X + i * (LANE_WIDTH + LANE_MARGIN); lane.y = 0; lanes.push(lane); game.addChild(lane); if (i > 0) { var divider = LK.getAsset('laneDivider', { anchorX: 0, anchorY: 0 }); divider.x = LANE_START_X + i * (LANE_WIDTH + LANE_MARGIN) - LANE_MARGIN / 2 - 10; divider.y = 0; laneDividers.push(divider); game.addChild(divider); } } // Hit line hitLine = LK.getAsset('laneDivider', { anchorX: 0, anchorY: 0 }); hitLine.width = 2048; hitLine.height = 16; hitLine.x = 0; hitLine.y = HIT_LINE_Y; game.addChild(hitLine); // Load notes currentSongData = selectedSong.notes[selectedDifficulty]; currentNotes = []; noteIndex = 0; score = 0; combo = 0; maxCombo = 0; accuracy = 0; totalNotes = currentSongData.length; hitNotes = 0; missNotes = 0; holdActive = null; swipeStart = null; swipeNote = null; isPlaying = true; for (var i = 0; i < currentSongData.length; ++i) { var n = currentSongData[i]; var note = new Note(); note.init(n[0], n[1], n[2], n[3], n[4]); // Initial position: y far above screen, will be updated in update loop note.x = LANE_START_X + n[1] * (LANE_WIDTH + LANE_MARGIN) + LANE_WIDTH / 2; note.y = -200; currentNotes.push(note); game.addChild(note); } // Score/Combo/Accuracy GUI scoreText = new Text2("Score: 0", { size: 80, fill: "#fff" }); scoreText.anchor.set(0, 0); gui.topRight.addChild(scoreText); comboText = new Text2("Combo: 0", { size: 80, fill: "#fff" }); comboText.anchor.set(0, 0); gui.topRight.addChild(comboText); accuracyText = new Text2("Accuracy: 100%", { size: 80, fill: "#fff" }); accuracyText.anchor.set(0, 0); gui.topRight.addChild(accuracyText); // Start music LK.playMusic(selectedSong.id); // Start timer startTime = Date.now(); } // --- GAMEPLAY LOGIC --- function getCurrentTime() { return Date.now() - startTime; } function getNoteY(noteTime) { // Notes fall from y = -200 to HIT_LINE_Y at the time they should be hit // We'll use a fixed speed so that notes reach HIT_LINE_Y at noteTime var speed = (HIT_LINE_Y + 200) / 2000; // 2 seconds to fall var t = getCurrentTime(); var dt = noteTime - t; return HIT_LINE_Y - dt * speed; } function getHoldTrailLength(note, t) { // For hold notes, trail from note head to end time var endTime = note.time + note.duration; var y1 = getNoteY(note.time); var y2 = getNoteY(endTime); return Math.max(0, y2 - y1); } function judgeNote(note, lane, y, eventType, swipeDir) { if (!note.active || note.hit) { return false; } var noteY = getNoteY(note.time); var hitWindow = 120; // ms var t = getCurrentTime(); var dt = Math.abs(note.time - t); if (note.type === 'tap') { if (lane === note.lane && Math.abs(y - HIT_LINE_Y) < 180 && dt < hitWindow) { note.hit = true; note.active = false; note.flash(); LK.getSound('tap').play(); score += 100; combo += 1; hitNotes += 1; maxCombo = Math.max(combo, maxCombo); return true; } } else if (note.type === 'hold') { if (eventType === 'down' && lane === note.lane && Math.abs(y - HIT_LINE_Y) < 180 && dt < hitWindow) { holdActive = { note: note, start: t }; note.flash(); LK.getSound('hold').play(); return true; } } else if (note.type === 'swipe') { if (eventType === 'swipe' && lane === note.lane && Math.abs(y - HIT_LINE_Y) < 180 && dt < hitWindow && swipeDir === note.swipeDir) { note.hit = true; note.active = false; note.flash(); LK.getSound('swipe').play(); score += 150; combo += 1; hitNotes += 1; maxCombo = Math.max(combo, maxCombo); return true; } } return false; } function endHold() { if (holdActive && holdActive.note && !holdActive.note.hit) { var t = getCurrentTime(); var note = holdActive.note; var holdEnd = note.time + note.duration; if (t >= holdEnd - 150) { note.hit = true; note.active = false; score += 200; combo += 1; hitNotes += 1; maxCombo = Math.max(combo, maxCombo); } else { combo = 0; missNotes += 1; } holdActive = null; } } // --- INPUT HANDLING --- var dragLane = null; var dragY = null; var dragNote = null; var dragStartX = null; var dragStartY = null; var dragStartTime = null; function getLaneFromX(x) { for (var i = 0; i < LANE_COUNT; ++i) { var lx = LANE_START_X + i * (LANE_WIDTH + LANE_MARGIN); if (x >= lx && x < lx + LANE_WIDTH) { return i; } } return -1; } function handleGameDown(x, y, obj) { if (GAME_STATE !== 'PLAY' || !isPlaying) { return; } var lane = getLaneFromX(x); if (lane === -1) { return; } dragLane = lane; dragY = y; dragStartX = x; dragStartY = y; dragStartTime = Date.now(); // Check for tap/hold notes for (var i = 0; i < currentNotes.length; ++i) { var note = currentNotes[i]; if (!note.active || note.hit) { continue; } if (note.type === 'tap' || note.type === 'hold') { if (judgeNote(note, lane, y, 'down')) { if (note.type === 'tap') { note.hit = true; note.active = false; } if (note.type === 'hold') { dragNote = note; } break; } } } } function handleGameUp(x, y, obj) { if (GAME_STATE !== 'PLAY' || !isPlaying) { return; } if (holdActive) { endHold(); } dragLane = null; dragNote = null; dragStartX = null; dragStartY = null; dragStartTime = null; } function handleGameMove(x, y, obj) { if (GAME_STATE !== 'PLAY' || !isPlaying) { return; } // For hold notes, check if finger is still on lane if (holdActive && dragNote) { var lane = getLaneFromX(x); if (lane !== dragNote.lane || Math.abs(y - HIT_LINE_Y) > 300) { // Released too early combo = 0; missNotes += 1; holdActive = null; dragNote = null; } } } function handleGameSwipe(x, y, obj) { if (GAME_STATE !== 'PLAY' || !isPlaying) { return; } if (dragStartX === null || dragStartY === null) { return; } var dx = x - dragStartX; var dy = y - dragStartY; var absDx = Math.abs(dx); var absDy = Math.abs(dy); if (absDx < 80 && absDy < 80) { return; } // Not enough movement var dir = null; if (absDx > absDy) { dir = dx > 0 ? 'right' : 'left'; } else { dir = dy > 0 ? 'down' : 'up'; } var lane = getLaneFromX(dragStartX); for (var i = 0; i < currentNotes.length; ++i) { var note = currentNotes[i]; if (!note.active || note.hit) { continue; } if (note.type === 'swipe') { if (judgeNote(note, lane, dragStartY, 'swipe', dir)) { break; } } } dragStartX = null; dragStartY = null; } // Attach input handlers game.down = function (x, y, obj) { handleGameDown(x, y, obj); }; game.up = function (x, y, obj) { handleGameUp(x, y, obj); }; game.move = function (x, y, obj) { handleGameMove(x, y, obj); // Detect swipe if (dragStartX !== null && dragStartY !== null) { var dx = x - dragStartX; var dy = y - dragStartY; if (Math.abs(dx) > 120 || Math.abs(dy) > 120) { handleGameSwipe(x, y, obj); } } }; // --- GAME UPDATE LOOP --- game.update = function () { if (GAME_STATE !== 'PLAY' || !isPlaying) { return; } var t = getCurrentTime(); // Update notes for (var i = 0; i < currentNotes.length; ++i) { var note = currentNotes[i]; if (!note.active) { continue; } // Update position note.x = LANE_START_X + note.lane * (LANE_WIDTH + LANE_MARGIN) + LANE_WIDTH / 2; note.y = getNoteY(note.time); // Missed note if (!note.hit && t - note.time > 200 && note.type !== 'hold') { note.active = false; combo = 0; missNotes += 1; } // For hold notes, if not held until end if (note.type === 'hold' && !note.hit && t - (note.time + note.duration) > 200) { note.active = false; combo = 0; missNotes += 1; } } // Remove notes that are far below screen for (var i = currentNotes.length - 1; i >= 0; --i) { var note = currentNotes[i]; if (note.y > 3000 || !note.active && note.y > HIT_LINE_Y + 400) { if (note.parent) { note.parent.removeChild(note); } currentNotes.splice(i, 1); } } // Update GUI scoreText.setText("Score: " + score); comboText.setText("Combo: " + combo); var acc = totalNotes > 0 ? Math.floor(100 * hitNotes / totalNotes) : 100; accuracyText.setText("Accuracy: " + acc + "%"); // End of song if (t > getSongEndTime() + 1000 && isPlaying) { isPlaying = false; LK.stopMusic(); resultTimeout = LK.setTimeout(function () { setGameState('RESULT'); }, 1200); } }; function getSongEndTime() { var last = currentSongData[currentSongData.length - 1]; if (!last) { return 0; } if (last[0] === 'hold') { return last[2] + last[3]; } return last[2] + 1000; } // --- RESULT SCREEN --- function showResult() { clearGameObjects(); var acc = totalNotes > 0 ? Math.floor(100 * hitNotes / totalNotes) : 100; var resultStr = (selectedLanguage === 'zh' ? "结果" : "Result") + "\n"; resultStr += (selectedLanguage === 'zh' ? "分数: " : "Score: ") + score + "\n"; resultStr += (selectedLanguage === 'zh' ? "最大连击: " : "Max Combo: ") + maxCombo + "\n"; resultStr += (selectedLanguage === 'zh' ? "准确率: " : "Accuracy: ") + acc + "%\n"; resultStr += (selectedLanguage === 'zh' ? "命中: " : "Hit: ") + hitNotes + "/" + totalNotes + "\n"; resultStr += (selectedLanguage === 'zh' ? "未命中: " : "Miss: ") + missNotes; resultText = new Text2(resultStr, { size: 90, fill: "#fff", align: "center" }); var screenWidth = LK.width || 2048; var screenHeight = LK.height || 2732; resultText.anchor.set(0.5, 0.5); resultText.x = screenWidth / 2; resultText.y = Math.floor(screenHeight * 0.36); gui.center.addChild(resultText); homeButton = new Text2(selectedLanguage === 'zh' ? "返回首页" : "Home", { size: 100, fill: "#fff" }); homeButton.anchor.set(0.5, 0.5); homeButton.x = screenWidth / 2; homeButton.y = Math.floor(screenHeight * 0.66); homeButton.interactive = true; homeButton.down = function (x, y, obj) { LK.getSound('Touch').play(); setGameState('HOME'); }; gui.center.addChild(homeButton); } // --- START GAME --- // Start at language selector (opening screen) setGameState('LANGUAGE');
===================================================================
--- original.js
+++ change.js
@@ -525,53 +525,56 @@
var screenWidth = LK.width || 2048;
var screenHeight = LK.height || 2732;
// Create SongStorybox container
var storyBox = new Container();
- // Add SongStorybox asset as background, centered and scaled
+ // Add SongStorybox asset as background, centered and scaled up for showcase
var boxAsset = LK.getAsset('SongStorybox', {
anchorX: 0.5,
anchorY: 0.5,
x: screenWidth / 2,
y: screenHeight / 2,
- scaleX: 8.5,
- scaleY: 7.5
+ scaleX: 13,
+ // Increased for larger showcase
+ scaleY: 11
});
storyBox.addChild(boxAsset);
// Calculate box bounds for layout
var boxW = boxAsset.width * boxAsset.scaleX;
var boxH = boxAsset.height * boxAsset.scaleY;
var boxCenterX = screenWidth / 2;
var boxTopY = screenHeight / 2 - boxH / 2;
- // Add song cover image, centered horizontally, near top of box
+ // Add song cover image, centered horizontally, near top of box, scaled up
var coverAsset = LK.getAsset(selectedSong.cover, {
anchorX: 0.5,
anchorY: 0,
x: boxCenterX,
- y: boxTopY + 60,
- scaleX: 1.2,
- scaleY: 1.2
+ y: boxTopY + boxH * 0.07,
+ // 7% from top of box
+ scaleX: 2.2,
+ // Larger cover
+ scaleY: 2.2
});
storyBox.addChild(coverAsset);
- // Add story text, centered, below cover
+ // Add story text, centered, below cover, larger and with more width
storyText = new Text2(story, {
- size: 54,
+ size: 70,
fill: "#fff",
wordWrap: true,
- wordWrapWidth: boxW - 160
+ wordWrapWidth: boxW - 320 // More margin for large box
});
storyText.anchor.set(0.5, 0);
storyText.x = boxCenterX;
- storyText.y = coverAsset.y + coverAsset.height * coverAsset.scaleY + 40;
+ storyText.y = coverAsset.y + coverAsset.height * coverAsset.scaleY + 60;
storyBox.addChild(storyText);
- // Add difficulty buttons, spaced below story text, all inside the box
- var diffYStart = storyText.y + storyText.height + 80;
- var diffSpacing = 120;
+ // Add difficulty buttons, spaced below story text, all inside the box, larger and centered
+ var diffYStart = storyText.y + storyText.height + 120;
+ var diffSpacing = 180;
difficultyButtons = [];
for (var i = 0; i < selectedSong.difficulties.length; ++i) {
(function (idx) {
var label = selectedSong.difficulties[idx];
var btn = new Text2(label, {
- size: 90,
+ size: 130,
fill: "#fff"
});
btn.anchor.set(0.5, 0.5);
btn.x = boxCenterX;
@@ -585,9 +588,11 @@
storyBox.addChild(btn);
difficultyButtons.push(btn);
})(i);
}
- // Add storyBox to gui.center
+ // Add storyBox to gui.center, centered on screen
+ storyBox.x = 0;
+ storyBox.y = 0;
gui.center.addChild(storyBox);
}
// --- DIFFICULTY SELECT ---
function showDifficulty() {
Game design for Kaleidoscope of Music Rhythm without game title, just the design for opening screen background. In-Game asset. 2d. High contrast. No shadows
Cyberpunk style design empty selector UI. In-Game asset. 2d. High contrast. No shadows
Cyberpunk style hold note for music rhythm game. In-Game asset. 2d. High contrast. No shadows
Cyberpunk style swipe note for music rhythm game. In-Game asset. 2d. High contrast. No shadows
Cyberpunk style tap note for music rhythm game. In-Game asset. 2d. High contrast. No shadows
Cyberpunk style kaleidoscope pattern design for homepage. In-Game asset. 2d. High contrast. No shadows
Cyberpunk style lane divider for music rhythm game that is horizontal and used for judging the touching of rhythm In-Game asset. 2d. High contrast. No shadows
Empty cyberpunk style storybox design in which it's size enable song cover, difficulty level and song description to be added in the storybox. In-Game asset. 2d. High contrast. No shadows
Round shape of song cover of anime style with Sky Journey theme. In-Game asset. 2d. High contrast. No shadows
Round shape song cover of cyberpunk anime style with the themed “Night Pulse”. In-Game asset. 2d. High contrast. No shadows
Round shape of anime style song cover with the themed Sunrise Waltz. In-Game asset. 2d. High contrast. No shadows
Anime style design for the round shape song cover of New Era Malay Style
Round shape, Replace Chinese word from “不知途”to“莫问前程”,others remaining the same
Empty cyberpunk style menu design. In-Game asset. 2d. High contrast. No shadows
Cyberpunk style pause symbol. In-Game asset. 2d. High contrast. No shadows
Cyberpunk style return symbol. In-Game asset. 2d. High contrast. No shadows