/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Fruit: Apple (extra points)
var Apple = Container.expand(function () {
	var self = Container.call(this);
	var appleAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	appleAsset.tint = 0xff2222; // Red
	appleAsset.scaleX = 1.1;
	appleAsset.scaleY = 1.1;
	tween(appleAsset, {
		alpha: 0.85
	}, {
		duration: 350,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	var baseSpeed = 10 + Math.random() * 3;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseSpeed += Math.min(8, Math.floor(LK.getScore() / 12));
	}
	self.speed = baseSpeed;
	self.type = "apple";
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Ball class
var Ball = Container.expand(function () {
	var self = Container.call(this);
	var ballAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Neon color palette for balls
	var colors = [0x00ffff, 0xff00ff, 0xffff00, 0x00ff00, 0xff8800, 0x00ffea, 0xff0088];
	ballAsset.color = colors[Math.floor(Math.random() * colors.length)];
	ballAsset.tint = ballAsset.color;
	// Neon glow effect: animate alpha for a pulsing glow
	tween(ballAsset, {
		alpha: 0.7
	}, {
		duration: 400,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	// Adjusted for human reflexes: start slower, increase with score, cap max speed
	var baseSpeed = 10 + Math.random() * 4;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseSpeed += Math.min(10, Math.floor(LK.getScore() / 8)); // increase 1 per 8 points, max +10
	}
	self.speed = baseSpeed;
	self.vx = (Math.random() - 0.5) * 10; // random horizontal speed
	self.update = function () {
		self.y += self.speed;
		self.x += self.vx;
		// Bounce off left/right walls
		if (self.x < 60 && self.vx < 0) {
			self.x = 60;
			self.vx *= -1;
		}
		if (self.x > 2048 - 60 && self.vx > 0) {
			self.x = 2048 - 60;
			self.vx *= -1;
		}
	};
	return self;
});
// Fruit: Banana (wider catch area)
var Banana = Container.expand(function () {
	var self = Container.call(this);
	var bananaAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	bananaAsset.tint = 0xfff700; // Yellow
	bananaAsset.scaleX = 1.5;
	bananaAsset.scaleY = 0.8;
	tween(bananaAsset, {
		alpha: 0.8
	}, {
		duration: 400,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	var baseSpeed = 9 + Math.random() * 2;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseSpeed += Math.min(7, Math.floor(LK.getScore() / 14));
	}
	self.speed = baseSpeed;
	self.type = "banana";
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Basket class
var Basket = Container.expand(function () {
	var self = Container.call(this);
	var basketAsset = self.attachAsset('basket', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Neon basket: random neon color and glow
	var basketColors = [0x00ffff, 0xff00ff, 0xffff00, 0x00ff00, 0xff8800, 0x00ffea, 0xff0088];
	basketAsset.tint = basketColors[Math.floor(Math.random() * basketColors.length)];
	tween(basketAsset, {
		alpha: 0.7
	}, {
		duration: 600,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	return self;
});
// Bomb class
var Bomb = Container.expand(function () {
	var self = Container.call(this);
	var bombAsset = self.attachAsset('bomb', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Neon bomb: magenta or cyan
	var bombColors = [0xff00ff, 0x00ffff, 0xffff00];
	bombAsset.tint = bombColors[Math.floor(Math.random() * bombColors.length)];
	tween(bombAsset, {
		alpha: 0.6
	}, {
		duration: 400,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	// Adjusted for human reflexes: start slower, increase with score, cap max speed
	var baseBombSpeed = 12 + Math.random() * 5;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseBombSpeed += Math.min(12, Math.floor(LK.getScore() / 7)); // increase 1 per 7 points, max +12
	}
	self.speed = baseBombSpeed;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Fruit: Grape (slows bombs for a short time)
var Grape = Container.expand(function () {
	var self = Container.call(this);
	var grapeAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	grapeAsset.tint = 0x9900ff; // Purple
	grapeAsset.scaleX = 1.0;
	grapeAsset.scaleY = 1.0;
	tween(grapeAsset, {
		alpha: 0.7
	}, {
		duration: 300,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	var baseSpeed = 11 + Math.random() * 2;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseSpeed += Math.min(7, Math.floor(LK.getScore() / 13));
	}
	self.speed = baseSpeed;
	self.type = "grape";
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// PowerUp class (neon star)
var PowerUp = Container.expand(function () {
	var self = Container.call(this);
	// Use a ball asset for now, but tint and scale to look like a power-up
	var starAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Neon star color
	var starColors = [0xFFD700, 0x00ffea, 0xff00ff, 0x00ff00];
	starAsset.tint = starColors[Math.floor(Math.random() * starColors.length)];
	starAsset.scaleX = 1.3;
	starAsset.scaleY = 1.3;
	// Animate alpha for a pulsing glow
	tween(starAsset, {
		alpha: 0.8
	}, {
		duration: 300,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	// Adjusted for human reflexes: start slower, increase with score, cap max speed
	var basePowerSpeed = 9 + Math.random() * 3;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		basePowerSpeed += Math.min(8, Math.floor(LK.getScore() / 10)); // increase 1 per 10 points, max +8
	}
	self.speed = basePowerSpeed;
	self.type = "score"; // default type
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// ShieldPowerUp class (neon blue ring)
var ShieldPowerUp = Container.expand(function () {
	var self = Container.call(this);
	var shieldAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	shieldAsset.tint = 0x00ffff;
	shieldAsset.scaleX = 1.5;
	shieldAsset.scaleY = 1.5;
	tween(shieldAsset, {
		alpha: 0.6
	}, {
		duration: 200,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	// Adjusted for human reflexes: start slower, increase with score, cap max speed
	var baseShieldSpeed = 8 + Math.random() * 2;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseShieldSpeed += Math.min(7, Math.floor(LK.getScore() / 12)); // increase 1 per 12 points, max +7
	}
	self.speed = baseShieldSpeed;
	self.type = "shield";
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Fruit: Watermelon (big, gives shield)
var Watermelon = Container.expand(function () {
	var self = Container.call(this);
	var melonAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	melonAsset.tint = 0x22ff44; // Green
	melonAsset.scaleX = 1.7;
	melonAsset.scaleY = 1.3;
	tween(melonAsset, {
		alpha: 0.8
	}, {
		duration: 500,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	var baseSpeed = 8 + Math.random() * 2;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseSpeed += Math.min(6, Math.floor(LK.getScore() / 15));
	}
	self.speed = baseSpeed;
	self.type = "watermelon";
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/ 
// Sound for missing a ball
// Sound for catching a bomb
// Sound for catching a ball
// Bomb: black ellipse
// Ball: colored ellipse
// Basket: wide rectangle
// Game area: 2048x2732
// No background image, only black background
// No background image, only black background
game.setBackgroundColor(0x000000);
// Neon-style game objective text at the start (small, English, subtle neon)
var objectiveTxt = new Text2('Goal: Catch the balls, avoid the bombs!', {
	size: 54,
	// smaller text
	fill: 0x00ffff,
	stroke: 0x222222,
	strokeThickness: 8,
	dropShadow: true,
	dropShadowColor: 0x00ffff,
	dropShadowBlur: 12,
	dropShadowDistance: 0,
	align: "center"
});
objectiveTxt.anchor.set(0.5, 0);
objectiveTxt.y = 90;
LK.gui.top.addChild(objectiveTxt);
// Add leaderboard button for competition
var leaderboardBtn = new Text2('🏆 Leaderboard', {
	size: 60,
	fill: 0xFFD700,
	stroke: 0x00ffff,
	strokeThickness: 8,
	dropShadow: true,
	dropShadowColor: 0xFFD700,
	dropShadowBlur: 10,
	dropShadowDistance: 0,
	align: "center"
});
leaderboardBtn.anchor.set(0.5, 0);
leaderboardBtn.x = 2048 - 250;
leaderboardBtn.y = 90;
leaderboardBtn.interactive = true;
leaderboardBtn.buttonMode = true;
leaderboardBtn.down = function () {
	if (typeof LK.showLeaderboard === "function") {
		LK.showLeaderboard();
	}
};
LK.gui.top.addChild(leaderboardBtn);
// Hide objective after 2.5 seconds
LK.setTimeout(function () {
	objectiveTxt.visible = false;
}, 2500);
// Score text
var scoreTxt = new Text2('0', {
	size: 120,
	fill: 0x00FFEA,
	stroke: 0xFF00FF,
	strokeThickness: 18,
	dropShadow: true,
	dropShadowColor: 0x00FFFF,
	dropShadowBlur: 24,
	dropShadowDistance: 0,
	align: "center"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Health bar UI
var maxHealth = 3;
var health = maxHealth;
var healthBarWidth = 320;
var healthBarHeight = 38;
var healthBarBg = LK.getAsset('ball', {
	anchorX: 0,
	anchorY: 0.5,
	scaleX: healthBarWidth / 100,
	scaleY: healthBarHeight / 100,
	x: 120,
	y: 160
});
healthBarBg.tint = 0x222222;
LK.gui.top.addChild(healthBarBg);
var healthBar = LK.getAsset('ball', {
	anchorX: 0,
	anchorY: 0.5,
	scaleX: healthBarWidth / 100,
	scaleY: healthBarHeight / 100,
	x: 120,
	y: 160
});
healthBar.tint = 0x00ff00;
LK.gui.top.addChild(healthBar);
// Health icon hearts
var healthHearts = [];
for (var h = 0; h < maxHealth; h++) {
	var heart = LK.getAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.32,
		scaleY: 0.32,
		x: 120 + 40 + h * 54,
		y: 160
	});
	heart.tint = 0xff2222;
	LK.gui.top.addChild(heart);
	healthHearts.push(heart);
}
// Misses text (shows "Missed!" when a ball is missed)
var missTxt = new Text2('', {
	size: 90,
	fill: 0x00FFFF,
	stroke: 0xFF00FF,
	strokeThickness: 14,
	dropShadow: true,
	dropShadowColor: 0x00FFFF,
	dropShadowBlur: 18,
	dropShadowDistance: 0,
	align: "center"
});
missTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(missTxt);
missTxt.visible = false;
// Basket
var basket = new Basket();
game.addChild(basket);
basket.y = 2732 - 180;
basket.x = 2048 / 2;
// Ball, bomb, and power-up arrays
var balls = [];
var bombs = [];
var powerups = [];
// Dragging
var dragNode = null;
// Touch indicator for user-friendly feedback
var touchIndicator = LK.getAsset('ball', {
	anchorX: 0.5,
	anchorY: 0.5
});
touchIndicator.tint = 0xFFD700;
touchIndicator.scaleX = 0.4;
touchIndicator.scaleY = 0.4;
touchIndicator.alpha = 0;
game.addChild(touchIndicator);
// Spawning control
var spawnTimer = 0;
var spawnInterval = 55; // frames between spawns, will decrease as score increases
// State
var lastScore = 0;
var gameOver = false;
// Combo scoring
var comboCount = 0;
var comboTimeout = null;
var comboTxt = new Text2('', {
	size: 80,
	fill: 0xFFD700,
	stroke: 0x00ffff,
	strokeThickness: 10,
	dropShadow: true,
	dropShadowColor: 0xFFD700,
	dropShadowBlur: 12,
	dropShadowDistance: 0,
	align: "center"
});
comboTxt.anchor.set(0.5, 0);
comboTxt.y = 200;
comboTxt.visible = false;
LK.gui.top.addChild(comboTxt);
// Helper: spawn a ball, bomb, or power-up
function spawnFallingObject() {
	// 80% ball, 20% bomb, 5% power-up, 3% shield power-up, plus fruits
	var rand = Math.random();
	var x = 150 + Math.random() * (2048 - 300);
	if (rand < 0.10) {
		var bomb = new Bomb();
		bomb.x = x;
		bomb.y = -60;
		bomb.lastIntersecting = false;
		// Add "-" indicator for bomb
		var minusTxt = new Text2('-', {
			size: 70,
			fill: 0xff2222,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		minusTxt.anchor.set(0.5, 1);
		minusTxt.y = -60;
		bomb.addChild(minusTxt);
		bomb.indicatorTxt = minusTxt;
		bombs.push(bomb);
		game.addChild(bomb);
	} else if (rand < 0.13) {
		// 3% chance for super bomb
		var superBomb = new Bomb();
		superBomb.x = x;
		superBomb.y = -60;
		superBomb.lastIntersecting = false;
		superBomb.isSuper = true;
		if (superBomb.children && superBomb.children.length > 0) {
			superBomb.children[0].tint = 0xffffff;
		}
		// Add "-" indicator for super bomb
		var minusTxt = new Text2('-', {
			size: 70,
			fill: 0xff2222,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		minusTxt.anchor.set(0.5, 1);
		minusTxt.y = -60;
		superBomb.addChild(minusTxt);
		superBomb.indicatorTxt = minusTxt;
		bombs.push(superBomb);
		game.addChild(superBomb);
	} else if (rand > 0.98) {
		// 2% chance for slow motion power-up
		var slowPower = new PowerUp();
		slowPower.x = x;
		slowPower.y = -60;
		slowPower.lastIntersecting = false;
		slowPower.type = "slow";
		if (slowPower.children && slowPower.children.length > 0) {
			slowPower.children[0].tint = 0x3b6eea;
		}
		// Add "+" indicator for slow powerup
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0x00ffea,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		slowPower.addChild(plusTxt);
		slowPower.indicatorTxt = plusTxt;
		powerups.push(slowPower);
		game.addChild(slowPower);
	} else if (rand > 0.96) {
		// 4% chance for shield power-up
		var shield = new ShieldPowerUp();
		shield.x = x;
		shield.y = -60;
		shield.lastIntersecting = false;
		// Add "+" indicator for shield
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0x00ffff,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		shield.addChild(plusTxt);
		shield.indicatorTxt = plusTxt;
		powerups.push(shield);
		game.addChild(shield);
	} else if (rand > 0.94) {
		// 2% chance for score power-up
		var powerup = new PowerUp();
		powerup.x = x;
		powerup.y = -60;
		powerup.lastIntersecting = false;
		// Add "+" indicator for score powerup
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0xFFD700,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		powerup.addChild(plusTxt);
		powerup.indicatorTxt = plusTxt;
		powerups.push(powerup);
		game.addChild(powerup);
	} else if (rand > 0.92) {
		// 2% chance for Watermelon (shield fruit)
		var watermelon = new Watermelon();
		watermelon.x = x;
		watermelon.y = -60;
		watermelon.lastIntersecting = false;
		// Add "+" indicator for watermelon
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0x22ff44,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		watermelon.addChild(plusTxt);
		watermelon.indicatorTxt = plusTxt;
		powerups.push(watermelon);
		game.addChild(watermelon);
	} else if (rand > 0.89) {
		// 3% chance for Grape (slows bombs)
		var grape = new Grape();
		grape.x = x;
		grape.y = -60;
		grape.lastIntersecting = false;
		// Add "+" indicator for grape
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0x9900ff,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		grape.addChild(plusTxt);
		grape.indicatorTxt = plusTxt;
		powerups.push(grape);
		game.addChild(grape);
	} else if (rand > 0.86) {
		// 3% chance for Banana (wider catch area)
		var banana = new Banana();
		banana.x = x;
		banana.y = -60;
		banana.lastIntersecting = false;
		// Add "+" indicator for banana
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0xfff700,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		banana.addChild(plusTxt);
		banana.indicatorTxt = plusTxt;
		powerups.push(banana);
		game.addChild(banana);
	} else if (rand > 0.83) {
		// 3% chance for Apple (extra points)
		var apple = new Apple();
		apple.x = x;
		apple.y = -60;
		apple.lastIntersecting = false;
		// Add "+" indicator for apple
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0xff2222,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		apple.addChild(plusTxt);
		apple.indicatorTxt = plusTxt;
		powerups.push(apple);
		game.addChild(apple);
	} else {
		var ball = new Ball();
		ball.x = x;
		ball.y = -60;
		ball.lastIntersecting = false;
		// Add "+" indicator for normal ball
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0x00ffff,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		ball.addChild(plusTxt);
		ball.indicatorTxt = plusTxt;
		balls.push(ball);
		game.addChild(ball);
	}
}
// Move handler for dragging basket
function handleMove(x, y, obj) {
	if (dragNode) {
		// Clamp basket within screen
		var halfWidth = dragNode.width / 2;
		var minX = halfWidth;
		var maxX = 2048 - halfWidth;
		var newX = Math.max(minX, Math.min(maxX, x));
		// Only update basket.x if it is not at the edge, or if moving away from the edge
		// This prevents the basket from "burning" or flashing at the edge
		if (!(dragNode.x <= minX && newX <= minX) &&
		// not stuck at left edge
		!(dragNode.x >= maxX && newX >= maxX) // not stuck at right edge
		) {
			dragNode.x = newX;
		}
		// Move touch indicator with finger
		touchIndicator.x = x;
		touchIndicator.y = y;
		touchIndicator.alpha = 0.7;
	}
}
// Touch/mouse events
game.down = function (x, y, obj) {
	// Allow drag from anywhere in lower 1/3 of screen for easier control
	if (y > 2732 * 2 / 3) {
		dragNode = basket;
		handleMove(x, y, obj);
		// Show and animate touch indicator
		touchIndicator.x = x;
		touchIndicator.y = y;
		touchIndicator.alpha = 1;
		tween(touchIndicator, {
			alpha: 0.7,
			scaleX: 0.6,
			scaleY: 0.6
		}, {
			duration: 120,
			yoyo: true,
			repeat: 1,
			onFinish: function onFinish() {
				// Keep indicator visible while dragging
				if (!dragNode) {
					touchIndicator.alpha = 0;
					touchIndicator.scaleX = 0.4;
					touchIndicator.scaleY = 0.4;
				}
			}
		});
	}
};
game.move = handleMove;
game.up = function (x, y, obj) {
	dragNode = null;
	touchIndicator.alpha = 0;
};
// Main update loop
game.update = function () {
	if (gameOver) return;
	// Change background color at each 5 points (neon palette)
	var neonBgColors = [0x000000, 0x0ff0fc, 0x1a0033, 0x3b6eea, 0x00ffea, 0xff00ff, 0x00ff00, 0xf75e5e, 0xf7c325];
	var score = LK.getScore();
	var bgIndex = Math.floor(score / 5) % neonBgColors.length;
	game.setBackgroundColor(neonBgColors[bgIndex]);
	// Challenge mode: basket moves left/right automatically every 20 points
	if (score > 0 && score % 20 === 0 && !basket.challengeActive) {
		basket.challengeActive = true;
		basket.challengeDir = Math.random() > 0.5 ? 1 : -1;
		basket.challengeTween = tween(basket, {
			x: basket.challengeDir > 0 ? 2048 - basket.width / 2 : basket.width / 2
		}, {
			duration: 2200,
			yoyo: true,
			repeat: 2,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				basket.challengeActive = false;
			}
		});
	}
	// Spawn balls/bombs
	spawnTimer++;
	// Decrease interval as score increases (min 35 for human reflexes)
	var interval = Math.max(35, spawnInterval - Math.floor(LK.getScore() / 10) * 3);
	if (spawnTimer >= interval) {
		spawnFallingObject();
		spawnTimer = 0;
	}
	// Speed up all balls every 10 points
	if (score > 0 && score % 10 === 0 && !game.lastSpeedupScore) {
		for (var si = 0; si < balls.length; si++) {
			balls[si].speed *= 1.08; // less aggressive speedup for human reflexes
			balls[si].vx *= 1.05;
		}
		game.lastSpeedupScore = score;
	}
	if (score % 10 !== 0) {
		game.lastSpeedupScore = null;
	}
	// Update balls
	// Use a local array to collect indices to remove, then remove after loop to avoid array shifting
	var ballsToRemove = [];
	for (var i = balls.length - 1; i >= 0; i--) {
		var ball = balls[i];
		if (ball.lastY === undefined) ball.lastY = ball.y;
		if (ball.lastIntersecting === undefined) ball.lastIntersecting = false;
		ball.update();
		// Check for catch
		var intersecting = ball.intersects(basket);
		if (!ball.lastIntersecting && intersecting) {
			// Caught!
			comboCount++;
			if (comboTimeout) {
				LK.clearTimeout(comboTimeout);
				comboTimeout = null;
			}
			if (comboCount > 1) {
				comboTxt.setText('Combo x' + comboCount + '!');
				comboTxt.visible = true;
				comboTxt.alpha = 1;
				tween(comboTxt, {
					alpha: 0
				}, {
					duration: 900,
					onFinish: function onFinish() {
						comboTxt.visible = false;
					}
				});
			}
			// Combo bonus: +1 for first, +2 for 2nd, +3 for 3rd, etc.
			var comboBonus = comboCount > 1 ? comboCount : 1;
			LK.setScore(LK.getScore() + comboBonus);
			// Streak bonus: every 5 consecutive catches, +10 bonus
			if (comboCount > 0 && comboCount % 5 === 0) {
				LK.setScore(LK.getScore() + 10);
				comboTxt.setText('Streak! +10');
				comboTxt.visible = true;
				comboTxt.alpha = 1;
				tween(comboTxt, {
					alpha: 0
				}, {
					duration: 900,
					onFinish: function onFinish() {
						comboTxt.visible = false;
					}
				});
			}
			// Edge catch bonus: if ball is caught at the left/right 20% of basket
			var basketLeft = basket.x - basket.width / 2;
			var basketRight = basket.x + basket.width / 2;
			if (ball.x < basketLeft + basket.width * 0.2 || ball.x > basketRight - basket.width * 0.2) {
				LK.setScore(LK.getScore() + 3);
				comboTxt.setText('Edge Catch! +3');
				comboTxt.visible = true;
				comboTxt.alpha = 1;
				tween(comboTxt, {
					alpha: 0
				}, {
					duration: 900,
					onFinish: function onFinish() {
						comboTxt.visible = false;
					}
				});
			}
			scoreTxt.setText(LK.getScore());
			LK.getSound('catch').play();
			var flashColors = [0x4ad991, 0xf75e5e, 0x3b6eea, 0xf7a325, 0xFFD700];
			LK.effects.flashScreen(flashColors[Math.floor(Math.random() * flashColors.length)], 200);
			LK.effects.flashObject(basket, 0x4ad991, 200);
			tween(ball, {
				y: basket.y,
				alpha: 0
			}, {
				duration: 200,
				easing: tween.easeIn,
				onFinish: function (ballRef) {
					return function () {
						if (ballRef && ballRef.destroy) ballRef.destroy();
					};
				}(ball)
			});
			ballsToRemove.push(i);
			// Reset combo if no catch in 1.2s
			comboTimeout = LK.setTimeout(function () {
				comboCount = 0;
				comboTxt.visible = false;
				comboTimeout = null;
			}, 1200);
			continue;
		}
		// Missed (goes below basket)
		if (ball.lastY < 2732 && ball.y >= 2732 - 80) {
			LK.getSound('miss').play();
			missTxt.setText('Missed!');
			missTxt.visible = true;
			comboCount = 0;
			if (comboTimeout) {
				LK.clearTimeout(comboTimeout);
				comboTimeout = null;
			}
			comboTxt.visible = false;
			LK.effects.flashScreen(0xff0000, 600);
			health = Math.max(0, health - 1);
			var healthFrac = health / maxHealth;
			healthBar.scaleX = healthBarWidth * healthFrac / 100;
			if (healthFrac > 0.66) {
				healthBar.tint = 0x00ff00;
			} else if (healthFrac > 0.33) {
				healthBar.tint = 0xffc700;
			} else {
				healthBar.tint = 0xff2222;
			}
			for (var hi = 0; hi < healthHearts.length; hi++) {
				healthHearts[hi].alpha = hi < health ? 1 : 0.25;
				healthHearts[hi].tint = hi < health ? 0xff2222 : 0x444444;
			}
			if (health <= 0) {
				LK.setTimeout(function () {
					LK.showGameOver();
					// Show leaderboard with other players' scores after game over
					if (typeof LK.showLeaderboard === "function") {
						LK.showLeaderboard({
							showOthers: true
						});
					}
				}, 600);
				gameOver = true;
				return;
			}
			if (ball && ball.destroy) ball.destroy();
			ballsToRemove.push(i);
			continue;
		}
		// Off screen (cleanup)
		if (ball.y > 2800) {
			if (ball && ball.destroy) ball.destroy();
			ballsToRemove.push(i);
			continue;
		}
		ball.lastY = ball.y;
		ball.lastIntersecting = intersecting;
	}
	// Remove balls after loop to avoid array shifting
	// Remove from highest index to lowest to avoid shifting issues
	ballsToRemove.sort(function (a, b) {
		return b - a;
	});
	for (var btr = 0; btr < ballsToRemove.length; btr++) {
		balls.splice(ballsToRemove[btr], 1);
	}
	// Update bombs
	var bombsToRemove = [];
	for (var j = bombs.length - 1; j >= 0; j--) {
		var bomb = bombs[j];
		if (bomb.lastY === undefined) bomb.lastY = bomb.y;
		if (bomb.lastIntersecting === undefined) bomb.lastIntersecting = false;
		bomb.update();
		// Check for catch
		var intersecting = bomb.intersects(basket);
		if (!bomb.lastIntersecting && intersecting) {
			if (basket.hasShield) {
				basket.hasShield = false;
				if (basket.shieldTween) {
					basket.shieldTween.stop();
					basket.shieldTween = null;
				}
				LK.effects.flashObject(basket, 0x00ffff, 400);
				LK.effects.flashScreen(0x00ffff, 200);
				if (bomb.isSuper) {
					for (var bi = balls.length - 1; bi >= 0; bi--) {
						balls[bi].destroy();
					}
					balls = [];
					LK.setScore(LK.getScore() + 15);
					scoreTxt.setText(LK.getScore());
					missTxt.setText('Super Bomb! Cleared!');
					missTxt.visible = true;
					if (missTxt.hideTimeout) {
						LK.clearTimeout(missTxt.hideTimeout);
						missTxt.hideTimeout = null;
					}
					missTxt.hideTimeout = LK.setTimeout(function () {
						missTxt.visible = false;
						missTxt.hideTimeout = null;
					}, 1200);
				}
				if (bomb && bomb.destroy) bomb.destroy();
				bombsToRemove.push(j);
				continue;
			}
			LK.getSound('boom').play();
			LK.effects.flashObject(basket, 0xff0000, 600);
			comboCount = 0;
			if (comboTimeout) {
				LK.clearTimeout(comboTimeout);
				comboTimeout = null;
			}
			comboTxt.visible = false;
			LK.effects.flashScreen(0x000000, 600);
			health = Math.max(0, health - 1);
			var healthFrac = health / maxHealth;
			healthBar.scaleX = healthBarWidth * healthFrac / 100;
			if (healthFrac > 0.66) {
				healthBar.tint = 0x00ff00;
			} else if (healthFrac > 0.33) {
				healthBar.tint = 0xffc700;
			} else {
				healthBar.tint = 0xff2222;
			}
			for (var hi = 0; hi < healthHearts.length; hi++) {
				healthHearts[hi].alpha = hi < health ? 1 : 0.25;
				healthHearts[hi].tint = hi < health ? 0xff2222 : 0x444444;
			}
			if (health <= 0) {
				LK.setTimeout(function () {
					LK.showGameOver();
					if (typeof LK.showLeaderboard === "function") {
						LK.showLeaderboard({
							showOthers: true
						});
					}
				}, 600);
				gameOver = true;
				return;
			}
			if (bomb && bomb.destroy) bomb.destroy();
			bombsToRemove.push(j);
			continue;
		}
		// Off screen (cleanup)
		if (bomb.y > 2800) {
			if (bomb && bomb.destroy) bomb.destroy();
			bombsToRemove.push(j);
			continue;
		}
		bomb.lastY = bomb.y;
		bomb.lastIntersecting = intersecting;
	}
	// Remove bombs after loop
	// Remove from highest index to lowest to avoid shifting issues
	bombsToRemove.sort(function (a, b) {
		return b - a;
	});
	for (var btr = 0; btr < bombsToRemove.length; btr++) {
		bombs.splice(bombsToRemove[btr], 1);
	}
	// Update power-ups
	var powerupsToRemove = [];
	for (var k = powerups.length - 1; k >= 0; k--) {
		var powerup = powerups[k];
		if (powerup.lastY === undefined) powerup.lastY = powerup.y;
		if (powerup.lastIntersecting === undefined) powerup.lastIntersecting = false;
		powerup.update();
		// Check for catch
		var intersecting = powerup.intersects(basket);
		if (!powerup.lastIntersecting && intersecting) {
			if (powerup.type === "shield" || powerup instanceof ShieldPowerUp || powerup instanceof Watermelon) {
				basket.hasShield = true;
				LK.effects.flashObject(basket, 0x00ffff, 400);
				LK.effects.flashScreen(0x00ffff, 200);
				if (!basket.shieldTween) {
					basket.shieldTween = tween(basket, {
						alpha: 1
					}, {
						duration: 200,
						yoyo: true,
						repeat: Infinity,
						easing: tween.easeInOut
					});
				}
				tween(powerup, {
					y: basket.y,
					alpha: 0
				}, {
					duration: 200,
					easing: tween.easeIn,
					onFinish: function (puRef) {
						return function () {
							if (puRef && puRef.destroy) puRef.destroy();
						};
					}(powerup)
				});
				powerupsToRemove.push(k);
				continue;
			} else if (powerup.type === "slow" || powerup instanceof Grape) {
				for (var bi = 0; bi < balls.length; bi++) {
					balls[bi].speed *= 0.4;
					balls[bi].vx *= 0.4;
				}
				for (var bj = 0; bj < bombs.length; bj++) {
					bombs[bj].speed *= 0.4;
				}
				for (var bp = 0; bp < powerups.length; bp++) {
					powerups[bp].speed *= 0.4;
				}
				missTxt.setText('Slow Motion!');
				missTxt.visible = true;
				if (missTxt.hideTimeout) {
					LK.clearTimeout(missTxt.hideTimeout);
					missTxt.hideTimeout = null;
				}
				missTxt.hideTimeout = LK.setTimeout(function () {
					missTxt.visible = false;
					missTxt.hideTimeout = null;
				}, 1200);
				LK.setTimeout(function () {
					for (var bi = 0; bi < balls.length; bi++) {
						balls[bi].speed /= 0.4;
						balls[bi].vx /= 0.4;
					}
					for (var bj = 0; bj < bombs.length; bj++) {
						bombs[bj].speed /= 0.4;
					}
					for (var bp = 0; bp < powerups.length; bp++) {
						powerups[bp].speed /= 0.4;
					}
				}, 3000);
				tween(powerup, {
					y: basket.y,
					alpha: 0
				}, {
					duration: 200,
					easing: tween.easeIn,
					onFinish: function (puRef) {
						return function () {
							if (puRef && puRef.destroy) puRef.destroy();
						};
					}(powerup)
				});
				powerupsToRemove.push(k);
				continue;
			} else if (powerup.type === "banana" || powerup instanceof Banana) {
				var originalScale = basket.scaleX || 1;
				basket.scaleX = originalScale * 1.5;
				basket.scaleY = (basket.scaleY || 1) * 1.1;
				LK.effects.flashObject(basket, 0xfff700, 300);
				missTxt.setText('Wide Basket!');
				missTxt.visible = true;
				if (missTxt.hideTimeout) {
					LK.clearTimeout(missTxt.hideTimeout);
					missTxt.hideTimeout = null;
				}
				missTxt.hideTimeout = LK.setTimeout(function () {
					missTxt.visible = false;
					missTxt.hideTimeout = null;
				}, 1200);
				LK.setTimeout(function () {
					basket.scaleX = originalScale;
					basket.scaleY = 1;
				}, 4000);
				tween(powerup, {
					y: basket.y,
					alpha: 0
				}, {
					duration: 200,
					easing: tween.easeIn,
					onFinish: function (puRef) {
						return function () {
							if (puRef && puRef.destroy) puRef.destroy();
						};
					}(powerup)
				});
				powerupsToRemove.push(k);
				continue;
			} else if (powerup.type === "apple" || powerup instanceof Apple) {
				LK.setScore(LK.getScore() + 5);
				scoreTxt.setText(LK.getScore());
				LK.getSound('catch').play();
				LK.effects.flashScreen(0xff2222, 350);
				LK.effects.flashObject(basket, 0xff2222, 300);
				missTxt.setText('Apple! +5');
				missTxt.visible = true;
				if (missTxt.hideTimeout) {
					LK.clearTimeout(missTxt.hideTimeout);
					missTxt.hideTimeout = null;
				}
				missTxt.hideTimeout = LK.setTimeout(function () {
					missTxt.visible = false;
					missTxt.hideTimeout = null;
				}, 1200);
				tween(powerup, {
					y: basket.y,
					alpha: 0
				}, {
					duration: 200,
					easing: tween.easeIn,
					onFinish: function (puRef) {
						return function () {
							if (puRef && puRef.destroy) puRef.destroy();
						};
					}(powerup)
				});
				powerupsToRemove.push(k);
				continue;
			} else {
				LK.setScore(LK.getScore() + 2);
				scoreTxt.setText(LK.getScore());
				LK.getSound('catch').play();
				LK.effects.flashScreen(0xFFD700, 350);
				LK.effects.flashObject(basket, 0xFFD700, 300);
				tween(powerup, {
					y: basket.y,
					alpha: 0
				}, {
					duration: 200,
					easing: tween.easeIn,
					onFinish: function (puRef) {
						return function () {
							if (puRef && puRef.destroy) puRef.destroy();
						};
					}(powerup)
				});
				powerupsToRemove.push(k);
				continue;
			}
		}
		// Off screen (cleanup)
		if (powerup.y > 2800) {
			if (powerup && powerup.destroy) powerup.destroy();
			powerupsToRemove.push(k);
			continue;
		}
		powerup.lastY = powerup.y;
		powerup.lastIntersecting = intersecting;
	}
	// Remove powerups after loop
	// Remove from highest index to lowest to avoid shifting issues
	powerupsToRemove.sort(function (a, b) {
		return b - a;
	});
	for (var putr = 0; putr < powerupsToRemove.length; putr++) {
		powerups.splice(powerupsToRemove[putr], 1);
	}
	// Hide miss text after a short time
	if (missTxt.visible) {
		if (!missTxt.hideTimeout) {
			missTxt.hideTimeout = LK.setTimeout(function () {
				missTxt.visible = false;
				missTxt.hideTimeout = null;
			}, 900);
		}
	}
	// Draw shield icon above basket if shield is active
	if (basket.hasShield) {
		if (!basket.shieldIcon) {
			basket.shieldIcon = LK.getAsset('ball', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			basket.shieldIcon.tint = 0x00ffff;
			basket.shieldIcon.scaleX = 0.5;
			basket.shieldIcon.scaleY = 0.5;
			game.addChild(basket.shieldIcon);
		}
		basket.shieldIcon.x = basket.x;
		basket.shieldIcon.y = basket.y - 70;
		basket.shieldIcon.visible = true;
	} else if (basket.shieldIcon) {
		basket.shieldIcon.visible = false;
	}
	// Rainbow basket after 40 points
	if (LK.getScore() >= 40 && basket.children && basket.children.length > 0) {
		var t = LK.ticks % 60 / 60;
		var r = Math.floor(127 * Math.sin(2 * Math.PI * t) + 128);
		var g = Math.floor(127 * Math.sin(2 * Math.PI * t + 2) + 128);
		var b = Math.floor(127 * Math.sin(2 * Math.PI * t + 4) + 128);
		basket.children[0].tint = r << 16 | g << 8 | b;
	}
	// Defensive: Always update lastX and lastY for basket to avoid undefined errors
	if (basket) {
		if (basket.lastX === undefined) basket.lastX = basket.x;
		if (basket.lastY === undefined) basket.lastY = basket.y;
		basket.lastX = basket.x;
		basket.lastY = basket.y;
	}
};
// Reset state on new game
LK.on('gameStart', function () {
	// Remove all balls, bombs, and powerups
	for (var i = 0; i < balls.length; i++) balls[i].destroy();
	for (var j = 0; j < bombs.length; j++) bombs[j].destroy();
	for (var k = 0; k < powerups.length; k++) powerups[k].destroy();
	balls = [];
	bombs = [];
	powerups = [];
	basket.x = 2048 / 2;
	basket.y = 2732 - 180;
	// Reset challenge mode state
	basket.challengeActive = false;
	basket.challengeDir = null;
	if (basket.challengeTween) {
		basket.challengeTween.stop();
		basket.challengeTween = null;
	}
	// Reset shield state
	basket.hasShield = false;
	if (basket.shieldTween) {
		basket.shieldTween.stop();
		basket.shieldTween = null;
	}
	// Randomize basket color on new game
	var basketColors = [0x3b6eea, 0x4ad991, 0xf75e5e, 0xf7a325, 0xFFD700];
	if (basket.children && basket.children.length > 0) {
		basket.children[0].tint = basketColors[Math.floor(Math.random() * basketColors.length)];
	}
	LK.setScore(0);
	scoreTxt.setText('0');
	missTxt.setText('');
	missTxt.visible = false;
	if (missTxt.hideTimeout) {
		LK.clearTimeout(missTxt.hideTimeout);
		missTxt.hideTimeout = null;
	}
	spawnTimer = 0;
	gameOver = false;
	game.missForgiven = false;
	// Reset combo
	comboCount = 0;
	if (comboTimeout) {
		LK.clearTimeout(comboTimeout);
		comboTimeout = null;
	}
	comboTxt.visible = false;
	// Reset health bar and hearts
	health = maxHealth;
	healthBar.scaleX = healthBarWidth / 100;
	healthBar.tint = 0x00ff00;
	for (var hi = 0; hi < healthHearts.length; hi++) {
		healthHearts[hi].alpha = 1;
		healthHearts[hi].tint = 0xff2222;
	}
}); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Fruit: Apple (extra points)
var Apple = Container.expand(function () {
	var self = Container.call(this);
	var appleAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	appleAsset.tint = 0xff2222; // Red
	appleAsset.scaleX = 1.1;
	appleAsset.scaleY = 1.1;
	tween(appleAsset, {
		alpha: 0.85
	}, {
		duration: 350,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	var baseSpeed = 10 + Math.random() * 3;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseSpeed += Math.min(8, Math.floor(LK.getScore() / 12));
	}
	self.speed = baseSpeed;
	self.type = "apple";
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Ball class
var Ball = Container.expand(function () {
	var self = Container.call(this);
	var ballAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Neon color palette for balls
	var colors = [0x00ffff, 0xff00ff, 0xffff00, 0x00ff00, 0xff8800, 0x00ffea, 0xff0088];
	ballAsset.color = colors[Math.floor(Math.random() * colors.length)];
	ballAsset.tint = ballAsset.color;
	// Neon glow effect: animate alpha for a pulsing glow
	tween(ballAsset, {
		alpha: 0.7
	}, {
		duration: 400,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	// Adjusted for human reflexes: start slower, increase with score, cap max speed
	var baseSpeed = 10 + Math.random() * 4;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseSpeed += Math.min(10, Math.floor(LK.getScore() / 8)); // increase 1 per 8 points, max +10
	}
	self.speed = baseSpeed;
	self.vx = (Math.random() - 0.5) * 10; // random horizontal speed
	self.update = function () {
		self.y += self.speed;
		self.x += self.vx;
		// Bounce off left/right walls
		if (self.x < 60 && self.vx < 0) {
			self.x = 60;
			self.vx *= -1;
		}
		if (self.x > 2048 - 60 && self.vx > 0) {
			self.x = 2048 - 60;
			self.vx *= -1;
		}
	};
	return self;
});
// Fruit: Banana (wider catch area)
var Banana = Container.expand(function () {
	var self = Container.call(this);
	var bananaAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	bananaAsset.tint = 0xfff700; // Yellow
	bananaAsset.scaleX = 1.5;
	bananaAsset.scaleY = 0.8;
	tween(bananaAsset, {
		alpha: 0.8
	}, {
		duration: 400,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	var baseSpeed = 9 + Math.random() * 2;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseSpeed += Math.min(7, Math.floor(LK.getScore() / 14));
	}
	self.speed = baseSpeed;
	self.type = "banana";
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Basket class
var Basket = Container.expand(function () {
	var self = Container.call(this);
	var basketAsset = self.attachAsset('basket', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Neon basket: random neon color and glow
	var basketColors = [0x00ffff, 0xff00ff, 0xffff00, 0x00ff00, 0xff8800, 0x00ffea, 0xff0088];
	basketAsset.tint = basketColors[Math.floor(Math.random() * basketColors.length)];
	tween(basketAsset, {
		alpha: 0.7
	}, {
		duration: 600,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	return self;
});
// Bomb class
var Bomb = Container.expand(function () {
	var self = Container.call(this);
	var bombAsset = self.attachAsset('bomb', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Neon bomb: magenta or cyan
	var bombColors = [0xff00ff, 0x00ffff, 0xffff00];
	bombAsset.tint = bombColors[Math.floor(Math.random() * bombColors.length)];
	tween(bombAsset, {
		alpha: 0.6
	}, {
		duration: 400,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	// Adjusted for human reflexes: start slower, increase with score, cap max speed
	var baseBombSpeed = 12 + Math.random() * 5;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseBombSpeed += Math.min(12, Math.floor(LK.getScore() / 7)); // increase 1 per 7 points, max +12
	}
	self.speed = baseBombSpeed;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Fruit: Grape (slows bombs for a short time)
var Grape = Container.expand(function () {
	var self = Container.call(this);
	var grapeAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	grapeAsset.tint = 0x9900ff; // Purple
	grapeAsset.scaleX = 1.0;
	grapeAsset.scaleY = 1.0;
	tween(grapeAsset, {
		alpha: 0.7
	}, {
		duration: 300,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	var baseSpeed = 11 + Math.random() * 2;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseSpeed += Math.min(7, Math.floor(LK.getScore() / 13));
	}
	self.speed = baseSpeed;
	self.type = "grape";
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// PowerUp class (neon star)
var PowerUp = Container.expand(function () {
	var self = Container.call(this);
	// Use a ball asset for now, but tint and scale to look like a power-up
	var starAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Neon star color
	var starColors = [0xFFD700, 0x00ffea, 0xff00ff, 0x00ff00];
	starAsset.tint = starColors[Math.floor(Math.random() * starColors.length)];
	starAsset.scaleX = 1.3;
	starAsset.scaleY = 1.3;
	// Animate alpha for a pulsing glow
	tween(starAsset, {
		alpha: 0.8
	}, {
		duration: 300,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	// Adjusted for human reflexes: start slower, increase with score, cap max speed
	var basePowerSpeed = 9 + Math.random() * 3;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		basePowerSpeed += Math.min(8, Math.floor(LK.getScore() / 10)); // increase 1 per 10 points, max +8
	}
	self.speed = basePowerSpeed;
	self.type = "score"; // default type
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// ShieldPowerUp class (neon blue ring)
var ShieldPowerUp = Container.expand(function () {
	var self = Container.call(this);
	var shieldAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	shieldAsset.tint = 0x00ffff;
	shieldAsset.scaleX = 1.5;
	shieldAsset.scaleY = 1.5;
	tween(shieldAsset, {
		alpha: 0.6
	}, {
		duration: 200,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	// Adjusted for human reflexes: start slower, increase with score, cap max speed
	var baseShieldSpeed = 8 + Math.random() * 2;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseShieldSpeed += Math.min(7, Math.floor(LK.getScore() / 12)); // increase 1 per 12 points, max +7
	}
	self.speed = baseShieldSpeed;
	self.type = "shield";
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Fruit: Watermelon (big, gives shield)
var Watermelon = Container.expand(function () {
	var self = Container.call(this);
	var melonAsset = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	melonAsset.tint = 0x22ff44; // Green
	melonAsset.scaleX = 1.7;
	melonAsset.scaleY = 1.3;
	tween(melonAsset, {
		alpha: 0.8
	}, {
		duration: 500,
		yoyo: true,
		repeat: Infinity,
		easing: tween.easeInOut
	});
	var baseSpeed = 8 + Math.random() * 2;
	if (typeof LK !== "undefined" && typeof LK.getScore === "function") {
		baseSpeed += Math.min(6, Math.floor(LK.getScore() / 15));
	}
	self.speed = baseSpeed;
	self.type = "watermelon";
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/ 
// Sound for missing a ball
// Sound for catching a bomb
// Sound for catching a ball
// Bomb: black ellipse
// Ball: colored ellipse
// Basket: wide rectangle
// Game area: 2048x2732
// No background image, only black background
// No background image, only black background
game.setBackgroundColor(0x000000);
// Neon-style game objective text at the start (small, English, subtle neon)
var objectiveTxt = new Text2('Goal: Catch the balls, avoid the bombs!', {
	size: 54,
	// smaller text
	fill: 0x00ffff,
	stroke: 0x222222,
	strokeThickness: 8,
	dropShadow: true,
	dropShadowColor: 0x00ffff,
	dropShadowBlur: 12,
	dropShadowDistance: 0,
	align: "center"
});
objectiveTxt.anchor.set(0.5, 0);
objectiveTxt.y = 90;
LK.gui.top.addChild(objectiveTxt);
// Add leaderboard button for competition
var leaderboardBtn = new Text2('🏆 Leaderboard', {
	size: 60,
	fill: 0xFFD700,
	stroke: 0x00ffff,
	strokeThickness: 8,
	dropShadow: true,
	dropShadowColor: 0xFFD700,
	dropShadowBlur: 10,
	dropShadowDistance: 0,
	align: "center"
});
leaderboardBtn.anchor.set(0.5, 0);
leaderboardBtn.x = 2048 - 250;
leaderboardBtn.y = 90;
leaderboardBtn.interactive = true;
leaderboardBtn.buttonMode = true;
leaderboardBtn.down = function () {
	if (typeof LK.showLeaderboard === "function") {
		LK.showLeaderboard();
	}
};
LK.gui.top.addChild(leaderboardBtn);
// Hide objective after 2.5 seconds
LK.setTimeout(function () {
	objectiveTxt.visible = false;
}, 2500);
// Score text
var scoreTxt = new Text2('0', {
	size: 120,
	fill: 0x00FFEA,
	stroke: 0xFF00FF,
	strokeThickness: 18,
	dropShadow: true,
	dropShadowColor: 0x00FFFF,
	dropShadowBlur: 24,
	dropShadowDistance: 0,
	align: "center"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Health bar UI
var maxHealth = 3;
var health = maxHealth;
var healthBarWidth = 320;
var healthBarHeight = 38;
var healthBarBg = LK.getAsset('ball', {
	anchorX: 0,
	anchorY: 0.5,
	scaleX: healthBarWidth / 100,
	scaleY: healthBarHeight / 100,
	x: 120,
	y: 160
});
healthBarBg.tint = 0x222222;
LK.gui.top.addChild(healthBarBg);
var healthBar = LK.getAsset('ball', {
	anchorX: 0,
	anchorY: 0.5,
	scaleX: healthBarWidth / 100,
	scaleY: healthBarHeight / 100,
	x: 120,
	y: 160
});
healthBar.tint = 0x00ff00;
LK.gui.top.addChild(healthBar);
// Health icon hearts
var healthHearts = [];
for (var h = 0; h < maxHealth; h++) {
	var heart = LK.getAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.32,
		scaleY: 0.32,
		x: 120 + 40 + h * 54,
		y: 160
	});
	heart.tint = 0xff2222;
	LK.gui.top.addChild(heart);
	healthHearts.push(heart);
}
// Misses text (shows "Missed!" when a ball is missed)
var missTxt = new Text2('', {
	size: 90,
	fill: 0x00FFFF,
	stroke: 0xFF00FF,
	strokeThickness: 14,
	dropShadow: true,
	dropShadowColor: 0x00FFFF,
	dropShadowBlur: 18,
	dropShadowDistance: 0,
	align: "center"
});
missTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(missTxt);
missTxt.visible = false;
// Basket
var basket = new Basket();
game.addChild(basket);
basket.y = 2732 - 180;
basket.x = 2048 / 2;
// Ball, bomb, and power-up arrays
var balls = [];
var bombs = [];
var powerups = [];
// Dragging
var dragNode = null;
// Touch indicator for user-friendly feedback
var touchIndicator = LK.getAsset('ball', {
	anchorX: 0.5,
	anchorY: 0.5
});
touchIndicator.tint = 0xFFD700;
touchIndicator.scaleX = 0.4;
touchIndicator.scaleY = 0.4;
touchIndicator.alpha = 0;
game.addChild(touchIndicator);
// Spawning control
var spawnTimer = 0;
var spawnInterval = 55; // frames between spawns, will decrease as score increases
// State
var lastScore = 0;
var gameOver = false;
// Combo scoring
var comboCount = 0;
var comboTimeout = null;
var comboTxt = new Text2('', {
	size: 80,
	fill: 0xFFD700,
	stroke: 0x00ffff,
	strokeThickness: 10,
	dropShadow: true,
	dropShadowColor: 0xFFD700,
	dropShadowBlur: 12,
	dropShadowDistance: 0,
	align: "center"
});
comboTxt.anchor.set(0.5, 0);
comboTxt.y = 200;
comboTxt.visible = false;
LK.gui.top.addChild(comboTxt);
// Helper: spawn a ball, bomb, or power-up
function spawnFallingObject() {
	// 80% ball, 20% bomb, 5% power-up, 3% shield power-up, plus fruits
	var rand = Math.random();
	var x = 150 + Math.random() * (2048 - 300);
	if (rand < 0.10) {
		var bomb = new Bomb();
		bomb.x = x;
		bomb.y = -60;
		bomb.lastIntersecting = false;
		// Add "-" indicator for bomb
		var minusTxt = new Text2('-', {
			size: 70,
			fill: 0xff2222,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		minusTxt.anchor.set(0.5, 1);
		minusTxt.y = -60;
		bomb.addChild(minusTxt);
		bomb.indicatorTxt = minusTxt;
		bombs.push(bomb);
		game.addChild(bomb);
	} else if (rand < 0.13) {
		// 3% chance for super bomb
		var superBomb = new Bomb();
		superBomb.x = x;
		superBomb.y = -60;
		superBomb.lastIntersecting = false;
		superBomb.isSuper = true;
		if (superBomb.children && superBomb.children.length > 0) {
			superBomb.children[0].tint = 0xffffff;
		}
		// Add "-" indicator for super bomb
		var minusTxt = new Text2('-', {
			size: 70,
			fill: 0xff2222,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		minusTxt.anchor.set(0.5, 1);
		minusTxt.y = -60;
		superBomb.addChild(minusTxt);
		superBomb.indicatorTxt = minusTxt;
		bombs.push(superBomb);
		game.addChild(superBomb);
	} else if (rand > 0.98) {
		// 2% chance for slow motion power-up
		var slowPower = new PowerUp();
		slowPower.x = x;
		slowPower.y = -60;
		slowPower.lastIntersecting = false;
		slowPower.type = "slow";
		if (slowPower.children && slowPower.children.length > 0) {
			slowPower.children[0].tint = 0x3b6eea;
		}
		// Add "+" indicator for slow powerup
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0x00ffea,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		slowPower.addChild(plusTxt);
		slowPower.indicatorTxt = plusTxt;
		powerups.push(slowPower);
		game.addChild(slowPower);
	} else if (rand > 0.96) {
		// 4% chance for shield power-up
		var shield = new ShieldPowerUp();
		shield.x = x;
		shield.y = -60;
		shield.lastIntersecting = false;
		// Add "+" indicator for shield
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0x00ffff,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		shield.addChild(plusTxt);
		shield.indicatorTxt = plusTxt;
		powerups.push(shield);
		game.addChild(shield);
	} else if (rand > 0.94) {
		// 2% chance for score power-up
		var powerup = new PowerUp();
		powerup.x = x;
		powerup.y = -60;
		powerup.lastIntersecting = false;
		// Add "+" indicator for score powerup
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0xFFD700,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		powerup.addChild(plusTxt);
		powerup.indicatorTxt = plusTxt;
		powerups.push(powerup);
		game.addChild(powerup);
	} else if (rand > 0.92) {
		// 2% chance for Watermelon (shield fruit)
		var watermelon = new Watermelon();
		watermelon.x = x;
		watermelon.y = -60;
		watermelon.lastIntersecting = false;
		// Add "+" indicator for watermelon
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0x22ff44,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		watermelon.addChild(plusTxt);
		watermelon.indicatorTxt = plusTxt;
		powerups.push(watermelon);
		game.addChild(watermelon);
	} else if (rand > 0.89) {
		// 3% chance for Grape (slows bombs)
		var grape = new Grape();
		grape.x = x;
		grape.y = -60;
		grape.lastIntersecting = false;
		// Add "+" indicator for grape
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0x9900ff,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		grape.addChild(plusTxt);
		grape.indicatorTxt = plusTxt;
		powerups.push(grape);
		game.addChild(grape);
	} else if (rand > 0.86) {
		// 3% chance for Banana (wider catch area)
		var banana = new Banana();
		banana.x = x;
		banana.y = -60;
		banana.lastIntersecting = false;
		// Add "+" indicator for banana
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0xfff700,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		banana.addChild(plusTxt);
		banana.indicatorTxt = plusTxt;
		powerups.push(banana);
		game.addChild(banana);
	} else if (rand > 0.83) {
		// 3% chance for Apple (extra points)
		var apple = new Apple();
		apple.x = x;
		apple.y = -60;
		apple.lastIntersecting = false;
		// Add "+" indicator for apple
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0xff2222,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		apple.addChild(plusTxt);
		apple.indicatorTxt = plusTxt;
		powerups.push(apple);
		game.addChild(apple);
	} else {
		var ball = new Ball();
		ball.x = x;
		ball.y = -60;
		ball.lastIntersecting = false;
		// Add "+" indicator for normal ball
		var plusTxt = new Text2('+', {
			size: 70,
			fill: 0x00ffff,
			stroke: 0x000000,
			strokeThickness: 8,
			align: "center"
		});
		plusTxt.anchor.set(0.5, 1);
		plusTxt.y = -60;
		ball.addChild(plusTxt);
		ball.indicatorTxt = plusTxt;
		balls.push(ball);
		game.addChild(ball);
	}
}
// Move handler for dragging basket
function handleMove(x, y, obj) {
	if (dragNode) {
		// Clamp basket within screen
		var halfWidth = dragNode.width / 2;
		var minX = halfWidth;
		var maxX = 2048 - halfWidth;
		var newX = Math.max(minX, Math.min(maxX, x));
		// Only update basket.x if it is not at the edge, or if moving away from the edge
		// This prevents the basket from "burning" or flashing at the edge
		if (!(dragNode.x <= minX && newX <= minX) &&
		// not stuck at left edge
		!(dragNode.x >= maxX && newX >= maxX) // not stuck at right edge
		) {
			dragNode.x = newX;
		}
		// Move touch indicator with finger
		touchIndicator.x = x;
		touchIndicator.y = y;
		touchIndicator.alpha = 0.7;
	}
}
// Touch/mouse events
game.down = function (x, y, obj) {
	// Allow drag from anywhere in lower 1/3 of screen for easier control
	if (y > 2732 * 2 / 3) {
		dragNode = basket;
		handleMove(x, y, obj);
		// Show and animate touch indicator
		touchIndicator.x = x;
		touchIndicator.y = y;
		touchIndicator.alpha = 1;
		tween(touchIndicator, {
			alpha: 0.7,
			scaleX: 0.6,
			scaleY: 0.6
		}, {
			duration: 120,
			yoyo: true,
			repeat: 1,
			onFinish: function onFinish() {
				// Keep indicator visible while dragging
				if (!dragNode) {
					touchIndicator.alpha = 0;
					touchIndicator.scaleX = 0.4;
					touchIndicator.scaleY = 0.4;
				}
			}
		});
	}
};
game.move = handleMove;
game.up = function (x, y, obj) {
	dragNode = null;
	touchIndicator.alpha = 0;
};
// Main update loop
game.update = function () {
	if (gameOver) return;
	// Change background color at each 5 points (neon palette)
	var neonBgColors = [0x000000, 0x0ff0fc, 0x1a0033, 0x3b6eea, 0x00ffea, 0xff00ff, 0x00ff00, 0xf75e5e, 0xf7c325];
	var score = LK.getScore();
	var bgIndex = Math.floor(score / 5) % neonBgColors.length;
	game.setBackgroundColor(neonBgColors[bgIndex]);
	// Challenge mode: basket moves left/right automatically every 20 points
	if (score > 0 && score % 20 === 0 && !basket.challengeActive) {
		basket.challengeActive = true;
		basket.challengeDir = Math.random() > 0.5 ? 1 : -1;
		basket.challengeTween = tween(basket, {
			x: basket.challengeDir > 0 ? 2048 - basket.width / 2 : basket.width / 2
		}, {
			duration: 2200,
			yoyo: true,
			repeat: 2,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				basket.challengeActive = false;
			}
		});
	}
	// Spawn balls/bombs
	spawnTimer++;
	// Decrease interval as score increases (min 35 for human reflexes)
	var interval = Math.max(35, spawnInterval - Math.floor(LK.getScore() / 10) * 3);
	if (spawnTimer >= interval) {
		spawnFallingObject();
		spawnTimer = 0;
	}
	// Speed up all balls every 10 points
	if (score > 0 && score % 10 === 0 && !game.lastSpeedupScore) {
		for (var si = 0; si < balls.length; si++) {
			balls[si].speed *= 1.08; // less aggressive speedup for human reflexes
			balls[si].vx *= 1.05;
		}
		game.lastSpeedupScore = score;
	}
	if (score % 10 !== 0) {
		game.lastSpeedupScore = null;
	}
	// Update balls
	// Use a local array to collect indices to remove, then remove after loop to avoid array shifting
	var ballsToRemove = [];
	for (var i = balls.length - 1; i >= 0; i--) {
		var ball = balls[i];
		if (ball.lastY === undefined) ball.lastY = ball.y;
		if (ball.lastIntersecting === undefined) ball.lastIntersecting = false;
		ball.update();
		// Check for catch
		var intersecting = ball.intersects(basket);
		if (!ball.lastIntersecting && intersecting) {
			// Caught!
			comboCount++;
			if (comboTimeout) {
				LK.clearTimeout(comboTimeout);
				comboTimeout = null;
			}
			if (comboCount > 1) {
				comboTxt.setText('Combo x' + comboCount + '!');
				comboTxt.visible = true;
				comboTxt.alpha = 1;
				tween(comboTxt, {
					alpha: 0
				}, {
					duration: 900,
					onFinish: function onFinish() {
						comboTxt.visible = false;
					}
				});
			}
			// Combo bonus: +1 for first, +2 for 2nd, +3 for 3rd, etc.
			var comboBonus = comboCount > 1 ? comboCount : 1;
			LK.setScore(LK.getScore() + comboBonus);
			// Streak bonus: every 5 consecutive catches, +10 bonus
			if (comboCount > 0 && comboCount % 5 === 0) {
				LK.setScore(LK.getScore() + 10);
				comboTxt.setText('Streak! +10');
				comboTxt.visible = true;
				comboTxt.alpha = 1;
				tween(comboTxt, {
					alpha: 0
				}, {
					duration: 900,
					onFinish: function onFinish() {
						comboTxt.visible = false;
					}
				});
			}
			// Edge catch bonus: if ball is caught at the left/right 20% of basket
			var basketLeft = basket.x - basket.width / 2;
			var basketRight = basket.x + basket.width / 2;
			if (ball.x < basketLeft + basket.width * 0.2 || ball.x > basketRight - basket.width * 0.2) {
				LK.setScore(LK.getScore() + 3);
				comboTxt.setText('Edge Catch! +3');
				comboTxt.visible = true;
				comboTxt.alpha = 1;
				tween(comboTxt, {
					alpha: 0
				}, {
					duration: 900,
					onFinish: function onFinish() {
						comboTxt.visible = false;
					}
				});
			}
			scoreTxt.setText(LK.getScore());
			LK.getSound('catch').play();
			var flashColors = [0x4ad991, 0xf75e5e, 0x3b6eea, 0xf7a325, 0xFFD700];
			LK.effects.flashScreen(flashColors[Math.floor(Math.random() * flashColors.length)], 200);
			LK.effects.flashObject(basket, 0x4ad991, 200);
			tween(ball, {
				y: basket.y,
				alpha: 0
			}, {
				duration: 200,
				easing: tween.easeIn,
				onFinish: function (ballRef) {
					return function () {
						if (ballRef && ballRef.destroy) ballRef.destroy();
					};
				}(ball)
			});
			ballsToRemove.push(i);
			// Reset combo if no catch in 1.2s
			comboTimeout = LK.setTimeout(function () {
				comboCount = 0;
				comboTxt.visible = false;
				comboTimeout = null;
			}, 1200);
			continue;
		}
		// Missed (goes below basket)
		if (ball.lastY < 2732 && ball.y >= 2732 - 80) {
			LK.getSound('miss').play();
			missTxt.setText('Missed!');
			missTxt.visible = true;
			comboCount = 0;
			if (comboTimeout) {
				LK.clearTimeout(comboTimeout);
				comboTimeout = null;
			}
			comboTxt.visible = false;
			LK.effects.flashScreen(0xff0000, 600);
			health = Math.max(0, health - 1);
			var healthFrac = health / maxHealth;
			healthBar.scaleX = healthBarWidth * healthFrac / 100;
			if (healthFrac > 0.66) {
				healthBar.tint = 0x00ff00;
			} else if (healthFrac > 0.33) {
				healthBar.tint = 0xffc700;
			} else {
				healthBar.tint = 0xff2222;
			}
			for (var hi = 0; hi < healthHearts.length; hi++) {
				healthHearts[hi].alpha = hi < health ? 1 : 0.25;
				healthHearts[hi].tint = hi < health ? 0xff2222 : 0x444444;
			}
			if (health <= 0) {
				LK.setTimeout(function () {
					LK.showGameOver();
					// Show leaderboard with other players' scores after game over
					if (typeof LK.showLeaderboard === "function") {
						LK.showLeaderboard({
							showOthers: true
						});
					}
				}, 600);
				gameOver = true;
				return;
			}
			if (ball && ball.destroy) ball.destroy();
			ballsToRemove.push(i);
			continue;
		}
		// Off screen (cleanup)
		if (ball.y > 2800) {
			if (ball && ball.destroy) ball.destroy();
			ballsToRemove.push(i);
			continue;
		}
		ball.lastY = ball.y;
		ball.lastIntersecting = intersecting;
	}
	// Remove balls after loop to avoid array shifting
	// Remove from highest index to lowest to avoid shifting issues
	ballsToRemove.sort(function (a, b) {
		return b - a;
	});
	for (var btr = 0; btr < ballsToRemove.length; btr++) {
		balls.splice(ballsToRemove[btr], 1);
	}
	// Update bombs
	var bombsToRemove = [];
	for (var j = bombs.length - 1; j >= 0; j--) {
		var bomb = bombs[j];
		if (bomb.lastY === undefined) bomb.lastY = bomb.y;
		if (bomb.lastIntersecting === undefined) bomb.lastIntersecting = false;
		bomb.update();
		// Check for catch
		var intersecting = bomb.intersects(basket);
		if (!bomb.lastIntersecting && intersecting) {
			if (basket.hasShield) {
				basket.hasShield = false;
				if (basket.shieldTween) {
					basket.shieldTween.stop();
					basket.shieldTween = null;
				}
				LK.effects.flashObject(basket, 0x00ffff, 400);
				LK.effects.flashScreen(0x00ffff, 200);
				if (bomb.isSuper) {
					for (var bi = balls.length - 1; bi >= 0; bi--) {
						balls[bi].destroy();
					}
					balls = [];
					LK.setScore(LK.getScore() + 15);
					scoreTxt.setText(LK.getScore());
					missTxt.setText('Super Bomb! Cleared!');
					missTxt.visible = true;
					if (missTxt.hideTimeout) {
						LK.clearTimeout(missTxt.hideTimeout);
						missTxt.hideTimeout = null;
					}
					missTxt.hideTimeout = LK.setTimeout(function () {
						missTxt.visible = false;
						missTxt.hideTimeout = null;
					}, 1200);
				}
				if (bomb && bomb.destroy) bomb.destroy();
				bombsToRemove.push(j);
				continue;
			}
			LK.getSound('boom').play();
			LK.effects.flashObject(basket, 0xff0000, 600);
			comboCount = 0;
			if (comboTimeout) {
				LK.clearTimeout(comboTimeout);
				comboTimeout = null;
			}
			comboTxt.visible = false;
			LK.effects.flashScreen(0x000000, 600);
			health = Math.max(0, health - 1);
			var healthFrac = health / maxHealth;
			healthBar.scaleX = healthBarWidth * healthFrac / 100;
			if (healthFrac > 0.66) {
				healthBar.tint = 0x00ff00;
			} else if (healthFrac > 0.33) {
				healthBar.tint = 0xffc700;
			} else {
				healthBar.tint = 0xff2222;
			}
			for (var hi = 0; hi < healthHearts.length; hi++) {
				healthHearts[hi].alpha = hi < health ? 1 : 0.25;
				healthHearts[hi].tint = hi < health ? 0xff2222 : 0x444444;
			}
			if (health <= 0) {
				LK.setTimeout(function () {
					LK.showGameOver();
					if (typeof LK.showLeaderboard === "function") {
						LK.showLeaderboard({
							showOthers: true
						});
					}
				}, 600);
				gameOver = true;
				return;
			}
			if (bomb && bomb.destroy) bomb.destroy();
			bombsToRemove.push(j);
			continue;
		}
		// Off screen (cleanup)
		if (bomb.y > 2800) {
			if (bomb && bomb.destroy) bomb.destroy();
			bombsToRemove.push(j);
			continue;
		}
		bomb.lastY = bomb.y;
		bomb.lastIntersecting = intersecting;
	}
	// Remove bombs after loop
	// Remove from highest index to lowest to avoid shifting issues
	bombsToRemove.sort(function (a, b) {
		return b - a;
	});
	for (var btr = 0; btr < bombsToRemove.length; btr++) {
		bombs.splice(bombsToRemove[btr], 1);
	}
	// Update power-ups
	var powerupsToRemove = [];
	for (var k = powerups.length - 1; k >= 0; k--) {
		var powerup = powerups[k];
		if (powerup.lastY === undefined) powerup.lastY = powerup.y;
		if (powerup.lastIntersecting === undefined) powerup.lastIntersecting = false;
		powerup.update();
		// Check for catch
		var intersecting = powerup.intersects(basket);
		if (!powerup.lastIntersecting && intersecting) {
			if (powerup.type === "shield" || powerup instanceof ShieldPowerUp || powerup instanceof Watermelon) {
				basket.hasShield = true;
				LK.effects.flashObject(basket, 0x00ffff, 400);
				LK.effects.flashScreen(0x00ffff, 200);
				if (!basket.shieldTween) {
					basket.shieldTween = tween(basket, {
						alpha: 1
					}, {
						duration: 200,
						yoyo: true,
						repeat: Infinity,
						easing: tween.easeInOut
					});
				}
				tween(powerup, {
					y: basket.y,
					alpha: 0
				}, {
					duration: 200,
					easing: tween.easeIn,
					onFinish: function (puRef) {
						return function () {
							if (puRef && puRef.destroy) puRef.destroy();
						};
					}(powerup)
				});
				powerupsToRemove.push(k);
				continue;
			} else if (powerup.type === "slow" || powerup instanceof Grape) {
				for (var bi = 0; bi < balls.length; bi++) {
					balls[bi].speed *= 0.4;
					balls[bi].vx *= 0.4;
				}
				for (var bj = 0; bj < bombs.length; bj++) {
					bombs[bj].speed *= 0.4;
				}
				for (var bp = 0; bp < powerups.length; bp++) {
					powerups[bp].speed *= 0.4;
				}
				missTxt.setText('Slow Motion!');
				missTxt.visible = true;
				if (missTxt.hideTimeout) {
					LK.clearTimeout(missTxt.hideTimeout);
					missTxt.hideTimeout = null;
				}
				missTxt.hideTimeout = LK.setTimeout(function () {
					missTxt.visible = false;
					missTxt.hideTimeout = null;
				}, 1200);
				LK.setTimeout(function () {
					for (var bi = 0; bi < balls.length; bi++) {
						balls[bi].speed /= 0.4;
						balls[bi].vx /= 0.4;
					}
					for (var bj = 0; bj < bombs.length; bj++) {
						bombs[bj].speed /= 0.4;
					}
					for (var bp = 0; bp < powerups.length; bp++) {
						powerups[bp].speed /= 0.4;
					}
				}, 3000);
				tween(powerup, {
					y: basket.y,
					alpha: 0
				}, {
					duration: 200,
					easing: tween.easeIn,
					onFinish: function (puRef) {
						return function () {
							if (puRef && puRef.destroy) puRef.destroy();
						};
					}(powerup)
				});
				powerupsToRemove.push(k);
				continue;
			} else if (powerup.type === "banana" || powerup instanceof Banana) {
				var originalScale = basket.scaleX || 1;
				basket.scaleX = originalScale * 1.5;
				basket.scaleY = (basket.scaleY || 1) * 1.1;
				LK.effects.flashObject(basket, 0xfff700, 300);
				missTxt.setText('Wide Basket!');
				missTxt.visible = true;
				if (missTxt.hideTimeout) {
					LK.clearTimeout(missTxt.hideTimeout);
					missTxt.hideTimeout = null;
				}
				missTxt.hideTimeout = LK.setTimeout(function () {
					missTxt.visible = false;
					missTxt.hideTimeout = null;
				}, 1200);
				LK.setTimeout(function () {
					basket.scaleX = originalScale;
					basket.scaleY = 1;
				}, 4000);
				tween(powerup, {
					y: basket.y,
					alpha: 0
				}, {
					duration: 200,
					easing: tween.easeIn,
					onFinish: function (puRef) {
						return function () {
							if (puRef && puRef.destroy) puRef.destroy();
						};
					}(powerup)
				});
				powerupsToRemove.push(k);
				continue;
			} else if (powerup.type === "apple" || powerup instanceof Apple) {
				LK.setScore(LK.getScore() + 5);
				scoreTxt.setText(LK.getScore());
				LK.getSound('catch').play();
				LK.effects.flashScreen(0xff2222, 350);
				LK.effects.flashObject(basket, 0xff2222, 300);
				missTxt.setText('Apple! +5');
				missTxt.visible = true;
				if (missTxt.hideTimeout) {
					LK.clearTimeout(missTxt.hideTimeout);
					missTxt.hideTimeout = null;
				}
				missTxt.hideTimeout = LK.setTimeout(function () {
					missTxt.visible = false;
					missTxt.hideTimeout = null;
				}, 1200);
				tween(powerup, {
					y: basket.y,
					alpha: 0
				}, {
					duration: 200,
					easing: tween.easeIn,
					onFinish: function (puRef) {
						return function () {
							if (puRef && puRef.destroy) puRef.destroy();
						};
					}(powerup)
				});
				powerupsToRemove.push(k);
				continue;
			} else {
				LK.setScore(LK.getScore() + 2);
				scoreTxt.setText(LK.getScore());
				LK.getSound('catch').play();
				LK.effects.flashScreen(0xFFD700, 350);
				LK.effects.flashObject(basket, 0xFFD700, 300);
				tween(powerup, {
					y: basket.y,
					alpha: 0
				}, {
					duration: 200,
					easing: tween.easeIn,
					onFinish: function (puRef) {
						return function () {
							if (puRef && puRef.destroy) puRef.destroy();
						};
					}(powerup)
				});
				powerupsToRemove.push(k);
				continue;
			}
		}
		// Off screen (cleanup)
		if (powerup.y > 2800) {
			if (powerup && powerup.destroy) powerup.destroy();
			powerupsToRemove.push(k);
			continue;
		}
		powerup.lastY = powerup.y;
		powerup.lastIntersecting = intersecting;
	}
	// Remove powerups after loop
	// Remove from highest index to lowest to avoid shifting issues
	powerupsToRemove.sort(function (a, b) {
		return b - a;
	});
	for (var putr = 0; putr < powerupsToRemove.length; putr++) {
		powerups.splice(powerupsToRemove[putr], 1);
	}
	// Hide miss text after a short time
	if (missTxt.visible) {
		if (!missTxt.hideTimeout) {
			missTxt.hideTimeout = LK.setTimeout(function () {
				missTxt.visible = false;
				missTxt.hideTimeout = null;
			}, 900);
		}
	}
	// Draw shield icon above basket if shield is active
	if (basket.hasShield) {
		if (!basket.shieldIcon) {
			basket.shieldIcon = LK.getAsset('ball', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			basket.shieldIcon.tint = 0x00ffff;
			basket.shieldIcon.scaleX = 0.5;
			basket.shieldIcon.scaleY = 0.5;
			game.addChild(basket.shieldIcon);
		}
		basket.shieldIcon.x = basket.x;
		basket.shieldIcon.y = basket.y - 70;
		basket.shieldIcon.visible = true;
	} else if (basket.shieldIcon) {
		basket.shieldIcon.visible = false;
	}
	// Rainbow basket after 40 points
	if (LK.getScore() >= 40 && basket.children && basket.children.length > 0) {
		var t = LK.ticks % 60 / 60;
		var r = Math.floor(127 * Math.sin(2 * Math.PI * t) + 128);
		var g = Math.floor(127 * Math.sin(2 * Math.PI * t + 2) + 128);
		var b = Math.floor(127 * Math.sin(2 * Math.PI * t + 4) + 128);
		basket.children[0].tint = r << 16 | g << 8 | b;
	}
	// Defensive: Always update lastX and lastY for basket to avoid undefined errors
	if (basket) {
		if (basket.lastX === undefined) basket.lastX = basket.x;
		if (basket.lastY === undefined) basket.lastY = basket.y;
		basket.lastX = basket.x;
		basket.lastY = basket.y;
	}
};
// Reset state on new game
LK.on('gameStart', function () {
	// Remove all balls, bombs, and powerups
	for (var i = 0; i < balls.length; i++) balls[i].destroy();
	for (var j = 0; j < bombs.length; j++) bombs[j].destroy();
	for (var k = 0; k < powerups.length; k++) powerups[k].destroy();
	balls = [];
	bombs = [];
	powerups = [];
	basket.x = 2048 / 2;
	basket.y = 2732 - 180;
	// Reset challenge mode state
	basket.challengeActive = false;
	basket.challengeDir = null;
	if (basket.challengeTween) {
		basket.challengeTween.stop();
		basket.challengeTween = null;
	}
	// Reset shield state
	basket.hasShield = false;
	if (basket.shieldTween) {
		basket.shieldTween.stop();
		basket.shieldTween = null;
	}
	// Randomize basket color on new game
	var basketColors = [0x3b6eea, 0x4ad991, 0xf75e5e, 0xf7a325, 0xFFD700];
	if (basket.children && basket.children.length > 0) {
		basket.children[0].tint = basketColors[Math.floor(Math.random() * basketColors.length)];
	}
	LK.setScore(0);
	scoreTxt.setText('0');
	missTxt.setText('');
	missTxt.visible = false;
	if (missTxt.hideTimeout) {
		LK.clearTimeout(missTxt.hideTimeout);
		missTxt.hideTimeout = null;
	}
	spawnTimer = 0;
	gameOver = false;
	game.missForgiven = false;
	// Reset combo
	comboCount = 0;
	if (comboTimeout) {
		LK.clearTimeout(comboTimeout);
		comboTimeout = null;
	}
	comboTxt.visible = false;
	// Reset health bar and hearts
	health = maxHealth;
	healthBar.scaleX = healthBarWidth / 100;
	healthBar.tint = 0x00ff00;
	for (var hi = 0; hi < healthHearts.length; hi++) {
		healthHearts[hi].alpha = 1;
		healthHearts[hi].tint = 0xff2222;
	}
});