/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	highScore: 0,
	bestCombo: 0
});
/**** 
* Classes
****/ 
var Ball = Container.expand(function () {
	var self = Container.call(this);
	var ballGraphics = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1,
		scaleY: 1
	});
	self.currentLane = 1; // 0=left, 1=center, 2=right
	self.targetY = 0;
	self.bounceHeight = 60;
	self.bounceSpeed = 0.05;
	self.bounceTime = 0;
	self.hasSpeedBoost = false;
	self.hasSlowMotion = false;
	self.doubleScoreActive = false;
	self.effectTimer = 0;
	self.moveTo = function (laneIndex) {
		if (laneIndex < 0 || laneIndex > 2) {
			return;
		}
		// Don't move if already in this lane
		if (self.currentLane === laneIndex) {
			return;
		}
		self.currentLane = laneIndex;
		var targetX = lanePositions[laneIndex];
		// Animate the movement
		tween(self, {
			x: targetX
		}, {
			duration: 150,
			easing: tween.easeOut
		});
	};
	self.activatePowerup = function (type) {
		switch (type) {
			case 'speed':
				self.hasSpeedBoost = true;
				self.effectTimer = 300; // 5 seconds at 60fps
				tween(ballGraphics, {
					tint: 0xFFFF00
				}, {
					duration: 200
				});
				break;
			case 'double':
				self.doubleScoreActive = true;
				self.effectTimer = 300;
				tween(ballGraphics, {
					tint: 0x00FF00
				}, {
					duration: 200
				});
				break;
			case 'slow':
				self.hasSlowMotion = true;
				self.effectTimer = 300;
				tween(ballGraphics, {
					tint: 0x9900FF
				}, {
					duration: 200
				});
				break;
		}
	};
	self.update = function () {
		// Update bounce animation
		self.bounceTime += self.bounceSpeed * (self.hasSpeedBoost ? 1.5 : self.hasSlowMotion ? 0.5 : 1);
		var bounceOffset = Math.sin(self.bounceTime) * self.bounceHeight;
		self.y = self.targetY - bounceOffset;
		// Update powerup timers
		if (self.effectTimer > 0) {
			self.effectTimer--;
			if (self.effectTimer === 0) {
				// Reset effects
				self.hasSpeedBoost = false;
				self.hasSlowMotion = false;
				self.doubleScoreActive = false;
				tween(ballGraphics, {
					tint: 0xFFFFFF
				}, {
					duration: 200
				});
			}
		}
	};
	return self;
});
var BeatTile = Container.expand(function () {
	var self = Container.call(this);
	var tileGraphics = self.attachAsset('beatTile', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.lane = 0;
	self.active = true;
	self.speed = 5;
	self.hit = false;
	self.update = function () {
		if (!self.active) {
			return;
		}
		self.y += self.speed * (ball.hasSpeedBoost ? 1.5 : ball.hasSlowMotion ? 0.5 : 1);
		// Check if the tile has gone too far off-screen
		if (self.y > 2732 + tileGraphics.height) {
			self.active = false;
		}
	};
	self.checkHit = function () {
		if (!self.active || self.hit) {
			return false;
		}
		// Check if ball is in the same lane and close enough in Y position
		if (self.lane === ball.currentLane) {
			var distance = Math.abs(self.y - ball.y);
			if (distance < 80) {
				self.hit = true;
				self.active = false;
				// Animate hit
				tween(tileGraphics, {
					alpha: 0,
					scaleX: 1.5,
					scaleY: 1.5
				}, {
					duration: 300,
					easing: tween.easeOut
				});
				return true;
			}
		}
		return false;
	};
	self.showMissedIndicator = function () {
		var missedIndicator = LK.getAsset('missedTile', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: self.x,
			y: self.y,
			alpha: 0.7
		});
		game.addChild(missedIndicator);
		tween(missedIndicator, {
			alpha: 0,
			scaleX: 1.3,
			scaleY: 1.3
		}, {
			duration: 500,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				missedIndicator.destroy();
			}
		});
	};
	return self;
});
var Powerup = Container.expand(function () {
	var self = Container.call(this);
	self.type = 'speed';
	self.active = true;
	self.speed = 5;
	self.lane = 0;
	self.initialize = function (powerupType) {
		self.type = powerupType;
		// Different asset based on type
		var assetId;
		switch (powerupType) {
			case 'speed':
				assetId = 'powerupSpeed';
				break;
			case 'double':
				assetId = 'powerupDouble';
				break;
			case 'slow':
				assetId = 'powerupSlow';
				break;
			default:
				assetId = 'powerupSpeed';
		}
		self.graphic = self.attachAsset(assetId, {
			anchorX: 0.5,
			anchorY: 0.5
		});
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		self.y += self.speed * (ball.hasSpeedBoost ? 1.5 : ball.hasSlowMotion ? 0.5 : 1);
		self.rotation += 0.03;
		// Check if collected
		if (self.lane === ball.currentLane && Math.abs(self.y - ball.y) < 70) {
			self.collect();
			return;
		}
		// Check if gone off-screen
		if (self.y > 2732 + 60) {
			self.active = false;
		}
	};
	self.collect = function () {
		self.active = false;
		// Animate collection
		tween(self, {
			alpha: 0,
			scaleX: 1.5,
			scaleY: 1.5
		}, {
			duration: 300,
			easing: tween.easeOut
		});
		// Play powerup collect sound
		LK.getSound('powerupCollect').play();
		// Create explosion effect
		var explosion = LK.getAsset('explosion', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: self.x,
			y: self.y
		});
		game.addChild(explosion);
		tween(explosion, {
			alpha: 0,
			scaleX: 2,
			scaleY: 2
		}, {
			duration: 500,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				explosion.destroy();
			}
		});
		// Apply effect
		ball.activatePowerup(self.type);
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x111133
});
/**** 
* Game Code
****/ 
// Game constants
// Add background image asset
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var lanePositions = [GAME_WIDTH / 4, GAME_WIDTH / 2, 3 * GAME_WIDTH / 4];
var beatGenerationSpeed = 90; // frames between beat tiles
var powerupChance = 0.15; // probability of a powerup spawning
var difficultyIncreaseRate = 0.0001; // how fast the game speeds up
// Game state
var beatTimer = 0;
var score = 0;
var combo = 0;
var highestCombo = 0;
var gameSpeed = 1;
var tiles = [];
var powerups = [];
var ball;
var scoreText;
var comboText;
var highScoreText;
// Set up game background
var background = LK.getAsset('background', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: GAME_WIDTH / 2,
	y: GAME_HEIGHT / 2
});
game.addChild(background);
// Create lane indicators
for (var i = 0; i < 3; i++) {
	var lane = LK.getAsset('lane', {
		anchorX: 0.5,
		anchorY: 0,
		x: lanePositions[i],
		y: 0,
		alpha: 0.3
	});
	game.addChild(lane);
}
// Set up game UI
scoreText = new Text2('Score: 0', {
	size: 80,
	fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topLeft.addChild(scoreText);
scoreText.x = 120; // Avoid the top-left 100x100 area
scoreText.y = 20;
comboText = new Text2('Combo: 0', {
	size: 80,
	fill: 0xFFFFFF
});
comboText.anchor.set(0, 0);
LK.gui.topLeft.addChild(comboText);
comboText.x = 120;
comboText.y = 110;
// High score display
highScoreText = new Text2('High Score: ' + storage.highScore, {
	size: 60,
	fill: 0xFFCC00
});
highScoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(highScoreText);
highScoreText.x = -20;
highScoreText.y = 20;
// Create player ball
ball = new Ball();
ball.x = lanePositions[1]; // Start in middle lane
ball.y = GAME_HEIGHT - 400; // Position near bottom
ball.targetY = ball.y;
game.addChild(ball);
// Start with some beat tiles
generateInitialTiles();
// Start music
LK.playMusic('gameMusic', {
	fade: {
		start: 0,
		end: 0.8,
		duration: 1000
	}
});
// Touch controls
function handleTouch(x, y) {
	// Determine which third of the screen was tapped
	if (x < GAME_WIDTH / 3) {
		ball.moveTo(0); // Left lane
	} else if (x < 2 * GAME_WIDTH / 3) {
		ball.moveTo(1); // Middle lane
	} else {
		ball.moveTo(2); // Right lane
	}
}
game.down = function (x, y, obj) {
	handleTouch(x, y);
};
function generateBeatTile() {
	var lane = Math.floor(Math.random() * 3);
	var tile = new BeatTile();
	tile.x = lanePositions[lane];
	tile.y = -100; // Start above the screen
	tile.lane = lane;
	tile.speed *= gameSpeed;
	game.addChild(tile);
	tiles.push(tile);
	// Sometimes spawn a powerup
	if (Math.random() < powerupChance) {
		generatePowerup(lane);
	}
}
function generatePowerup(lane) {
	var powerupTypes = ['speed', 'double', 'slow'];
	var type = powerupTypes[Math.floor(Math.random() * powerupTypes.length)];
	var powerup = new Powerup();
	powerup.initialize(type);
	powerup.x = lanePositions[lane];
	powerup.y = -200; // Start above the screen
	powerup.lane = lane;
	powerup.speed *= gameSpeed;
	game.addChild(powerup);
	powerups.push(powerup);
}
function generateInitialTiles() {
	// Create a few initial tiles to get started
	for (var i = 0; i < 5; i++) {
		var lane = Math.floor(Math.random() * 3);
		var tile = new BeatTile();
		tile.x = lanePositions[lane];
		tile.y = -100 - i * 400; // Stagger them
		tile.lane = lane;
		tile.speed *= gameSpeed;
		game.addChild(tile);
		tiles.push(tile);
	}
}
function updateScore(points) {
	var pointsToAdd = points;
	// Apply combo multiplier (starting from 1)
	if (combo > 0) {
		pointsToAdd = Math.floor(points * (1 + combo * 0.1));
	}
	// Apply double score powerup
	if (ball.doubleScoreActive) {
		pointsToAdd *= 2;
	}
	score += pointsToAdd;
	scoreText.setText('Score: ' + score);
	// Show score popup
	var scorePopup = new Text2('+' + pointsToAdd, {
		size: 70,
		fill: 0xFFFF00
	});
	scorePopup.anchor.set(0.5, 0.5);
	scorePopup.x = ball.x;
	scorePopup.y = ball.y - 100;
	game.addChild(scorePopup);
	tween(scorePopup, {
		alpha: 0,
		y: scorePopup.y - 100
	}, {
		duration: 800,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			scorePopup.destroy();
		}
	});
}
game.update = function () {
	// Update game speed
	gameSpeed += difficultyIncreaseRate;
	// Generate new beat tiles
	beatTimer++;
	if (beatTimer >= beatGenerationSpeed) {
		beatTimer = 0;
		generateBeatTile();
		// Slightly decrease time between beats as game progresses
		beatGenerationSpeed = Math.max(40, beatGenerationSpeed - 0.1);
	}
	// Update all game objects
	for (var i = tiles.length - 1; i >= 0; i--) {
		var tile = tiles[i];
		tile.update();
		// Check for hits
		if (tile.active && !tile.hit && tile.checkHit()) {
			// Increase combo
			combo++;
			if (combo > highestCombo) {
				highestCombo = combo;
			}
			comboText.setText("Combo: " + combo);
			// Play tile hit sound
			LK.getSound('tileHit').play();
			// Update score
			updateScore(10);
		}
		// Clean up inactive tiles
		if (!tile.active) {
			tiles.splice(i, 1);
		}
	}
	// Update powerups
	for (var j = powerups.length - 1; j >= 0; j--) {
		var powerup = powerups[j];
		powerup.update();
		if (!powerup.active) {
			powerups.splice(j, 1);
		}
	}
	// Update player
	ball.update();
	// Check for game over
	if (score > 1000) {
		// Save high score
		if (score > storage.highScore) {
			storage.highScore = score;
		}
		// Save best combo
		if (highestCombo > storage.bestCombo) {
			storage.bestCombo = highestCombo;
		}
		LK.showYouWin();
	}
	// Play comboBreak sound if combo is reset
	if (combo === 0 && highestCombo > 0) {
		LK.getSound('comboBreak').play();
	}
	// Play beatMiss sound if a tile is missed
	for (var i = tiles.length - 1; i >= 0; i--) {
		var tile = tiles[i];
		if (!tile.active && !tile.hit) {
			LK.getSound('beatMiss').play();
		}
	}
};
// Clean up function if game is destroyed
game.destroy = function () {
	// Stop any tweens
	for (var i = 0; i < tiles.length; i++) {
		tween.stop(tiles[i]);
	}
	for (var j = 0; j < powerups.length; j++) {
		tween.stop(powerups[j]);
	}
	tween.stop(ball);
	// Stop music
	LK.stopMusic();
}; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	highScore: 0,
	bestCombo: 0
});
/**** 
* Classes
****/ 
var Ball = Container.expand(function () {
	var self = Container.call(this);
	var ballGraphics = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1,
		scaleY: 1
	});
	self.currentLane = 1; // 0=left, 1=center, 2=right
	self.targetY = 0;
	self.bounceHeight = 60;
	self.bounceSpeed = 0.05;
	self.bounceTime = 0;
	self.hasSpeedBoost = false;
	self.hasSlowMotion = false;
	self.doubleScoreActive = false;
	self.effectTimer = 0;
	self.moveTo = function (laneIndex) {
		if (laneIndex < 0 || laneIndex > 2) {
			return;
		}
		// Don't move if already in this lane
		if (self.currentLane === laneIndex) {
			return;
		}
		self.currentLane = laneIndex;
		var targetX = lanePositions[laneIndex];
		// Animate the movement
		tween(self, {
			x: targetX
		}, {
			duration: 150,
			easing: tween.easeOut
		});
	};
	self.activatePowerup = function (type) {
		switch (type) {
			case 'speed':
				self.hasSpeedBoost = true;
				self.effectTimer = 300; // 5 seconds at 60fps
				tween(ballGraphics, {
					tint: 0xFFFF00
				}, {
					duration: 200
				});
				break;
			case 'double':
				self.doubleScoreActive = true;
				self.effectTimer = 300;
				tween(ballGraphics, {
					tint: 0x00FF00
				}, {
					duration: 200
				});
				break;
			case 'slow':
				self.hasSlowMotion = true;
				self.effectTimer = 300;
				tween(ballGraphics, {
					tint: 0x9900FF
				}, {
					duration: 200
				});
				break;
		}
	};
	self.update = function () {
		// Update bounce animation
		self.bounceTime += self.bounceSpeed * (self.hasSpeedBoost ? 1.5 : self.hasSlowMotion ? 0.5 : 1);
		var bounceOffset = Math.sin(self.bounceTime) * self.bounceHeight;
		self.y = self.targetY - bounceOffset;
		// Update powerup timers
		if (self.effectTimer > 0) {
			self.effectTimer--;
			if (self.effectTimer === 0) {
				// Reset effects
				self.hasSpeedBoost = false;
				self.hasSlowMotion = false;
				self.doubleScoreActive = false;
				tween(ballGraphics, {
					tint: 0xFFFFFF
				}, {
					duration: 200
				});
			}
		}
	};
	return self;
});
var BeatTile = Container.expand(function () {
	var self = Container.call(this);
	var tileGraphics = self.attachAsset('beatTile', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.lane = 0;
	self.active = true;
	self.speed = 5;
	self.hit = false;
	self.update = function () {
		if (!self.active) {
			return;
		}
		self.y += self.speed * (ball.hasSpeedBoost ? 1.5 : ball.hasSlowMotion ? 0.5 : 1);
		// Check if the tile has gone too far off-screen
		if (self.y > 2732 + tileGraphics.height) {
			self.active = false;
		}
	};
	self.checkHit = function () {
		if (!self.active || self.hit) {
			return false;
		}
		// Check if ball is in the same lane and close enough in Y position
		if (self.lane === ball.currentLane) {
			var distance = Math.abs(self.y - ball.y);
			if (distance < 80) {
				self.hit = true;
				self.active = false;
				// Animate hit
				tween(tileGraphics, {
					alpha: 0,
					scaleX: 1.5,
					scaleY: 1.5
				}, {
					duration: 300,
					easing: tween.easeOut
				});
				return true;
			}
		}
		return false;
	};
	self.showMissedIndicator = function () {
		var missedIndicator = LK.getAsset('missedTile', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: self.x,
			y: self.y,
			alpha: 0.7
		});
		game.addChild(missedIndicator);
		tween(missedIndicator, {
			alpha: 0,
			scaleX: 1.3,
			scaleY: 1.3
		}, {
			duration: 500,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				missedIndicator.destroy();
			}
		});
	};
	return self;
});
var Powerup = Container.expand(function () {
	var self = Container.call(this);
	self.type = 'speed';
	self.active = true;
	self.speed = 5;
	self.lane = 0;
	self.initialize = function (powerupType) {
		self.type = powerupType;
		// Different asset based on type
		var assetId;
		switch (powerupType) {
			case 'speed':
				assetId = 'powerupSpeed';
				break;
			case 'double':
				assetId = 'powerupDouble';
				break;
			case 'slow':
				assetId = 'powerupSlow';
				break;
			default:
				assetId = 'powerupSpeed';
		}
		self.graphic = self.attachAsset(assetId, {
			anchorX: 0.5,
			anchorY: 0.5
		});
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		self.y += self.speed * (ball.hasSpeedBoost ? 1.5 : ball.hasSlowMotion ? 0.5 : 1);
		self.rotation += 0.03;
		// Check if collected
		if (self.lane === ball.currentLane && Math.abs(self.y - ball.y) < 70) {
			self.collect();
			return;
		}
		// Check if gone off-screen
		if (self.y > 2732 + 60) {
			self.active = false;
		}
	};
	self.collect = function () {
		self.active = false;
		// Animate collection
		tween(self, {
			alpha: 0,
			scaleX: 1.5,
			scaleY: 1.5
		}, {
			duration: 300,
			easing: tween.easeOut
		});
		// Play powerup collect sound
		LK.getSound('powerupCollect').play();
		// Create explosion effect
		var explosion = LK.getAsset('explosion', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: self.x,
			y: self.y
		});
		game.addChild(explosion);
		tween(explosion, {
			alpha: 0,
			scaleX: 2,
			scaleY: 2
		}, {
			duration: 500,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				explosion.destroy();
			}
		});
		// Apply effect
		ball.activatePowerup(self.type);
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x111133
});
/**** 
* Game Code
****/ 
// Game constants
// Add background image asset
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var lanePositions = [GAME_WIDTH / 4, GAME_WIDTH / 2, 3 * GAME_WIDTH / 4];
var beatGenerationSpeed = 90; // frames between beat tiles
var powerupChance = 0.15; // probability of a powerup spawning
var difficultyIncreaseRate = 0.0001; // how fast the game speeds up
// Game state
var beatTimer = 0;
var score = 0;
var combo = 0;
var highestCombo = 0;
var gameSpeed = 1;
var tiles = [];
var powerups = [];
var ball;
var scoreText;
var comboText;
var highScoreText;
// Set up game background
var background = LK.getAsset('background', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: GAME_WIDTH / 2,
	y: GAME_HEIGHT / 2
});
game.addChild(background);
// Create lane indicators
for (var i = 0; i < 3; i++) {
	var lane = LK.getAsset('lane', {
		anchorX: 0.5,
		anchorY: 0,
		x: lanePositions[i],
		y: 0,
		alpha: 0.3
	});
	game.addChild(lane);
}
// Set up game UI
scoreText = new Text2('Score: 0', {
	size: 80,
	fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topLeft.addChild(scoreText);
scoreText.x = 120; // Avoid the top-left 100x100 area
scoreText.y = 20;
comboText = new Text2('Combo: 0', {
	size: 80,
	fill: 0xFFFFFF
});
comboText.anchor.set(0, 0);
LK.gui.topLeft.addChild(comboText);
comboText.x = 120;
comboText.y = 110;
// High score display
highScoreText = new Text2('High Score: ' + storage.highScore, {
	size: 60,
	fill: 0xFFCC00
});
highScoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(highScoreText);
highScoreText.x = -20;
highScoreText.y = 20;
// Create player ball
ball = new Ball();
ball.x = lanePositions[1]; // Start in middle lane
ball.y = GAME_HEIGHT - 400; // Position near bottom
ball.targetY = ball.y;
game.addChild(ball);
// Start with some beat tiles
generateInitialTiles();
// Start music
LK.playMusic('gameMusic', {
	fade: {
		start: 0,
		end: 0.8,
		duration: 1000
	}
});
// Touch controls
function handleTouch(x, y) {
	// Determine which third of the screen was tapped
	if (x < GAME_WIDTH / 3) {
		ball.moveTo(0); // Left lane
	} else if (x < 2 * GAME_WIDTH / 3) {
		ball.moveTo(1); // Middle lane
	} else {
		ball.moveTo(2); // Right lane
	}
}
game.down = function (x, y, obj) {
	handleTouch(x, y);
};
function generateBeatTile() {
	var lane = Math.floor(Math.random() * 3);
	var tile = new BeatTile();
	tile.x = lanePositions[lane];
	tile.y = -100; // Start above the screen
	tile.lane = lane;
	tile.speed *= gameSpeed;
	game.addChild(tile);
	tiles.push(tile);
	// Sometimes spawn a powerup
	if (Math.random() < powerupChance) {
		generatePowerup(lane);
	}
}
function generatePowerup(lane) {
	var powerupTypes = ['speed', 'double', 'slow'];
	var type = powerupTypes[Math.floor(Math.random() * powerupTypes.length)];
	var powerup = new Powerup();
	powerup.initialize(type);
	powerup.x = lanePositions[lane];
	powerup.y = -200; // Start above the screen
	powerup.lane = lane;
	powerup.speed *= gameSpeed;
	game.addChild(powerup);
	powerups.push(powerup);
}
function generateInitialTiles() {
	// Create a few initial tiles to get started
	for (var i = 0; i < 5; i++) {
		var lane = Math.floor(Math.random() * 3);
		var tile = new BeatTile();
		tile.x = lanePositions[lane];
		tile.y = -100 - i * 400; // Stagger them
		tile.lane = lane;
		tile.speed *= gameSpeed;
		game.addChild(tile);
		tiles.push(tile);
	}
}
function updateScore(points) {
	var pointsToAdd = points;
	// Apply combo multiplier (starting from 1)
	if (combo > 0) {
		pointsToAdd = Math.floor(points * (1 + combo * 0.1));
	}
	// Apply double score powerup
	if (ball.doubleScoreActive) {
		pointsToAdd *= 2;
	}
	score += pointsToAdd;
	scoreText.setText('Score: ' + score);
	// Show score popup
	var scorePopup = new Text2('+' + pointsToAdd, {
		size: 70,
		fill: 0xFFFF00
	});
	scorePopup.anchor.set(0.5, 0.5);
	scorePopup.x = ball.x;
	scorePopup.y = ball.y - 100;
	game.addChild(scorePopup);
	tween(scorePopup, {
		alpha: 0,
		y: scorePopup.y - 100
	}, {
		duration: 800,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			scorePopup.destroy();
		}
	});
}
game.update = function () {
	// Update game speed
	gameSpeed += difficultyIncreaseRate;
	// Generate new beat tiles
	beatTimer++;
	if (beatTimer >= beatGenerationSpeed) {
		beatTimer = 0;
		generateBeatTile();
		// Slightly decrease time between beats as game progresses
		beatGenerationSpeed = Math.max(40, beatGenerationSpeed - 0.1);
	}
	// Update all game objects
	for (var i = tiles.length - 1; i >= 0; i--) {
		var tile = tiles[i];
		tile.update();
		// Check for hits
		if (tile.active && !tile.hit && tile.checkHit()) {
			// Increase combo
			combo++;
			if (combo > highestCombo) {
				highestCombo = combo;
			}
			comboText.setText("Combo: " + combo);
			// Play tile hit sound
			LK.getSound('tileHit').play();
			// Update score
			updateScore(10);
		}
		// Clean up inactive tiles
		if (!tile.active) {
			tiles.splice(i, 1);
		}
	}
	// Update powerups
	for (var j = powerups.length - 1; j >= 0; j--) {
		var powerup = powerups[j];
		powerup.update();
		if (!powerup.active) {
			powerups.splice(j, 1);
		}
	}
	// Update player
	ball.update();
	// Check for game over
	if (score > 1000) {
		// Save high score
		if (score > storage.highScore) {
			storage.highScore = score;
		}
		// Save best combo
		if (highestCombo > storage.bestCombo) {
			storage.bestCombo = highestCombo;
		}
		LK.showYouWin();
	}
	// Play comboBreak sound if combo is reset
	if (combo === 0 && highestCombo > 0) {
		LK.getSound('comboBreak').play();
	}
	// Play beatMiss sound if a tile is missed
	for (var i = tiles.length - 1; i >= 0; i--) {
		var tile = tiles[i];
		if (!tile.active && !tile.hit) {
			LK.getSound('beatMiss').play();
		}
	}
};
// Clean up function if game is destroyed
game.destroy = function () {
	// Stop any tweens
	for (var i = 0; i < tiles.length; i++) {
		tween.stop(tiles[i]);
	}
	for (var j = 0; j < powerups.length; j++) {
		tween.stop(powerups[j]);
	}
	tween.stop(ball);
	// Stop music
	LK.stopMusic();
};
:quality(85)/https://cdn.frvr.ai/67e3e7ce0de700590fa36884.png%3F3) 
 Design: Square or circular glowing pads that react when hit. Effect: A pulse effect when the ball lands perfectly. Variations: Different colors per beat type (e.g., blue for normal, red for speed boosts).. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67e3f345f4509c053e8b3b40.png%3F3) 
 Design: A faded-out or cracked tile to indicate a miss. Effect: A quick screen shake or particle effect when touched.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67e3f387f4509c053e8b3b4d.png%3F3) 
 Design: A dynamic, glowing path that scrolls forward. Style Options: Cyberpunk neon rails Floating musical staff lines A galaxy wave track. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67e3f43ef4509c053e8b3b56.png%3F3) 
 PowerUpDouble ⭐ Golden glow tile Score x2 for 5 sec. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67e3f49ef4509c053e8b3b61.png%3F3) 
 PowerUpSlow ⏳ Blue time freeze tile Slows music briefly. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67e3f529f4509c053e8b3b6e.png%3F3) 
 PowerUpSpeed ⚡ Red speed trail tile Speeds up for bonus. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67ebba78b6f22e1325c614a5.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/685dfa51d1f4e958f8e2d21c.png%3F3)