/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Enemy
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGfx = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.width = enemyGfx.width;
	self.height = enemyGfx.height;
	self.speed = 5 + Math.random() * 4;
	self.hp = 1;
	self.shootCooldown = 0;
	self.type = 'normal'; // or 'boss'
	self.update = function () {
		// Check if enemy is in falling state
		if (self.isFalling) {
			return; // Let the falling animation be managed separately
		}
		self.x -= self.speed;
		if (self.shootCooldown > 0) {
			self.shootCooldown--;
		}
	};
	return self;
});
// Enemy bullet
var EnemyBullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletGfx = self.attachAsset('enemyBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 8;
	self.update = function () {
		self.x -= self.speed;
	};
	return self;
});
// Explosion effect
var Explosion = Container.expand(function () {
	var self = Container.call(this);
	var explosionGfx = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5,
		tint: 0xff5500
	});
	self.lifespan = 20;
	self.scale = 0.2;
	// Animation effect
	self.start = function (size) {
		self.scale = size || 1;
		explosionGfx.scale.x = 0.2;
		explosionGfx.scale.y = 0.2;
		explosionGfx.alpha = 1;
		explosionGfx.tint = 0xff5500;
		// Growth animation
		tween(explosionGfx, {
			scaleX: self.scale,
			scaleY: self.scale
		}, {
			duration: 200,
			easing: tween.easeOut
		});
		// Color change animation
		tween(explosionGfx, {
			tint: 0xffcc00
		}, {
			duration: 100,
			easing: tween.linear,
			onFinish: function onFinish() {
				tween(explosionGfx, {
					tint: 0xffffaa,
					alpha: 0
				}, {
					duration: 300,
					easing: tween.easeOut
				});
			}
		});
	};
	self.update = function () {
		self.lifespan--;
		if (self.lifespan <= 0) {
			self.destroy();
		}
	};
	return self;
});
// Player bullet
var PlayerBullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletGfx = self.attachAsset('playerBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 12;
	self.update = function () {
		// Default angle is 0 (right)
		if (typeof self.angle === "undefined") {
			self.angle = 0;
		}
		self.x += self.speed * Math.cos(self.angle);
		self.y += self.speed * Math.sin(self.angle);
	};
	return self;
});
// Power-up
var Powerup = Container.expand(function () {
	var self = Container.call(this);
	var powerGfx = self.attachAsset('powerup', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 6;
	self.type = 'power'; // could be 'power', 'heal', etc.
	self.update = function () {
		self.x -= self.speed;
	};
	return self;
});
// Player spaceship
var Ship = Container.expand(function () {
	var self = Container.call(this);
	var shipGfx = self.attachAsset('ship', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.width = shipGfx.width;
	self.height = shipGfx.height;
	self.fireCooldown = 0;
	self.powerLevel = 1; // 1=single, 2=double, 3=triple shot
	self.invincible = false;
	self.invincibleTimer = 0;
	// Invincibility flash effect
	self.setInvincible = function (duration) {
		self.invincible = true;
		self.invincibleTimer = duration;
		tween(shipGfx, {
			alpha: 0.4
		}, {
			duration: 100,
			easing: tween.linear,
			onFinish: function onFinish() {
				tween(shipGfx, {
					alpha: 1
				}, {
					duration: 100,
					easing: tween.linear
				});
			}
		});
	};
	// Called every tick
	self.update = function () {
		if (self.invincible) {
			self.invincibleTimer -= 1;
			if (self.invincibleTimer <= 0) {
				self.invincible = false;
				shipGfx.alpha = 1;
			}
		}
		// Track last drag direction for multi-directional shooting
		if (typeof self.lastShootAngle === "undefined") {
			self.lastShootAngle = 0;
		}
		if (typeof self.lastX === "undefined") {
			self.lastX = self.x;
		}
		if (typeof self.lastY === "undefined") {
			self.lastY = self.y;
		}
		if (self.x !== self.lastX || self.y !== self.lastY) {
			// Calculate angle of movement
			var dx = self.x - self.lastX;
			var dy = self.y - self.lastY;
			if (dx !== 0 || dy !== 0) {
				self.lastShootAngle = Math.atan2(dy, dx);
			}
		}
		self.lastX = self.x;
		self.lastY = self.y;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000010
});
/**** 
* Game Code
****/ 
// Background
var background = LK.getAsset('background', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0
});
game.addChild(background);
// Music
// Sound effects
// Boss
// Power-up
// Enemy bullet
// Enemy
// Player bullet
// Spaceship (player)
// Play background music
LK.playMusic('bgmusic');
// Game variables
var ship;
var playerBullets = [];
var enemies = [];
var enemyBullets = [];
var powerups = [];
var fallingEnemies = [];
var scoreTxt;
var levelTxt;
var dragNode = null;
var lastShipX = 0,
	lastShipY = 0;
var spawnTimer = 0;
var powerupTimer = 0;
var level = 1;
var gameOver = false;
// Bullet pools for reusing objects (reduces garbage collection)
var playerBulletPool = [];
var enemyBulletPool = [];
// Helper function to get bullet from pool or create new one
function getPlayerBulletFromPool() {
	if (playerBulletPool.length > 0) {
		var bullet = playerBulletPool.pop();
		bullet.visible = true;
		return bullet;
	}
	return new PlayerBullet();
}
function getEnemyBulletFromPool() {
	if (enemyBulletPool.length > 0) {
		var bullet = enemyBulletPool.pop();
		bullet.visible = true;
		return bullet;
	}
	return new EnemyBullet();
}
// Helper function to return bullet to pool
function returnPlayerBulletToPool(bullet, index) {
	bullet.visible = false;
	playerBulletPool.push(bullet);
	playerBullets.splice(index, 1);
}
function returnEnemyBulletToPool(bullet, index) {
	bullet.visible = false;
	enemyBulletPool.push(bullet);
	enemyBullets.splice(index, 1);
}
// Score display
scoreTxt = new Text2('0', {
	size: 120,
	fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Level display removed
// Create player ship
ship = new Ship();
game.addChild(ship);
ship.x = 2048 / 2;
ship.y = 2732 / 2;
// Make ship visible and interactive
ship.interactive = true;
ship.buttonMode = true;
// Helper: clamp ship inside screen
function clampShipPosition() {
	var halfW = ship.width / 2;
	var halfH = ship.height / 2;
	if (ship.x < 100 + halfW) {
		ship.x = 100 + halfW;
	}
	if (ship.x > 2048 - halfW) {
		ship.x = 2048 - halfW;
	}
	if (ship.y < halfH) {
		ship.y = halfH;
	}
	if (ship.y > 2732 - halfH) {
		ship.y = 2732 - halfH;
	}
}
// Handle dragging ship
function handleMove(x, y, obj) {
	if (dragNode) {
		// Direct positioning for immediate response
		dragNode.x = x;
		dragNode.y = y;
		clampShipPosition();
	}
}
game.move = handleMove;
game.down = function (x, y, obj) {
	// Improved touch detection with slightly larger hitbox for better responsiveness
	var local = ship.toLocal(game.toGlobal({
		x: x,
		y: y
	}));
	var touchPadding = 20; // Extra padding for easier touch
	if (local.x > -ship.width / 2 - touchPadding && local.x < ship.width / 2 + touchPadding && local.y > -ship.height / 2 - touchPadding && local.y < ship.height / 2 + touchPadding) {
		dragNode = ship;
		// Immediate position update
		handleMove(x, y, obj);
	}
};
game.up = function (x, y, obj) {
	// Make sure position is updated one last time before releasing
	if (dragNode) {
		handleMove(x, y, obj);
	}
	dragNode = null;
};
// Spawn enemy
function spawnEnemy() {
	var e = new Enemy();
	e.x = 2048 + e.width / 2;
	e.y = 200 + Math.random() * (2732 - 400);
	e.hp = 1 + Math.floor(level / 2);
	e.speed = 5 + Math.random() * 4 + level * 0.6;
	e.shootCooldown = 90 + Math.floor(Math.random() * 80);
	enemies.push(e);
	game.addChild(e);
}
// Spawn powerup
function spawnPowerup() {
	var p = new Powerup();
	p.x = 2048 + 60;
	p.y = 200 + Math.random() * (2732 - 400);
	p.type = 'power';
	powerups.push(p);
	game.addChild(p);
}
// Main update loop
game.update = function () {
	if (gameOver) {
		return;
	}
	// Ship update
	ship.update();
	// Auto-fire
	if (ship.fireCooldown > 0) {
		ship.fireCooldown--;
	}
	if (ship.fireCooldown <= 0) {
		// Fire based on power level, but allow multi-directional shooting
		var bulletAngles = [ship.lastShootAngle || 0];
		if (ship.powerLevel === 2) {
			bulletAngles = [(ship.lastShootAngle || 0) - Math.PI / 16, (ship.lastShootAngle || 0) + Math.PI / 16];
		}
		if (ship.powerLevel >= 3) {
			bulletAngles = [(ship.lastShootAngle || 0) - Math.PI / 8, ship.lastShootAngle || 0, (ship.lastShootAngle || 0) + Math.PI / 8];
		}
		for (var i = 0; i < bulletAngles.length; ++i) {
			var b = getPlayerBulletFromPool();
			// Start at ship's nose
			b.x = ship.x + Math.cos(bulletAngles[i]) * (ship.width / 2 + 10);
			b.y = ship.y + Math.sin(bulletAngles[i]) * (ship.width / 2 + 10);
			b.angle = bulletAngles[i];
			playerBullets.push(b);
			if (!b.parent) {
				game.addChild(b);
			}
		}
		LK.getSound('shoot').play();
		ship.fireCooldown = 18;
	}
	// Update player bullets - optimized to reduce collision checking
	var bulletsToRemove = [];
	for (var i = playerBullets.length - 1; i >= 0; --i) {
		var b = playerBullets[i];
		b.update();
		// Remove if off screen
		if (b.x > 2048 + 50 || b.x < -50 || b.y > 2732 + 50 || b.y < -50) {
			returnPlayerBulletToPool(b, i);
			continue;
		}
		// Check if bullet already marked for removal
		if (bulletsToRemove.indexOf(i) !== -1) {
			continue;
		}
		// Hit enemy - only check enemies in proximity
		var bulletHitSomething = false;
		for (var j = enemies.length - 1; j >= 0; --j) {
			var e = enemies[j];
			// Only check collision if enemy is close to bullet (rough proximity check)
			if (Math.abs(e.x - b.x) < 150 && Math.abs(e.y - b.y) < 150) {
				if (b.intersects(e)) {
					e.hp--;
					LK.getSound('explosion').play();
					// Small hit explosion
					var hitExplosion = new Explosion();
					hitExplosion.x = b.x;
					hitExplosion.y = b.y;
					hitExplosion.start(0.5);
					game.addChild(hitExplosion);
					bulletHitSomething = true;
					if (e.hp <= 0) {
						// Create explosion at enemy position
						var explosion = new Explosion();
						explosion.x = e.x;
						explosion.y = e.y;
						explosion.start(1.2);
						game.addChild(explosion);
						LK.setScore(LK.getScore() + 10);
						scoreTxt.setText(LK.getScore());
						// Level progression for endless game
						if (LK.getScore() > 0 && LK.getScore() % 100 === 0) {
							level++;
							// Flash effect
							LK.effects.flashScreen(0x00ff00, 800);
							// Power up as reward every few levels
							if (level % 3 === 0) {
								ship.powerLevel = Math.min(ship.powerLevel + 1, 3);
							}
						}
						// Add falling animation instead of destroying immediately
						e.isFalling = true;
						e.fallSpeed = 2;
						e.fallRotation = (Math.random() - 0.5) * 0.2;
						e.fallAlpha = 1;
						// Remove from enemies array but don't destroy yet
						enemies.splice(j, 1);
						// Add to separate falling enemies array to be managed separately
						if (!fallingEnemies) {
							fallingEnemies = [];
						}
						fallingEnemies.push(e);
					}
					break;
				}
			}
		}
		// If bullet hit an enemy, return the bullet to the pool and continue to next bullet
		if (bulletHitSomething) {
			returnPlayerBulletToPool(b, i);
			continue;
		}
	}
	// Update enemies - optimized
	var enemiesNearPlayer = 0;
	for (var i = enemies.length - 1; i >= 0; --i) {
		var e = enemies[i];
		e.update();
		// Remove if off screen
		if (e.x < -e.width / 2) {
			e.destroy();
			enemies.splice(i, 1);
			continue;
		}
		// Check if enemy is near player
		var isNearPlayer = Math.abs(e.x - ship.x) < 400;
		if (isNearPlayer) {
			enemiesNearPlayer++;
		}
		// Enemy shoots
		if (e.shootCooldown <= 0 && e.x < 2048 && e.x > 0) {
			// Limit shooting frequency based on how many enemies are near player
			if (enemiesNearPlayer < 3 || Math.random() < 0.3) {
				var eb = getEnemyBulletFromPool();
				eb.x = e.x - e.width / 2 - 10;
				eb.y = e.y;
				enemyBullets.push(eb);
				if (!eb.parent) {
					game.addChild(eb);
				}
				LK.getSound('enemyShoot').play();
			}
			// Increase cooldown when many enemies are present
			var cooldownBase = 80 + Math.floor(Math.random() * 60);
			e.shootCooldown = cooldownBase * (1 + (enemies.length > 10 ? 0.5 : 0));
		}
		// Collide with ship - only check when close
		if (!ship.invincible && isNearPlayer && Math.abs(e.y - ship.y) < 150) {
			if (e.intersects(ship)) {
				// Ship hit
				// Create explosion at collision point
				var explosion = new Explosion();
				explosion.x = (ship.x + e.x) / 2;
				explosion.y = (ship.y + e.y) / 2;
				explosion.start(1);
				game.addChild(explosion);
				// Game over immediately when player is hit by enemy
				gameOver = true;
				LK.effects.flashObject(ship, 0xff0000, 600);
				LK.effects.flashScreen(0xff0000, 400);
				LK.showGameOver();
				return;
			}
		}
	}
	// Update enemy bullets - batch process with reduced collision checks
	var bulletsToCheck = [];
	// First update all bullets and mark ones to remove (off-screen)
	for (var i = enemyBullets.length - 1; i >= 0; --i) {
		var eb = enemyBullets[i];
		eb.update();
		if (eb.x < -50) {
			returnEnemyBulletToPool(eb, i);
			continue;
		}
		// Only check collision if ship is not invincible and bullet is near ship
		if (!ship.invincible && Math.abs(eb.x - ship.x) < 150 && Math.abs(eb.y - ship.y) < 150) {
			bulletsToCheck.push({
				index: i,
				bullet: eb
			});
		}
	}
	// Now only check collisions for bullets near the ship
	if (!ship.invincible) {
		for (var i = 0; i < bulletsToCheck.length; i++) {
			var bulletInfo = bulletsToCheck[i];
			var eb = bulletInfo.bullet;
			if (eb.intersects(ship)) {
				// Create explosion at bullet position
				var explosion = new Explosion();
				explosion.x = eb.x;
				explosion.y = eb.y;
				explosion.start(1);
				game.addChild(explosion);
				LK.effects.flashObject(ship, 0xff0000, 600);
				LK.effects.flashScreen(0xff0000, 400);
				eb.destroy();
				enemyBullets.splice(bulletInfo.index, 1);
				// Game over immediately when player is hit by bullet
				gameOver = true;
				LK.showGameOver();
				return;
				break; // Exit loop after first hit
			}
		}
	}
	// Update powerups - only check collection when close
	for (var i = powerups.length - 1; i >= 0; --i) {
		var p = powerups[i];
		p.update();
		if (p.x < -50) {
			p.destroy();
			powerups.splice(i, 1);
			continue;
		}
		// Collect - only check intersection when close to ship
		if (Math.abs(p.x - ship.x) < 120 && Math.abs(p.y - ship.y) < 120) {
			if (p.intersects(ship)) {
				LK.getSound('powerup').play();
				ship.powerLevel = Math.min(ship.powerLevel + 1, 3);
				LK.setScore(LK.getScore() + 30);
				scoreTxt.setText(LK.getScore());
				p.destroy();
				powerups.splice(i, 1);
			}
		}
	}
	// Spawning logic - always active in endless mode
	spawnTimer--;
	if (spawnTimer <= 0) {
		// Spawn more enemies at higher levels
		var enemiesToSpawn = 1 + Math.floor(level / 5);
		for (var i = 0; i < enemiesToSpawn; i++) {
			if (enemies.length < 25) {
				// Cap max enemies to prevent lag
				spawnEnemy();
			}
		}
		spawnTimer = Math.max(30, 100 - level * 3);
	}
	// Powerup spawn
	powerupTimer--;
	if (powerupTimer <= 0) {
		spawnPowerup();
		powerupTimer = 600 + Math.floor(Math.random() * 400);
	}
	// Increase enemy difficulty with level
	if (LK.ticks % 600 === 0) {
		for (var i = 0; i < enemies.length; i++) {
			// Slightly increase enemy speed based on level
			if (Math.random() < 0.3) {
				enemies[i].speed += 0.2;
			}
		}
	}
	// Update falling enemies
	if (fallingEnemies && fallingEnemies.length > 0) {
		for (var i = fallingEnemies.length - 1; i >= 0; i--) {
			var fe = fallingEnemies[i];
			if (fe.isFalling) {
				// Add gravity effect
				fe.fallSpeed += 0.3;
				fe.y += fe.fallSpeed;
				// Add rotation
				fe.rotation += fe.fallRotation;
				// Fade out
				fe.fallAlpha -= 0.02;
				if (fe.fallAlpha <= 0) {
					fe.fallAlpha = 0;
				}
				fe.alpha = fe.fallAlpha;
				// Remove when fallen off screen or fully faded
				if (fe.y > 2732 + fe.height || fe.fallAlpha <= 0) {
					fe.destroy();
					fallingEnemies.splice(i, 1);
				}
			}
		}
	}
	// No win condition - endless game
};
// Reset game state on restart
game.on('reset', function () {
	// Return bullets to pools instead of destroying
	for (var i = 0; i < playerBullets.length; ++i) {
		playerBullets[i].visible = false;
		playerBulletPool.push(playerBullets[i]);
	}
	for (var i = 0; i < enemyBullets.length; ++i) {
		enemyBullets[i].visible = false;
		enemyBulletPool.push(enemyBullets[i]);
	}
	// Destroy other objects
	for (var i = 0; i < enemies.length; ++i) {
		enemies[i].destroy();
	}
	// Destroy falling enemies
	if (fallingEnemies) {
		for (var i = 0; i < fallingEnemies.length; ++i) {
			fallingEnemies[i].destroy();
		}
	}
	for (var i = 0; i < powerups.length; ++i) {
		powerups[i].destroy();
	}
	playerBullets = [];
	enemies = [];
	enemyBullets = [];
	powerups = [];
	fallingEnemies = [];
	level = 1;
	ship.x = 2048 / 2; // Center horizontally
	ship.y = 2732 / 2;
	ship.powerLevel = 1;
	ship.invincible = false;
	ship.invincibleTimer = 0;
	LK.setScore(0);
	scoreTxt.setText('0');
	spawnTimer = 30;
	powerupTimer = 400;
	gameOver = false;
}); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Enemy
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGfx = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.width = enemyGfx.width;
	self.height = enemyGfx.height;
	self.speed = 5 + Math.random() * 4;
	self.hp = 1;
	self.shootCooldown = 0;
	self.type = 'normal'; // or 'boss'
	self.update = function () {
		// Check if enemy is in falling state
		if (self.isFalling) {
			return; // Let the falling animation be managed separately
		}
		self.x -= self.speed;
		if (self.shootCooldown > 0) {
			self.shootCooldown--;
		}
	};
	return self;
});
// Enemy bullet
var EnemyBullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletGfx = self.attachAsset('enemyBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 8;
	self.update = function () {
		self.x -= self.speed;
	};
	return self;
});
// Explosion effect
var Explosion = Container.expand(function () {
	var self = Container.call(this);
	var explosionGfx = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5,
		tint: 0xff5500
	});
	self.lifespan = 20;
	self.scale = 0.2;
	// Animation effect
	self.start = function (size) {
		self.scale = size || 1;
		explosionGfx.scale.x = 0.2;
		explosionGfx.scale.y = 0.2;
		explosionGfx.alpha = 1;
		explosionGfx.tint = 0xff5500;
		// Growth animation
		tween(explosionGfx, {
			scaleX: self.scale,
			scaleY: self.scale
		}, {
			duration: 200,
			easing: tween.easeOut
		});
		// Color change animation
		tween(explosionGfx, {
			tint: 0xffcc00
		}, {
			duration: 100,
			easing: tween.linear,
			onFinish: function onFinish() {
				tween(explosionGfx, {
					tint: 0xffffaa,
					alpha: 0
				}, {
					duration: 300,
					easing: tween.easeOut
				});
			}
		});
	};
	self.update = function () {
		self.lifespan--;
		if (self.lifespan <= 0) {
			self.destroy();
		}
	};
	return self;
});
// Player bullet
var PlayerBullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletGfx = self.attachAsset('playerBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 12;
	self.update = function () {
		// Default angle is 0 (right)
		if (typeof self.angle === "undefined") {
			self.angle = 0;
		}
		self.x += self.speed * Math.cos(self.angle);
		self.y += self.speed * Math.sin(self.angle);
	};
	return self;
});
// Power-up
var Powerup = Container.expand(function () {
	var self = Container.call(this);
	var powerGfx = self.attachAsset('powerup', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 6;
	self.type = 'power'; // could be 'power', 'heal', etc.
	self.update = function () {
		self.x -= self.speed;
	};
	return self;
});
// Player spaceship
var Ship = Container.expand(function () {
	var self = Container.call(this);
	var shipGfx = self.attachAsset('ship', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.width = shipGfx.width;
	self.height = shipGfx.height;
	self.fireCooldown = 0;
	self.powerLevel = 1; // 1=single, 2=double, 3=triple shot
	self.invincible = false;
	self.invincibleTimer = 0;
	// Invincibility flash effect
	self.setInvincible = function (duration) {
		self.invincible = true;
		self.invincibleTimer = duration;
		tween(shipGfx, {
			alpha: 0.4
		}, {
			duration: 100,
			easing: tween.linear,
			onFinish: function onFinish() {
				tween(shipGfx, {
					alpha: 1
				}, {
					duration: 100,
					easing: tween.linear
				});
			}
		});
	};
	// Called every tick
	self.update = function () {
		if (self.invincible) {
			self.invincibleTimer -= 1;
			if (self.invincibleTimer <= 0) {
				self.invincible = false;
				shipGfx.alpha = 1;
			}
		}
		// Track last drag direction for multi-directional shooting
		if (typeof self.lastShootAngle === "undefined") {
			self.lastShootAngle = 0;
		}
		if (typeof self.lastX === "undefined") {
			self.lastX = self.x;
		}
		if (typeof self.lastY === "undefined") {
			self.lastY = self.y;
		}
		if (self.x !== self.lastX || self.y !== self.lastY) {
			// Calculate angle of movement
			var dx = self.x - self.lastX;
			var dy = self.y - self.lastY;
			if (dx !== 0 || dy !== 0) {
				self.lastShootAngle = Math.atan2(dy, dx);
			}
		}
		self.lastX = self.x;
		self.lastY = self.y;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000010
});
/**** 
* Game Code
****/ 
// Background
var background = LK.getAsset('background', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0
});
game.addChild(background);
// Music
// Sound effects
// Boss
// Power-up
// Enemy bullet
// Enemy
// Player bullet
// Spaceship (player)
// Play background music
LK.playMusic('bgmusic');
// Game variables
var ship;
var playerBullets = [];
var enemies = [];
var enemyBullets = [];
var powerups = [];
var fallingEnemies = [];
var scoreTxt;
var levelTxt;
var dragNode = null;
var lastShipX = 0,
	lastShipY = 0;
var spawnTimer = 0;
var powerupTimer = 0;
var level = 1;
var gameOver = false;
// Bullet pools for reusing objects (reduces garbage collection)
var playerBulletPool = [];
var enemyBulletPool = [];
// Helper function to get bullet from pool or create new one
function getPlayerBulletFromPool() {
	if (playerBulletPool.length > 0) {
		var bullet = playerBulletPool.pop();
		bullet.visible = true;
		return bullet;
	}
	return new PlayerBullet();
}
function getEnemyBulletFromPool() {
	if (enemyBulletPool.length > 0) {
		var bullet = enemyBulletPool.pop();
		bullet.visible = true;
		return bullet;
	}
	return new EnemyBullet();
}
// Helper function to return bullet to pool
function returnPlayerBulletToPool(bullet, index) {
	bullet.visible = false;
	playerBulletPool.push(bullet);
	playerBullets.splice(index, 1);
}
function returnEnemyBulletToPool(bullet, index) {
	bullet.visible = false;
	enemyBulletPool.push(bullet);
	enemyBullets.splice(index, 1);
}
// Score display
scoreTxt = new Text2('0', {
	size: 120,
	fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Level display removed
// Create player ship
ship = new Ship();
game.addChild(ship);
ship.x = 2048 / 2;
ship.y = 2732 / 2;
// Make ship visible and interactive
ship.interactive = true;
ship.buttonMode = true;
// Helper: clamp ship inside screen
function clampShipPosition() {
	var halfW = ship.width / 2;
	var halfH = ship.height / 2;
	if (ship.x < 100 + halfW) {
		ship.x = 100 + halfW;
	}
	if (ship.x > 2048 - halfW) {
		ship.x = 2048 - halfW;
	}
	if (ship.y < halfH) {
		ship.y = halfH;
	}
	if (ship.y > 2732 - halfH) {
		ship.y = 2732 - halfH;
	}
}
// Handle dragging ship
function handleMove(x, y, obj) {
	if (dragNode) {
		// Direct positioning for immediate response
		dragNode.x = x;
		dragNode.y = y;
		clampShipPosition();
	}
}
game.move = handleMove;
game.down = function (x, y, obj) {
	// Improved touch detection with slightly larger hitbox for better responsiveness
	var local = ship.toLocal(game.toGlobal({
		x: x,
		y: y
	}));
	var touchPadding = 20; // Extra padding for easier touch
	if (local.x > -ship.width / 2 - touchPadding && local.x < ship.width / 2 + touchPadding && local.y > -ship.height / 2 - touchPadding && local.y < ship.height / 2 + touchPadding) {
		dragNode = ship;
		// Immediate position update
		handleMove(x, y, obj);
	}
};
game.up = function (x, y, obj) {
	// Make sure position is updated one last time before releasing
	if (dragNode) {
		handleMove(x, y, obj);
	}
	dragNode = null;
};
// Spawn enemy
function spawnEnemy() {
	var e = new Enemy();
	e.x = 2048 + e.width / 2;
	e.y = 200 + Math.random() * (2732 - 400);
	e.hp = 1 + Math.floor(level / 2);
	e.speed = 5 + Math.random() * 4 + level * 0.6;
	e.shootCooldown = 90 + Math.floor(Math.random() * 80);
	enemies.push(e);
	game.addChild(e);
}
// Spawn powerup
function spawnPowerup() {
	var p = new Powerup();
	p.x = 2048 + 60;
	p.y = 200 + Math.random() * (2732 - 400);
	p.type = 'power';
	powerups.push(p);
	game.addChild(p);
}
// Main update loop
game.update = function () {
	if (gameOver) {
		return;
	}
	// Ship update
	ship.update();
	// Auto-fire
	if (ship.fireCooldown > 0) {
		ship.fireCooldown--;
	}
	if (ship.fireCooldown <= 0) {
		// Fire based on power level, but allow multi-directional shooting
		var bulletAngles = [ship.lastShootAngle || 0];
		if (ship.powerLevel === 2) {
			bulletAngles = [(ship.lastShootAngle || 0) - Math.PI / 16, (ship.lastShootAngle || 0) + Math.PI / 16];
		}
		if (ship.powerLevel >= 3) {
			bulletAngles = [(ship.lastShootAngle || 0) - Math.PI / 8, ship.lastShootAngle || 0, (ship.lastShootAngle || 0) + Math.PI / 8];
		}
		for (var i = 0; i < bulletAngles.length; ++i) {
			var b = getPlayerBulletFromPool();
			// Start at ship's nose
			b.x = ship.x + Math.cos(bulletAngles[i]) * (ship.width / 2 + 10);
			b.y = ship.y + Math.sin(bulletAngles[i]) * (ship.width / 2 + 10);
			b.angle = bulletAngles[i];
			playerBullets.push(b);
			if (!b.parent) {
				game.addChild(b);
			}
		}
		LK.getSound('shoot').play();
		ship.fireCooldown = 18;
	}
	// Update player bullets - optimized to reduce collision checking
	var bulletsToRemove = [];
	for (var i = playerBullets.length - 1; i >= 0; --i) {
		var b = playerBullets[i];
		b.update();
		// Remove if off screen
		if (b.x > 2048 + 50 || b.x < -50 || b.y > 2732 + 50 || b.y < -50) {
			returnPlayerBulletToPool(b, i);
			continue;
		}
		// Check if bullet already marked for removal
		if (bulletsToRemove.indexOf(i) !== -1) {
			continue;
		}
		// Hit enemy - only check enemies in proximity
		var bulletHitSomething = false;
		for (var j = enemies.length - 1; j >= 0; --j) {
			var e = enemies[j];
			// Only check collision if enemy is close to bullet (rough proximity check)
			if (Math.abs(e.x - b.x) < 150 && Math.abs(e.y - b.y) < 150) {
				if (b.intersects(e)) {
					e.hp--;
					LK.getSound('explosion').play();
					// Small hit explosion
					var hitExplosion = new Explosion();
					hitExplosion.x = b.x;
					hitExplosion.y = b.y;
					hitExplosion.start(0.5);
					game.addChild(hitExplosion);
					bulletHitSomething = true;
					if (e.hp <= 0) {
						// Create explosion at enemy position
						var explosion = new Explosion();
						explosion.x = e.x;
						explosion.y = e.y;
						explosion.start(1.2);
						game.addChild(explosion);
						LK.setScore(LK.getScore() + 10);
						scoreTxt.setText(LK.getScore());
						// Level progression for endless game
						if (LK.getScore() > 0 && LK.getScore() % 100 === 0) {
							level++;
							// Flash effect
							LK.effects.flashScreen(0x00ff00, 800);
							// Power up as reward every few levels
							if (level % 3 === 0) {
								ship.powerLevel = Math.min(ship.powerLevel + 1, 3);
							}
						}
						// Add falling animation instead of destroying immediately
						e.isFalling = true;
						e.fallSpeed = 2;
						e.fallRotation = (Math.random() - 0.5) * 0.2;
						e.fallAlpha = 1;
						// Remove from enemies array but don't destroy yet
						enemies.splice(j, 1);
						// Add to separate falling enemies array to be managed separately
						if (!fallingEnemies) {
							fallingEnemies = [];
						}
						fallingEnemies.push(e);
					}
					break;
				}
			}
		}
		// If bullet hit an enemy, return the bullet to the pool and continue to next bullet
		if (bulletHitSomething) {
			returnPlayerBulletToPool(b, i);
			continue;
		}
	}
	// Update enemies - optimized
	var enemiesNearPlayer = 0;
	for (var i = enemies.length - 1; i >= 0; --i) {
		var e = enemies[i];
		e.update();
		// Remove if off screen
		if (e.x < -e.width / 2) {
			e.destroy();
			enemies.splice(i, 1);
			continue;
		}
		// Check if enemy is near player
		var isNearPlayer = Math.abs(e.x - ship.x) < 400;
		if (isNearPlayer) {
			enemiesNearPlayer++;
		}
		// Enemy shoots
		if (e.shootCooldown <= 0 && e.x < 2048 && e.x > 0) {
			// Limit shooting frequency based on how many enemies are near player
			if (enemiesNearPlayer < 3 || Math.random() < 0.3) {
				var eb = getEnemyBulletFromPool();
				eb.x = e.x - e.width / 2 - 10;
				eb.y = e.y;
				enemyBullets.push(eb);
				if (!eb.parent) {
					game.addChild(eb);
				}
				LK.getSound('enemyShoot').play();
			}
			// Increase cooldown when many enemies are present
			var cooldownBase = 80 + Math.floor(Math.random() * 60);
			e.shootCooldown = cooldownBase * (1 + (enemies.length > 10 ? 0.5 : 0));
		}
		// Collide with ship - only check when close
		if (!ship.invincible && isNearPlayer && Math.abs(e.y - ship.y) < 150) {
			if (e.intersects(ship)) {
				// Ship hit
				// Create explosion at collision point
				var explosion = new Explosion();
				explosion.x = (ship.x + e.x) / 2;
				explosion.y = (ship.y + e.y) / 2;
				explosion.start(1);
				game.addChild(explosion);
				// Game over immediately when player is hit by enemy
				gameOver = true;
				LK.effects.flashObject(ship, 0xff0000, 600);
				LK.effects.flashScreen(0xff0000, 400);
				LK.showGameOver();
				return;
			}
		}
	}
	// Update enemy bullets - batch process with reduced collision checks
	var bulletsToCheck = [];
	// First update all bullets and mark ones to remove (off-screen)
	for (var i = enemyBullets.length - 1; i >= 0; --i) {
		var eb = enemyBullets[i];
		eb.update();
		if (eb.x < -50) {
			returnEnemyBulletToPool(eb, i);
			continue;
		}
		// Only check collision if ship is not invincible and bullet is near ship
		if (!ship.invincible && Math.abs(eb.x - ship.x) < 150 && Math.abs(eb.y - ship.y) < 150) {
			bulletsToCheck.push({
				index: i,
				bullet: eb
			});
		}
	}
	// Now only check collisions for bullets near the ship
	if (!ship.invincible) {
		for (var i = 0; i < bulletsToCheck.length; i++) {
			var bulletInfo = bulletsToCheck[i];
			var eb = bulletInfo.bullet;
			if (eb.intersects(ship)) {
				// Create explosion at bullet position
				var explosion = new Explosion();
				explosion.x = eb.x;
				explosion.y = eb.y;
				explosion.start(1);
				game.addChild(explosion);
				LK.effects.flashObject(ship, 0xff0000, 600);
				LK.effects.flashScreen(0xff0000, 400);
				eb.destroy();
				enemyBullets.splice(bulletInfo.index, 1);
				// Game over immediately when player is hit by bullet
				gameOver = true;
				LK.showGameOver();
				return;
				break; // Exit loop after first hit
			}
		}
	}
	// Update powerups - only check collection when close
	for (var i = powerups.length - 1; i >= 0; --i) {
		var p = powerups[i];
		p.update();
		if (p.x < -50) {
			p.destroy();
			powerups.splice(i, 1);
			continue;
		}
		// Collect - only check intersection when close to ship
		if (Math.abs(p.x - ship.x) < 120 && Math.abs(p.y - ship.y) < 120) {
			if (p.intersects(ship)) {
				LK.getSound('powerup').play();
				ship.powerLevel = Math.min(ship.powerLevel + 1, 3);
				LK.setScore(LK.getScore() + 30);
				scoreTxt.setText(LK.getScore());
				p.destroy();
				powerups.splice(i, 1);
			}
		}
	}
	// Spawning logic - always active in endless mode
	spawnTimer--;
	if (spawnTimer <= 0) {
		// Spawn more enemies at higher levels
		var enemiesToSpawn = 1 + Math.floor(level / 5);
		for (var i = 0; i < enemiesToSpawn; i++) {
			if (enemies.length < 25) {
				// Cap max enemies to prevent lag
				spawnEnemy();
			}
		}
		spawnTimer = Math.max(30, 100 - level * 3);
	}
	// Powerup spawn
	powerupTimer--;
	if (powerupTimer <= 0) {
		spawnPowerup();
		powerupTimer = 600 + Math.floor(Math.random() * 400);
	}
	// Increase enemy difficulty with level
	if (LK.ticks % 600 === 0) {
		for (var i = 0; i < enemies.length; i++) {
			// Slightly increase enemy speed based on level
			if (Math.random() < 0.3) {
				enemies[i].speed += 0.2;
			}
		}
	}
	// Update falling enemies
	if (fallingEnemies && fallingEnemies.length > 0) {
		for (var i = fallingEnemies.length - 1; i >= 0; i--) {
			var fe = fallingEnemies[i];
			if (fe.isFalling) {
				// Add gravity effect
				fe.fallSpeed += 0.3;
				fe.y += fe.fallSpeed;
				// Add rotation
				fe.rotation += fe.fallRotation;
				// Fade out
				fe.fallAlpha -= 0.02;
				if (fe.fallAlpha <= 0) {
					fe.fallAlpha = 0;
				}
				fe.alpha = fe.fallAlpha;
				// Remove when fallen off screen or fully faded
				if (fe.y > 2732 + fe.height || fe.fallAlpha <= 0) {
					fe.destroy();
					fallingEnemies.splice(i, 1);
				}
			}
		}
	}
	// No win condition - endless game
};
// Reset game state on restart
game.on('reset', function () {
	// Return bullets to pools instead of destroying
	for (var i = 0; i < playerBullets.length; ++i) {
		playerBullets[i].visible = false;
		playerBulletPool.push(playerBullets[i]);
	}
	for (var i = 0; i < enemyBullets.length; ++i) {
		enemyBullets[i].visible = false;
		enemyBulletPool.push(enemyBullets[i]);
	}
	// Destroy other objects
	for (var i = 0; i < enemies.length; ++i) {
		enemies[i].destroy();
	}
	// Destroy falling enemies
	if (fallingEnemies) {
		for (var i = 0; i < fallingEnemies.length; ++i) {
			fallingEnemies[i].destroy();
		}
	}
	for (var i = 0; i < powerups.length; ++i) {
		powerups[i].destroy();
	}
	playerBullets = [];
	enemies = [];
	enemyBullets = [];
	powerups = [];
	fallingEnemies = [];
	level = 1;
	ship.x = 2048 / 2; // Center horizontally
	ship.y = 2732 / 2;
	ship.powerLevel = 1;
	ship.invincible = false;
	ship.invincibleTimer = 0;
	LK.setScore(0);
	scoreTxt.setText('0');
	spawnTimer = 30;
	powerupTimer = 400;
	gameOver = false;
});
:quality(85)/https://cdn.frvr.ai/6815787e2f4bd641fc093738.png%3F3) 
 pufferfish disney 2d image style. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/681579782f4bd641fc09373f.png%3F3) 
 clown fish disney 2d image style. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/68157aba2f4bd641fc09375a.png%3F3) 
 oval blue sea buble comic 2d image style. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/68157b372f4bd641fc093763.png%3F3) 
 green seaweet comic 2d image style. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/68157bbe2f4bd641fc093770.png%3F3) 
 veryy quite coral reef under sea disney 2d image style. In-Game asset. 2d. High contrast. No shadows