User prompt
the player not changing for other colors like yellow,blue,pink,orange,purple,green!
User prompt
Add the 7 colors to the player list of changing colors to change to it.
User prompt
change the player color to the first respawning color and when i match it change to the next respawned color so on..
User prompt
change the colors auto not by click
User prompt
the player didn't change same like the blocks colors!
User prompt
if the respawning color is blue change player to blue if green change to green etc..
User prompt
change the player colors to the respawning colors not just red!
User prompt
change to next color when i match
User prompt
change the player to the respawning colors
User prompt
the cube must change randomly to the close color cube automatique
User prompt
Please fix the bug: 'Uncaught TypeError: playerCharacter.containsPoint is not a function' in or related to this line: 'if (playerCharacter.containsPoint(playerCharacter.toLocal({' Line Number: 154
User prompt
let the player can follow the cursor left and right at the same time.
User prompt
Please fix the bug: 'Uncaught TypeError: LK.Point is not a constructor' in or related to this line: 'if (playerCharacter.containsPoint(playerCharacter.toLocal(new LK.Point(x, y)))) {' Line Number: 154
User prompt
Please fix the bug: 'Uncaught TypeError: Point is not a constructor' in or related to this line: 'if (playerCharacter.containsPoint(playerCharacter.toLocal(new Point(x, y)))) {' Line Number: 154
User prompt
Please fix the bug: 'Uncaught TypeError: LK.Point is not a constructor' in or related to this line: 'if (playerCharacter.containsPoint(playerCharacter.toLocal(new LK.Point(x, y)))) {' Line Number: 154
User prompt
the player must go to the left and right to match the colors
Code edit (1 edits merged)
Please save this source code
User prompt
Chromatic Cadence
Initial prompt
Make a terrain of 7 colors each one have different sound they come from the top going to the bottom and the player change to the 7 colors same as the music and must collect the sound terrain in time to do the perfect music.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var PlayerCharacter = Container.expand(function () { var self = Container.call(this); var characterGraphics = self.attachAsset('playerCharacter', { anchorX: 0.5, anchorY: 0.5 }); // Set brown transparent color characterGraphics.alpha = 0.7; return self; }); //Storage library which should be used for persistent game data // var storage = LK.import('@upit/storage.v1'); //Library for using the camera (the background becomes the user's camera video feed) and the microphone. It can access face coordinates for interactive play, as well detect microphone volume / voice interactions // var facekit = LK.import('@upit/facekit.v1'); //Classes can only be defined here. You cannot create inline classes in the games code. var TerrainBlock = Container.expand(function (color, speed, noteId) { var self = Container.call(this); self.color = color; self.speed = speed; self.noteId = noteId; var blockGraphics = self.attachAsset('terrainBlock' + self.color, { anchorX: 0.5, anchorY: 0.5 }); // Create vertical line extending from block self.line = new Container(); // Get color hex value from colorMap var lineColor = 0xFFFFFF; // Default white if (color === 'Red') { lineColor = 0xFF0000; } else if (color === 'Orange') { lineColor = 0xFFA500; } else if (color === 'Yellow') { lineColor = 0xFFFF00; } else if (color === 'Green') { lineColor = 0x008000; } else if (color === 'Blue') { lineColor = 0x0000FF; } else if (color === 'Indigo') { lineColor = 0x4B0082; } else if (color === 'Violet') { lineColor = 0xEE82EE; } // Create thin vertical line shape var lineGraphics = LK.getAsset('line' + self.color, { width: 50, height: 500, // Shorter line color: lineColor, shape: 'box', anchorX: 0.5, anchorY: 1 }); self.line.addChild(lineGraphics); self.addChild(self.line); self.update = function () { self.y += self.speed; // Keep line positioned at block center extending upward if (self.line) { self.line.x = 0; self.line.y = 0; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 //Init game with black background }); /**** * Game Code ****/ //Minimalistic tween library which should be used for animations over time, including tinting / colouring an object, scaling, rotating, or changing any game object property. //Only include the plugins you need to create the game. //We have access to the following plugins. (Note that the variable names used are mandetory for each plugin) // Initialize assets used in this game. Scale them according to what is needed for the game. // or via static code analysis based on their usage in the code. // Assets are automatically created and loaded either dynamically during gameplay /* Supported Types: 1. Shape: - Simple geometric figures with these properties: * width: (required) pixel width of the shape. * height: (required) pixel height of the shape. * color: (required) color of the shape. * shape: (required) type of shape. Valid options: 'box', 'ellipse'. 2. Image: - Imported images with these properties: * width: (required) pixel resolution width. * height: (required) pixel resolution height. * id: (required) identifier for the image. * flipX: (optional) horizontal flip. Valid values: 0 (no flip), 1 (flip). * flipY: (optional) vertical flip. Valid values: 0 (no flip), 1 (flip). * orientation: (optional) rotation in multiples of 90 degrees, clockwise. Valid values: - 0: No rotation. - 1: Rotate 90 degrees. - 2: Rotate 180 degrees. - 3: Rotate 270 degrees. Note: Width and height remain unchanged upon flipping. 3. Sound: - Sound effects with these properties: * id: (required) identifier for the sound. * volume: (optional) custom volume. Valid values are a float from 0 to 1. 4. Music: - In contract to sound effects, only one music can be played at a time - Music is using the same API to initilize just like sound. - Music loops by default - Music with these config options: * id: (required) identifier for the sound. * volume: (optional) custom volume. Valid values are a float from 0 to 1. * start: (optional) a float from 0 to 1 used for cropping and indicates the start of the cropping * end: (optional) a float from 0 to 1 used for cropping and indicates the end of the cropping */ //Note game dimensions are 2048x2732 var gameState = 'intro'; // 'intro', 'playing', 'finished', 'finalScore', 'win', or 'scores' var introContainer = null; var startButton = null; var scoreButton = null; var finalScoreScreenContainer = null; // For final score screen elements var finalScoreTextElement = null; // For the text on final score screen var scoreDisplayContainer = null; // For score display screen var gameBackground = null; // To manage the game's background image var dragNode = null; // Centralized declaration, used by player controls var terrainBlocks = []; // Original line // PlayerCharacter and scoreTxt are already declared globally and initialized to null later // var playerCharacter = null; // var scoreTxt = null; // Forward declaration for the main game initialization logic function initializeMainGame() { // Add game background, ensuring any old one is removed if (gameBackground && typeof gameBackground.destroy === 'function') { gameBackground.destroy(); } gameBackground = LK.getAsset('Gamebackground', { // Use the global gameBackground variable x: 0, y: 0, width: 2048, height: 2732, anchorX: 0, // Optional, default is 0 for x=0, y=0 anchorY: 0 // Optional, default is 0 for x=0, y=0 }); game.addChildAt(gameBackground, 0); // Add at index 0 to ensure it's in the back LK.playMusic('Gamemusic1', { loop: false, onFinish: handleMusicEnd }); // Play music without looping and set onFinish callback // Re-initialize scoreTxt if it was part of a previous game state and cleaned up if (scoreTxt && typeof scoreTxt.destroy === 'function') { if (scoreTxt.parent && typeof scoreTxt.parent.removeChild === 'function') { scoreTxt.parent.removeChild(scoreTxt); } scoreTxt.destroy(); } scoreTxt = new Text2('0', { size: 150, fill: 0xFFFFFF }); scoreTxt.setText(LK.getScore()); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); playerCharacter = new PlayerCharacter(); // Position player character near the bottom center playerCharacter.x = 2048 / 2; playerCharacter.y = 2732 - playerCharacter.height - 100; // Offset from bottom game.addChild(playerCharacter); // Event listeners for player control // These are assigned when the game starts, so gameState is 'playing' game.down = function (x, y, obj) { if (!playerCharacter) { return; } // Guard against playerCharacter not being ready // Check if the touch is on the player character dragNode = playerCharacter; }; game.move = function (x, y, obj) { if (!playerCharacter) { return; } // Guard // Move the player character horizontally based on the cursor's x position, // ensuring it stays within the horizontal bounds of the screen. playerCharacter.x = Math.max(playerCharacter.width / 2, Math.min(2048 - playerCharacter.width / 2, x)); }; game.up = function (x, y, obj) { if (!playerCharacter) { return; } // Guard dragNode = null; // Stop dragging }; // Define the rhythm pattern (intervals in milliseconds between spawns) beatIntervalsPattern = [600, 600, 600, 600, 400, 400, 600, 600, 600, 600, 400, 400, 500, 500, 500, 500, 400, 400, 600, 600]; currentBeatInPatternIndex = 0; timeForNextBlockSpawn = Date.now() + beatIntervalsPattern[0]; // lastSpawnTime = Date.now(); // Initialize block spawning timer to start spawning blocks - Replaced by new system gameStartTime = Date.now(); // Track when the game started } var playerCharacter = null; var scoreTxt = null; // var spawnInterval = 1200; // Milliseconds between block spawns - Replaced by beatIntervalsPattern // var lastSpawnTime = 4; - Replaced by timeForNextBlockSpawn var beatIntervalsPattern = []; // Defines the ms duration between each block spawn var currentBeatInPatternIndex = 0; // Tracks the current position in the beatIntervalsPattern var timeForNextBlockSpawn = 0; // Timestamp for when the next block should spawn var terrainSpeed = 9; var gameStartTime = 0; // Track when the game started var gameDuration = 173000; // 2:53 in milliseconds (173 seconds) // Mapping colors to hex and sound IDs var colorMap = { 'Red': '#FF0000', 'Orange': '#FFA500', 'Yellow': '#FFFF00', 'Green': '#008000', 'Blue': '#0000FF', 'Indigo': '#4B0082', 'Violet': '#EE82EE' }; // Play background music // Music, score, player, and event handlers are now initialized in initializeMainGame(). var colorNoteMap = { 'Red': 'noteC', 'Orange': 'noteD', 'Yellow': 'noteE', 'Green': 'noteF', 'Blue': 'noteG', 'Indigo': 'noteA', 'Violet': 'noteB' }; game.setBackgroundColor(0x000000); // Change background color to black function cleanupGameElements() { if (playerCharacter && typeof playerCharacter.destroy === 'function') { playerCharacter.destroy(); playerCharacter = null; } for (var i = terrainBlocks.length - 1; i >= 0; i--) { if (terrainBlocks[i] && typeof terrainBlocks[i].destroy === 'function') { terrainBlocks[i].destroy(); } } terrainBlocks = []; if (scoreTxt) { if (scoreTxt.parent && typeof scoreTxt.parent.removeChild === 'function') { scoreTxt.parent.removeChild(scoreTxt); } if (typeof scoreTxt.destroy === 'function') { scoreTxt.destroy(); } scoreTxt = null; } if (gameBackground && typeof gameBackground.destroy === 'function') { gameBackground.destroy(); gameBackground = null; } // Clear game-specific event listeners game.down = null; game.move = null; game.up = null; } function showFinalScoreScreen() { gameState = 'finalScore'; // Set state before cleanup cleanupGameElements(); // Clean up active game elements first finalScoreScreenContainer = new Container(); game.addChild(finalScoreScreenContainer); // Reuse Introbackground for the final score screen var finalScoreBackgroundAsset = LK.getAsset('Introbackground', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, width: 2048, height: 2732 }); finalScoreScreenContainer.addChild(finalScoreBackgroundAsset); finalScoreBackgroundAsset.interactive = true; // Make the background tappable var currentScore = LK.getScore(); // Save the score saveHighScore(currentScore); // Add "You Lose" text var loseText = new Text2('YOU LOSE', { size: 180, fill: 0xFF0000, // Red color align: 'center' }); loseText.anchor.set(0.5, 0.5); loseText.x = 2048 / 2; loseText.y = 2732 / 2 - 300; finalScoreScreenContainer.addChild(loseText); finalScoreTextElement = new Text2('Final Score: ' + currentScore, { size: 120, fill: 0xFFFFFF, align: 'center' // PIXI v4 Text style property }); finalScoreTextElement.anchor.set(0.5, 0.5); finalScoreTextElement.x = 2048 / 2; finalScoreTextElement.y = 2732 / 2 - 50; // Position above center finalScoreScreenContainer.addChild(finalScoreTextElement); var tapToContinueText = new Text2('Tap to Restart', { size: 80, fill: 0xFFFFFF, align: 'center' // PIXI v4 Text style property }); tapToContinueText.anchor.set(0.5, 0.5); tapToContinueText.x = 2048 / 2; tapToContinueText.y = 2732 / 2 + 150; // Position below the score finalScoreScreenContainer.addChild(tapToContinueText); finalScoreBackgroundAsset.down = function () { // Attach tap listener to the background if (gameState === 'finalScore') { resetToIntro(); } }; } function showWinScreen() { gameState = 'win'; // Set state to win cleanupGameElements(); // Clean up active game elements first // Save the score before showing win screen saveHighScore(LK.getScore()); var winScreenContainer = new Container(); game.addChild(winScreenContainer); // Create transparent score background var scoreBackgroundAsset = LK.getAsset('scoreBackground', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0.7 // Transparent background }); winScreenContainer.addChild(scoreBackgroundAsset); var winText = new Text2('YOU WIN!', { size: 180, fill: 0xFFD700, // Gold color align: 'center' }); winText.anchor.set(0.5, 0.5); winText.x = 2048 / 2; winText.y = 2732 / 2 - 200; winScreenContainer.addChild(winText); var finalScoreText = new Text2('Final Score: ' + LK.getScore(), { size: 120, fill: 0xFFFFFF, align: 'center' }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = 2048 / 2; finalScoreText.y = 2732 / 2; winScreenContainer.addChild(finalScoreText); // Show You Win after a short delay LK.setTimeout(function () { LK.showYouWin(); }, 2000); } function handleMusicEnd() { // This function is called when the game music finishes if (gameState === 'playing') { // Proceed only if the game was actively playing gameState = 'finished'; // Set state to finished to stop all game updates // Stop any remaining game elements from updating for (var i = terrainBlocks.length - 1; i >= 0; i--) { if (terrainBlocks[i]) { terrainBlocks[i].update = function () {}; // Disable update function } } // Small delay to ensure smooth transition LK.setTimeout(function () { // Check if player scored more than 2000 for win condition if (LK.getScore() >= 2000) { showWinScreen(); // Show custom win screen with score background } else { showFinalScoreScreen(); } }, 500); } } function showScoreDisplay() { gameState = 'scores'; // Clean up intro screen if (introContainer && typeof introContainer.destroy === 'function') { introContainer.destroy(); introContainer = null; } startButton = null; scoreButton = null; // Create score display container scoreDisplayContainer = new Container(); game.addChild(scoreDisplayContainer); // Add score background var scoreBackgroundAsset = LK.getAsset('scoreBackground', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0.9 }); scoreDisplayContainer.addChild(scoreBackgroundAsset); scoreBackgroundAsset.interactive = true; // Add title text var titleText = new Text2('HIGH SCORES', { size: 120, fill: 0xFFD700, align: 'center' }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 400; scoreDisplayContainer.addChild(titleText); // Get stored scores or initialize var highScores = storage.highScores || []; // Display scores var scoreY = 600; if (highScores.length === 0) { var noScoresText = new Text2('No scores yet!', { size: 80, fill: 0xFFFFFF, align: 'center' }); noScoresText.anchor.set(0.5, 0.5); noScoresText.x = 2048 / 2; noScoresText.y = scoreY; scoreDisplayContainer.addChild(noScoresText); } else { // Show top 10 scores var displayCount = Math.min(10, highScores.length); for (var i = 0; i < displayCount; i++) { var scoreText = new Text2(i + 1 + '. ' + highScores[i], { size: 70, fill: 0xFFFFFF, align: 'center' }); scoreText.anchor.set(0.5, 0.5); scoreText.x = 2048 / 2; scoreText.y = scoreY + i * 100; scoreDisplayContainer.addChild(scoreText); } } // Add back button text var backText = new Text2('Tap to go back', { size: 60, fill: 0xFFFFFF, align: 'center' }); backText.anchor.set(0.5, 0.5); backText.x = 2048 / 2; backText.y = 2732 - 200; scoreDisplayContainer.addChild(backText); // Handle tap to go back scoreBackgroundAsset.down = function () { if (scoreDisplayContainer && typeof scoreDisplayContainer.destroy === 'function') { scoreDisplayContainer.destroy(); scoreDisplayContainer = null; } setupIntroScreen(); }; } function saveHighScore(score) { // Get existing high scores or initialize empty array var highScores = storage.highScores || []; // Add new score highScores.push(score); // Sort in descending order highScores.sort(function (a, b) { return b - a; }); // Keep only top 10 scores if (highScores.length > 10) { highScores = highScores.slice(0, 10); } // Save back to storage storage.highScores = highScores; } function resetToIntro() { if (finalScoreScreenContainer && typeof finalScoreScreenContainer.destroy === 'function') { finalScoreScreenContainer.destroy(); finalScoreScreenContainer = null; } // finalScoreTextElement is a child of finalScoreScreenContainer, so it's destroyed with it. finalScoreTextElement = null; LK.setScore(0); // Reset the score for the new game session setupIntroScreen(); // Transition back to the intro screen } function setupIntroScreen() { gameState = 'intro'; // Set current game state to intro // Clean up previous intro elements if any (e.g., if returning from final score) if (introContainer && typeof introContainer.destroy === 'function') { introContainer.destroy(); } introContainer = new Container(); game.addChild(introContainer); var introBackgroundAsset = LK.getAsset('Introbackground', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, width: 2048, height: 2732 }); introContainer.addChild(introBackgroundAsset); // Clean up previous start button if any if (startButton && typeof startButton.destroy === 'function') { startButton.destroy(); } // Clean up previous score button if any if (scoreButton && typeof scoreButton.destroy === 'function') { scoreButton.destroy(); } var startButtonAsset = LK.getAsset('Startbutton', { anchorX: 0.5, anchorY: 0.5 }); startButtonAsset.x = 2048 / 2 - 250; // Move left to make room for score button startButtonAsset.y = 2732 - 100 - startButtonAsset.height / 2; // Position near bottom introContainer.addChild(startButtonAsset); startButton = startButtonAsset; // Assign to global variable // Create and add score button var scoreButtonAsset = LK.getAsset('Scorebutton', { anchorX: 0.5, anchorY: 0.5 }); scoreButtonAsset.x = startButtonAsset.x + startButtonAsset.width / 2 + 100 + scoreButtonAsset.width / 2; // Position to the right of start button with 100px gap scoreButtonAsset.y = startButtonAsset.y; // Same height as start button introContainer.addChild(scoreButtonAsset); scoreButton = scoreButtonAsset; // Assign to global variable startButton.down = function () { if (gameState !== 'intro') { // Ensure action only if in intro state return; } gameState = 'playing'; // Transition to playing state if (introContainer && typeof introContainer.destroy === 'function') { introContainer.destroy(); // Clean up intro screen elements introContainer = null; } startButton = null; // Clear button reference scoreButton = null; // Clear button reference initializeMainGame(); // Initialize and start the main game }; scoreButton.down = function () { if (gameState !== 'intro') { return; } showScoreDisplay(); }; } // Initial call to set up the intro screen when the game first loads setupIntroScreen(); // The original scoreTxt, playerCharacter, and game event handlers (down, move, up) // are removed from here as they are now part of initializeMainGame. // The old dragNode declaration was also removed as it's now global. game.update = function () { if (gameState !== 'playing') { return; // Don't run game logic if not in 'playing' state } var currentTime = Date.now(); // Check if game duration has exceeded 2:53 if (currentTime - gameStartTime >= gameDuration) { // Stop the game after 2:53 gameState = 'finished'; // Stop music if still playing LK.stopMusic(); // Stop all blocks from updating for (var i = terrainBlocks.length - 1; i >= 0; i--) { if (terrainBlocks[i]) { terrainBlocks[i].update = function () {}; // Disable update function } } // Show final score after a short delay LK.setTimeout(function () { // Check if player scored more than 2000 for win condition if (LK.getScore() >= 2000) { showWinScreen(); // Show custom win screen with score background } else { showFinalScoreScreen(); } }, 500); return; // Exit update function } // Spawn new terrain blocks based on music rhythm if (currentTime >= timeForNextBlockSpawn && gameState === 'playing') { var colors = Object.keys(colorMap); var randomColor = colors[Math.floor(Math.random() * colors.length)]; var noteId = colorNoteMap[randomColor]; var newBlock = new TerrainBlock(randomColor, terrainSpeed, noteId); // Position block randomly at the top within game width newBlock.x = Math.random() * (2048 - newBlock.width) + newBlock.width / 2; newBlock.y = -newBlock.height; // Start above the screen terrainBlocks.push(newBlock); game.addChild(newBlock); currentBeatInPatternIndex++; if (currentBeatInPatternIndex >= beatIntervalsPattern.length) { currentBeatInPatternIndex = 0; // Loop the pattern } timeForNextBlockSpawn = currentTime + beatIntervalsPattern[currentBeatInPatternIndex]; // Gradually increase game speed / difficulty (terrainSpeed only) terrainSpeed = Math.min(15, terrainSpeed + 0.05); } // Update and check collisions for terrain blocks // Update and check collisions for terrain blocks for (var i = terrainBlocks.length - 1; i >= 0; i--) { var block = terrainBlocks[i]; if (block.lastY === undefined) { block.lastY = block.y; } // Check if block is off-screen if (block.lastY < 2732 + block.height && block.y >= 2732 + block.height) { // Missed block - just remove it without penalty block.destroy(); terrainBlocks.splice(i, 1); continue; // Skip to next block } // Check for intersection with player character var currentIntersecting = block.intersects(playerCharacter); if (currentIntersecting) { // Collect any color block LK.setScore(LK.getScore() + 10); scoreTxt.setText(LK.getScore()); // Create animation effect based on block color var animationAsset = null; if (block.color === 'Red') { animationAsset = LK.getAsset('Redanimation1', { anchorX: 0.5, anchorY: 0.5 }); } else if (block.color === 'Orange') { animationAsset = LK.getAsset('Orangeanimation1', { anchorX: 0.5, anchorY: 0.5 }); } else if (block.color === 'Yellow') { animationAsset = LK.getAsset('Yellowanimation1', { anchorX: 0.5, anchorY: 0.5 }); } else if (block.color === 'Green') { animationAsset = LK.getAsset('Greenanimation1', { anchorX: 0.5, anchorY: 0.5 }); } else if (block.color === 'Blue') { animationAsset = LK.getAsset('Blueanimation1', { anchorX: 0.5, anchorY: 0.5 }); } else if (block.color === 'Indigo') { animationAsset = LK.getAsset('Purpleanimation1', { anchorX: 0.5, anchorY: 0.5 }); } else if (block.color === 'Violet') { animationAsset = LK.getAsset('Pinkanimation1', { anchorX: 0.5, anchorY: 0.5 }); } if (animationAsset) { // Position animation at block location animationAsset.x = block.x; animationAsset.y = block.y; game.addChild(animationAsset); // Animate the animation asset tween(animationAsset, { scaleX: 3, scaleY: 3, alpha: 0, rotation: Math.PI * 2 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { animationAsset.destroy(); } }); } // Add visual feedback with scale animation on player tween(playerCharacter, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(playerCharacter, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeIn }); } }); // Flash effect on collected block tween(block, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut }); // Also fade out the line if (block.line) { tween(block.line, { alpha: 0 }, { duration: 200, easing: tween.easeOut }); } // Play specific sound based on block color with smooth volume fade var sound = null; if (block.color === 'Red') { sound = LK.getSound('redsound1'); } else if (block.color === 'Orange') { sound = LK.getSound('orangesound1'); } else if (block.color === 'Yellow') { sound = LK.getSound('yellowsound1'); } else if (block.color === 'Green') { sound = LK.getSound('greensound1'); } else if (block.color === 'Blue') { sound = LK.getSound('bluesound1'); } else if (block.color === 'Indigo') { sound = LK.getSound('purplesound1'); } else if (block.color === 'Violet') { sound = LK.getSound('pinksound1'); } if (sound) { // Set initial volume to 0 for fade-in effect sound.volume = 0; sound.play(); // Tween volume from 0 to 1 over 200ms for smooth fade-in tween(sound, { volume: 1 }, { duration: 200, easing: tween.easeOut }); } block.destroy(); terrainBlocks.splice(i, 1); } block.lastY = block.y; } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var PlayerCharacter = Container.expand(function () {
var self = Container.call(this);
var characterGraphics = self.attachAsset('playerCharacter', {
anchorX: 0.5,
anchorY: 0.5
});
// Set brown transparent color
characterGraphics.alpha = 0.7;
return self;
});
//Storage library which should be used for persistent game data
// var storage = LK.import('@upit/storage.v1');
//Library for using the camera (the background becomes the user's camera video feed) and the microphone. It can access face coordinates for interactive play, as well detect microphone volume / voice interactions
// var facekit = LK.import('@upit/facekit.v1');
//Classes can only be defined here. You cannot create inline classes in the games code.
var TerrainBlock = Container.expand(function (color, speed, noteId) {
var self = Container.call(this);
self.color = color;
self.speed = speed;
self.noteId = noteId;
var blockGraphics = self.attachAsset('terrainBlock' + self.color, {
anchorX: 0.5,
anchorY: 0.5
});
// Create vertical line extending from block
self.line = new Container();
// Get color hex value from colorMap
var lineColor = 0xFFFFFF; // Default white
if (color === 'Red') {
lineColor = 0xFF0000;
} else if (color === 'Orange') {
lineColor = 0xFFA500;
} else if (color === 'Yellow') {
lineColor = 0xFFFF00;
} else if (color === 'Green') {
lineColor = 0x008000;
} else if (color === 'Blue') {
lineColor = 0x0000FF;
} else if (color === 'Indigo') {
lineColor = 0x4B0082;
} else if (color === 'Violet') {
lineColor = 0xEE82EE;
}
// Create thin vertical line shape
var lineGraphics = LK.getAsset('line' + self.color, {
width: 50,
height: 500,
// Shorter line
color: lineColor,
shape: 'box',
anchorX: 0.5,
anchorY: 1
});
self.line.addChild(lineGraphics);
self.addChild(self.line);
self.update = function () {
self.y += self.speed;
// Keep line positioned at block center extending upward
if (self.line) {
self.line.x = 0;
self.line.y = 0;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 //Init game with black background
});
/****
* Game Code
****/
//Minimalistic tween library which should be used for animations over time, including tinting / colouring an object, scaling, rotating, or changing any game object property.
//Only include the plugins you need to create the game.
//We have access to the following plugins. (Note that the variable names used are mandetory for each plugin)
// Initialize assets used in this game. Scale them according to what is needed for the game.
// or via static code analysis based on their usage in the code.
// Assets are automatically created and loaded either dynamically during gameplay
/*
Supported Types:
1. Shape:
- Simple geometric figures with these properties:
* width: (required) pixel width of the shape.
* height: (required) pixel height of the shape.
* color: (required) color of the shape.
* shape: (required) type of shape. Valid options: 'box', 'ellipse'.
2. Image:
- Imported images with these properties:
* width: (required) pixel resolution width.
* height: (required) pixel resolution height.
* id: (required) identifier for the image.
* flipX: (optional) horizontal flip. Valid values: 0 (no flip), 1 (flip).
* flipY: (optional) vertical flip. Valid values: 0 (no flip), 1 (flip).
* orientation: (optional) rotation in multiples of 90 degrees, clockwise. Valid values:
- 0: No rotation.
- 1: Rotate 90 degrees.
- 2: Rotate 180 degrees.
- 3: Rotate 270 degrees.
Note: Width and height remain unchanged upon flipping.
3. Sound:
- Sound effects with these properties:
* id: (required) identifier for the sound.
* volume: (optional) custom volume. Valid values are a float from 0 to 1.
4. Music:
- In contract to sound effects, only one music can be played at a time
- Music is using the same API to initilize just like sound.
- Music loops by default
- Music with these config options:
* id: (required) identifier for the sound.
* volume: (optional) custom volume. Valid values are a float from 0 to 1.
* start: (optional) a float from 0 to 1 used for cropping and indicates the start of the cropping
* end: (optional) a float from 0 to 1 used for cropping and indicates the end of the cropping
*/
//Note game dimensions are 2048x2732
var gameState = 'intro'; // 'intro', 'playing', 'finished', 'finalScore', 'win', or 'scores'
var introContainer = null;
var startButton = null;
var scoreButton = null;
var finalScoreScreenContainer = null; // For final score screen elements
var finalScoreTextElement = null; // For the text on final score screen
var scoreDisplayContainer = null; // For score display screen
var gameBackground = null; // To manage the game's background image
var dragNode = null; // Centralized declaration, used by player controls
var terrainBlocks = []; // Original line
// PlayerCharacter and scoreTxt are already declared globally and initialized to null later
// var playerCharacter = null;
// var scoreTxt = null;
// Forward declaration for the main game initialization logic
function initializeMainGame() {
// Add game background, ensuring any old one is removed
if (gameBackground && typeof gameBackground.destroy === 'function') {
gameBackground.destroy();
}
gameBackground = LK.getAsset('Gamebackground', {
// Use the global gameBackground variable
x: 0,
y: 0,
width: 2048,
height: 2732,
anchorX: 0,
// Optional, default is 0 for x=0, y=0
anchorY: 0 // Optional, default is 0 for x=0, y=0
});
game.addChildAt(gameBackground, 0); // Add at index 0 to ensure it's in the back
LK.playMusic('Gamemusic1', {
loop: false,
onFinish: handleMusicEnd
}); // Play music without looping and set onFinish callback
// Re-initialize scoreTxt if it was part of a previous game state and cleaned up
if (scoreTxt && typeof scoreTxt.destroy === 'function') {
if (scoreTxt.parent && typeof scoreTxt.parent.removeChild === 'function') {
scoreTxt.parent.removeChild(scoreTxt);
}
scoreTxt.destroy();
}
scoreTxt = new Text2('0', {
size: 150,
fill: 0xFFFFFF
});
scoreTxt.setText(LK.getScore());
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
playerCharacter = new PlayerCharacter();
// Position player character near the bottom center
playerCharacter.x = 2048 / 2;
playerCharacter.y = 2732 - playerCharacter.height - 100; // Offset from bottom
game.addChild(playerCharacter);
// Event listeners for player control
// These are assigned when the game starts, so gameState is 'playing'
game.down = function (x, y, obj) {
if (!playerCharacter) {
return;
} // Guard against playerCharacter not being ready
// Check if the touch is on the player character
dragNode = playerCharacter;
};
game.move = function (x, y, obj) {
if (!playerCharacter) {
return;
} // Guard
// Move the player character horizontally based on the cursor's x position,
// ensuring it stays within the horizontal bounds of the screen.
playerCharacter.x = Math.max(playerCharacter.width / 2, Math.min(2048 - playerCharacter.width / 2, x));
};
game.up = function (x, y, obj) {
if (!playerCharacter) {
return;
} // Guard
dragNode = null; // Stop dragging
};
// Define the rhythm pattern (intervals in milliseconds between spawns)
beatIntervalsPattern = [600, 600, 600, 600, 400, 400, 600, 600, 600, 600, 400, 400, 500, 500, 500, 500, 400, 400, 600, 600];
currentBeatInPatternIndex = 0;
timeForNextBlockSpawn = Date.now() + beatIntervalsPattern[0];
// lastSpawnTime = Date.now(); // Initialize block spawning timer to start spawning blocks - Replaced by new system
gameStartTime = Date.now(); // Track when the game started
}
var playerCharacter = null;
var scoreTxt = null;
// var spawnInterval = 1200; // Milliseconds between block spawns - Replaced by beatIntervalsPattern
// var lastSpawnTime = 4; - Replaced by timeForNextBlockSpawn
var beatIntervalsPattern = []; // Defines the ms duration between each block spawn
var currentBeatInPatternIndex = 0; // Tracks the current position in the beatIntervalsPattern
var timeForNextBlockSpawn = 0; // Timestamp for when the next block should spawn
var terrainSpeed = 9;
var gameStartTime = 0; // Track when the game started
var gameDuration = 173000; // 2:53 in milliseconds (173 seconds)
// Mapping colors to hex and sound IDs
var colorMap = {
'Red': '#FF0000',
'Orange': '#FFA500',
'Yellow': '#FFFF00',
'Green': '#008000',
'Blue': '#0000FF',
'Indigo': '#4B0082',
'Violet': '#EE82EE'
};
// Play background music
// Music, score, player, and event handlers are now initialized in initializeMainGame().
var colorNoteMap = {
'Red': 'noteC',
'Orange': 'noteD',
'Yellow': 'noteE',
'Green': 'noteF',
'Blue': 'noteG',
'Indigo': 'noteA',
'Violet': 'noteB'
};
game.setBackgroundColor(0x000000); // Change background color to black
function cleanupGameElements() {
if (playerCharacter && typeof playerCharacter.destroy === 'function') {
playerCharacter.destroy();
playerCharacter = null;
}
for (var i = terrainBlocks.length - 1; i >= 0; i--) {
if (terrainBlocks[i] && typeof terrainBlocks[i].destroy === 'function') {
terrainBlocks[i].destroy();
}
}
terrainBlocks = [];
if (scoreTxt) {
if (scoreTxt.parent && typeof scoreTxt.parent.removeChild === 'function') {
scoreTxt.parent.removeChild(scoreTxt);
}
if (typeof scoreTxt.destroy === 'function') {
scoreTxt.destroy();
}
scoreTxt = null;
}
if (gameBackground && typeof gameBackground.destroy === 'function') {
gameBackground.destroy();
gameBackground = null;
}
// Clear game-specific event listeners
game.down = null;
game.move = null;
game.up = null;
}
function showFinalScoreScreen() {
gameState = 'finalScore'; // Set state before cleanup
cleanupGameElements(); // Clean up active game elements first
finalScoreScreenContainer = new Container();
game.addChild(finalScoreScreenContainer);
// Reuse Introbackground for the final score screen
var finalScoreBackgroundAsset = LK.getAsset('Introbackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
width: 2048,
height: 2732
});
finalScoreScreenContainer.addChild(finalScoreBackgroundAsset);
finalScoreBackgroundAsset.interactive = true; // Make the background tappable
var currentScore = LK.getScore();
// Save the score
saveHighScore(currentScore);
// Add "You Lose" text
var loseText = new Text2('YOU LOSE', {
size: 180,
fill: 0xFF0000,
// Red color
align: 'center'
});
loseText.anchor.set(0.5, 0.5);
loseText.x = 2048 / 2;
loseText.y = 2732 / 2 - 300;
finalScoreScreenContainer.addChild(loseText);
finalScoreTextElement = new Text2('Final Score: ' + currentScore, {
size: 120,
fill: 0xFFFFFF,
align: 'center' // PIXI v4 Text style property
});
finalScoreTextElement.anchor.set(0.5, 0.5);
finalScoreTextElement.x = 2048 / 2;
finalScoreTextElement.y = 2732 / 2 - 50; // Position above center
finalScoreScreenContainer.addChild(finalScoreTextElement);
var tapToContinueText = new Text2('Tap to Restart', {
size: 80,
fill: 0xFFFFFF,
align: 'center' // PIXI v4 Text style property
});
tapToContinueText.anchor.set(0.5, 0.5);
tapToContinueText.x = 2048 / 2;
tapToContinueText.y = 2732 / 2 + 150; // Position below the score
finalScoreScreenContainer.addChild(tapToContinueText);
finalScoreBackgroundAsset.down = function () {
// Attach tap listener to the background
if (gameState === 'finalScore') {
resetToIntro();
}
};
}
function showWinScreen() {
gameState = 'win'; // Set state to win
cleanupGameElements(); // Clean up active game elements first
// Save the score before showing win screen
saveHighScore(LK.getScore());
var winScreenContainer = new Container();
game.addChild(winScreenContainer);
// Create transparent score background
var scoreBackgroundAsset = LK.getAsset('scoreBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0.7 // Transparent background
});
winScreenContainer.addChild(scoreBackgroundAsset);
var winText = new Text2('YOU WIN!', {
size: 180,
fill: 0xFFD700,
// Gold color
align: 'center'
});
winText.anchor.set(0.5, 0.5);
winText.x = 2048 / 2;
winText.y = 2732 / 2 - 200;
winScreenContainer.addChild(winText);
var finalScoreText = new Text2('Final Score: ' + LK.getScore(), {
size: 120,
fill: 0xFFFFFF,
align: 'center'
});
finalScoreText.anchor.set(0.5, 0.5);
finalScoreText.x = 2048 / 2;
finalScoreText.y = 2732 / 2;
winScreenContainer.addChild(finalScoreText);
// Show You Win after a short delay
LK.setTimeout(function () {
LK.showYouWin();
}, 2000);
}
function handleMusicEnd() {
// This function is called when the game music finishes
if (gameState === 'playing') {
// Proceed only if the game was actively playing
gameState = 'finished'; // Set state to finished to stop all game updates
// Stop any remaining game elements from updating
for (var i = terrainBlocks.length - 1; i >= 0; i--) {
if (terrainBlocks[i]) {
terrainBlocks[i].update = function () {}; // Disable update function
}
}
// Small delay to ensure smooth transition
LK.setTimeout(function () {
// Check if player scored more than 2000 for win condition
if (LK.getScore() >= 2000) {
showWinScreen(); // Show custom win screen with score background
} else {
showFinalScoreScreen();
}
}, 500);
}
}
function showScoreDisplay() {
gameState = 'scores';
// Clean up intro screen
if (introContainer && typeof introContainer.destroy === 'function') {
introContainer.destroy();
introContainer = null;
}
startButton = null;
scoreButton = null;
// Create score display container
scoreDisplayContainer = new Container();
game.addChild(scoreDisplayContainer);
// Add score background
var scoreBackgroundAsset = LK.getAsset('scoreBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0.9
});
scoreDisplayContainer.addChild(scoreBackgroundAsset);
scoreBackgroundAsset.interactive = true;
// Add title text
var titleText = new Text2('HIGH SCORES', {
size: 120,
fill: 0xFFD700,
align: 'center'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 400;
scoreDisplayContainer.addChild(titleText);
// Get stored scores or initialize
var highScores = storage.highScores || [];
// Display scores
var scoreY = 600;
if (highScores.length === 0) {
var noScoresText = new Text2('No scores yet!', {
size: 80,
fill: 0xFFFFFF,
align: 'center'
});
noScoresText.anchor.set(0.5, 0.5);
noScoresText.x = 2048 / 2;
noScoresText.y = scoreY;
scoreDisplayContainer.addChild(noScoresText);
} else {
// Show top 10 scores
var displayCount = Math.min(10, highScores.length);
for (var i = 0; i < displayCount; i++) {
var scoreText = new Text2(i + 1 + '. ' + highScores[i], {
size: 70,
fill: 0xFFFFFF,
align: 'center'
});
scoreText.anchor.set(0.5, 0.5);
scoreText.x = 2048 / 2;
scoreText.y = scoreY + i * 100;
scoreDisplayContainer.addChild(scoreText);
}
}
// Add back button text
var backText = new Text2('Tap to go back', {
size: 60,
fill: 0xFFFFFF,
align: 'center'
});
backText.anchor.set(0.5, 0.5);
backText.x = 2048 / 2;
backText.y = 2732 - 200;
scoreDisplayContainer.addChild(backText);
// Handle tap to go back
scoreBackgroundAsset.down = function () {
if (scoreDisplayContainer && typeof scoreDisplayContainer.destroy === 'function') {
scoreDisplayContainer.destroy();
scoreDisplayContainer = null;
}
setupIntroScreen();
};
}
function saveHighScore(score) {
// Get existing high scores or initialize empty array
var highScores = storage.highScores || [];
// Add new score
highScores.push(score);
// Sort in descending order
highScores.sort(function (a, b) {
return b - a;
});
// Keep only top 10 scores
if (highScores.length > 10) {
highScores = highScores.slice(0, 10);
}
// Save back to storage
storage.highScores = highScores;
}
function resetToIntro() {
if (finalScoreScreenContainer && typeof finalScoreScreenContainer.destroy === 'function') {
finalScoreScreenContainer.destroy();
finalScoreScreenContainer = null;
}
// finalScoreTextElement is a child of finalScoreScreenContainer, so it's destroyed with it.
finalScoreTextElement = null;
LK.setScore(0); // Reset the score for the new game session
setupIntroScreen(); // Transition back to the intro screen
}
function setupIntroScreen() {
gameState = 'intro'; // Set current game state to intro
// Clean up previous intro elements if any (e.g., if returning from final score)
if (introContainer && typeof introContainer.destroy === 'function') {
introContainer.destroy();
}
introContainer = new Container();
game.addChild(introContainer);
var introBackgroundAsset = LK.getAsset('Introbackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
width: 2048,
height: 2732
});
introContainer.addChild(introBackgroundAsset);
// Clean up previous start button if any
if (startButton && typeof startButton.destroy === 'function') {
startButton.destroy();
}
// Clean up previous score button if any
if (scoreButton && typeof scoreButton.destroy === 'function') {
scoreButton.destroy();
}
var startButtonAsset = LK.getAsset('Startbutton', {
anchorX: 0.5,
anchorY: 0.5
});
startButtonAsset.x = 2048 / 2 - 250; // Move left to make room for score button
startButtonAsset.y = 2732 - 100 - startButtonAsset.height / 2; // Position near bottom
introContainer.addChild(startButtonAsset);
startButton = startButtonAsset; // Assign to global variable
// Create and add score button
var scoreButtonAsset = LK.getAsset('Scorebutton', {
anchorX: 0.5,
anchorY: 0.5
});
scoreButtonAsset.x = startButtonAsset.x + startButtonAsset.width / 2 + 100 + scoreButtonAsset.width / 2; // Position to the right of start button with 100px gap
scoreButtonAsset.y = startButtonAsset.y; // Same height as start button
introContainer.addChild(scoreButtonAsset);
scoreButton = scoreButtonAsset; // Assign to global variable
startButton.down = function () {
if (gameState !== 'intro') {
// Ensure action only if in intro state
return;
}
gameState = 'playing'; // Transition to playing state
if (introContainer && typeof introContainer.destroy === 'function') {
introContainer.destroy(); // Clean up intro screen elements
introContainer = null;
}
startButton = null; // Clear button reference
scoreButton = null; // Clear button reference
initializeMainGame(); // Initialize and start the main game
};
scoreButton.down = function () {
if (gameState !== 'intro') {
return;
}
showScoreDisplay();
};
}
// Initial call to set up the intro screen when the game first loads
setupIntroScreen();
// The original scoreTxt, playerCharacter, and game event handlers (down, move, up)
// are removed from here as they are now part of initializeMainGame.
// The old dragNode declaration was also removed as it's now global.
game.update = function () {
if (gameState !== 'playing') {
return; // Don't run game logic if not in 'playing' state
}
var currentTime = Date.now();
// Check if game duration has exceeded 2:53
if (currentTime - gameStartTime >= gameDuration) {
// Stop the game after 2:53
gameState = 'finished';
// Stop music if still playing
LK.stopMusic();
// Stop all blocks from updating
for (var i = terrainBlocks.length - 1; i >= 0; i--) {
if (terrainBlocks[i]) {
terrainBlocks[i].update = function () {}; // Disable update function
}
}
// Show final score after a short delay
LK.setTimeout(function () {
// Check if player scored more than 2000 for win condition
if (LK.getScore() >= 2000) {
showWinScreen(); // Show custom win screen with score background
} else {
showFinalScoreScreen();
}
}, 500);
return; // Exit update function
}
// Spawn new terrain blocks based on music rhythm
if (currentTime >= timeForNextBlockSpawn && gameState === 'playing') {
var colors = Object.keys(colorMap);
var randomColor = colors[Math.floor(Math.random() * colors.length)];
var noteId = colorNoteMap[randomColor];
var newBlock = new TerrainBlock(randomColor, terrainSpeed, noteId);
// Position block randomly at the top within game width
newBlock.x = Math.random() * (2048 - newBlock.width) + newBlock.width / 2;
newBlock.y = -newBlock.height; // Start above the screen
terrainBlocks.push(newBlock);
game.addChild(newBlock);
currentBeatInPatternIndex++;
if (currentBeatInPatternIndex >= beatIntervalsPattern.length) {
currentBeatInPatternIndex = 0; // Loop the pattern
}
timeForNextBlockSpawn = currentTime + beatIntervalsPattern[currentBeatInPatternIndex];
// Gradually increase game speed / difficulty (terrainSpeed only)
terrainSpeed = Math.min(15, terrainSpeed + 0.05);
}
// Update and check collisions for terrain blocks
// Update and check collisions for terrain blocks
for (var i = terrainBlocks.length - 1; i >= 0; i--) {
var block = terrainBlocks[i];
if (block.lastY === undefined) {
block.lastY = block.y;
}
// Check if block is off-screen
if (block.lastY < 2732 + block.height && block.y >= 2732 + block.height) {
// Missed block - just remove it without penalty
block.destroy();
terrainBlocks.splice(i, 1);
continue; // Skip to next block
}
// Check for intersection with player character
var currentIntersecting = block.intersects(playerCharacter);
if (currentIntersecting) {
// Collect any color block
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
// Create animation effect based on block color
var animationAsset = null;
if (block.color === 'Red') {
animationAsset = LK.getAsset('Redanimation1', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (block.color === 'Orange') {
animationAsset = LK.getAsset('Orangeanimation1', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (block.color === 'Yellow') {
animationAsset = LK.getAsset('Yellowanimation1', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (block.color === 'Green') {
animationAsset = LK.getAsset('Greenanimation1', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (block.color === 'Blue') {
animationAsset = LK.getAsset('Blueanimation1', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (block.color === 'Indigo') {
animationAsset = LK.getAsset('Purpleanimation1', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (block.color === 'Violet') {
animationAsset = LK.getAsset('Pinkanimation1', {
anchorX: 0.5,
anchorY: 0.5
});
}
if (animationAsset) {
// Position animation at block location
animationAsset.x = block.x;
animationAsset.y = block.y;
game.addChild(animationAsset);
// Animate the animation asset
tween(animationAsset, {
scaleX: 3,
scaleY: 3,
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
animationAsset.destroy();
}
});
}
// Add visual feedback with scale animation on player
tween(playerCharacter, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(playerCharacter, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeIn
});
}
});
// Flash effect on collected block
tween(block, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut
});
// Also fade out the line
if (block.line) {
tween(block.line, {
alpha: 0
}, {
duration: 200,
easing: tween.easeOut
});
}
// Play specific sound based on block color with smooth volume fade
var sound = null;
if (block.color === 'Red') {
sound = LK.getSound('redsound1');
} else if (block.color === 'Orange') {
sound = LK.getSound('orangesound1');
} else if (block.color === 'Yellow') {
sound = LK.getSound('yellowsound1');
} else if (block.color === 'Green') {
sound = LK.getSound('greensound1');
} else if (block.color === 'Blue') {
sound = LK.getSound('bluesound1');
} else if (block.color === 'Indigo') {
sound = LK.getSound('purplesound1');
} else if (block.color === 'Violet') {
sound = LK.getSound('pinksound1');
}
if (sound) {
// Set initial volume to 0 for fade-in effect
sound.volume = 0;
sound.play();
// Tween volume from 0 to 1 over 200ms for smooth fade-in
tween(sound, {
volume: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
block.destroy();
terrainBlocks.splice(i, 1);
}
block.lastY = block.y;
}
};