/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
// Enemy Bullet
var EnemyBullet = Container.expand(function () {
	var self = Container.call(this);
	var bullet = self.attachAsset('enemyBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 18;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Enemy Ship
var EnemyShip = Container.expand(function () {
	var self = Container.call(this);
	var ship = self.attachAsset('enemyShip', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.width = ship.width;
	self.height = ship.height;
	self.speed = 4 + Math.random() * 2;
	self.shootCooldown = 60 + Math.floor(Math.random() * 60);
	self.shootTimer = Math.floor(Math.random() * self.shootCooldown);
	self.hp = 1;
	self.update = function () {
		self.y += self.speed;
		if (self.shootTimer > 0) {
			self.shootTimer--;
		}
	};
	return self;
});
// Player Bullet
var PlayerBullet = Container.expand(function () {
	var self = Container.call(this);
	var bullet = self.attachAsset('playerBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = -32;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Player Ship
var PlayerShip = Container.expand(function () {
	var self = Container.call(this);
	var ship = self.attachAsset('playerShip', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.width = ship.width;
	self.height = ship.height;
	self.canShoot = true;
	self.shootCooldown = 24; // frames between shots (reduced fire rate)
	self.shootTimer = 0;
	// self.lives = 1; // For MVP, 1 hit = game over
	self.poweredUp = false;
	self.powerupTimer = 0;
	// Power-up effect
	self.setPowerup = function (duration) {
		self.poweredUp = true;
		self.powerupTimer = duration;
		ship.tint = 0x00ff99;
	};
	self.clearPowerup = function () {
		self.poweredUp = false;
		self.powerupTimer = 0;
		ship.tint = 0xffffff;
	};
	self.update = function () {
		if (self.shootTimer > 0) self.shootTimer--;
		if (self.poweredUp) {
			self.powerupTimer--;
			if (self.powerupTimer <= 0) {
				self.clearPowerup();
			}
		}
	};
	return self;
});
// Powerup
var Powerup = Container.expand(function () {
	var self = Container.call(this);
	var p = self.attachAsset('powerup', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 8;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000010
});
/**** 
* Game Code
****/ 
// Add starfield background image
var background = LK.getAsset('starfield', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: 2732 / 2,
	scaleX: 2048 / 1024,
	// assuming starfield asset is 1024x1366, scale to fit
	scaleY: 2732 / 1366
});
game.addChild(background);
// Tap-to-start overlay
var tapToStartTxt = new Text2('Tap to Start', {
	size: 180,
	fill: 0xffffff,
	font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
tapToStartTxt.anchor.set(0.5, 0.5);
tapToStartTxt.x = 2048 / 2;
tapToStartTxt.y = 2732 / 2;
LK.gui.center.addChild(tapToStartTxt);
var gameStarted = false;
var savedUpdate = null;
// Pause game logic until tap
savedUpdate = game.update;
game.update = function () {
	if (!gameStarted) return;
	savedUpdate();
};
// Pause music until start
var musicStarted = false;
// Block all input except tap to start
var origMove = game.move;
var origDown = game.down;
var origUp = game.up;
game.move = function () {
	if (gameStarted && origMove) origMove.apply(this, arguments);
};
game.down = function (x, y, obj) {
	if (!gameStarted) {
		gameStarted = true;
		LK.gui.center.removeChild(tapToStartTxt);
		if (!musicStarted) {
			LK.playMusic('galacticMusic');
			musicStarted = true;
		}
		// Restore input handlers
		if (origDown) origDown.apply(this, arguments);
		return;
	}
	if (origDown) origDown.apply(this, arguments);
};
game.up = function () {
	if (gameStarted && origUp) origUp.apply(this, arguments);
};
// Score display
var scoreTxt = new Text2('0', {
	size: 120,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Highscore display
var highscore = storage.highscore || 0;
var highscoreTxt = new Text2("HI " + highscore, {
	size: 80,
	fill: 0xFFD700
});
highscoreTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(highscoreTxt);
// Powerup countdown display (lower right)
var powerupCountdownTxt = new Text2('', {
	size: 80,
	fill: 0x00ff99
});
powerupCountdownTxt.anchor.set(1, 1); // bottom right
LK.gui.bottomRight.addChild(powerupCountdownTxt);
// Lives display (top left, but offset to avoid menu)
var livesTxt = new Text2('♥♥♥', {
	size: 100,
	fill: 0xff4444
});
livesTxt.anchor.set(0, 0);
livesTxt.x = 110; // leave 100px for menu
livesTxt.y = 0;
LK.gui.top.addChild(livesTxt);
// Game variables
var player;
var playerBullets = [];
var enemies = [];
var enemyBullets = [];
var powerups = [];
var dragNode = null;
var lastPlayerHit = false;
var spawnTimer = 0;
var powerupSpawnTimer = 0;
// Enemy shooting control
var enemyShootingEnabled = false;
var enemyShootInterval = 120; // initial interval (frames between shots, high so they don't shoot at first)
var lastEnemyShootInterval = 120;
// Helper: Clamp value
function clamp(val, min, max) {
	return Math.max(min, Math.min(max, val));
}
// Initialize player
player = new PlayerShip();
player.lives = 3;
player.x = 2048 / 2;
player.y = 2732 - 220;
game.addChild(player);
// Move handler (drag player ship)
function handleMove(x, y, obj) {
	if (dragNode === player) {
		// Clamp player within screen bounds
		var halfW = player.width / 2;
		var halfH = player.height / 2;
		player.x = clamp(x, halfW, 2048 - halfW);
		player.y = clamp(y, 2048, 2732 - halfH); // Only allow movement in lower 700px
	}
}
game.move = handleMove;
game.down = function (x, y, obj) {
	// Only start drag if touch is on player
	var local = player.toLocal(game.toGlobal({
		x: x,
		y: y
	}));
	if (local.x >= -player.width / 2 && local.x <= player.width / 2 && local.y >= -player.height / 2 && local.y <= player.height / 2) {
		dragNode = player;
		handleMove(x, y, obj);
	}
};
game.up = function (x, y, obj) {
	dragNode = null;
};
// Fire player bullet (auto-fire, no mouse button needed)
function firePlayerBullet() {
	if (player.shootTimer === 0) {
		var bullet = new PlayerBullet();
		bullet.x = player.x;
		bullet.y = player.y - player.height / 2 - 10;
		playerBullets.push(bullet);
		game.addChild(bullet);
		LK.getSound('shoot').play();
		player.shootTimer = player.poweredUp ? 6 : player.shootCooldown;
		// Power-up: triple shot
		if (player.poweredUp) {
			for (var i = -1; i <= 1; i += 2) {
				var b = new PlayerBullet();
				b.x = player.x + i * 50;
				b.y = player.y - player.height / 2 - 10;
				b.rotation = i * 0.18;
				b.update = function (angle) {
					return function () {
						this.y += this.speed * Math.cos(angle);
						this.x += this.speed * Math.sin(angle);
					};
				}(i * 0.18);
				playerBullets.push(b);
				game.addChild(b);
			}
		}
	}
}
// Spawn enemy
function spawnEnemy() {
	var enemy = new EnemyShip();
	enemy.x = 180 + Math.random() * (2048 - 360);
	enemy.y = -enemy.height / 2 - 10;
	// Set initial shootCooldown based on current global interval
	enemy.shootCooldown = enemyShootingEnabled ? enemyShootInterval + Math.floor(Math.random() * 30) : 120 + Math.floor(Math.random() * 60);
	enemy.shootTimer = Math.floor(Math.random() * enemy.shootCooldown);
	enemies.push(enemy);
	game.addChild(enemy);
}
// Spawn powerup
function spawnPowerup() {
	var p = new Powerup();
	p.x = 180 + Math.random() * (2048 - 360);
	p.y = -p.height / 2 - 10;
	powerups.push(p);
	game.addChild(p);
}
// Main update loop
game.update = function () {
	// Player update
	player.update();
	// Update lives display
	var livesStr = '';
	for (var i = 0; i < player.lives; i++) livesStr += '♥';
	livesTxt.setText(livesStr);
	// Update powerup countdown text
	if (player.poweredUp && player.powerupTimer > 0) {
		// Show seconds left, rounded up
		var seconds = Math.ceil(player.powerupTimer / 60);
		powerupCountdownTxt.setText(seconds + "s");
	} else {
		powerupCountdownTxt.setText('');
	}
	// Player auto-fire
	if (LK.ticks % 2 === 0) {
		firePlayerBullet();
	}
	// Update player bullets
	for (var i = playerBullets.length - 1; i >= 0; i--) {
		var b = playerBullets[i];
		b.update();
		// Remove if off screen
		if (b.y < -80) {
			b.destroy();
			playerBullets.splice(i, 1);
			continue;
		}
		// Check collision with enemies
		for (var j = enemies.length - 1; j >= 0; j--) {
			var e = enemies[j];
			if (b.intersects(e)) {
				e.hp--;
				if (e.hp <= 0) {
					// Explosion effect
					LK.effects.flashObject(e, 0xffffff, 200);
					// Add explosion sprite at enemy position
					var explosion = LK.getAsset('explosion', {
						anchorX: 0.5,
						anchorY: 0.5,
						x: e.x,
						y: e.y
					});
					game.addChild(explosion);
					// Animate explosion fade out and destroy after 400ms
					tween(explosion, {
						alpha: 0
					}, {
						duration: 400,
						onFinish: function onFinish() {
							explosion.destroy();
						}
					});
					LK.getSound('explosion').play();
					LK.setScore(LK.getScore() + 10);
					scoreTxt.setText(LK.getScore());
					// Highscore logic
					if (LK.getScore() > highscore) {
						highscore = LK.getScore();
						storage.highscore = highscore;
						highscoreTxt.setText("HI " + highscore);
					}
					e.destroy();
					enemies.splice(j, 1);
				}
				b.destroy();
				playerBullets.splice(i, 1);
				break;
			}
		}
	}
	// Update enemies
	var playerWasHitThisFrame = false; // Track if player was hit this frame
	for (var i = enemies.length - 1; i >= 0; i--) {
		var e = enemies[i];
		e.update();
		// Remove if off screen
		if (e.y > 2732 + e.height) {
			e.destroy();
			enemies.splice(i, 1);
			continue;
		}
		// Enemy shooting logic
		// Enable enemy shooting after player reaches 200 points
		if (!enemyShootingEnabled && LK.getScore() >= 200) {
			enemyShootingEnabled = true;
		}
		// Gradually increase fire rate after enemy shooting is enabled
		if (enemyShootingEnabled) {
			// Decrease interval every 10 seconds, down to a minimum
			var minInterval = 24; // fastest fire rate (lower = faster)
			var maxInterval = 120; // slowest fire rate (at start)
			// Use ticks since enabling shooting to ramp up fire rate
			if (typeof enemyShootingStartTick === "undefined") {
				enemyShootingStartTick = LK.ticks;
			}
			var elapsed = LK.ticks - enemyShootingStartTick;
			var interval = Math.max(minInterval, maxInterval - Math.floor(elapsed / 600) * 8);
			enemyShootInterval = interval;
			// If interval changed, update all enemies' shootCooldown
			if (enemyShootInterval !== lastEnemyShootInterval) {
				for (var j = 0; j < enemies.length; j++) {
					enemies[j].shootCooldown = enemyShootInterval + Math.floor(Math.random() * 30);
				}
				lastEnemyShootInterval = enemyShootInterval;
			}
		}
		// Enemy shooting
		if (enemyShootingEnabled && e.shootTimer === 0) {
			var eb = new EnemyBullet();
			eb.x = e.x;
			eb.y = e.y + e.height / 2 + 10;
			enemyBullets.push(eb);
			game.addChild(eb);
			LK.getSound('enemyShoot').play();
			e.shootTimer = e.shootCooldown;
		}
		// Check collision with player
		if (e.intersects(player)) {
			if (!e.lastHitPlayer) {
				if (!lastPlayerHit && !playerWasHitThisFrame) {
					LK.effects.flashScreen(0xff0000, 800);
					LK.getSound('explosion').play();
					player.lives--;
					playerWasHitThisFrame = true;
					if (player.lives <= 0) {
						player.lives = 0;
						livesTxt.setText('');
						LK.showGameOver();
					} else {
						// Reset player position and give brief invulnerability
						player.x = 2048 / 2;
						player.y = 2732 - 220;
					}
					lastPlayerHit = true;
				}
				e.lastHitPlayer = true;
			}
		} else {
			e.lastHitPlayer = false;
		}
	}
	// Update enemy bullets
	for (var i = enemyBullets.length - 1; i >= 0; i--) {
		var eb = enemyBullets[i];
		eb.update();
		if (eb.y > 2732 + 60) {
			eb.destroy();
			enemyBullets.splice(i, 1);
			continue;
		}
		// Check collision with player
		if (eb.intersects(player)) {
			if (!eb.lastHitPlayer) {
				if (!lastPlayerHit && !playerWasHitThisFrame) {
					LK.effects.flashScreen(0xff0000, 800);
					LK.getSound('explosion').play();
					player.lives--;
					playerWasHitThisFrame = true;
					if (player.lives <= 0) {
						player.lives = 0;
						livesTxt.setText('');
						LK.showGameOver();
					} else {
						// Reset player position and give brief invulnerability
						player.x = 2048 / 2;
						player.y = 2732 - 220;
					}
					lastPlayerHit = true;
				}
				eb.lastHitPlayer = true;
			}
		} else {
			eb.lastHitPlayer = false;
		}
	}
	// Update powerups
	for (var i = powerups.length - 1; i >= 0; i--) {
		var p = powerups[i];
		p.update();
		if (p.y > 2732 + 60) {
			p.destroy();
			powerups.splice(i, 1);
			continue;
		}
		// Check collision with player
		if (p.intersects(player)) {
			player.setPowerup(600); // 10 seconds at 60fps
			LK.getSound('powerup').play();
			p.destroy();
			powerups.splice(i, 1);
		}
	}
	// Enemy spawn logic
	spawnTimer--;
	if (spawnTimer <= 0) {
		spawnEnemy();
		// After 600 points, spawn an extra enemy each spawn cycle
		if (LK.getScore() >= 600) {
			spawnEnemy();
		}
		spawnTimer = 36 + Math.floor(Math.random() * 24); // spawn every 1s approx
	}
	// Powerup spawn logic
	powerupSpawnTimer--;
	if (powerupSpawnTimer <= 0) {
		if (Math.random() < 0.18) {
			spawnPowerup();
		}
		powerupSpawnTimer = 360 + Math.floor(Math.random() * 240); // every 6-10s
	}
	// Reset lastPlayerHit if player is alive
	if (!player.destroyed) {
		lastPlayerHit = false;
	}
};
// Reset game state on game over
LK.on('gameover', function () {
	// Clean up all objects
	for (var i = 0; i < playerBullets.length; i++) playerBullets[i].destroy();
	for (var i = 0; i < enemies.length; i++) enemies[i].destroy();
	for (var i = 0; i < enemyBullets.length; i++) enemyBullets[i].destroy();
	for (var i = 0; i < powerups.length; i++) powerups[i].destroy();
	playerBullets = [];
	enemies = [];
	enemyBullets = [];
	powerups = [];
	lastPlayerHit = false;
	// Reset player lives
	if (player) player.lives = 3;
	// Update lives display
	var livesStr = '';
	for (var i = 0; i < 3; i++) livesStr += '♥';
	livesTxt.setText(livesStr);
	// Music will be handled by LK
	// Update highscore display in case storage was externally changed
	highscore = storage.highscore || 0;
	highscoreTxt.setText("HI " + highscore);
});
// Reset game state on win (not used in MVP, but for future)
LK.on('youwin', function () {
	for (var i = 0; i < playerBullets.length; i++) playerBullets[i].destroy();
	for (var i = 0; i < enemies.length; i++) enemies[i].destroy();
	for (var i = 0; i < enemyBullets.length; i++) enemyBullets[i].destroy();
	for (var i = 0; i < powerups.length; i++) powerups[i].destroy();
	playerBullets = [];
	enemies = [];
	enemyBullets = [];
	powerups = [];
	lastPlayerHit = false;
	// Reset player lives
	if (player) player.lives = 3;
	// Update lives display
	var livesStr = '';
	for (var i = 0; i < 3; i++) livesStr += '♥';
	livesTxt.setText(livesStr);
	// Update highscore display in case storage was externally changed
	highscore = storage.highscore || 0;
	highscoreTxt.setText("HI " + highscore);
}); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
// Enemy Bullet
var EnemyBullet = Container.expand(function () {
	var self = Container.call(this);
	var bullet = self.attachAsset('enemyBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 18;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Enemy Ship
var EnemyShip = Container.expand(function () {
	var self = Container.call(this);
	var ship = self.attachAsset('enemyShip', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.width = ship.width;
	self.height = ship.height;
	self.speed = 4 + Math.random() * 2;
	self.shootCooldown = 60 + Math.floor(Math.random() * 60);
	self.shootTimer = Math.floor(Math.random() * self.shootCooldown);
	self.hp = 1;
	self.update = function () {
		self.y += self.speed;
		if (self.shootTimer > 0) {
			self.shootTimer--;
		}
	};
	return self;
});
// Player Bullet
var PlayerBullet = Container.expand(function () {
	var self = Container.call(this);
	var bullet = self.attachAsset('playerBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = -32;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Player Ship
var PlayerShip = Container.expand(function () {
	var self = Container.call(this);
	var ship = self.attachAsset('playerShip', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.width = ship.width;
	self.height = ship.height;
	self.canShoot = true;
	self.shootCooldown = 24; // frames between shots (reduced fire rate)
	self.shootTimer = 0;
	// self.lives = 1; // For MVP, 1 hit = game over
	self.poweredUp = false;
	self.powerupTimer = 0;
	// Power-up effect
	self.setPowerup = function (duration) {
		self.poweredUp = true;
		self.powerupTimer = duration;
		ship.tint = 0x00ff99;
	};
	self.clearPowerup = function () {
		self.poweredUp = false;
		self.powerupTimer = 0;
		ship.tint = 0xffffff;
	};
	self.update = function () {
		if (self.shootTimer > 0) self.shootTimer--;
		if (self.poweredUp) {
			self.powerupTimer--;
			if (self.powerupTimer <= 0) {
				self.clearPowerup();
			}
		}
	};
	return self;
});
// Powerup
var Powerup = Container.expand(function () {
	var self = Container.call(this);
	var p = self.attachAsset('powerup', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 8;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000010
});
/**** 
* Game Code
****/ 
// Add starfield background image
var background = LK.getAsset('starfield', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: 2732 / 2,
	scaleX: 2048 / 1024,
	// assuming starfield asset is 1024x1366, scale to fit
	scaleY: 2732 / 1366
});
game.addChild(background);
// Tap-to-start overlay
var tapToStartTxt = new Text2('Tap to Start', {
	size: 180,
	fill: 0xffffff,
	font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
tapToStartTxt.anchor.set(0.5, 0.5);
tapToStartTxt.x = 2048 / 2;
tapToStartTxt.y = 2732 / 2;
LK.gui.center.addChild(tapToStartTxt);
var gameStarted = false;
var savedUpdate = null;
// Pause game logic until tap
savedUpdate = game.update;
game.update = function () {
	if (!gameStarted) return;
	savedUpdate();
};
// Pause music until start
var musicStarted = false;
// Block all input except tap to start
var origMove = game.move;
var origDown = game.down;
var origUp = game.up;
game.move = function () {
	if (gameStarted && origMove) origMove.apply(this, arguments);
};
game.down = function (x, y, obj) {
	if (!gameStarted) {
		gameStarted = true;
		LK.gui.center.removeChild(tapToStartTxt);
		if (!musicStarted) {
			LK.playMusic('galacticMusic');
			musicStarted = true;
		}
		// Restore input handlers
		if (origDown) origDown.apply(this, arguments);
		return;
	}
	if (origDown) origDown.apply(this, arguments);
};
game.up = function () {
	if (gameStarted && origUp) origUp.apply(this, arguments);
};
// Score display
var scoreTxt = new Text2('0', {
	size: 120,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Highscore display
var highscore = storage.highscore || 0;
var highscoreTxt = new Text2("HI " + highscore, {
	size: 80,
	fill: 0xFFD700
});
highscoreTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(highscoreTxt);
// Powerup countdown display (lower right)
var powerupCountdownTxt = new Text2('', {
	size: 80,
	fill: 0x00ff99
});
powerupCountdownTxt.anchor.set(1, 1); // bottom right
LK.gui.bottomRight.addChild(powerupCountdownTxt);
// Lives display (top left, but offset to avoid menu)
var livesTxt = new Text2('♥♥♥', {
	size: 100,
	fill: 0xff4444
});
livesTxt.anchor.set(0, 0);
livesTxt.x = 110; // leave 100px for menu
livesTxt.y = 0;
LK.gui.top.addChild(livesTxt);
// Game variables
var player;
var playerBullets = [];
var enemies = [];
var enemyBullets = [];
var powerups = [];
var dragNode = null;
var lastPlayerHit = false;
var spawnTimer = 0;
var powerupSpawnTimer = 0;
// Enemy shooting control
var enemyShootingEnabled = false;
var enemyShootInterval = 120; // initial interval (frames between shots, high so they don't shoot at first)
var lastEnemyShootInterval = 120;
// Helper: Clamp value
function clamp(val, min, max) {
	return Math.max(min, Math.min(max, val));
}
// Initialize player
player = new PlayerShip();
player.lives = 3;
player.x = 2048 / 2;
player.y = 2732 - 220;
game.addChild(player);
// Move handler (drag player ship)
function handleMove(x, y, obj) {
	if (dragNode === player) {
		// Clamp player within screen bounds
		var halfW = player.width / 2;
		var halfH = player.height / 2;
		player.x = clamp(x, halfW, 2048 - halfW);
		player.y = clamp(y, 2048, 2732 - halfH); // Only allow movement in lower 700px
	}
}
game.move = handleMove;
game.down = function (x, y, obj) {
	// Only start drag if touch is on player
	var local = player.toLocal(game.toGlobal({
		x: x,
		y: y
	}));
	if (local.x >= -player.width / 2 && local.x <= player.width / 2 && local.y >= -player.height / 2 && local.y <= player.height / 2) {
		dragNode = player;
		handleMove(x, y, obj);
	}
};
game.up = function (x, y, obj) {
	dragNode = null;
};
// Fire player bullet (auto-fire, no mouse button needed)
function firePlayerBullet() {
	if (player.shootTimer === 0) {
		var bullet = new PlayerBullet();
		bullet.x = player.x;
		bullet.y = player.y - player.height / 2 - 10;
		playerBullets.push(bullet);
		game.addChild(bullet);
		LK.getSound('shoot').play();
		player.shootTimer = player.poweredUp ? 6 : player.shootCooldown;
		// Power-up: triple shot
		if (player.poweredUp) {
			for (var i = -1; i <= 1; i += 2) {
				var b = new PlayerBullet();
				b.x = player.x + i * 50;
				b.y = player.y - player.height / 2 - 10;
				b.rotation = i * 0.18;
				b.update = function (angle) {
					return function () {
						this.y += this.speed * Math.cos(angle);
						this.x += this.speed * Math.sin(angle);
					};
				}(i * 0.18);
				playerBullets.push(b);
				game.addChild(b);
			}
		}
	}
}
// Spawn enemy
function spawnEnemy() {
	var enemy = new EnemyShip();
	enemy.x = 180 + Math.random() * (2048 - 360);
	enemy.y = -enemy.height / 2 - 10;
	// Set initial shootCooldown based on current global interval
	enemy.shootCooldown = enemyShootingEnabled ? enemyShootInterval + Math.floor(Math.random() * 30) : 120 + Math.floor(Math.random() * 60);
	enemy.shootTimer = Math.floor(Math.random() * enemy.shootCooldown);
	enemies.push(enemy);
	game.addChild(enemy);
}
// Spawn powerup
function spawnPowerup() {
	var p = new Powerup();
	p.x = 180 + Math.random() * (2048 - 360);
	p.y = -p.height / 2 - 10;
	powerups.push(p);
	game.addChild(p);
}
// Main update loop
game.update = function () {
	// Player update
	player.update();
	// Update lives display
	var livesStr = '';
	for (var i = 0; i < player.lives; i++) livesStr += '♥';
	livesTxt.setText(livesStr);
	// Update powerup countdown text
	if (player.poweredUp && player.powerupTimer > 0) {
		// Show seconds left, rounded up
		var seconds = Math.ceil(player.powerupTimer / 60);
		powerupCountdownTxt.setText(seconds + "s");
	} else {
		powerupCountdownTxt.setText('');
	}
	// Player auto-fire
	if (LK.ticks % 2 === 0) {
		firePlayerBullet();
	}
	// Update player bullets
	for (var i = playerBullets.length - 1; i >= 0; i--) {
		var b = playerBullets[i];
		b.update();
		// Remove if off screen
		if (b.y < -80) {
			b.destroy();
			playerBullets.splice(i, 1);
			continue;
		}
		// Check collision with enemies
		for (var j = enemies.length - 1; j >= 0; j--) {
			var e = enemies[j];
			if (b.intersects(e)) {
				e.hp--;
				if (e.hp <= 0) {
					// Explosion effect
					LK.effects.flashObject(e, 0xffffff, 200);
					// Add explosion sprite at enemy position
					var explosion = LK.getAsset('explosion', {
						anchorX: 0.5,
						anchorY: 0.5,
						x: e.x,
						y: e.y
					});
					game.addChild(explosion);
					// Animate explosion fade out and destroy after 400ms
					tween(explosion, {
						alpha: 0
					}, {
						duration: 400,
						onFinish: function onFinish() {
							explosion.destroy();
						}
					});
					LK.getSound('explosion').play();
					LK.setScore(LK.getScore() + 10);
					scoreTxt.setText(LK.getScore());
					// Highscore logic
					if (LK.getScore() > highscore) {
						highscore = LK.getScore();
						storage.highscore = highscore;
						highscoreTxt.setText("HI " + highscore);
					}
					e.destroy();
					enemies.splice(j, 1);
				}
				b.destroy();
				playerBullets.splice(i, 1);
				break;
			}
		}
	}
	// Update enemies
	var playerWasHitThisFrame = false; // Track if player was hit this frame
	for (var i = enemies.length - 1; i >= 0; i--) {
		var e = enemies[i];
		e.update();
		// Remove if off screen
		if (e.y > 2732 + e.height) {
			e.destroy();
			enemies.splice(i, 1);
			continue;
		}
		// Enemy shooting logic
		// Enable enemy shooting after player reaches 200 points
		if (!enemyShootingEnabled && LK.getScore() >= 200) {
			enemyShootingEnabled = true;
		}
		// Gradually increase fire rate after enemy shooting is enabled
		if (enemyShootingEnabled) {
			// Decrease interval every 10 seconds, down to a minimum
			var minInterval = 24; // fastest fire rate (lower = faster)
			var maxInterval = 120; // slowest fire rate (at start)
			// Use ticks since enabling shooting to ramp up fire rate
			if (typeof enemyShootingStartTick === "undefined") {
				enemyShootingStartTick = LK.ticks;
			}
			var elapsed = LK.ticks - enemyShootingStartTick;
			var interval = Math.max(minInterval, maxInterval - Math.floor(elapsed / 600) * 8);
			enemyShootInterval = interval;
			// If interval changed, update all enemies' shootCooldown
			if (enemyShootInterval !== lastEnemyShootInterval) {
				for (var j = 0; j < enemies.length; j++) {
					enemies[j].shootCooldown = enemyShootInterval + Math.floor(Math.random() * 30);
				}
				lastEnemyShootInterval = enemyShootInterval;
			}
		}
		// Enemy shooting
		if (enemyShootingEnabled && e.shootTimer === 0) {
			var eb = new EnemyBullet();
			eb.x = e.x;
			eb.y = e.y + e.height / 2 + 10;
			enemyBullets.push(eb);
			game.addChild(eb);
			LK.getSound('enemyShoot').play();
			e.shootTimer = e.shootCooldown;
		}
		// Check collision with player
		if (e.intersects(player)) {
			if (!e.lastHitPlayer) {
				if (!lastPlayerHit && !playerWasHitThisFrame) {
					LK.effects.flashScreen(0xff0000, 800);
					LK.getSound('explosion').play();
					player.lives--;
					playerWasHitThisFrame = true;
					if (player.lives <= 0) {
						player.lives = 0;
						livesTxt.setText('');
						LK.showGameOver();
					} else {
						// Reset player position and give brief invulnerability
						player.x = 2048 / 2;
						player.y = 2732 - 220;
					}
					lastPlayerHit = true;
				}
				e.lastHitPlayer = true;
			}
		} else {
			e.lastHitPlayer = false;
		}
	}
	// Update enemy bullets
	for (var i = enemyBullets.length - 1; i >= 0; i--) {
		var eb = enemyBullets[i];
		eb.update();
		if (eb.y > 2732 + 60) {
			eb.destroy();
			enemyBullets.splice(i, 1);
			continue;
		}
		// Check collision with player
		if (eb.intersects(player)) {
			if (!eb.lastHitPlayer) {
				if (!lastPlayerHit && !playerWasHitThisFrame) {
					LK.effects.flashScreen(0xff0000, 800);
					LK.getSound('explosion').play();
					player.lives--;
					playerWasHitThisFrame = true;
					if (player.lives <= 0) {
						player.lives = 0;
						livesTxt.setText('');
						LK.showGameOver();
					} else {
						// Reset player position and give brief invulnerability
						player.x = 2048 / 2;
						player.y = 2732 - 220;
					}
					lastPlayerHit = true;
				}
				eb.lastHitPlayer = true;
			}
		} else {
			eb.lastHitPlayer = false;
		}
	}
	// Update powerups
	for (var i = powerups.length - 1; i >= 0; i--) {
		var p = powerups[i];
		p.update();
		if (p.y > 2732 + 60) {
			p.destroy();
			powerups.splice(i, 1);
			continue;
		}
		// Check collision with player
		if (p.intersects(player)) {
			player.setPowerup(600); // 10 seconds at 60fps
			LK.getSound('powerup').play();
			p.destroy();
			powerups.splice(i, 1);
		}
	}
	// Enemy spawn logic
	spawnTimer--;
	if (spawnTimer <= 0) {
		spawnEnemy();
		// After 600 points, spawn an extra enemy each spawn cycle
		if (LK.getScore() >= 600) {
			spawnEnemy();
		}
		spawnTimer = 36 + Math.floor(Math.random() * 24); // spawn every 1s approx
	}
	// Powerup spawn logic
	powerupSpawnTimer--;
	if (powerupSpawnTimer <= 0) {
		if (Math.random() < 0.18) {
			spawnPowerup();
		}
		powerupSpawnTimer = 360 + Math.floor(Math.random() * 240); // every 6-10s
	}
	// Reset lastPlayerHit if player is alive
	if (!player.destroyed) {
		lastPlayerHit = false;
	}
};
// Reset game state on game over
LK.on('gameover', function () {
	// Clean up all objects
	for (var i = 0; i < playerBullets.length; i++) playerBullets[i].destroy();
	for (var i = 0; i < enemies.length; i++) enemies[i].destroy();
	for (var i = 0; i < enemyBullets.length; i++) enemyBullets[i].destroy();
	for (var i = 0; i < powerups.length; i++) powerups[i].destroy();
	playerBullets = [];
	enemies = [];
	enemyBullets = [];
	powerups = [];
	lastPlayerHit = false;
	// Reset player lives
	if (player) player.lives = 3;
	// Update lives display
	var livesStr = '';
	for (var i = 0; i < 3; i++) livesStr += '♥';
	livesTxt.setText(livesStr);
	// Music will be handled by LK
	// Update highscore display in case storage was externally changed
	highscore = storage.highscore || 0;
	highscoreTxt.setText("HI " + highscore);
});
// Reset game state on win (not used in MVP, but for future)
LK.on('youwin', function () {
	for (var i = 0; i < playerBullets.length; i++) playerBullets[i].destroy();
	for (var i = 0; i < enemies.length; i++) enemies[i].destroy();
	for (var i = 0; i < enemyBullets.length; i++) enemyBullets[i].destroy();
	for (var i = 0; i < powerups.length; i++) powerups[i].destroy();
	playerBullets = [];
	enemies = [];
	enemyBullets = [];
	powerups = [];
	lastPlayerHit = false;
	// Reset player lives
	if (player) player.lives = 3;
	// Update lives display
	var livesStr = '';
	for (var i = 0; i < 3; i++) livesStr += '♥';
	livesTxt.setText(livesStr);
	// Update highscore display in case storage was externally changed
	highscore = storage.highscore || 0;
	highscoreTxt.setText("HI " + highscore);
});
:quality(85)/https://cdn.frvr.ai/6834e07f5175c50674439f64.png%3F3) 
 spaceship seen from above. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6834e0ff5175c50674439f6e.png%3F3) 
 spaceship seen from up going down. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6834e3c75175c50674439f9a.png%3F3) 
 color blue
:quality(85)/https://cdn.frvr.ai/6834e47c5175c50674439fa4.png%3F3) 
 red laser beam. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6834e9845175c50674439fe5.png%3F3) 
 color green
:quality(85)/https://cdn.frvr.ai/6834ec315175c5067443a007.png%3F3) 
 explosion. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6834ecc35175c5067443a011.png%3F3) 
 starfield banner
:quality(85)/https://cdn.frvr.ai/6840b3aeca168837478c56d4.png%3F3) 
 make box yellow