/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { currentLevel: 1, highestLevel: 1 }); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ var Goal = Container.expand(function () { var self = Container.call(this); var goalGraphics = self.attachAsset('goal', { anchorX: 0.5, anchorY: 0.5 }); // Speed at which the goal moves self.speed = -5; // Pulsating animation effect self.pulse = function () { tween(goalGraphics, { scaleX: 1.1, scaleY: 1.1 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(goalGraphics, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.easeInOut, onFinish: self.pulse }); } }); }; self.pulse(); self.update = function () { self.x += self.speed; // Check if off-screen if (self.x < -100) { self.destroy(); return true; // Signal this goal was destroyed } return false; }; return self; }); var LevelIndicator = Container.expand(function () { var self = Container.call(this); var indicatorGraphics = self.attachAsset('levelIndicator', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); var levelText = new Text2('1', { size: 24, fill: 0x000000 }); levelText.anchor.set(0.5, 0.5); self.addChild(levelText); self.setLevel = function (level) { levelText.setText(level); // Flash the indicator when level changes indicatorGraphics.alpha = 1; tween(indicatorGraphics, { alpha: 0.7 }, { duration: 500, easing: tween.easeOut }); }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // The player's vertical velocity self.velocity = 0; self.gravity = 0.5; // Base downward movement self.baseDownForce = 3; // Multiplier for volume-based ascension self.liftMultiplier = 15; // Whether the player is allowed to move (for intro/outro animations) self.canMove = true; self.update = function () { if (!self.canMove) { return; } // Apply volume-based lift force if (facekit.volume > 0.05) { self.velocity = -facekit.volume * self.liftMultiplier; // Visualize volume with a tint (blue to red) var intensity = Math.min(facekit.volume * 2, 1); var color = tween.linear(intensity, 0x3498db, 0xe74c3c); playerGraphics.tint = color; } else { // Reset tint when quiet playerGraphics.tint = 0x3498db; // Apply gravity self.velocity += self.gravity; } // Apply constant downward force self.velocity += self.baseDownForce; // Limit max velocity self.velocity = Math.max(Math.min(self.velocity, 25), -25); // Update position self.y += self.velocity; // Constrain to screen if (self.y < 80) { self.y = 80; self.velocity = 0; } if (self.y > 2732 - 80) { self.y = 2732 - 80; self.velocity = 0; } }; // Reset player state self.reset = function (startX, startY) { self.x = startX; self.y = startY; self.velocity = 0; self.canMove = true; playerGraphics.alpha = 1; playerGraphics.tint = 0x3498db; }; return self; }); var Wall = Container.expand(function () { var self = Container.call(this); var wallGraphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); // Speed at which the wall moves self.speed = -5; self.update = function () { self.x += self.speed; // Remove if off-screen if (self.x < -100) { self.destroy(); return true; // Signal this wall was destroyed } return false; }; // Method to change the wall's appearance self.setProperties = function (width, height, color) { wallGraphics.width = width; wallGraphics.height = height; wallGraphics.tint = color; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Game state variables var currentLevel = storage.currentLevel || 1; var highestLevel = storage.highestLevel || 1; var walls = []; var player; var goal; var levelIndicator; var gameActive = false; var levelCompleted = false; var volumeIndicator; var totalLevels = 30; var volumeHistory = []; // Level generation parameters var obstaclePatterns = [ // Level 1-5: Simple patterns function () { return [{ x: 2048, y: 1400, width: 500, height: 30 }]; }, function () { return [{ x: 2048, y: 800, width: 500, height: 30 }, { x: 2048, y: 1800, width: 500, height: 30 }]; }, function () { return [{ x: 2048, y: 1366, width: 700, height: 30 }]; }, function () { return [{ x: 2048, y: 600, width: 400, height: 30 }, { x: 2048, y: 2100, width: 400, height: 30 }]; }, function () { return [{ x: 2048, y: 900, width: 300, height: 30 }, { x: 2048, y: 1800, width: 300, height: 30 }]; }, // Level 6-10: Moving gaps function () { return [{ x: 2048, y: 700, width: 800, height: 30 }, { x: 2048, y: 1900, width: 800, height: 30 }]; }, function () { return [{ x: 2048, y: 500, width: 600, height: 30 }, { x: 2048, y: 1200, width: 600, height: 30 }, { x: 2048, y: 1900, width: 600, height: 30 }]; }, function () { return [{ x: 2048, y: 800, width: 400, height: 30 }, { x: 2048, y: 1500, width: 400, height: 30 }, { x: 2048, y: 2200, width: 400, height: 30 }]; }, function () { return [{ x: 2048, y: 600, width: 350, height: 30 }, { x: 2048, y: 1366, width: 900, height: 30 }, { x: 2048, y: 2100, width: 350, height: 30 }]; }, function () { return [{ x: 2048, y: 400, width: 300, height: 30 }, { x: 2048, y: 900, width: 300, height: 30 }, { x: 2048, y: 1400, width: 300, height: 30 }, { x: 2048, y: 1900, width: 300, height: 30 }, { x: 2048, y: 2400, width: 300, height: 30 }]; }, // Level 11-15: Complex patterns function () { var obstacles = []; for (var i = 0; i < 8; i++) { obstacles.push({ x: 2048 + i * 250, y: 700 + i % 2 * 1200, width: 150, height: 30 }); } return obstacles; }, function () { var obstacles = []; for (var i = 0; i < 6; i++) { obstacles.push({ x: 2048 + i * 300, y: 600 + i % 3 * 700, width: 200, height: 30 }); } return obstacles; }, function () { var obstacles = []; for (var i = 0; i < 5; i++) { obstacles.push({ x: 2048 + i * 350, y: 700 + Math.sin(i * 0.7) * 900, width: 250, height: 30 }); } return obstacles; }, function () { var obstacles = []; var baseY = 1366; for (var i = 0; i < 7; i++) { var offset = i % 2 === 0 ? 700 : -700; obstacles.push({ x: 2048 + i * 300, y: baseY + offset, width: 180, height: 30 }); } return obstacles; }, function () { var obstacles = []; for (var i = 0; i < 10; i++) { obstacles.push({ x: 2048 + i * 250, y: 800 + i % 4 * 400, width: 150, height: 30 }); } return obstacles; }, // Level 16-20: Increasing difficulty function () { var obstacles = []; var positions = [500, 900, 1300, 1700, 2100]; for (var i = 0; i < 8; i++) { var yPos = positions[Math.floor(Math.random() * positions.length)]; obstacles.push({ x: 2048 + i * 300, y: yPos, width: 180, height: 30 }); } return obstacles; }, function () { var obstacles = []; for (var i = 0; i < 6; i++) { obstacles.push({ x: 2048 + i * 400, y: 700 + Math.cos(i * 0.9) * 900, width: 300, height: 30 }); } return obstacles; }, function () { var obstacles = []; for (var i = 0; i < 15; i++) { if (i % 3 !== 0) { // Skip every third to create gaps obstacles.push({ x: 2048 + i * 200, y: 500 + i % 5 * 400, width: 150, height: 30 }); } } return obstacles; }, function () { var obstacles = []; var zigzag = true; for (var i = 0; i < 12; i++) { var yPos = zigzag ? 600 + i % 3 * 700 : 2100 - i % 3 * 700; obstacles.push({ x: 2048 + i * 230, y: yPos, width: 150, height: 30 }); if (i % 3 === 2) { zigzag = !zigzag; } } return obstacles; }, function () { var obstacles = []; for (var i = 0; i < 20; i++) { // Create a spiral pattern var angle = i * 0.3; var radius = 500 + i * 30; var yPos = 1366 + Math.sin(angle) * (radius / 3); obstacles.push({ x: 2048 + i * 200, y: yPos, width: 120, height: 30 }); } return obstacles; }, // Level 21-25: Advanced patterns function () { var obstacles = []; // Create a wave pattern for (var i = 0; i < 15; i++) { obstacles.push({ x: 2048 + i * 180, y: 1366 + Math.sin(i * 0.5) * 800, width: 100, height: 30 }); } return obstacles; }, function () { var obstacles = []; // Create a double helix pattern for (var i = 0; i < 20; i++) { obstacles.push({ x: 2048 + i * 150, y: 1366 + Math.sin(i * 0.4) * 700, width: 90, height: 30 }); obstacles.push({ x: 2048 + i * 150, y: 1366 + Math.sin(i * 0.4 + Math.PI) * 700, width: 90, height: 30 }); } return obstacles; }, function () { var obstacles = []; // Create random clusters for (var i = 0; i < 5; i++) { var clusterX = 2048 + i * 500; for (var j = 0; j < 4; j++) { obstacles.push({ x: clusterX + (Math.random() * 200 - 100), y: 600 + j * 500 + (Math.random() * 200 - 100), width: 120, height: 30 }); } } return obstacles; }, function () { var obstacles = []; // Create a pulsating pattern for (var i = 0; i < 15; i++) { var width = 100 + Math.sin(i * 0.4) * 50; obstacles.push({ x: 2048 + i * 200, y: 600 + i % 4 * 500, width: width, height: 30 }); } return obstacles; }, function () { var obstacles = []; // Create a moving wall with small openings for (var i = 0; i < 30; i++) { if (i % 5 !== 2) { // Create openings obstacles.push({ x: 2048 + Math.floor(i / 5) * 400, y: 300 + i * 80, width: 200, height: 30 }); } } return obstacles; }, // Level 26-30: Expert challenges function () { var obstacles = []; // Create a tight slalom for (var i = 0; i < 12; i++) { var yOffset = i % 2 === 0 ? 1000 : -1000; obstacles.push({ x: 2048 + i * 250, y: 1366 + yOffset, width: 1500, height: 30 }); } return obstacles; }, function () { var obstacles = []; // Create a tunnel that gets progressively narrower var tunnelWidth = 1000; for (var i = 0; i < 10; i++) { tunnelWidth = Math.max(300, tunnelWidth - 70); var halfTunnel = tunnelWidth / 2; obstacles.push({ x: 2048 + i * 300, y: 1366 - halfTunnel - 30, width: 200, height: 30 }); obstacles.push({ x: 2048 + i * 300, y: 1366 + halfTunnel, width: 200, height: 30 }); } return obstacles; }, function () { var obstacles = []; // Create moving blocks that require precise timing for (var i = 0; i < 8; i++) { for (var j = 0; j < 5; j++) { if ((i + j) % 2 === 0) { obstacles.push({ x: 2048 + i * 350, y: 400 + j * 500, width: 150, height: 30 }); } } } return obstacles; }, function () { var obstacles = []; // Create a complex maze-like pattern var positions = [[0, 1, 1, 0, 1], [1, 0, 1, 0, 1], [1, 0, 0, 0, 1], [1, 0, 1, 1, 1], [1, 0, 0, 0, 0], [1, 1, 1, 1, 0]]; for (var i = 0; i < positions.length; i++) { for (var j = 0; j < positions[i].length; j++) { if (positions[i][j] === 1) { obstacles.push({ x: 2048 + i * 300, y: 500 + j * 400, width: 220, height: 30 }); } } } return obstacles; }, function () { var obstacles = []; // The final challenge - all techniques combined // Wave pattern for (var i = 0; i < 5; i++) { obstacles.push({ x: 2048 + i * 300, y: 1366 + Math.sin(i * 0.8) * 600, width: 180, height: 30 }); } // Tight slalom for (var i = 0; i < 3; i++) { var yOffset = i % 2 === 0 ? 800 : -800; obstacles.push({ x: 2048 + 1500 + i * 250, y: 1366 + yOffset, width: 1200, height: 30 }); } // Final gauntlet for (var i = 0; i < 5; i++) { if (i !== 2) { // Gap in the middle obstacles.push({ x: 2048 + 2500, y: 400 + i * 500, width: 100, height: 30 }); } } return obstacles; }]; // Initialize UI elements var scoreTxt = new Text2('Level: 1/' + totalLevels, { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var instructionsTxt = new Text2('Make noise to rise\nStay quiet to fall', { size: 60, fill: 0xFFFFFF }); instructionsTxt.anchor.set(0.5, 0); instructionsTxt.y = 100; LK.gui.top.addChild(instructionsTxt); // Volume indicator volumeIndicator = new Container(); var volumeBarBg = LK.getAsset('wall', { anchorX: 0, anchorY: 0.5, width: 50, height: 400, tint: 0x000000, alpha: 0.3 }); volumeIndicator.addChild(volumeBarBg); var volumeBar = LK.getAsset('wall', { anchorX: 0, anchorY: 1, width: 50, height: 0, tint: 0x3498db }); volumeIndicator.addChild(volumeBar); volumeIndicator.x = 150; volumeIndicator.y = 1366; // Center of screen height LK.gui.addChild(volumeIndicator); // Level indicator levelIndicator = new LevelIndicator(); levelIndicator.x = 120; levelIndicator.y = 120; LK.gui.addChild(levelIndicator); levelIndicator.setLevel(currentLevel); // Initialize the player player = new Player(); player.x = 400; player.y = 1366; // Center of screen height game.addChild(player); // Set up the first level setupLevel(currentLevel); // Play background music LK.playMusic('bgMusic', { fade: { start: 0, end: 0.3, duration: 1000 } }); // Main update function game.update = function () { // Update volume history for smoother response volumeHistory.push(facekit.volume); if (volumeHistory.length > 5) { volumeHistory.shift(); } // Calculate average volume var avgVolume = 0; for (var i = 0; i < volumeHistory.length; i++) { avgVolume += volumeHistory[i]; } avgVolume /= volumeHistory.length; // Update volume indicator volumeBar.height = avgVolume * 400; volumeBar.tint = avgVolume < 0.3 ? 0x3498db : avgVolume < 0.7 ? 0xf39c12 : 0xe74c3c; // Only update gameplay if the game is active if (gameActive && !levelCompleted) { // Update all walls for (var i = walls.length - 1; i >= 0; i--) { var removed = walls[i].update(); if (removed) { walls.splice(i, 1); } } // Check if goal is reached or destroyed if (goal) { var goalRemoved = goal.update(); if (goalRemoved) { goal = null; } else if (player.intersects(goal)) { levelCompleted = true; completeLevel(); } } // Check collisions with walls var collision = false; for (var i = 0; i < walls.length; i++) { if (player.intersects(walls[i])) { collision = true; break; } } if (collision) { gameOver(); } // Calculate spawn timing based on level if (LK.ticks % Math.max(120 - currentLevel * 2, 30) === 0 && walls.length < 40) { spawnObstacles(); } // Spawn goal after certain time if (LK.ticks % 600 === 0 && !goal) { spawnGoal(); } } // Hide instructions after 3 seconds if (LK.ticks === 180) { tween(instructionsTxt, { alpha: 0 }, { duration: 1000, easing: tween.easeOut }); } }; // Setup a new level function setupLevel(level) { // Ensure level is in bounds level = Math.max(1, Math.min(level, totalLevels)); currentLevel = level; // Update storage storage.currentLevel = currentLevel; if (currentLevel > highestLevel) { highestLevel = currentLevel; storage.highestLevel = highestLevel; } // Update score text scoreTxt.setText('Level: ' + currentLevel + '/' + totalLevels); // Update level indicator levelIndicator.setLevel(currentLevel); // Reset game state walls = []; if (goal) { goal.destroy(); goal = null; } levelCompleted = false; // Reset player position player.reset(400, 1366); // Set wall speed based on level Wall.prototype.speed = -5 - currentLevel * 0.2; if (goal) { goal.speed = Wall.prototype.speed; } // Start game after a short delay LK.setTimeout(function () { gameActive = true; }, 1000); } // Spawn obstacles based on the current level function spawnObstacles() { // Get the appropriate pattern generator for the current level var patternIndex = Math.min(currentLevel - 1, obstaclePatterns.length - 1); var obstacles = obstaclePatterns[patternIndex](); // Create wall objects for (var i = 0; i < obstacles.length; i++) { var wall = new Wall(); wall.x = obstacles[i].x; wall.y = obstacles[i].y; wall.setProperties(obstacles[i].width, obstacles[i].height, 0xe74c3c); walls.push(wall); game.addChild(wall); } } // Spawn the level goal function spawnGoal() { goal = new Goal(); goal.x = 2048 + 200; // Start off screen goal.y = 1366; // Center of screen height goal.speed = Wall.prototype.speed; // Match wall speed game.addChild(goal); } // Handle level completion function completeLevel() { gameActive = false; // Play sound LK.getSound('levelComplete').play(); // Animate player tween(player, { scaleX: 1.5, scaleY: 1.5 }, { duration: 500, easing: tween.bounceOut, onFinish: function onFinish() { tween(player, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.easeIn }); } }); // Show level complete message var levelCompleteTxt = new Text2('Level ' + currentLevel + ' Complete!', { size: 120, fill: 0xFFFFFF }); levelCompleteTxt.anchor.set(0.5, 0.5); levelCompleteTxt.x = 1024; levelCompleteTxt.y = 1366; levelCompleteTxt.alpha = 0; LK.gui.addChild(levelCompleteTxt); tween(levelCompleteTxt, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.bounceOut, onFinish: function onFinish() { tween(levelCompleteTxt, { alpha: 0 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { levelCompleteTxt.destroy(); // Check if the player has completed all levels if (currentLevel === totalLevels) { // Game completed! var gameCompleteTxt = new Text2('Congratulations!\nYou completed all levels!', { size: 100, fill: 0xFFFFFF }); gameCompleteTxt.anchor.set(0.5, 0.5); gameCompleteTxt.x = 1024; gameCompleteTxt.y = 1366; LK.gui.addChild(gameCompleteTxt); LK.setTimeout(function () { gameCompleteTxt.destroy(); currentLevel = 1; setupLevel(currentLevel); }, 3000); } else { // Next level setupLevel(currentLevel + 1); } } }); } }); } // Handle game over function gameOver() { gameActive = false; // Play sound LK.getSound('gameOver').play(); // Animate player player.canMove = false; tween(player, { alpha: 0.3 }, { duration: 500, easing: tween.easeOut }); // Show game over message var gameOverTxt = new Text2('Level Failed', { size: 120, fill: 0xFFFFFF }); gameOverTxt.anchor.set(0.5, 0.5); gameOverTxt.x = 1024; gameOverTxt.y = 1366; gameOverTxt.alpha = 0; LK.gui.addChild(gameOverTxt); tween(gameOverTxt, { alpha: 1 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { LK.setTimeout(function () { tween(gameOverTxt, { alpha: 0 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { gameOverTxt.destroy(); setupLevel(currentLevel); } }); }, 1500); } }); // Screen flash LK.effects.flashScreen(0xe74c3c, 500); }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
currentLevel: 1,
highestLevel: 1
});
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
var Goal = Container.expand(function () {
var self = Container.call(this);
var goalGraphics = self.attachAsset('goal', {
anchorX: 0.5,
anchorY: 0.5
});
// Speed at which the goal moves
self.speed = -5;
// Pulsating animation effect
self.pulse = function () {
tween(goalGraphics, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(goalGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: self.pulse
});
}
});
};
self.pulse();
self.update = function () {
self.x += self.speed;
// Check if off-screen
if (self.x < -100) {
self.destroy();
return true; // Signal this goal was destroyed
}
return false;
};
return self;
});
var LevelIndicator = Container.expand(function () {
var self = Container.call(this);
var indicatorGraphics = self.attachAsset('levelIndicator', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
var levelText = new Text2('1', {
size: 24,
fill: 0x000000
});
levelText.anchor.set(0.5, 0.5);
self.addChild(levelText);
self.setLevel = function (level) {
levelText.setText(level);
// Flash the indicator when level changes
indicatorGraphics.alpha = 1;
tween(indicatorGraphics, {
alpha: 0.7
}, {
duration: 500,
easing: tween.easeOut
});
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// The player's vertical velocity
self.velocity = 0;
self.gravity = 0.5;
// Base downward movement
self.baseDownForce = 3;
// Multiplier for volume-based ascension
self.liftMultiplier = 15;
// Whether the player is allowed to move (for intro/outro animations)
self.canMove = true;
self.update = function () {
if (!self.canMove) {
return;
}
// Apply volume-based lift force
if (facekit.volume > 0.05) {
self.velocity = -facekit.volume * self.liftMultiplier;
// Visualize volume with a tint (blue to red)
var intensity = Math.min(facekit.volume * 2, 1);
var color = tween.linear(intensity, 0x3498db, 0xe74c3c);
playerGraphics.tint = color;
} else {
// Reset tint when quiet
playerGraphics.tint = 0x3498db;
// Apply gravity
self.velocity += self.gravity;
}
// Apply constant downward force
self.velocity += self.baseDownForce;
// Limit max velocity
self.velocity = Math.max(Math.min(self.velocity, 25), -25);
// Update position
self.y += self.velocity;
// Constrain to screen
if (self.y < 80) {
self.y = 80;
self.velocity = 0;
}
if (self.y > 2732 - 80) {
self.y = 2732 - 80;
self.velocity = 0;
}
};
// Reset player state
self.reset = function (startX, startY) {
self.x = startX;
self.y = startY;
self.velocity = 0;
self.canMove = true;
playerGraphics.alpha = 1;
playerGraphics.tint = 0x3498db;
};
return self;
});
var Wall = Container.expand(function () {
var self = Container.call(this);
var wallGraphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
// Speed at which the wall moves
self.speed = -5;
self.update = function () {
self.x += self.speed;
// Remove if off-screen
if (self.x < -100) {
self.destroy();
return true; // Signal this wall was destroyed
}
return false;
};
// Method to change the wall's appearance
self.setProperties = function (width, height, color) {
wallGraphics.width = width;
wallGraphics.height = height;
wallGraphics.tint = color;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game state variables
var currentLevel = storage.currentLevel || 1;
var highestLevel = storage.highestLevel || 1;
var walls = [];
var player;
var goal;
var levelIndicator;
var gameActive = false;
var levelCompleted = false;
var volumeIndicator;
var totalLevels = 30;
var volumeHistory = [];
// Level generation parameters
var obstaclePatterns = [
// Level 1-5: Simple patterns
function () {
return [{
x: 2048,
y: 1400,
width: 500,
height: 30
}];
}, function () {
return [{
x: 2048,
y: 800,
width: 500,
height: 30
}, {
x: 2048,
y: 1800,
width: 500,
height: 30
}];
}, function () {
return [{
x: 2048,
y: 1366,
width: 700,
height: 30
}];
}, function () {
return [{
x: 2048,
y: 600,
width: 400,
height: 30
}, {
x: 2048,
y: 2100,
width: 400,
height: 30
}];
}, function () {
return [{
x: 2048,
y: 900,
width: 300,
height: 30
}, {
x: 2048,
y: 1800,
width: 300,
height: 30
}];
},
// Level 6-10: Moving gaps
function () {
return [{
x: 2048,
y: 700,
width: 800,
height: 30
}, {
x: 2048,
y: 1900,
width: 800,
height: 30
}];
}, function () {
return [{
x: 2048,
y: 500,
width: 600,
height: 30
}, {
x: 2048,
y: 1200,
width: 600,
height: 30
}, {
x: 2048,
y: 1900,
width: 600,
height: 30
}];
}, function () {
return [{
x: 2048,
y: 800,
width: 400,
height: 30
}, {
x: 2048,
y: 1500,
width: 400,
height: 30
}, {
x: 2048,
y: 2200,
width: 400,
height: 30
}];
}, function () {
return [{
x: 2048,
y: 600,
width: 350,
height: 30
}, {
x: 2048,
y: 1366,
width: 900,
height: 30
}, {
x: 2048,
y: 2100,
width: 350,
height: 30
}];
}, function () {
return [{
x: 2048,
y: 400,
width: 300,
height: 30
}, {
x: 2048,
y: 900,
width: 300,
height: 30
}, {
x: 2048,
y: 1400,
width: 300,
height: 30
}, {
x: 2048,
y: 1900,
width: 300,
height: 30
}, {
x: 2048,
y: 2400,
width: 300,
height: 30
}];
},
// Level 11-15: Complex patterns
function () {
var obstacles = [];
for (var i = 0; i < 8; i++) {
obstacles.push({
x: 2048 + i * 250,
y: 700 + i % 2 * 1200,
width: 150,
height: 30
});
}
return obstacles;
}, function () {
var obstacles = [];
for (var i = 0; i < 6; i++) {
obstacles.push({
x: 2048 + i * 300,
y: 600 + i % 3 * 700,
width: 200,
height: 30
});
}
return obstacles;
}, function () {
var obstacles = [];
for (var i = 0; i < 5; i++) {
obstacles.push({
x: 2048 + i * 350,
y: 700 + Math.sin(i * 0.7) * 900,
width: 250,
height: 30
});
}
return obstacles;
}, function () {
var obstacles = [];
var baseY = 1366;
for (var i = 0; i < 7; i++) {
var offset = i % 2 === 0 ? 700 : -700;
obstacles.push({
x: 2048 + i * 300,
y: baseY + offset,
width: 180,
height: 30
});
}
return obstacles;
}, function () {
var obstacles = [];
for (var i = 0; i < 10; i++) {
obstacles.push({
x: 2048 + i * 250,
y: 800 + i % 4 * 400,
width: 150,
height: 30
});
}
return obstacles;
},
// Level 16-20: Increasing difficulty
function () {
var obstacles = [];
var positions = [500, 900, 1300, 1700, 2100];
for (var i = 0; i < 8; i++) {
var yPos = positions[Math.floor(Math.random() * positions.length)];
obstacles.push({
x: 2048 + i * 300,
y: yPos,
width: 180,
height: 30
});
}
return obstacles;
}, function () {
var obstacles = [];
for (var i = 0; i < 6; i++) {
obstacles.push({
x: 2048 + i * 400,
y: 700 + Math.cos(i * 0.9) * 900,
width: 300,
height: 30
});
}
return obstacles;
}, function () {
var obstacles = [];
for (var i = 0; i < 15; i++) {
if (i % 3 !== 0) {
// Skip every third to create gaps
obstacles.push({
x: 2048 + i * 200,
y: 500 + i % 5 * 400,
width: 150,
height: 30
});
}
}
return obstacles;
}, function () {
var obstacles = [];
var zigzag = true;
for (var i = 0; i < 12; i++) {
var yPos = zigzag ? 600 + i % 3 * 700 : 2100 - i % 3 * 700;
obstacles.push({
x: 2048 + i * 230,
y: yPos,
width: 150,
height: 30
});
if (i % 3 === 2) {
zigzag = !zigzag;
}
}
return obstacles;
}, function () {
var obstacles = [];
for (var i = 0; i < 20; i++) {
// Create a spiral pattern
var angle = i * 0.3;
var radius = 500 + i * 30;
var yPos = 1366 + Math.sin(angle) * (radius / 3);
obstacles.push({
x: 2048 + i * 200,
y: yPos,
width: 120,
height: 30
});
}
return obstacles;
},
// Level 21-25: Advanced patterns
function () {
var obstacles = [];
// Create a wave pattern
for (var i = 0; i < 15; i++) {
obstacles.push({
x: 2048 + i * 180,
y: 1366 + Math.sin(i * 0.5) * 800,
width: 100,
height: 30
});
}
return obstacles;
}, function () {
var obstacles = [];
// Create a double helix pattern
for (var i = 0; i < 20; i++) {
obstacles.push({
x: 2048 + i * 150,
y: 1366 + Math.sin(i * 0.4) * 700,
width: 90,
height: 30
});
obstacles.push({
x: 2048 + i * 150,
y: 1366 + Math.sin(i * 0.4 + Math.PI) * 700,
width: 90,
height: 30
});
}
return obstacles;
}, function () {
var obstacles = [];
// Create random clusters
for (var i = 0; i < 5; i++) {
var clusterX = 2048 + i * 500;
for (var j = 0; j < 4; j++) {
obstacles.push({
x: clusterX + (Math.random() * 200 - 100),
y: 600 + j * 500 + (Math.random() * 200 - 100),
width: 120,
height: 30
});
}
}
return obstacles;
}, function () {
var obstacles = [];
// Create a pulsating pattern
for (var i = 0; i < 15; i++) {
var width = 100 + Math.sin(i * 0.4) * 50;
obstacles.push({
x: 2048 + i * 200,
y: 600 + i % 4 * 500,
width: width,
height: 30
});
}
return obstacles;
}, function () {
var obstacles = [];
// Create a moving wall with small openings
for (var i = 0; i < 30; i++) {
if (i % 5 !== 2) {
// Create openings
obstacles.push({
x: 2048 + Math.floor(i / 5) * 400,
y: 300 + i * 80,
width: 200,
height: 30
});
}
}
return obstacles;
},
// Level 26-30: Expert challenges
function () {
var obstacles = [];
// Create a tight slalom
for (var i = 0; i < 12; i++) {
var yOffset = i % 2 === 0 ? 1000 : -1000;
obstacles.push({
x: 2048 + i * 250,
y: 1366 + yOffset,
width: 1500,
height: 30
});
}
return obstacles;
}, function () {
var obstacles = [];
// Create a tunnel that gets progressively narrower
var tunnelWidth = 1000;
for (var i = 0; i < 10; i++) {
tunnelWidth = Math.max(300, tunnelWidth - 70);
var halfTunnel = tunnelWidth / 2;
obstacles.push({
x: 2048 + i * 300,
y: 1366 - halfTunnel - 30,
width: 200,
height: 30
});
obstacles.push({
x: 2048 + i * 300,
y: 1366 + halfTunnel,
width: 200,
height: 30
});
}
return obstacles;
}, function () {
var obstacles = [];
// Create moving blocks that require precise timing
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 5; j++) {
if ((i + j) % 2 === 0) {
obstacles.push({
x: 2048 + i * 350,
y: 400 + j * 500,
width: 150,
height: 30
});
}
}
}
return obstacles;
}, function () {
var obstacles = [];
// Create a complex maze-like pattern
var positions = [[0, 1, 1, 0, 1], [1, 0, 1, 0, 1], [1, 0, 0, 0, 1], [1, 0, 1, 1, 1], [1, 0, 0, 0, 0], [1, 1, 1, 1, 0]];
for (var i = 0; i < positions.length; i++) {
for (var j = 0; j < positions[i].length; j++) {
if (positions[i][j] === 1) {
obstacles.push({
x: 2048 + i * 300,
y: 500 + j * 400,
width: 220,
height: 30
});
}
}
}
return obstacles;
}, function () {
var obstacles = [];
// The final challenge - all techniques combined
// Wave pattern
for (var i = 0; i < 5; i++) {
obstacles.push({
x: 2048 + i * 300,
y: 1366 + Math.sin(i * 0.8) * 600,
width: 180,
height: 30
});
}
// Tight slalom
for (var i = 0; i < 3; i++) {
var yOffset = i % 2 === 0 ? 800 : -800;
obstacles.push({
x: 2048 + 1500 + i * 250,
y: 1366 + yOffset,
width: 1200,
height: 30
});
}
// Final gauntlet
for (var i = 0; i < 5; i++) {
if (i !== 2) {
// Gap in the middle
obstacles.push({
x: 2048 + 2500,
y: 400 + i * 500,
width: 100,
height: 30
});
}
}
return obstacles;
}];
// Initialize UI elements
var scoreTxt = new Text2('Level: 1/' + totalLevels, {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var instructionsTxt = new Text2('Make noise to rise\nStay quiet to fall', {
size: 60,
fill: 0xFFFFFF
});
instructionsTxt.anchor.set(0.5, 0);
instructionsTxt.y = 100;
LK.gui.top.addChild(instructionsTxt);
// Volume indicator
volumeIndicator = new Container();
var volumeBarBg = LK.getAsset('wall', {
anchorX: 0,
anchorY: 0.5,
width: 50,
height: 400,
tint: 0x000000,
alpha: 0.3
});
volumeIndicator.addChild(volumeBarBg);
var volumeBar = LK.getAsset('wall', {
anchorX: 0,
anchorY: 1,
width: 50,
height: 0,
tint: 0x3498db
});
volumeIndicator.addChild(volumeBar);
volumeIndicator.x = 150;
volumeIndicator.y = 1366; // Center of screen height
LK.gui.addChild(volumeIndicator);
// Level indicator
levelIndicator = new LevelIndicator();
levelIndicator.x = 120;
levelIndicator.y = 120;
LK.gui.addChild(levelIndicator);
levelIndicator.setLevel(currentLevel);
// Initialize the player
player = new Player();
player.x = 400;
player.y = 1366; // Center of screen height
game.addChild(player);
// Set up the first level
setupLevel(currentLevel);
// Play background music
LK.playMusic('bgMusic', {
fade: {
start: 0,
end: 0.3,
duration: 1000
}
});
// Main update function
game.update = function () {
// Update volume history for smoother response
volumeHistory.push(facekit.volume);
if (volumeHistory.length > 5) {
volumeHistory.shift();
}
// Calculate average volume
var avgVolume = 0;
for (var i = 0; i < volumeHistory.length; i++) {
avgVolume += volumeHistory[i];
}
avgVolume /= volumeHistory.length;
// Update volume indicator
volumeBar.height = avgVolume * 400;
volumeBar.tint = avgVolume < 0.3 ? 0x3498db : avgVolume < 0.7 ? 0xf39c12 : 0xe74c3c;
// Only update gameplay if the game is active
if (gameActive && !levelCompleted) {
// Update all walls
for (var i = walls.length - 1; i >= 0; i--) {
var removed = walls[i].update();
if (removed) {
walls.splice(i, 1);
}
}
// Check if goal is reached or destroyed
if (goal) {
var goalRemoved = goal.update();
if (goalRemoved) {
goal = null;
} else if (player.intersects(goal)) {
levelCompleted = true;
completeLevel();
}
}
// Check collisions with walls
var collision = false;
for (var i = 0; i < walls.length; i++) {
if (player.intersects(walls[i])) {
collision = true;
break;
}
}
if (collision) {
gameOver();
}
// Calculate spawn timing based on level
if (LK.ticks % Math.max(120 - currentLevel * 2, 30) === 0 && walls.length < 40) {
spawnObstacles();
}
// Spawn goal after certain time
if (LK.ticks % 600 === 0 && !goal) {
spawnGoal();
}
}
// Hide instructions after 3 seconds
if (LK.ticks === 180) {
tween(instructionsTxt, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut
});
}
};
// Setup a new level
function setupLevel(level) {
// Ensure level is in bounds
level = Math.max(1, Math.min(level, totalLevels));
currentLevel = level;
// Update storage
storage.currentLevel = currentLevel;
if (currentLevel > highestLevel) {
highestLevel = currentLevel;
storage.highestLevel = highestLevel;
}
// Update score text
scoreTxt.setText('Level: ' + currentLevel + '/' + totalLevels);
// Update level indicator
levelIndicator.setLevel(currentLevel);
// Reset game state
walls = [];
if (goal) {
goal.destroy();
goal = null;
}
levelCompleted = false;
// Reset player position
player.reset(400, 1366);
// Set wall speed based on level
Wall.prototype.speed = -5 - currentLevel * 0.2;
if (goal) {
goal.speed = Wall.prototype.speed;
}
// Start game after a short delay
LK.setTimeout(function () {
gameActive = true;
}, 1000);
}
// Spawn obstacles based on the current level
function spawnObstacles() {
// Get the appropriate pattern generator for the current level
var patternIndex = Math.min(currentLevel - 1, obstaclePatterns.length - 1);
var obstacles = obstaclePatterns[patternIndex]();
// Create wall objects
for (var i = 0; i < obstacles.length; i++) {
var wall = new Wall();
wall.x = obstacles[i].x;
wall.y = obstacles[i].y;
wall.setProperties(obstacles[i].width, obstacles[i].height, 0xe74c3c);
walls.push(wall);
game.addChild(wall);
}
}
// Spawn the level goal
function spawnGoal() {
goal = new Goal();
goal.x = 2048 + 200; // Start off screen
goal.y = 1366; // Center of screen height
goal.speed = Wall.prototype.speed; // Match wall speed
game.addChild(goal);
}
// Handle level completion
function completeLevel() {
gameActive = false;
// Play sound
LK.getSound('levelComplete').play();
// Animate player
tween(player, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeIn
});
}
});
// Show level complete message
var levelCompleteTxt = new Text2('Level ' + currentLevel + ' Complete!', {
size: 120,
fill: 0xFFFFFF
});
levelCompleteTxt.anchor.set(0.5, 0.5);
levelCompleteTxt.x = 1024;
levelCompleteTxt.y = 1366;
levelCompleteTxt.alpha = 0;
LK.gui.addChild(levelCompleteTxt);
tween(levelCompleteTxt, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(levelCompleteTxt, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
levelCompleteTxt.destroy();
// Check if the player has completed all levels
if (currentLevel === totalLevels) {
// Game completed!
var gameCompleteTxt = new Text2('Congratulations!\nYou completed all levels!', {
size: 100,
fill: 0xFFFFFF
});
gameCompleteTxt.anchor.set(0.5, 0.5);
gameCompleteTxt.x = 1024;
gameCompleteTxt.y = 1366;
LK.gui.addChild(gameCompleteTxt);
LK.setTimeout(function () {
gameCompleteTxt.destroy();
currentLevel = 1;
setupLevel(currentLevel);
}, 3000);
} else {
// Next level
setupLevel(currentLevel + 1);
}
}
});
}
});
}
// Handle game over
function gameOver() {
gameActive = false;
// Play sound
LK.getSound('gameOver').play();
// Animate player
player.canMove = false;
tween(player, {
alpha: 0.3
}, {
duration: 500,
easing: tween.easeOut
});
// Show game over message
var gameOverTxt = new Text2('Level Failed', {
size: 120,
fill: 0xFFFFFF
});
gameOverTxt.anchor.set(0.5, 0.5);
gameOverTxt.x = 1024;
gameOverTxt.y = 1366;
gameOverTxt.alpha = 0;
LK.gui.addChild(gameOverTxt);
tween(gameOverTxt, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(gameOverTxt, {
alpha: 0
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
gameOverTxt.destroy();
setupLevel(currentLevel);
}
});
}, 1500);
}
});
// Screen flash
LK.effects.flashScreen(0xe74c3c, 500);
}