/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
// --- Enemy Class ---
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	// Attach enemy asset (image)
	var enemyAsset = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = enemyAsset.width / 2;
	self.speed = 3;
	self.angle = 0;
	self.hasSpawnedText = false; // Flag to track if this enemy already spawned text
	self.update = function () {
		// Store lastX, lastY for good practice (if needed for triggers)
		if (typeof self.lastX === "undefined") self.lastX = self.x;
		if (typeof self.lastY === "undefined") self.lastY = self.y;
		// Move in direction of angle
		self.x += Math.cos(self.angle) * self.speed * globalSpeedMultiplier;
		self.y += Math.sin(self.angle) * self.speed * globalSpeedMultiplier;
		// Update lastX, lastY
		self.lastX = self.x;
		self.lastY = self.y;
	};
	return self;
});
// --- Enemy2 Class (Red, smaller, faster) ---
var Enemy2 = Container.expand(function () {
	var self = Container.call(this);
	// Attach enemy2 asset (image)
	var enemyAsset = self.attachAsset('enemy2', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = enemyAsset.width / 2;
	self.speed = 5; // Faster than regular enemy
	self.angle = 0;
	self.hasSpawnedText = false; // Flag to track if this enemy already spawned text
	self.update = function () {
		// Store lastX, lastY for good practice
		if (typeof self.lastX === "undefined") self.lastX = self.x;
		if (typeof self.lastY === "undefined") self.lastY = self.y;
		// Move in direction of angle
		self.x += Math.cos(self.angle) * self.speed * globalSpeedMultiplier;
		self.y += Math.sin(self.angle) * self.speed * globalSpeedMultiplier;
		// Update lastX, lastY
		self.lastX = self.x;
		self.lastY = self.y;
	};
	return self;
});
// --- Enemy3 Class (Purple, wide, special movement) ---
var Enemy3 = Container.expand(function () {
	var self = Container.call(this);
	// Attach enemy3 asset (image)
	var enemyAsset = self.attachAsset('enemy3', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = enemyAsset.width / 2;
	self.speed = 2; // Slower but wider
	self.angle = 0;
	self.wobbleOffset = 0; // For special movement pattern
	self.hasSpawnedText = false; // Flag to track if this enemy already spawned text
	self.update = function () {
		// Store lastX, lastY for good practice
		if (typeof self.lastX === "undefined") self.lastX = self.x;
		if (typeof self.lastY === "undefined") self.lastY = self.y;
		// Special wobble movement
		self.wobbleOffset += 0.1;
		var wobbleX = Math.cos(self.wobbleOffset) * 50; // Side-to-side wobble
		var wobbleY = Math.sin(self.wobbleOffset * 0.5) * 30; // Up-down wobble
		// Move in direction of angle with wobble
		self.x += Math.cos(self.angle) * self.speed * globalSpeedMultiplier + wobbleX * 0.02;
		self.y += Math.sin(self.angle) * self.speed * globalSpeedMultiplier + wobbleY * 0.02;
		// Update lastX, lastY
		self.lastX = self.x;
		self.lastY = self.y;
	};
	return self;
});
// --- Player Class ---
var Player = Container.expand(function () {
	var self = Container.call(this);
	// Attach player asset
	var playerAsset = self.attachAsset('player', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Set radius for collision
	self.radius = playerAsset.width / 2;
	// Flash effect on hit
	self.flash = function () {
		LK.effects.flashObject(self, 0xff0000, 600);
	};
	return self;
});
// --- Powerup Class ---
var Powerup = Container.expand(function () {
	var self = Container.call(this);
	// Attach powerup asset
	var powerupAsset = self.attachAsset('powerup', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Set radius for collision
	self.radius = powerupAsset.width / 2;
	return self;
});
// --- Trail Class ---
var Trail = Container.expand(function (assetId) {
	var self = Container.call(this);
	// Attach the same asset as the enemy
	var trailAsset = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Start with some transparency
	self.alpha = 0.6;
	// Fade out over time using tween
	tween(self, {
		alpha: 0
	}, {
		duration: 700,
		onFinish: function onFinish() {
			if (self.parent) {
				self.destroy();
			}
		}
	});
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x181c24
});
/**** 
* Game Code
****/ 
// --- Game Variables ---
// --- Asset Initialization ---
// Red, smaller, faster
// Purple, wide, special
var player;
var enemies = [];
var powerups = [];
var trails = [];
var dragNode = null;
var lastPlayerPos = {
	x: 0,
	y: 0
};
var lastHit = false;
var score = 0;
var scoreTxt;
var survivalTime = 0;
var timeTxt;
var spawnTimer = 0;
var spawnInterval = 120; // frames (reduced from 150 to 120 for better balance)
var powerupTimer = 0;
var powerupInterval = 300; // frames (was 600, now twice as frequent)
var difficultyTimer = 0;
var minSpawnInterval = 60; // Increased from 30 to 60 to keep a reasonable minimum spawn rate
var gameStarted = false; // Control when gameplay begins
globalSpeedMultiplier = 1.0; // Reset speed multiplier
var globalSpeedMultiplier = 1.0; // Multiplier for all enemy speeds
var enemy2SpawnMultiplier = 1.0; // Multiplier for Enemy2 spawn chance
var enemy3SpawnMultiplier = 1.0; // Multiplier for Enemy3 spawn chance
var bestScore = storage.bestScore || 0; // Load best score from storage
var bestScoreTxt;
var dodgeSoundIndex = 0; // Track which dodge sound to play next
// --- UI ---
scoreTxt = new Text2('Score: 0', {
	size: 100,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
timeTxt = new Text2('Time: 0.0', {
	size: 70,
	fill: 0xB0EAFF
});
timeTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timeTxt);
timeTxt.y = 110;
bestScoreTxt = new Text2('Best: ' + bestScore, {
	size: 60,
	fill: 0x00FF00
});
bestScoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(bestScoreTxt);
bestScoreTxt.y = 180;
// Warning text about shuriken increase
var warningTxt = new Text2('Shurikens Will Increase Every 10 Seconds Be Careful!', {
	size: 60,
	fill: 0xFFFF00
});
warningTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(warningTxt);
warningTxt.y = 300;
// Fade out warning text after 3 seconds
tween(warningTxt, {
	alpha: 0
}, {
	duration: 3000,
	onFinish: function onFinish() {
		warningTxt.visible = false;
		gameStarted = true; // Start the game when text fades out
	}
});
// --- Player ---
player = new Player();
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// --- Helper Functions ---
function resetGameVars() {
	// Check if current score is a new record before resetting
	if (score > bestScore) {
		bestScore = score;
		storage.bestScore = bestScore; // Save to storage
	}
	enemies = [];
	powerups = [];
	trails = [];
	score = 0;
	survivalTime = 0;
	spawnTimer = 0;
	spawnInterval = 90;
	powerupTimer = 0;
	difficultyTimer = 0;
	lastHit = false;
	gameStarted = false; // Reset game start state
	globalSpeedMultiplier = 1.0; // Reset speed multiplier
	enemy2SpawnMultiplier = 1.0; // Reset Enemy2 spawn multiplier
	enemy3SpawnMultiplier = 1.0; // Reset Enemy3 spawn multiplier
	scoreTxt.setText('Score: 0');
	timeTxt.setText('Time: 0.0');
	bestScoreTxt.setText('Best: ' + bestScore);
	player.x = 2048 / 2;
	player.y = 2732 / 2;
	// Show warning text again on reset
	warningTxt.visible = true;
	warningTxt.alpha = 1;
	// Fade out warning text after 3 seconds
	tween(warningTxt, {
		alpha: 0
	}, {
		duration: 3000,
		onFinish: function onFinish() {
			warningTxt.visible = false;
			gameStarted = true; // Start the game when text fades out
		}
	});
}
// --- Spawning ---
function spawnEnemy() {
	// Spawn at random edge, move toward player
	var enemy;
	// After 10 seconds, start mixing in Enemy2, after 20 seconds add Enemy3
	if (survivalTime >= 20) {
		var r = Math.random();
		var enemy2Chance = Math.min(0.5, 0.3 * enemy2SpawnMultiplier);
		var enemy3Chance = Math.min(0.4, 0.2 * enemy3SpawnMultiplier);
		var enemyChance = Math.max(0.1, 0.4 - (enemy2Chance - 0.3) - (enemy3Chance - 0.2));
		if (r < enemyChance) {
			enemy = new Enemy();
		} else if (r < enemyChance + enemy2Chance) {
			enemy = new Enemy2();
		} else {
			enemy = new Enemy3();
		}
	} else if (survivalTime >= 10) {
		var r = Math.random();
		var enemy2Chance = Math.min(0.7, 0.4 * enemy2SpawnMultiplier);
		var enemyChance = Math.max(0.3, 0.6 - (enemy2Chance - 0.4));
		if (r < enemyChance) {
			enemy = new Enemy();
		} else {
			enemy = new Enemy2();
		}
	} else {
		enemy = new Enemy();
	}
	var edge = Math.floor(Math.random() * 4);
	var x, y;
	if (edge === 0) {
		// Top
		x = 200 + Math.random() * (2048 - 400);
		y = -80;
	} else if (edge === 1) {
		// Bottom
		x = 200 + Math.random() * (2048 - 400);
		y = 2732 + 80;
	} else if (edge === 2) {
		// Left
		x = -80;
		y = 200 + Math.random() * (2732 - 400);
	} else {
		// Right
		x = 2048 + 80;
		y = 200 + Math.random() * (2732 - 400);
	}
	enemy.x = x;
	enemy.y = y;
	// Track spawn time for trail duration control
	enemy.spawnTime = LK.ticks;
	// Aim at player
	var dx = player.x - x;
	var dy = player.y - y;
	enemy.angle = Math.atan2(dy, dx);
	if (typeof baseEnemySpeed === "undefined") {
		baseEnemySpeed = 3;
	}
	// Only set speed for Enemy (default), others use their own
	if (enemy instanceof Enemy) {
		enemy.speed = baseEnemySpeed + Math.random() * 1 + survivalTime / 40; // Reduced random from 2 to 1, survival bonus from /20 to /40
	}
	// Add more variety: after 30 seconds, occasionally spawn a random fast Enemy2 or a wobbly Enemy3
	if (survivalTime >= 30 && Math.random() < 0.15) {
		if (Math.random() < 0.5) {
			enemy = new Enemy2();
			enemy.speed += 2 + Math.random() * 2; // Super fast
		} else {
			enemy = new Enemy3();
			enemy.speed += 1 + Math.random(); // Extra wobbly
		}
		enemy.x = x;
		enemy.y = y;
		enemy.spawnTime = LK.ticks;
		enemy.angle = Math.atan2(dy, dx);
	}
	enemies.push(enemy);
	game.addChild(enemy);
}
function spawnPowerup() {
	var powerup = new Powerup();
	powerup.x = 200 + Math.random() * (2048 - 400);
	powerup.y = 200 + Math.random() * (2732 - 400);
	powerups.push(powerup);
	game.addChild(powerup);
}
// --- Collision ---
function circleIntersect(a, b) {
	var dx = a.x - b.x;
	var dy = a.y - b.y;
	var dist = Math.sqrt(dx * dx + dy * dy);
	return dist < (a.radius + b.radius) * 0.85;
}
// --- Drag Controls ---
function handleMove(x, y, obj) {
	if (dragNode) {
		// Only move player if dragging (i.e., finger/mouse is moving after down)
		// Calculate movement delta from lastPlayerPos
		if (lastPlayerPos.active) {
			var dx = x - lastPlayerPos.x;
			var dy = y - lastPlayerPos.y;
			// Only move if there is a delta (prevents teleport on first touch)
			if (dx !== 0 || dy !== 0) {
				var newX = dragNode.x + dx;
				var newY = dragNode.y + dy;
				// Clamp to game area (avoid top left 100x100)
				var px = Math.max(100 + player.radius, Math.min(2048 - player.radius, newX));
				var py = Math.max(100 + player.radius, Math.min(2732 - player.radius, newY));
				dragNode.x = px;
				dragNode.y = py;
			}
		}
		// Update lastPlayerPos for next move
		lastPlayerPos.x = x;
		lastPlayerPos.y = y;
		lastPlayerPos.active = true;
	}
}
game.move = handleMove;
game.down = function (x, y, obj) {
	dragNode = player;
	// Record initial drag position, but do not move player yet
	lastPlayerPos.x = x;
	lastPlayerPos.y = y;
	lastPlayerPos.active = false; // Prevents teleport on first move
};
game.up = function (x, y, obj) {
	dragNode = null;
	lastPlayerPos.active = false;
};
// --- Main Update Loop ---
game.update = function () {
	// Don't start gameplay until warning text has faded out
	if (!gameStarted) {
		return;
	}
	// Survival time
	survivalTime += 1 / 60;
	timeTxt.setText('Time: ' + survivalTime.toFixed(1));
	// Difficulty scaling
	difficultyTimer++;
	if (difficultyTimer % 600 === 0) {
		// Every 10 seconds, increase difficulty
		// Decrease spawn interval (more frequent spawns)
		if (spawnInterval > minSpawnInterval) {
			spawnInterval -= 3; // Reduced from 8 to 3 for more gradual spawn rate increase
			if (spawnInterval < minSpawnInterval) spawnInterval = minSpawnInterval;
		}
		// Increase number of enemies spawned per interval (only every other interval)
		if (typeof enemiesPerSpawn === "undefined") {
			enemiesPerSpawn = 1;
		}
		if (difficultyTimer % 1200 === 0) {
			// Only increase every 20 seconds instead of 10
			enemiesPerSpawn++;
		}
		// Increase base enemy speed
		if (typeof baseEnemySpeed === "undefined") {
			baseEnemySpeed = 3;
		}
		baseEnemySpeed += 0.3; // Reduced from 1.0 to 0.3 for more gradual speed increase
		// Increase global speed multiplier for all enemies
		globalSpeedMultiplier += 0.1; // Reduced from 0.3 to 0.1 for more gradual speed increase
		// Increase Enemy2 and Enemy3 spawn rates
		enemy2SpawnMultiplier += 0.2; // Reduced from 0.5 to 0.2
		enemy3SpawnMultiplier += 0.15; // Reduced from 0.4 to 0.15
		// Introduce new enemy types as time passes
		// (handled in spawnEnemy, but you can add more logic here if needed)
	}
	// Enemy spawn
	spawnTimer++;
	if (spawnTimer >= spawnInterval) {
		// Spawn multiple enemies per interval as difficulty increases
		if (typeof enemiesPerSpawn === "undefined") {
			enemiesPerSpawn = 1;
		}
		for (var s = 0; s < enemiesPerSpawn; s++) {
			spawnEnemy();
		}
		spawnTimer = 0;
	}
	// Powerup spawn
	powerupTimer++;
	if (powerupTimer >= powerupInterval) {
		// Spawn 2 powerups per interval for more frequent yellow balls
		for (var i = 0; i < 2; i++) {
			spawnPowerup();
		}
		powerupTimer = 0;
	}
	// Update enemies
	for (var i = enemies.length - 1; i >= 0; i--) {
		var e = enemies[i];
		e.update();
		// Create trail only when enemy is moving faster than base speed AND within spawn time limits
		var shouldCreateTrail = false;
		var timeSinceSpawn = (LK.ticks - (e.spawnTime || 0)) / 60; // Convert to seconds
		// Enemy has 2.25 seconds, Enemy2 and Enemy3 have 1 second
		var trailTimeLimit = e instanceof Enemy ? 2.25 : 1.0;
		if (timeSinceSpawn <= trailTimeLimit) {
			if (e instanceof Enemy && e.speed > baseEnemySpeed + 1) {
				shouldCreateTrail = true;
			} else if (e instanceof Enemy2 && e.speed > 5) {
				shouldCreateTrail = true;
			} else if (e instanceof Enemy3 && e.speed > 2) {
				shouldCreateTrail = true;
			}
		}
		if (shouldCreateTrail && LK.ticks % 8 === 0) {
			var assetId = 'enemy'; // Default
			if (e instanceof Enemy2) assetId = 'enemy2';
			if (e instanceof Enemy3) assetId = 'enemy3';
			var trail = new Trail(assetId);
			trail.x = e.x;
			trail.y = e.y;
			trail.rotation = e.rotation || 0;
			trails.push(trail);
			game.addChild(trail);
		}
		// Remove if off screen
		if (e.x < -200 || e.x > 2248 || e.y < -200 || e.y > 2932) {
			e.destroy();
			enemies.splice(i, 1);
			continue;
		}
		// Check for close calls (near misses)
		var dx = e.x - player.x;
		var dy = e.y - player.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		var closeCallDistance = (e.radius + player.radius) * 1.5; // 1.5x collision distance
		// Initialize lastWasClose if not set
		if (typeof e.lastWasClose === "undefined") e.lastWasClose = false;
		var isCloseNow = distance <= closeCallDistance;
		// Trigger close call effect when transitioning from not close to close, but only once per enemy
		if (!e.lastWasClose && isCloseNow && !circleIntersect(e, player) && !e.hasSpawnedText) {
			// Create encouraging text
			var messages = ['Good!', 'Wow!', 'Excellent!', 'Nice!', 'Amazing!'];
			var message = messages[Math.floor(Math.random() * messages.length)];
			var encourageText = new Text2(message, {
				size: 120,
				fill: 0x00FF00
			});
			encourageText.anchor.set(0.5, 0.5);
			encourageText.x = player.x + (Math.random() - 0.5) * 200; // Random offset around player
			encourageText.y = player.y + (Math.random() - 0.5) * 200;
			// Ensure text stays within screen bounds
			encourageText.x = Math.max(100, Math.min(2048 - 100, encourageText.x));
			encourageText.y = Math.max(100, Math.min(2732 - 100, encourageText.y));
			game.addChild(encourageText);
			// Animate text: pop up, then fade out
			encourageText.scaleX = 0.1;
			encourageText.scaleY = 0.1;
			encourageText.alpha = 1;
			// --- Bonus Points and Bonus Text ---
			score += 10;
			scoreTxt.setText('Score: ' + score);
			// Show "Bonus Point +10" text near the score table (top center)
			var bonusText = new Text2("Bonus Point +10", {
				size: 80,
				fill: 0xFFD700
			});
			bonusText.anchor.set(0.5, 0);
			bonusText.x = scoreTxt.x;
			bonusText.y = scoreTxt.y + scoreTxt.height + 10;
			LK.gui.top.addChild(bonusText);
			bonusText.alpha = 1;
			bonusText.scaleX = 0.7;
			bonusText.scaleY = 0.7;
			tween(bonusText, {
				scaleX: 1.1,
				scaleY: 1.1,
				y: bonusText.y - 30
			}, {
				duration: 180,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(bonusText, {
						alpha: 0,
						y: bonusText.y - 30
					}, {
						duration: 600,
						onFinish: function onFinish() {
							if (bonusText.parent) bonusText.destroy();
						}
					});
				}
			});
			// Mark this enemy as having spawned text
			e.hasSpawnedText = true;
			// Play dodge sound effect - alternate between two sounds
			var soundName = dodgeSoundIndex === 0 ? 'dodge' : 'dodge2';
			LK.getSound(soundName).play();
			dodgeSoundIndex = (dodgeSoundIndex + 1) % 2; // Alternate between 0 and 1
			// Player pop and flash effect for juicy feedback
			tween(player, {
				scaleX: 1.25,
				scaleY: 1.25
			}, {
				duration: 80,
				onFinish: function onFinish() {
					tween(player, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 120
					});
				}
			});
			LK.effects.flashObject(player, 0x00ffcc, 200);
			// First tween: pop up
			tween(encourageText, {
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 200,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					// Second tween: fade out
					tween(encourageText, {
						alpha: 0,
						scaleX: 0.8,
						scaleY: 0.8,
						y: encourageText.y - 50
					}, {
						duration: 800,
						easing: tween.easeIn,
						onFinish: function onFinish() {
							if (encourageText.parent) {
								encourageText.destroy();
							}
						}
					});
				}
			});
		}
		// Update last close state
		e.lastWasClose = isCloseNow;
		// Collision with player
		if (circleIntersect(e, player)) {
			if (!lastHit) {
				// Player hit: pop and flash effect
				tween(player, {
					scaleX: 1.4,
					scaleY: 1.4
				}, {
					duration: 100,
					onFinish: function onFinish() {
						tween(player, {
							scaleX: 1,
							scaleY: 1
						}, {
							duration: 180
						});
					}
				});
				player.flash();
				LK.effects.flashScreen(0xff0000, 600);
				// Update best score before showing game over
				if (score > bestScore) {
					bestScore = score;
					storage.bestScore = bestScore; // Save to storage
					bestScoreTxt.setText('Best: ' + bestScore);
					LK.showGameOver('New Record: ' + score);
				} else {
					LK.showGameOver();
				}
				lastHit = true;
				return;
			}
		}
	}
	// Clean up destroyed trails
	for (var t = trails.length - 1; t >= 0; t--) {
		var trail = trails[t];
		if (!trail.parent || trail.alpha <= 0) {
			if (trail.parent) trail.destroy();
			trails.splice(t, 1);
		}
	}
	// Remove dead enemies if game over
	if (lastHit) {
		for (var j = 0; j < enemies.length; j++) {
			enemies[j].destroy();
		}
		enemies = [];
		for (var k = 0; k < powerups.length; k++) {
			powerups[k].destroy();
		}
		powerups = [];
		for (var l = 0; l < trails.length; l++) {
			trails[l].destroy();
		}
		trails = [];
		return;
	}
	// Update powerups
	for (var p = powerups.length - 1; p >= 0; p--) {
		var pu = powerups[p];
		// Collision with player
		if (circleIntersect(pu, player)) {
			score += 10;
			scoreTxt.setText('Score: ' + score);
			// Create pop effect before destroying powerup
			tween(pu, {
				scaleX: 2.5,
				scaleY: 2.5,
				alpha: 0
			}, {
				duration: 300,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					if (pu.parent) {
						pu.destroy();
					}
				}
			});
			// Player pop and flash effect for collecting powerup
			tween(player, {
				scaleX: 1.18,
				scaleY: 1.18
			}, {
				duration: 80,
				onFinish: function onFinish() {
					tween(player, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 120
					});
				}
			});
			LK.effects.flashObject(player, 0xffff00, 180);
			powerups.splice(p, 1);
			continue;
		}
	}
	// Score increases with time
	if (Math.floor(survivalTime * 10) % 10 === 0) {
		var newScore = Math.floor(survivalTime);
		if (newScore > score) {
			score = newScore;
			scoreTxt.setText('Score: ' + score);
		}
	}
};
// --- Game Over Reset ---
LK.on('gameover', function () {
	resetGameVars();
});
// --- You Win (not used in endless, but for completeness) ---
LK.on('youwin', function () {
	resetGameVars();
});
// --- Start Game Music ---
LK.playMusic('Game-music'); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
// --- Enemy Class ---
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	// Attach enemy asset (image)
	var enemyAsset = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = enemyAsset.width / 2;
	self.speed = 3;
	self.angle = 0;
	self.hasSpawnedText = false; // Flag to track if this enemy already spawned text
	self.update = function () {
		// Store lastX, lastY for good practice (if needed for triggers)
		if (typeof self.lastX === "undefined") self.lastX = self.x;
		if (typeof self.lastY === "undefined") self.lastY = self.y;
		// Move in direction of angle
		self.x += Math.cos(self.angle) * self.speed * globalSpeedMultiplier;
		self.y += Math.sin(self.angle) * self.speed * globalSpeedMultiplier;
		// Update lastX, lastY
		self.lastX = self.x;
		self.lastY = self.y;
	};
	return self;
});
// --- Enemy2 Class (Red, smaller, faster) ---
var Enemy2 = Container.expand(function () {
	var self = Container.call(this);
	// Attach enemy2 asset (image)
	var enemyAsset = self.attachAsset('enemy2', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = enemyAsset.width / 2;
	self.speed = 5; // Faster than regular enemy
	self.angle = 0;
	self.hasSpawnedText = false; // Flag to track if this enemy already spawned text
	self.update = function () {
		// Store lastX, lastY for good practice
		if (typeof self.lastX === "undefined") self.lastX = self.x;
		if (typeof self.lastY === "undefined") self.lastY = self.y;
		// Move in direction of angle
		self.x += Math.cos(self.angle) * self.speed * globalSpeedMultiplier;
		self.y += Math.sin(self.angle) * self.speed * globalSpeedMultiplier;
		// Update lastX, lastY
		self.lastX = self.x;
		self.lastY = self.y;
	};
	return self;
});
// --- Enemy3 Class (Purple, wide, special movement) ---
var Enemy3 = Container.expand(function () {
	var self = Container.call(this);
	// Attach enemy3 asset (image)
	var enemyAsset = self.attachAsset('enemy3', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = enemyAsset.width / 2;
	self.speed = 2; // Slower but wider
	self.angle = 0;
	self.wobbleOffset = 0; // For special movement pattern
	self.hasSpawnedText = false; // Flag to track if this enemy already spawned text
	self.update = function () {
		// Store lastX, lastY for good practice
		if (typeof self.lastX === "undefined") self.lastX = self.x;
		if (typeof self.lastY === "undefined") self.lastY = self.y;
		// Special wobble movement
		self.wobbleOffset += 0.1;
		var wobbleX = Math.cos(self.wobbleOffset) * 50; // Side-to-side wobble
		var wobbleY = Math.sin(self.wobbleOffset * 0.5) * 30; // Up-down wobble
		// Move in direction of angle with wobble
		self.x += Math.cos(self.angle) * self.speed * globalSpeedMultiplier + wobbleX * 0.02;
		self.y += Math.sin(self.angle) * self.speed * globalSpeedMultiplier + wobbleY * 0.02;
		// Update lastX, lastY
		self.lastX = self.x;
		self.lastY = self.y;
	};
	return self;
});
// --- Player Class ---
var Player = Container.expand(function () {
	var self = Container.call(this);
	// Attach player asset
	var playerAsset = self.attachAsset('player', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Set radius for collision
	self.radius = playerAsset.width / 2;
	// Flash effect on hit
	self.flash = function () {
		LK.effects.flashObject(self, 0xff0000, 600);
	};
	return self;
});
// --- Powerup Class ---
var Powerup = Container.expand(function () {
	var self = Container.call(this);
	// Attach powerup asset
	var powerupAsset = self.attachAsset('powerup', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Set radius for collision
	self.radius = powerupAsset.width / 2;
	return self;
});
// --- Trail Class ---
var Trail = Container.expand(function (assetId) {
	var self = Container.call(this);
	// Attach the same asset as the enemy
	var trailAsset = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Start with some transparency
	self.alpha = 0.6;
	// Fade out over time using tween
	tween(self, {
		alpha: 0
	}, {
		duration: 700,
		onFinish: function onFinish() {
			if (self.parent) {
				self.destroy();
			}
		}
	});
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x181c24
});
/**** 
* Game Code
****/ 
// --- Game Variables ---
// --- Asset Initialization ---
// Red, smaller, faster
// Purple, wide, special
var player;
var enemies = [];
var powerups = [];
var trails = [];
var dragNode = null;
var lastPlayerPos = {
	x: 0,
	y: 0
};
var lastHit = false;
var score = 0;
var scoreTxt;
var survivalTime = 0;
var timeTxt;
var spawnTimer = 0;
var spawnInterval = 120; // frames (reduced from 150 to 120 for better balance)
var powerupTimer = 0;
var powerupInterval = 300; // frames (was 600, now twice as frequent)
var difficultyTimer = 0;
var minSpawnInterval = 60; // Increased from 30 to 60 to keep a reasonable minimum spawn rate
var gameStarted = false; // Control when gameplay begins
globalSpeedMultiplier = 1.0; // Reset speed multiplier
var globalSpeedMultiplier = 1.0; // Multiplier for all enemy speeds
var enemy2SpawnMultiplier = 1.0; // Multiplier for Enemy2 spawn chance
var enemy3SpawnMultiplier = 1.0; // Multiplier for Enemy3 spawn chance
var bestScore = storage.bestScore || 0; // Load best score from storage
var bestScoreTxt;
var dodgeSoundIndex = 0; // Track which dodge sound to play next
// --- UI ---
scoreTxt = new Text2('Score: 0', {
	size: 100,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
timeTxt = new Text2('Time: 0.0', {
	size: 70,
	fill: 0xB0EAFF
});
timeTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timeTxt);
timeTxt.y = 110;
bestScoreTxt = new Text2('Best: ' + bestScore, {
	size: 60,
	fill: 0x00FF00
});
bestScoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(bestScoreTxt);
bestScoreTxt.y = 180;
// Warning text about shuriken increase
var warningTxt = new Text2('Shurikens Will Increase Every 10 Seconds Be Careful!', {
	size: 60,
	fill: 0xFFFF00
});
warningTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(warningTxt);
warningTxt.y = 300;
// Fade out warning text after 3 seconds
tween(warningTxt, {
	alpha: 0
}, {
	duration: 3000,
	onFinish: function onFinish() {
		warningTxt.visible = false;
		gameStarted = true; // Start the game when text fades out
	}
});
// --- Player ---
player = new Player();
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// --- Helper Functions ---
function resetGameVars() {
	// Check if current score is a new record before resetting
	if (score > bestScore) {
		bestScore = score;
		storage.bestScore = bestScore; // Save to storage
	}
	enemies = [];
	powerups = [];
	trails = [];
	score = 0;
	survivalTime = 0;
	spawnTimer = 0;
	spawnInterval = 90;
	powerupTimer = 0;
	difficultyTimer = 0;
	lastHit = false;
	gameStarted = false; // Reset game start state
	globalSpeedMultiplier = 1.0; // Reset speed multiplier
	enemy2SpawnMultiplier = 1.0; // Reset Enemy2 spawn multiplier
	enemy3SpawnMultiplier = 1.0; // Reset Enemy3 spawn multiplier
	scoreTxt.setText('Score: 0');
	timeTxt.setText('Time: 0.0');
	bestScoreTxt.setText('Best: ' + bestScore);
	player.x = 2048 / 2;
	player.y = 2732 / 2;
	// Show warning text again on reset
	warningTxt.visible = true;
	warningTxt.alpha = 1;
	// Fade out warning text after 3 seconds
	tween(warningTxt, {
		alpha: 0
	}, {
		duration: 3000,
		onFinish: function onFinish() {
			warningTxt.visible = false;
			gameStarted = true; // Start the game when text fades out
		}
	});
}
// --- Spawning ---
function spawnEnemy() {
	// Spawn at random edge, move toward player
	var enemy;
	// After 10 seconds, start mixing in Enemy2, after 20 seconds add Enemy3
	if (survivalTime >= 20) {
		var r = Math.random();
		var enemy2Chance = Math.min(0.5, 0.3 * enemy2SpawnMultiplier);
		var enemy3Chance = Math.min(0.4, 0.2 * enemy3SpawnMultiplier);
		var enemyChance = Math.max(0.1, 0.4 - (enemy2Chance - 0.3) - (enemy3Chance - 0.2));
		if (r < enemyChance) {
			enemy = new Enemy();
		} else if (r < enemyChance + enemy2Chance) {
			enemy = new Enemy2();
		} else {
			enemy = new Enemy3();
		}
	} else if (survivalTime >= 10) {
		var r = Math.random();
		var enemy2Chance = Math.min(0.7, 0.4 * enemy2SpawnMultiplier);
		var enemyChance = Math.max(0.3, 0.6 - (enemy2Chance - 0.4));
		if (r < enemyChance) {
			enemy = new Enemy();
		} else {
			enemy = new Enemy2();
		}
	} else {
		enemy = new Enemy();
	}
	var edge = Math.floor(Math.random() * 4);
	var x, y;
	if (edge === 0) {
		// Top
		x = 200 + Math.random() * (2048 - 400);
		y = -80;
	} else if (edge === 1) {
		// Bottom
		x = 200 + Math.random() * (2048 - 400);
		y = 2732 + 80;
	} else if (edge === 2) {
		// Left
		x = -80;
		y = 200 + Math.random() * (2732 - 400);
	} else {
		// Right
		x = 2048 + 80;
		y = 200 + Math.random() * (2732 - 400);
	}
	enemy.x = x;
	enemy.y = y;
	// Track spawn time for trail duration control
	enemy.spawnTime = LK.ticks;
	// Aim at player
	var dx = player.x - x;
	var dy = player.y - y;
	enemy.angle = Math.atan2(dy, dx);
	if (typeof baseEnemySpeed === "undefined") {
		baseEnemySpeed = 3;
	}
	// Only set speed for Enemy (default), others use their own
	if (enemy instanceof Enemy) {
		enemy.speed = baseEnemySpeed + Math.random() * 1 + survivalTime / 40; // Reduced random from 2 to 1, survival bonus from /20 to /40
	}
	// Add more variety: after 30 seconds, occasionally spawn a random fast Enemy2 or a wobbly Enemy3
	if (survivalTime >= 30 && Math.random() < 0.15) {
		if (Math.random() < 0.5) {
			enemy = new Enemy2();
			enemy.speed += 2 + Math.random() * 2; // Super fast
		} else {
			enemy = new Enemy3();
			enemy.speed += 1 + Math.random(); // Extra wobbly
		}
		enemy.x = x;
		enemy.y = y;
		enemy.spawnTime = LK.ticks;
		enemy.angle = Math.atan2(dy, dx);
	}
	enemies.push(enemy);
	game.addChild(enemy);
}
function spawnPowerup() {
	var powerup = new Powerup();
	powerup.x = 200 + Math.random() * (2048 - 400);
	powerup.y = 200 + Math.random() * (2732 - 400);
	powerups.push(powerup);
	game.addChild(powerup);
}
// --- Collision ---
function circleIntersect(a, b) {
	var dx = a.x - b.x;
	var dy = a.y - b.y;
	var dist = Math.sqrt(dx * dx + dy * dy);
	return dist < (a.radius + b.radius) * 0.85;
}
// --- Drag Controls ---
function handleMove(x, y, obj) {
	if (dragNode) {
		// Only move player if dragging (i.e., finger/mouse is moving after down)
		// Calculate movement delta from lastPlayerPos
		if (lastPlayerPos.active) {
			var dx = x - lastPlayerPos.x;
			var dy = y - lastPlayerPos.y;
			// Only move if there is a delta (prevents teleport on first touch)
			if (dx !== 0 || dy !== 0) {
				var newX = dragNode.x + dx;
				var newY = dragNode.y + dy;
				// Clamp to game area (avoid top left 100x100)
				var px = Math.max(100 + player.radius, Math.min(2048 - player.radius, newX));
				var py = Math.max(100 + player.radius, Math.min(2732 - player.radius, newY));
				dragNode.x = px;
				dragNode.y = py;
			}
		}
		// Update lastPlayerPos for next move
		lastPlayerPos.x = x;
		lastPlayerPos.y = y;
		lastPlayerPos.active = true;
	}
}
game.move = handleMove;
game.down = function (x, y, obj) {
	dragNode = player;
	// Record initial drag position, but do not move player yet
	lastPlayerPos.x = x;
	lastPlayerPos.y = y;
	lastPlayerPos.active = false; // Prevents teleport on first move
};
game.up = function (x, y, obj) {
	dragNode = null;
	lastPlayerPos.active = false;
};
// --- Main Update Loop ---
game.update = function () {
	// Don't start gameplay until warning text has faded out
	if (!gameStarted) {
		return;
	}
	// Survival time
	survivalTime += 1 / 60;
	timeTxt.setText('Time: ' + survivalTime.toFixed(1));
	// Difficulty scaling
	difficultyTimer++;
	if (difficultyTimer % 600 === 0) {
		// Every 10 seconds, increase difficulty
		// Decrease spawn interval (more frequent spawns)
		if (spawnInterval > minSpawnInterval) {
			spawnInterval -= 3; // Reduced from 8 to 3 for more gradual spawn rate increase
			if (spawnInterval < minSpawnInterval) spawnInterval = minSpawnInterval;
		}
		// Increase number of enemies spawned per interval (only every other interval)
		if (typeof enemiesPerSpawn === "undefined") {
			enemiesPerSpawn = 1;
		}
		if (difficultyTimer % 1200 === 0) {
			// Only increase every 20 seconds instead of 10
			enemiesPerSpawn++;
		}
		// Increase base enemy speed
		if (typeof baseEnemySpeed === "undefined") {
			baseEnemySpeed = 3;
		}
		baseEnemySpeed += 0.3; // Reduced from 1.0 to 0.3 for more gradual speed increase
		// Increase global speed multiplier for all enemies
		globalSpeedMultiplier += 0.1; // Reduced from 0.3 to 0.1 for more gradual speed increase
		// Increase Enemy2 and Enemy3 spawn rates
		enemy2SpawnMultiplier += 0.2; // Reduced from 0.5 to 0.2
		enemy3SpawnMultiplier += 0.15; // Reduced from 0.4 to 0.15
		// Introduce new enemy types as time passes
		// (handled in spawnEnemy, but you can add more logic here if needed)
	}
	// Enemy spawn
	spawnTimer++;
	if (spawnTimer >= spawnInterval) {
		// Spawn multiple enemies per interval as difficulty increases
		if (typeof enemiesPerSpawn === "undefined") {
			enemiesPerSpawn = 1;
		}
		for (var s = 0; s < enemiesPerSpawn; s++) {
			spawnEnemy();
		}
		spawnTimer = 0;
	}
	// Powerup spawn
	powerupTimer++;
	if (powerupTimer >= powerupInterval) {
		// Spawn 2 powerups per interval for more frequent yellow balls
		for (var i = 0; i < 2; i++) {
			spawnPowerup();
		}
		powerupTimer = 0;
	}
	// Update enemies
	for (var i = enemies.length - 1; i >= 0; i--) {
		var e = enemies[i];
		e.update();
		// Create trail only when enemy is moving faster than base speed AND within spawn time limits
		var shouldCreateTrail = false;
		var timeSinceSpawn = (LK.ticks - (e.spawnTime || 0)) / 60; // Convert to seconds
		// Enemy has 2.25 seconds, Enemy2 and Enemy3 have 1 second
		var trailTimeLimit = e instanceof Enemy ? 2.25 : 1.0;
		if (timeSinceSpawn <= trailTimeLimit) {
			if (e instanceof Enemy && e.speed > baseEnemySpeed + 1) {
				shouldCreateTrail = true;
			} else if (e instanceof Enemy2 && e.speed > 5) {
				shouldCreateTrail = true;
			} else if (e instanceof Enemy3 && e.speed > 2) {
				shouldCreateTrail = true;
			}
		}
		if (shouldCreateTrail && LK.ticks % 8 === 0) {
			var assetId = 'enemy'; // Default
			if (e instanceof Enemy2) assetId = 'enemy2';
			if (e instanceof Enemy3) assetId = 'enemy3';
			var trail = new Trail(assetId);
			trail.x = e.x;
			trail.y = e.y;
			trail.rotation = e.rotation || 0;
			trails.push(trail);
			game.addChild(trail);
		}
		// Remove if off screen
		if (e.x < -200 || e.x > 2248 || e.y < -200 || e.y > 2932) {
			e.destroy();
			enemies.splice(i, 1);
			continue;
		}
		// Check for close calls (near misses)
		var dx = e.x - player.x;
		var dy = e.y - player.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		var closeCallDistance = (e.radius + player.radius) * 1.5; // 1.5x collision distance
		// Initialize lastWasClose if not set
		if (typeof e.lastWasClose === "undefined") e.lastWasClose = false;
		var isCloseNow = distance <= closeCallDistance;
		// Trigger close call effect when transitioning from not close to close, but only once per enemy
		if (!e.lastWasClose && isCloseNow && !circleIntersect(e, player) && !e.hasSpawnedText) {
			// Create encouraging text
			var messages = ['Good!', 'Wow!', 'Excellent!', 'Nice!', 'Amazing!'];
			var message = messages[Math.floor(Math.random() * messages.length)];
			var encourageText = new Text2(message, {
				size: 120,
				fill: 0x00FF00
			});
			encourageText.anchor.set(0.5, 0.5);
			encourageText.x = player.x + (Math.random() - 0.5) * 200; // Random offset around player
			encourageText.y = player.y + (Math.random() - 0.5) * 200;
			// Ensure text stays within screen bounds
			encourageText.x = Math.max(100, Math.min(2048 - 100, encourageText.x));
			encourageText.y = Math.max(100, Math.min(2732 - 100, encourageText.y));
			game.addChild(encourageText);
			// Animate text: pop up, then fade out
			encourageText.scaleX = 0.1;
			encourageText.scaleY = 0.1;
			encourageText.alpha = 1;
			// --- Bonus Points and Bonus Text ---
			score += 10;
			scoreTxt.setText('Score: ' + score);
			// Show "Bonus Point +10" text near the score table (top center)
			var bonusText = new Text2("Bonus Point +10", {
				size: 80,
				fill: 0xFFD700
			});
			bonusText.anchor.set(0.5, 0);
			bonusText.x = scoreTxt.x;
			bonusText.y = scoreTxt.y + scoreTxt.height + 10;
			LK.gui.top.addChild(bonusText);
			bonusText.alpha = 1;
			bonusText.scaleX = 0.7;
			bonusText.scaleY = 0.7;
			tween(bonusText, {
				scaleX: 1.1,
				scaleY: 1.1,
				y: bonusText.y - 30
			}, {
				duration: 180,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(bonusText, {
						alpha: 0,
						y: bonusText.y - 30
					}, {
						duration: 600,
						onFinish: function onFinish() {
							if (bonusText.parent) bonusText.destroy();
						}
					});
				}
			});
			// Mark this enemy as having spawned text
			e.hasSpawnedText = true;
			// Play dodge sound effect - alternate between two sounds
			var soundName = dodgeSoundIndex === 0 ? 'dodge' : 'dodge2';
			LK.getSound(soundName).play();
			dodgeSoundIndex = (dodgeSoundIndex + 1) % 2; // Alternate between 0 and 1
			// Player pop and flash effect for juicy feedback
			tween(player, {
				scaleX: 1.25,
				scaleY: 1.25
			}, {
				duration: 80,
				onFinish: function onFinish() {
					tween(player, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 120
					});
				}
			});
			LK.effects.flashObject(player, 0x00ffcc, 200);
			// First tween: pop up
			tween(encourageText, {
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 200,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					// Second tween: fade out
					tween(encourageText, {
						alpha: 0,
						scaleX: 0.8,
						scaleY: 0.8,
						y: encourageText.y - 50
					}, {
						duration: 800,
						easing: tween.easeIn,
						onFinish: function onFinish() {
							if (encourageText.parent) {
								encourageText.destroy();
							}
						}
					});
				}
			});
		}
		// Update last close state
		e.lastWasClose = isCloseNow;
		// Collision with player
		if (circleIntersect(e, player)) {
			if (!lastHit) {
				// Player hit: pop and flash effect
				tween(player, {
					scaleX: 1.4,
					scaleY: 1.4
				}, {
					duration: 100,
					onFinish: function onFinish() {
						tween(player, {
							scaleX: 1,
							scaleY: 1
						}, {
							duration: 180
						});
					}
				});
				player.flash();
				LK.effects.flashScreen(0xff0000, 600);
				// Update best score before showing game over
				if (score > bestScore) {
					bestScore = score;
					storage.bestScore = bestScore; // Save to storage
					bestScoreTxt.setText('Best: ' + bestScore);
					LK.showGameOver('New Record: ' + score);
				} else {
					LK.showGameOver();
				}
				lastHit = true;
				return;
			}
		}
	}
	// Clean up destroyed trails
	for (var t = trails.length - 1; t >= 0; t--) {
		var trail = trails[t];
		if (!trail.parent || trail.alpha <= 0) {
			if (trail.parent) trail.destroy();
			trails.splice(t, 1);
		}
	}
	// Remove dead enemies if game over
	if (lastHit) {
		for (var j = 0; j < enemies.length; j++) {
			enemies[j].destroy();
		}
		enemies = [];
		for (var k = 0; k < powerups.length; k++) {
			powerups[k].destroy();
		}
		powerups = [];
		for (var l = 0; l < trails.length; l++) {
			trails[l].destroy();
		}
		trails = [];
		return;
	}
	// Update powerups
	for (var p = powerups.length - 1; p >= 0; p--) {
		var pu = powerups[p];
		// Collision with player
		if (circleIntersect(pu, player)) {
			score += 10;
			scoreTxt.setText('Score: ' + score);
			// Create pop effect before destroying powerup
			tween(pu, {
				scaleX: 2.5,
				scaleY: 2.5,
				alpha: 0
			}, {
				duration: 300,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					if (pu.parent) {
						pu.destroy();
					}
				}
			});
			// Player pop and flash effect for collecting powerup
			tween(player, {
				scaleX: 1.18,
				scaleY: 1.18
			}, {
				duration: 80,
				onFinish: function onFinish() {
					tween(player, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 120
					});
				}
			});
			LK.effects.flashObject(player, 0xffff00, 180);
			powerups.splice(p, 1);
			continue;
		}
	}
	// Score increases with time
	if (Math.floor(survivalTime * 10) % 10 === 0) {
		var newScore = Math.floor(survivalTime);
		if (newScore > score) {
			score = newScore;
			scoreTxt.setText('Score: ' + score);
		}
	}
};
// --- Game Over Reset ---
LK.on('gameover', function () {
	resetGameVars();
});
// --- You Win (not used in endless, but for completeness) ---
LK.on('youwin', function () {
	resetGameVars();
});
// --- Start Game Music ---
LK.playMusic('Game-music');