/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var Boss = Container.expand(function () {
	var self = Container.call(this);
	var bossGraphic = self.attachAsset('boss', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 1.5;
	self.health = 10;
	self.attackCooldown = 0;
	self.attackPattern = 0;
	self.scoreValue = 2000;
	self.active = true;
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		return self;
	};
	self.takeDamage = function () {
		if (!self.active) {
			return;
		}
		// Boss takes 1 damage per hit, dies after 5 hits
		self.health -= 1;
		// Flash boss
		LK.effects.flashObject(self, 0xffffff, 300);
		LK.getSound('hit').play();
		if (self.health <= 0) {
			self.die();
		} else {
			// Speed up as health decreases
			self.speed = 1.5 + (5 - self.health) * 0.2;
		}
	};
	self.die = function () {
		if (!self.active) {
			return;
		}
		self.active = false;
		LK.getSound('bossDeath').play();
		// Flash and fade out
		LK.effects.flashObject(self, 0xffff00, 500);
		tween(self, {
			alpha: 0
		}, {
			duration: 1000,
			onFinish: function onFinish() {
				self.destroy();
			}
		});
		currentWave++;
		bossDefeated = true;
		nextWaveTimer = 180; // 3 seconds until next wave
		return self.scoreValue;
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		// Move toward hero but more intelligently
		if (hero) {
			var dx = hero.x - self.x;
			var dy = hero.y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			// Different movement patterns
			if (self.attackPattern === 0) {
				// Direct approach
				if (dist > 0) {
					self.x += dx / dist * self.speed;
					self.y += dy / dist * self.speed;
				}
			} else if (self.attackPattern === 1) {
				// Circle around
				var angle = Math.atan2(dy, dx) + Math.PI / 4;
				self.x += Math.cos(angle) * self.speed * 1.5;
				self.y += Math.sin(angle) * self.speed * 1.5;
			} else if (self.attackPattern === 2) {
				// Charge attack
				if (self.attackCooldown > 30) {
					self.x += dx / dist * self.speed * 2.5;
					self.y += dy / dist * self.speed * 2.5;
				} else {
					// Wait
				}
			}
			if (hero.invulnerable <= 0 && !hero.isDashing) {
				if (self.intersects(hero)) {
					hero.takeDamage();
				}
			}
		}
		// Attack pattern cooldown
		self.attackCooldown--;
		if (self.attackCooldown <= 0) {
			self.attackPattern = (self.attackPattern + 1) % 3;
			self.attackCooldown = 120; // 2 seconds per pattern
		}
		// Keep within screen bounds
		self.x = Math.max(100, Math.min(2048 - 100, self.x));
		self.y = Math.max(100, Math.min(2732 - 100, self.y));
	};
	return self;
});
var Bullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletGraphic = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	bulletGraphic.tint = 0xffffff; // White bullet for the hero
	self.speed = 15;
	self.damage = 1;
	self.active = true;
	self.init = function (x, y, direction) {
		self.x = x;
		self.y = y;
		self.direction = direction || {
			x: 0,
			y: -1
		}; // Default direction is up
		return self;
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		// Move in the specified direction
		self.x += self.direction.x * self.speed;
		self.y += self.direction.y * self.speed;
		// Remove if off-screen
		if (self.x < -50 || self.x > 2048 + 50 || self.y < -50 || self.y > 2732 + 50) {
			self.destroy();
		}
	};
	return self;
});
var DashTrail = Container.expand(function () {
	var self = Container.call(this);
	var trailGraphic = self.attachAsset('dashTrail', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.7
	});
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		self.lifetime = 20; // frames the trail will live
		return self;
	};
	self.update = function () {
		self.lifetime--;
		trailGraphic.alpha = self.lifetime / 20 * 0.7;
		if (self.lifetime <= 0) {
			self.destroy();
		}
	};
	return self;
});
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGraphic = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 2;
	self.health = 1;
	self.scoreValue = 100;
	self.active = true;
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		// Initialize last position for rotation tracking
		self.lastX = x;
		self.lastY = y;
		// Set initial rotation
		if (hero) {
			var dx = hero.x - self.x;
			var dy = hero.y - self.y;
			enemyGraphic.rotation = Math.atan2(dy, dx);
		}
		return self;
	};
	self.takeDamage = function () {
		if (!self.active) {
			return;
		}
		// Enemies die from one hit
		self.health = 0;
		self.die();
	};
	self.die = function () {
		if (!self.active) {
			return;
		}
		self.active = false;
		LK.getSound('hit').play();
		// Flash, fade out, and fall animation
		tween(self, {
			alpha: 0,
			y: self.y + 300,
			// Fall down animation
			rotation: Math.random() * Math.PI * 2,
			// Random rotation
			scaleX: 0.5,
			scaleY: 0.5
		}, {
			duration: 800,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				self.destroy();
			}
		});
		return self.scoreValue;
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		// Move toward hero
		if (hero && !hero.isDashing) {
			var dx = hero.x - self.x;
			var dy = hero.y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist > 0) {
				self.x += dx / dist * self.speed;
				self.y += dy / dist * self.speed;
				// Spider walking animation
				if (LK.ticks % 10 === 0) {
					// Spider leg movement animation
					tween(enemyGraphic, {
						scaleX: 1.1,
						scaleY: 0.9,
						rotation: Math.atan2(dy, dx) + (Math.random() * 0.2 - 0.1)
					}, {
						duration: 200,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							tween(enemyGraphic, {
								scaleX: 1,
								scaleY: 1,
								rotation: Math.atan2(dy, dx)
							}, {
								duration: 200,
								easing: tween.easeOut
							});
						}
					});
				}
			}
		}
		// Check for collision with hero
		if (hero && !hero.isDashing && hero.invulnerable <= 0) {
			if (self.intersects(hero)) {
				hero.takeDamage();
			}
		}
	};
	return self;
});
var Hero = Container.expand(function () {
	var self = Container.call(this);
	var heroGraphic = self.attachAsset('hero', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Simple click handler that does nothing (placeholder)
	self.down = function (x, y, obj) {
		// No auto-shoot toggle functionality
	};
	self.shootSpeed = 15; // Bullet speed
	self.fireRate = 15; // Frames between shots
	self.shootCooldown = 0;
	self.health = 3;
	self.invulnerable = 0;
	self.combo = 0;
	self.score = 0;
	self.powerBoost = 1; // Base power multiplier
	self.shootBullet = function (targetX, targetY) {
		if (self.shootCooldown > 0) {
			return;
		}
		var dx = targetX - self.x;
		var dy = targetY - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		// Normalize direction
		var dirX = dx / distance;
		var dirY = dy / distance;
		// Create bullet
		var bullet = new Bullet().init(self.x, self.y, {
			x: dirX,
			y: dirY
		});
		bullet.damage = self.powerBoost; // Apply power boost to bullet damage
		// Visual shooting effect
		tween(heroGraphic, {
			scaleX: 1.2,
			scaleY: 0.9
		}, {
			duration: 100,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(heroGraphic, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 200,
					easing: tween.elasticOut
				});
			}
		});
		// Set cooldown
		self.shootCooldown = self.fireRate;
		// Add bullet to game
		game.addChild(bullet);
		if (!bullets) {
			bullets = [];
		}
		bullets.push(bullet);
		// Play shoot sound
		LK.getSound('hit').play();
	};
	self.takeDamage = function () {
		if (self.invulnerable > 0) {
			return;
		}
		self.health--;
		self.invulnerable = 60; // invulnerable for 1 second
		self.combo = 0; // Reset combo
		// Flash hero red
		LK.effects.flashObject(self, 0xff0000, 500);
		// Play damage sound
		LK.getSound('damage').play();
		if (self.health <= 0) {
			LK.showGameOver();
		}
	};
	self.addScore = function (points) {
		self.combo++;
		var comboMultiplier = Math.min(4, 1 + self.combo * 0.1);
		var scoreToAdd = Math.floor(points * comboMultiplier);
		self.score += scoreToAdd;
		LK.setScore(self.score);
	};
	self.update = function () {
		// Keep within screen bounds
		self.x = Math.max(50, Math.min(2048 - 50, self.x));
		self.y = Math.max(50, Math.min(2732 - 50, self.y));
		// Cooldowns
		if (self.shootCooldown > 0) {
			self.shootCooldown--;
		}
		if (self.invulnerable > 0) {
			self.invulnerable--;
			// Flicker effect during invulnerability
			heroGraphic.alpha = LK.ticks % 6 < 3 ? 0.4 : 1;
		} else {
			// Normal appearance when not invulnerable
			heroGraphic.alpha = 1;
			heroGraphic.tint = 0xFFFFFF; // Normal color
		}
	};
	return self;
});
var PowerUp = Container.expand(function () {
	var self = Container.call(this);
	var powerUpGraphic = self.attachAsset('powerUp', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.type = 'health'; // Default type
	self.active = true;
	self.lifetime = 300; // 5 seconds
	self.init = function (x, y, type) {
		self.x = x;
		self.y = y;
		self.type = type || self.type;
		// Set color based on type
		if (self.type === 'health') {
			powerUpGraphic.tint = 0x2ecc71; // Green
		} else if (self.type === 'speed') {
			powerUpGraphic.tint = 0x3498db; // Blue
		} else if (self.type === 'power') {
			powerUpGraphic.tint = 0xe74c3c; // Red
		} else if (self.type === 'strength') {
			powerUpGraphic.tint = 0x9b59b6; // Purple
		}
		return self;
	};
	self.collect = function () {
		if (!self.active) {
			return;
		}
		self.active = false;
		LK.getSound('powerup').play();
		if (self.type === 'health' && hero.health < 3) {
			hero.health++;
		} else if (self.type === 'speed') {
			hero.dashSpeed = 80; // Even faster dash
			hero.dashDistance = 900; // Even longer dash
			// Visual indicator of speed boost
			tween(hero, {
				alpha: 0.7
			}, {
				duration: 200,
				onFinish: function onFinish() {
					tween(hero, {
						alpha: 1
					}, {
						duration: 200
					});
				}
			});
			// Reset after 10 seconds
			LK.setTimeout(function () {
				if (hero) {
					hero.dashSpeed = 60;
					hero.dashDistance = 700;
				}
			}, 10000);
		} else if (self.type === 'strength') {
			// Increase hero's attack strength more permanently
			hero.powerBoost = Math.min(5, hero.powerBoost + 1);
			// Visual indicator of strength boost
			tween(hero, {
				tint: 0x9b59b6
			}, {
				duration: 500,
				onFinish: function onFinish() {
					tween(hero, {
						tint: 0xFFFFFF
					}, {
						duration: 500
					});
				}
			});
			// Show strength level
			var strengthTxt = new Text2('STRENGTH +' + hero.powerBoost + '!', {
				size: 80,
				fill: 0x9b59b6
			});
			strengthTxt.anchor.set(0.5, 0.5);
			strengthTxt.x = 2048 / 2;
			strengthTxt.y = 2732 / 2;
			game.addChild(strengthTxt);
			// Fade out the text
			tween(strengthTxt, {
				alpha: 0,
				y: strengthTxt.y - 100
			}, {
				duration: 1500,
				onFinish: function onFinish() {
					strengthTxt.destroy();
				}
			});
		} else if (self.type === 'power') {
			// Clear all enemies
			for (var i = enemies.length - 1; i >= 0; i--) {
				if (enemies[i].active) {
					var points = enemies[i].die();
					hero.addScore(points);
				}
			}
			// Increase hero's attack strength
			hero.powerBoost = 3;
			// Visual indicator of power boost
			tween(hero, {
				tint: 0xFF0000
			}, {
				duration: 300
			});
			// Reset after 10 seconds
			LK.setTimeout(function () {
				if (hero) {
					hero.powerBoost = 1;
					tween(hero, {
						tint: 0xFFFFFF
					}, {
						duration: 500
					});
				}
			}, 10000);
		}
		// Flash and fade out
		tween(self, {
			alpha: 0,
			scaleX: 2,
			scaleY: 2
		}, {
			duration: 300,
			onFinish: function onFinish() {
				self.destroy();
			}
		});
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		// Floating animation
		self.y += Math.sin(LK.ticks * 0.1) * 0.5;
		// Rotate slowly
		powerUpGraphic.rotation += 0.02;
		// Check for collision with hero
		if (hero && (hero.intersects(self) || hero.isDashing && self.distanceTo(hero) < 100)) {
			self.collect();
		}
		// Expire after lifetime
		self.lifetime--;
		if (self.lifetime <= 0) {
			tween(self, {
				alpha: 0
			}, {
				duration: 300,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
			self.active = false;
		}
	};
	self.distanceTo = function (target) {
		var dx = target.x - self.x;
		var dy = target.y - self.y;
		return Math.sqrt(dx * dx + dy * dy);
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000022
});
/**** 
* Game Code
****/ 
// Game state variables
var hero;
var enemies = [];
var bullets = [];
var powerUps = [];
var trails = [];
var gameTime = 0;
var spawnTimer = 0;
var bossTimer = 0;
var currentWave = 0;
var bossDefeated = false;
var nextWaveTimer = 0;
var swipeStart = {
	x: 0,
	y: 0
};
var isSwipeActive = false;
// UI elements
var scoreTxt;
var timeTxt;
var healthTxt;
var comboTxt;
// Game constants
var SPAWN_INTERVAL = 90; // Frames between enemy spawns
var POWER_UP_CHANCE = 0.15; // Chance to spawn power-up on enemy defeat
var BOSS_INTERVAL = 1800; // Spawn boss every 30 seconds (60fps * 30)
var MAX_ENEMIES = 15; // Maximum enemies on screen at once
// Initialize game elements
function initGame() {
	// Add background
	var background = game.addChild(LK.getAsset('background', {
		anchorX: 0,
		anchorY: 0,
		x: 0,
		y: 0
	}));
	// Create hero
	hero = new Hero();
	hero.x = 2048 / 2;
	hero.y = 2732 / 2;
	game.addChild(hero);
	// Auto-shoot indicator removed
	// Create UI elements
	scoreTxt = new Text2('Score: 0', {
		size: 60,
		fill: 0xFFFFFF
	});
	scoreTxt.anchor.set(0, 0);
	LK.gui.topRight.addChild(scoreTxt);
	timeTxt = new Text2('Time: 0s', {
		size: 60,
		fill: 0xFFFFFF
	});
	timeTxt.anchor.set(1, 0);
	LK.gui.top.addChild(timeTxt);
	healthTxt = new Text2('❤️❤️❤️', {
		size: 60,
		fill: 0xFFFFFF
	});
	healthTxt.anchor.set(0, 0);
	LK.gui.bottom.addChild(healthTxt);
	comboTxt = new Text2('Combo: 0x', {
		size: 60,
		fill: 0xFFFFFF
	});
	comboTxt.anchor.set(1, 0);
	LK.gui.bottom.addChild(comboTxt);
	// Initialize game timers
	gameTime = 0;
	spawnTimer = 0;
	bossTimer = BOSS_INTERVAL;
	// Play background music
	LK.playMusic('gameMusic', {
		fade: {
			start: 0,
			end: 0.5,
			duration: 1000
		}
	});
}
// This function is no longer needed in endless mode
// Spawn a regular enemy
function spawnEnemy() {
	// Enforce a maximum number of enemies
	if (enemies.length >= MAX_ENEMIES) {
		return;
	}
	var edge = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left
	var x, y;
	switch (edge) {
		case 0:
			// Top
			x = Math.random() * 2048;
			y = -50;
			break;
		case 1:
			// Right
			x = 2048 + 50;
			y = Math.random() * 2732;
			break;
		case 2:
			// Bottom
			x = Math.random() * 2048;
			y = 2732 + 50;
			break;
		case 3:
			// Left
			x = -50;
			y = Math.random() * 2732;
			break;
	}
	var enemy = new Enemy().init(x, y);
	var seconds = Math.floor(gameTime / 60);
	// Speed increases with game time
	enemy.speed = 2 + Math.min(3, seconds / 30);
	enemy.health = 1; // Enemies always have 1 health
	// Scale score value based on time played
	enemy.scoreValue = 100 + Math.floor(seconds / 30) * 20;
	game.addChild(enemy);
	enemies.push(enemy);
}
// Spawn a boss
function spawnBoss() {
	var boss = new Boss().init(2048 / 2, -200);
	var seconds = Math.floor(gameTime / 60);
	// Boss health and score scale with game time
	boss.health = 5 + Math.floor(seconds / 60);
	boss.scoreValue = 2000 + seconds * 50;
	game.addChild(boss);
	enemies.push(boss);
	// Make a dramatic entrance
	tween(boss, {
		y: 400
	}, {
		duration: 2000,
		easing: tween.bounceOut
	});
}
// Spawn a power-up
function spawnPowerUp(x, y) {
	var types = ['health', 'speed', 'power', 'strength'];
	var type = types[Math.floor(Math.random() * types.length)];
	var powerUp = new PowerUp().init(x, y, type);
	game.addChild(powerUp);
	powerUps.push(powerUp);
}
// Handle touch/mouse down
game.down = function (x, y, obj) {
	isSwipeActive = true;
	swipeStart.x = x;
	swipeStart.y = y;
};
// Handle touch/mouse up
game.up = function (x, y, obj) {
	if (isSwipeActive) {
		// Instead of dashing, shoot in the direction of the swipe
		var dx = x - swipeStart.x;
		var dy = y - swipeStart.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		// If it's a significant swipe, shoot in that direction
		if (distance > 20) {
			// Calculate target point to shoot towards
			var targetX = hero.x + dx * 10;
			var targetY = hero.y + dy * 10;
			hero.shootBullet(targetX, targetY);
		} else {
			// If it's just a tap, shoot upward
			hero.shootBullet(hero.x, hero.y - 100);
		}
		isSwipeActive = false;
	}
};
// Handle touch/mouse move
game.move = function (x, y, obj) {
	// We'll use swipe up/down instead of tracking movement
};
// Main game update loop
game.update = function () {
	// Update game time (in seconds)
	gameTime++;
	var seconds = Math.floor(gameTime / 60);
	timeTxt.setText('Time: ' + seconds + 's');
	// Update UI
	scoreTxt.setText('Score: ' + LK.getScore());
	comboTxt.setText('Combo: ' + hero.combo + 'x');
	// Update health display
	var healthStr = '';
	for (var i = 0; i < hero.health; i++) {
		healthStr += '❤️';
	}
	healthTxt.setText(healthStr);
	// Spawn enemies - continuous spawn
	spawnTimer++;
	if (spawnTimer >= SPAWN_INTERVAL && enemies.length < MAX_ENEMIES) {
		// Spawn rate increases over time
		var difficulty = Math.min(0.9, 0.4 + seconds / 120);
		// Higher chance to spawn as time goes on
		if (Math.random() < difficulty) {
			spawnEnemy();
		}
		spawnTimer = 0;
	}
	// Boss timer
	bossTimer--;
	if (bossTimer <= 0) {
		spawnBoss();
		bossTimer = BOSS_INTERVAL;
	}
	// Increase difficulty based on time
	var speedIncrease = Math.min(3, seconds / 60);
	var enemySpeedModifier = 1 + speedIncrease * 0.5;
	// Update game objects
	updateGameObjects();
	// Detect collisions between bullets and enemies
	for (var b = bullets.length - 1; b >= 0; b--) {
		var bullet = bullets[b];
		if (!bullet.active) {
			continue;
		}
		var hitEnemy = false;
		for (var i = enemies.length - 1; i >= 0; i--) {
			var enemy = enemies[i];
			if (!enemy.active) {
				continue;
			}
			if (bullet.intersects(enemy)) {
				// Bullet hit enemy
				hitEnemy = true;
				// Call enemy's takeDamage method
				enemy.takeDamage();
				// Visual feedback
				LK.effects.flashObject(enemy, 0xFFFFFF, 100);
				// Award points if enemy dead
				if (!enemy.active) {
					hero.addScore(enemy.scoreValue);
					// Maybe spawn a power-up
					if (Math.random() < POWER_UP_CHANCE) {
						spawnPowerUp(enemy.x, enemy.y);
					}
				}
				break;
			}
		}
		// Remove bullet if it hit something
		if (hitEnemy) {
			bullet.destroy();
			bullets.splice(b, 1);
		}
	}
	// Clean up destroyed objects
	cleanupDestroyedObjects();
};
// Update all game objects
function updateGameObjects() {
	// Update hero
	if (hero) {
		hero.update();
	}
	// Update enemies
	for (var i = 0; i < enemies.length; i++) {
		if (enemies[i]) {
			enemies[i].update();
		}
	}
	// Update power-ups
	for (var i = 0; i < powerUps.length; i++) {
		if (powerUps[i]) {
			powerUps[i].update();
		}
	}
	// Update bullets
	for (var i = 0; i < bullets.length; i++) {
		if (bullets[i]) {
			bullets[i].update();
		}
	}
	// Update trails
	for (var i = 0; i < trails.length; i++) {
		if (trails[i]) {
			trails[i].update();
		}
	}
}
// Clean up destroyed objects
function cleanupDestroyedObjects() {
	// Clean up destroyed enemies
	for (var i = enemies.length - 1; i >= 0; i--) {
		if (!enemies[i] || !enemies[i].parent) {
			enemies.splice(i, 1);
		}
	}
	// Clean up destroyed power-ups
	for (var i = powerUps.length - 1; i >= 0; i--) {
		if (!powerUps[i] || !powerUps[i].parent) {
			powerUps.splice(i, 1);
		}
	}
	// Clean up destroyed trails
	for (var i = trails.length - 1; i >= 0; i--) {
		if (!trails[i] || !trails[i].parent) {
			trails.splice(i, 1);
		}
	}
	// Clean up destroyed bullets
	for (var i = bullets.length - 1; i >= 0; i--) {
		if (!bullets[i] || !bullets[i].parent) {
			bullets.splice(i, 1);
		}
	}
}
// Initialize the game
initGame(); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var Boss = Container.expand(function () {
	var self = Container.call(this);
	var bossGraphic = self.attachAsset('boss', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 1.5;
	self.health = 10;
	self.attackCooldown = 0;
	self.attackPattern = 0;
	self.scoreValue = 2000;
	self.active = true;
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		return self;
	};
	self.takeDamage = function () {
		if (!self.active) {
			return;
		}
		// Boss takes 1 damage per hit, dies after 5 hits
		self.health -= 1;
		// Flash boss
		LK.effects.flashObject(self, 0xffffff, 300);
		LK.getSound('hit').play();
		if (self.health <= 0) {
			self.die();
		} else {
			// Speed up as health decreases
			self.speed = 1.5 + (5 - self.health) * 0.2;
		}
	};
	self.die = function () {
		if (!self.active) {
			return;
		}
		self.active = false;
		LK.getSound('bossDeath').play();
		// Flash and fade out
		LK.effects.flashObject(self, 0xffff00, 500);
		tween(self, {
			alpha: 0
		}, {
			duration: 1000,
			onFinish: function onFinish() {
				self.destroy();
			}
		});
		currentWave++;
		bossDefeated = true;
		nextWaveTimer = 180; // 3 seconds until next wave
		return self.scoreValue;
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		// Move toward hero but more intelligently
		if (hero) {
			var dx = hero.x - self.x;
			var dy = hero.y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			// Different movement patterns
			if (self.attackPattern === 0) {
				// Direct approach
				if (dist > 0) {
					self.x += dx / dist * self.speed;
					self.y += dy / dist * self.speed;
				}
			} else if (self.attackPattern === 1) {
				// Circle around
				var angle = Math.atan2(dy, dx) + Math.PI / 4;
				self.x += Math.cos(angle) * self.speed * 1.5;
				self.y += Math.sin(angle) * self.speed * 1.5;
			} else if (self.attackPattern === 2) {
				// Charge attack
				if (self.attackCooldown > 30) {
					self.x += dx / dist * self.speed * 2.5;
					self.y += dy / dist * self.speed * 2.5;
				} else {
					// Wait
				}
			}
			if (hero.invulnerable <= 0 && !hero.isDashing) {
				if (self.intersects(hero)) {
					hero.takeDamage();
				}
			}
		}
		// Attack pattern cooldown
		self.attackCooldown--;
		if (self.attackCooldown <= 0) {
			self.attackPattern = (self.attackPattern + 1) % 3;
			self.attackCooldown = 120; // 2 seconds per pattern
		}
		// Keep within screen bounds
		self.x = Math.max(100, Math.min(2048 - 100, self.x));
		self.y = Math.max(100, Math.min(2732 - 100, self.y));
	};
	return self;
});
var Bullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletGraphic = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	bulletGraphic.tint = 0xffffff; // White bullet for the hero
	self.speed = 15;
	self.damage = 1;
	self.active = true;
	self.init = function (x, y, direction) {
		self.x = x;
		self.y = y;
		self.direction = direction || {
			x: 0,
			y: -1
		}; // Default direction is up
		return self;
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		// Move in the specified direction
		self.x += self.direction.x * self.speed;
		self.y += self.direction.y * self.speed;
		// Remove if off-screen
		if (self.x < -50 || self.x > 2048 + 50 || self.y < -50 || self.y > 2732 + 50) {
			self.destroy();
		}
	};
	return self;
});
var DashTrail = Container.expand(function () {
	var self = Container.call(this);
	var trailGraphic = self.attachAsset('dashTrail', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.7
	});
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		self.lifetime = 20; // frames the trail will live
		return self;
	};
	self.update = function () {
		self.lifetime--;
		trailGraphic.alpha = self.lifetime / 20 * 0.7;
		if (self.lifetime <= 0) {
			self.destroy();
		}
	};
	return self;
});
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGraphic = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 2;
	self.health = 1;
	self.scoreValue = 100;
	self.active = true;
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		// Initialize last position for rotation tracking
		self.lastX = x;
		self.lastY = y;
		// Set initial rotation
		if (hero) {
			var dx = hero.x - self.x;
			var dy = hero.y - self.y;
			enemyGraphic.rotation = Math.atan2(dy, dx);
		}
		return self;
	};
	self.takeDamage = function () {
		if (!self.active) {
			return;
		}
		// Enemies die from one hit
		self.health = 0;
		self.die();
	};
	self.die = function () {
		if (!self.active) {
			return;
		}
		self.active = false;
		LK.getSound('hit').play();
		// Flash, fade out, and fall animation
		tween(self, {
			alpha: 0,
			y: self.y + 300,
			// Fall down animation
			rotation: Math.random() * Math.PI * 2,
			// Random rotation
			scaleX: 0.5,
			scaleY: 0.5
		}, {
			duration: 800,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				self.destroy();
			}
		});
		return self.scoreValue;
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		// Move toward hero
		if (hero && !hero.isDashing) {
			var dx = hero.x - self.x;
			var dy = hero.y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist > 0) {
				self.x += dx / dist * self.speed;
				self.y += dy / dist * self.speed;
				// Spider walking animation
				if (LK.ticks % 10 === 0) {
					// Spider leg movement animation
					tween(enemyGraphic, {
						scaleX: 1.1,
						scaleY: 0.9,
						rotation: Math.atan2(dy, dx) + (Math.random() * 0.2 - 0.1)
					}, {
						duration: 200,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							tween(enemyGraphic, {
								scaleX: 1,
								scaleY: 1,
								rotation: Math.atan2(dy, dx)
							}, {
								duration: 200,
								easing: tween.easeOut
							});
						}
					});
				}
			}
		}
		// Check for collision with hero
		if (hero && !hero.isDashing && hero.invulnerable <= 0) {
			if (self.intersects(hero)) {
				hero.takeDamage();
			}
		}
	};
	return self;
});
var Hero = Container.expand(function () {
	var self = Container.call(this);
	var heroGraphic = self.attachAsset('hero', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Simple click handler that does nothing (placeholder)
	self.down = function (x, y, obj) {
		// No auto-shoot toggle functionality
	};
	self.shootSpeed = 15; // Bullet speed
	self.fireRate = 15; // Frames between shots
	self.shootCooldown = 0;
	self.health = 3;
	self.invulnerable = 0;
	self.combo = 0;
	self.score = 0;
	self.powerBoost = 1; // Base power multiplier
	self.shootBullet = function (targetX, targetY) {
		if (self.shootCooldown > 0) {
			return;
		}
		var dx = targetX - self.x;
		var dy = targetY - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		// Normalize direction
		var dirX = dx / distance;
		var dirY = dy / distance;
		// Create bullet
		var bullet = new Bullet().init(self.x, self.y, {
			x: dirX,
			y: dirY
		});
		bullet.damage = self.powerBoost; // Apply power boost to bullet damage
		// Visual shooting effect
		tween(heroGraphic, {
			scaleX: 1.2,
			scaleY: 0.9
		}, {
			duration: 100,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(heroGraphic, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 200,
					easing: tween.elasticOut
				});
			}
		});
		// Set cooldown
		self.shootCooldown = self.fireRate;
		// Add bullet to game
		game.addChild(bullet);
		if (!bullets) {
			bullets = [];
		}
		bullets.push(bullet);
		// Play shoot sound
		LK.getSound('hit').play();
	};
	self.takeDamage = function () {
		if (self.invulnerable > 0) {
			return;
		}
		self.health--;
		self.invulnerable = 60; // invulnerable for 1 second
		self.combo = 0; // Reset combo
		// Flash hero red
		LK.effects.flashObject(self, 0xff0000, 500);
		// Play damage sound
		LK.getSound('damage').play();
		if (self.health <= 0) {
			LK.showGameOver();
		}
	};
	self.addScore = function (points) {
		self.combo++;
		var comboMultiplier = Math.min(4, 1 + self.combo * 0.1);
		var scoreToAdd = Math.floor(points * comboMultiplier);
		self.score += scoreToAdd;
		LK.setScore(self.score);
	};
	self.update = function () {
		// Keep within screen bounds
		self.x = Math.max(50, Math.min(2048 - 50, self.x));
		self.y = Math.max(50, Math.min(2732 - 50, self.y));
		// Cooldowns
		if (self.shootCooldown > 0) {
			self.shootCooldown--;
		}
		if (self.invulnerable > 0) {
			self.invulnerable--;
			// Flicker effect during invulnerability
			heroGraphic.alpha = LK.ticks % 6 < 3 ? 0.4 : 1;
		} else {
			// Normal appearance when not invulnerable
			heroGraphic.alpha = 1;
			heroGraphic.tint = 0xFFFFFF; // Normal color
		}
	};
	return self;
});
var PowerUp = Container.expand(function () {
	var self = Container.call(this);
	var powerUpGraphic = self.attachAsset('powerUp', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.type = 'health'; // Default type
	self.active = true;
	self.lifetime = 300; // 5 seconds
	self.init = function (x, y, type) {
		self.x = x;
		self.y = y;
		self.type = type || self.type;
		// Set color based on type
		if (self.type === 'health') {
			powerUpGraphic.tint = 0x2ecc71; // Green
		} else if (self.type === 'speed') {
			powerUpGraphic.tint = 0x3498db; // Blue
		} else if (self.type === 'power') {
			powerUpGraphic.tint = 0xe74c3c; // Red
		} else if (self.type === 'strength') {
			powerUpGraphic.tint = 0x9b59b6; // Purple
		}
		return self;
	};
	self.collect = function () {
		if (!self.active) {
			return;
		}
		self.active = false;
		LK.getSound('powerup').play();
		if (self.type === 'health' && hero.health < 3) {
			hero.health++;
		} else if (self.type === 'speed') {
			hero.dashSpeed = 80; // Even faster dash
			hero.dashDistance = 900; // Even longer dash
			// Visual indicator of speed boost
			tween(hero, {
				alpha: 0.7
			}, {
				duration: 200,
				onFinish: function onFinish() {
					tween(hero, {
						alpha: 1
					}, {
						duration: 200
					});
				}
			});
			// Reset after 10 seconds
			LK.setTimeout(function () {
				if (hero) {
					hero.dashSpeed = 60;
					hero.dashDistance = 700;
				}
			}, 10000);
		} else if (self.type === 'strength') {
			// Increase hero's attack strength more permanently
			hero.powerBoost = Math.min(5, hero.powerBoost + 1);
			// Visual indicator of strength boost
			tween(hero, {
				tint: 0x9b59b6
			}, {
				duration: 500,
				onFinish: function onFinish() {
					tween(hero, {
						tint: 0xFFFFFF
					}, {
						duration: 500
					});
				}
			});
			// Show strength level
			var strengthTxt = new Text2('STRENGTH +' + hero.powerBoost + '!', {
				size: 80,
				fill: 0x9b59b6
			});
			strengthTxt.anchor.set(0.5, 0.5);
			strengthTxt.x = 2048 / 2;
			strengthTxt.y = 2732 / 2;
			game.addChild(strengthTxt);
			// Fade out the text
			tween(strengthTxt, {
				alpha: 0,
				y: strengthTxt.y - 100
			}, {
				duration: 1500,
				onFinish: function onFinish() {
					strengthTxt.destroy();
				}
			});
		} else if (self.type === 'power') {
			// Clear all enemies
			for (var i = enemies.length - 1; i >= 0; i--) {
				if (enemies[i].active) {
					var points = enemies[i].die();
					hero.addScore(points);
				}
			}
			// Increase hero's attack strength
			hero.powerBoost = 3;
			// Visual indicator of power boost
			tween(hero, {
				tint: 0xFF0000
			}, {
				duration: 300
			});
			// Reset after 10 seconds
			LK.setTimeout(function () {
				if (hero) {
					hero.powerBoost = 1;
					tween(hero, {
						tint: 0xFFFFFF
					}, {
						duration: 500
					});
				}
			}, 10000);
		}
		// Flash and fade out
		tween(self, {
			alpha: 0,
			scaleX: 2,
			scaleY: 2
		}, {
			duration: 300,
			onFinish: function onFinish() {
				self.destroy();
			}
		});
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		// Floating animation
		self.y += Math.sin(LK.ticks * 0.1) * 0.5;
		// Rotate slowly
		powerUpGraphic.rotation += 0.02;
		// Check for collision with hero
		if (hero && (hero.intersects(self) || hero.isDashing && self.distanceTo(hero) < 100)) {
			self.collect();
		}
		// Expire after lifetime
		self.lifetime--;
		if (self.lifetime <= 0) {
			tween(self, {
				alpha: 0
			}, {
				duration: 300,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
			self.active = false;
		}
	};
	self.distanceTo = function (target) {
		var dx = target.x - self.x;
		var dy = target.y - self.y;
		return Math.sqrt(dx * dx + dy * dy);
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000022
});
/**** 
* Game Code
****/ 
// Game state variables
var hero;
var enemies = [];
var bullets = [];
var powerUps = [];
var trails = [];
var gameTime = 0;
var spawnTimer = 0;
var bossTimer = 0;
var currentWave = 0;
var bossDefeated = false;
var nextWaveTimer = 0;
var swipeStart = {
	x: 0,
	y: 0
};
var isSwipeActive = false;
// UI elements
var scoreTxt;
var timeTxt;
var healthTxt;
var comboTxt;
// Game constants
var SPAWN_INTERVAL = 90; // Frames between enemy spawns
var POWER_UP_CHANCE = 0.15; // Chance to spawn power-up on enemy defeat
var BOSS_INTERVAL = 1800; // Spawn boss every 30 seconds (60fps * 30)
var MAX_ENEMIES = 15; // Maximum enemies on screen at once
// Initialize game elements
function initGame() {
	// Add background
	var background = game.addChild(LK.getAsset('background', {
		anchorX: 0,
		anchorY: 0,
		x: 0,
		y: 0
	}));
	// Create hero
	hero = new Hero();
	hero.x = 2048 / 2;
	hero.y = 2732 / 2;
	game.addChild(hero);
	// Auto-shoot indicator removed
	// Create UI elements
	scoreTxt = new Text2('Score: 0', {
		size: 60,
		fill: 0xFFFFFF
	});
	scoreTxt.anchor.set(0, 0);
	LK.gui.topRight.addChild(scoreTxt);
	timeTxt = new Text2('Time: 0s', {
		size: 60,
		fill: 0xFFFFFF
	});
	timeTxt.anchor.set(1, 0);
	LK.gui.top.addChild(timeTxt);
	healthTxt = new Text2('❤️❤️❤️', {
		size: 60,
		fill: 0xFFFFFF
	});
	healthTxt.anchor.set(0, 0);
	LK.gui.bottom.addChild(healthTxt);
	comboTxt = new Text2('Combo: 0x', {
		size: 60,
		fill: 0xFFFFFF
	});
	comboTxt.anchor.set(1, 0);
	LK.gui.bottom.addChild(comboTxt);
	// Initialize game timers
	gameTime = 0;
	spawnTimer = 0;
	bossTimer = BOSS_INTERVAL;
	// Play background music
	LK.playMusic('gameMusic', {
		fade: {
			start: 0,
			end: 0.5,
			duration: 1000
		}
	});
}
// This function is no longer needed in endless mode
// Spawn a regular enemy
function spawnEnemy() {
	// Enforce a maximum number of enemies
	if (enemies.length >= MAX_ENEMIES) {
		return;
	}
	var edge = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left
	var x, y;
	switch (edge) {
		case 0:
			// Top
			x = Math.random() * 2048;
			y = -50;
			break;
		case 1:
			// Right
			x = 2048 + 50;
			y = Math.random() * 2732;
			break;
		case 2:
			// Bottom
			x = Math.random() * 2048;
			y = 2732 + 50;
			break;
		case 3:
			// Left
			x = -50;
			y = Math.random() * 2732;
			break;
	}
	var enemy = new Enemy().init(x, y);
	var seconds = Math.floor(gameTime / 60);
	// Speed increases with game time
	enemy.speed = 2 + Math.min(3, seconds / 30);
	enemy.health = 1; // Enemies always have 1 health
	// Scale score value based on time played
	enemy.scoreValue = 100 + Math.floor(seconds / 30) * 20;
	game.addChild(enemy);
	enemies.push(enemy);
}
// Spawn a boss
function spawnBoss() {
	var boss = new Boss().init(2048 / 2, -200);
	var seconds = Math.floor(gameTime / 60);
	// Boss health and score scale with game time
	boss.health = 5 + Math.floor(seconds / 60);
	boss.scoreValue = 2000 + seconds * 50;
	game.addChild(boss);
	enemies.push(boss);
	// Make a dramatic entrance
	tween(boss, {
		y: 400
	}, {
		duration: 2000,
		easing: tween.bounceOut
	});
}
// Spawn a power-up
function spawnPowerUp(x, y) {
	var types = ['health', 'speed', 'power', 'strength'];
	var type = types[Math.floor(Math.random() * types.length)];
	var powerUp = new PowerUp().init(x, y, type);
	game.addChild(powerUp);
	powerUps.push(powerUp);
}
// Handle touch/mouse down
game.down = function (x, y, obj) {
	isSwipeActive = true;
	swipeStart.x = x;
	swipeStart.y = y;
};
// Handle touch/mouse up
game.up = function (x, y, obj) {
	if (isSwipeActive) {
		// Instead of dashing, shoot in the direction of the swipe
		var dx = x - swipeStart.x;
		var dy = y - swipeStart.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		// If it's a significant swipe, shoot in that direction
		if (distance > 20) {
			// Calculate target point to shoot towards
			var targetX = hero.x + dx * 10;
			var targetY = hero.y + dy * 10;
			hero.shootBullet(targetX, targetY);
		} else {
			// If it's just a tap, shoot upward
			hero.shootBullet(hero.x, hero.y - 100);
		}
		isSwipeActive = false;
	}
};
// Handle touch/mouse move
game.move = function (x, y, obj) {
	// We'll use swipe up/down instead of tracking movement
};
// Main game update loop
game.update = function () {
	// Update game time (in seconds)
	gameTime++;
	var seconds = Math.floor(gameTime / 60);
	timeTxt.setText('Time: ' + seconds + 's');
	// Update UI
	scoreTxt.setText('Score: ' + LK.getScore());
	comboTxt.setText('Combo: ' + hero.combo + 'x');
	// Update health display
	var healthStr = '';
	for (var i = 0; i < hero.health; i++) {
		healthStr += '❤️';
	}
	healthTxt.setText(healthStr);
	// Spawn enemies - continuous spawn
	spawnTimer++;
	if (spawnTimer >= SPAWN_INTERVAL && enemies.length < MAX_ENEMIES) {
		// Spawn rate increases over time
		var difficulty = Math.min(0.9, 0.4 + seconds / 120);
		// Higher chance to spawn as time goes on
		if (Math.random() < difficulty) {
			spawnEnemy();
		}
		spawnTimer = 0;
	}
	// Boss timer
	bossTimer--;
	if (bossTimer <= 0) {
		spawnBoss();
		bossTimer = BOSS_INTERVAL;
	}
	// Increase difficulty based on time
	var speedIncrease = Math.min(3, seconds / 60);
	var enemySpeedModifier = 1 + speedIncrease * 0.5;
	// Update game objects
	updateGameObjects();
	// Detect collisions between bullets and enemies
	for (var b = bullets.length - 1; b >= 0; b--) {
		var bullet = bullets[b];
		if (!bullet.active) {
			continue;
		}
		var hitEnemy = false;
		for (var i = enemies.length - 1; i >= 0; i--) {
			var enemy = enemies[i];
			if (!enemy.active) {
				continue;
			}
			if (bullet.intersects(enemy)) {
				// Bullet hit enemy
				hitEnemy = true;
				// Call enemy's takeDamage method
				enemy.takeDamage();
				// Visual feedback
				LK.effects.flashObject(enemy, 0xFFFFFF, 100);
				// Award points if enemy dead
				if (!enemy.active) {
					hero.addScore(enemy.scoreValue);
					// Maybe spawn a power-up
					if (Math.random() < POWER_UP_CHANCE) {
						spawnPowerUp(enemy.x, enemy.y);
					}
				}
				break;
			}
		}
		// Remove bullet if it hit something
		if (hitEnemy) {
			bullet.destroy();
			bullets.splice(b, 1);
		}
	}
	// Clean up destroyed objects
	cleanupDestroyedObjects();
};
// Update all game objects
function updateGameObjects() {
	// Update hero
	if (hero) {
		hero.update();
	}
	// Update enemies
	for (var i = 0; i < enemies.length; i++) {
		if (enemies[i]) {
			enemies[i].update();
		}
	}
	// Update power-ups
	for (var i = 0; i < powerUps.length; i++) {
		if (powerUps[i]) {
			powerUps[i].update();
		}
	}
	// Update bullets
	for (var i = 0; i < bullets.length; i++) {
		if (bullets[i]) {
			bullets[i].update();
		}
	}
	// Update trails
	for (var i = 0; i < trails.length; i++) {
		if (trails[i]) {
			trails[i].update();
		}
	}
}
// Clean up destroyed objects
function cleanupDestroyedObjects() {
	// Clean up destroyed enemies
	for (var i = enemies.length - 1; i >= 0; i--) {
		if (!enemies[i] || !enemies[i].parent) {
			enemies.splice(i, 1);
		}
	}
	// Clean up destroyed power-ups
	for (var i = powerUps.length - 1; i >= 0; i--) {
		if (!powerUps[i] || !powerUps[i].parent) {
			powerUps.splice(i, 1);
		}
	}
	// Clean up destroyed trails
	for (var i = trails.length - 1; i >= 0; i--) {
		if (!trails[i] || !trails[i].parent) {
			trails.splice(i, 1);
		}
	}
	// Clean up destroyed bullets
	for (var i = bullets.length - 1; i >= 0; i--) {
		if (!bullets[i] || !bullets[i].parent) {
			bullets.splice(i, 1);
		}
	}
}
// Initialize the game
initGame();
:quality(85)/https://cdn.frvr.ai/6805d0256a444924b4b446a8.png%3F3) 
 colored spider. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6805d0fd6a444924b4b446bd.png%3F3) 
 white silk web. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/680636cbedac01de2ca7a717.png%3F3) 
 amazing spider web on tree branch. anime image. green landscape Single Game Texture. In-Game asset. 2d.
:quality(85)/https://cdn.frvr.ai/680637c3edac01de2ca7a734.png%3F3) 
 flyn lady bug 2d cartoon objek. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/68063874edac01de2ca7a74b.png%3F3) 
 flyin evil woodpecker bird. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows