/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGraphics = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedX = (Math.random() - 0.5) * 3;
	self.speedY = (Math.random() - 0.5) * 3;
	self.health = 1;
	self.update = function () {
		self.x += self.speedX;
		self.y += self.speedY;
		// Bounce off screen edges
		if (self.x < 30 || self.x > 2018) {
			self.speedX *= -1;
		}
		if (self.y < 30 || self.y > 2702) {
			self.speedY *= -1;
		}
	};
	return self;
});
var FireProjectile = Container.expand(function () {
	var self = Container.call(this);
	var fireGraphics = self.attachAsset('fireProjectile', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedX = 0;
	self.speedY = 8; // Downward speed
	self.lifetime = 0;
	self.gravity = 0.3;
	self.update = function () {
		self.x += self.speedX;
		self.y += self.speedY;
		self.speedY += self.gravity; // Fire falls with gravity
		self.lifetime++;
		// Add fire effect with slight flickering
		fireGraphics.alpha = 0.8 + Math.sin(self.lifetime * 0.3) * 0.2;
	};
	return self;
});
var Jar = Container.expand(function () {
	var self = Container.call(this);
	var jarGraphics = self.attachAsset('jar', {
		anchorX: 0.5,
		anchorY: 1.0
	});
	self.broken = false;
	self.jumpTimer = Math.random() * 120 + 60; // Random jump intervals
	self.moveTimer = Math.random() * 180 + 120; // Random movement intervals
	self.moveDirection = Math.random() < 0.5 ? -1 : 1; // Random initial direction
	self.isJumping = false;
	self.originalY = 0; // Store original platform position
	self.update = function () {
		if (!self.broken && self.platform) {
			// Update timers
			self.jumpTimer--;
			self.moveTimer--;
			// Jump behavior
			if (self.jumpTimer <= 0 && !self.isJumping) {
				self.jump();
				self.jumpTimer = Math.random() * 180 + 120; // Reset jump timer
			}
			// Movement behavior
			if (self.moveTimer <= 0) {
				self.moveDirection *= -1; // Change direction
				self.moveTimer = Math.random() * 240 + 180; // Reset move timer
			}
			// Horizontal movement within platform bounds
			var moveAmount = Math.sin(LK.ticks * 0.05) * 2 * self.moveDirection;
			var newX = self.platform.x + moveAmount;
			// Keep jar on platform
			var platformWidth = self.platform.width || 200;
			if (newX >= self.platform.x - platformWidth / 3 && newX <= self.platform.x + platformWidth / 3) {
				self.x = newX;
			} else {
				self.x = self.platform.x;
			}
			// Keep jar positioned on platform
			if (!self.isJumping) {
				self.y = self.platform.y - self.platform.height / 2;
				self.originalY = self.y;
			}
			// Fire attack if this jar can attack
			if (self.canAttack) {
				self.attackTimer--;
				if (self.attackTimer <= 0) {
					self.fireAttack();
					self.attackTimer = Math.random() * 180 + 120; // Random fire intervals
				}
			}
		}
	};
	self.jump = function () {
		if (!self.isJumping && !self.broken) {
			self.isJumping = true;
			var jumpHeight = 80 + Math.random() * 40; // Random jump height
			// Play jar sound when jumping
			LK.getSound('jar').play();
			// Jump up
			tween(self, {
				y: self.originalY - jumpHeight
			}, {
				duration: 400,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					// Fall back down
					tween(self, {
						y: self.originalY
					}, {
						duration: 400,
						easing: tween.easeIn,
						onFinish: function onFinish() {
							self.isJumping = false;
						}
					});
				}
			});
		}
	};
	self.breakJar = function () {
		if (!self.broken) {
			self.broken = true;
			LK.getSound('jarBreak').play();
			LK.setScore(LK.getScore() + 5);
			scoreTxt.setText(LK.getScore());
			// Track jars broken for level progression
			jarsBrokenThisLevel++;
			// Check if all jars are broken (count remaining unbroken jars)
			var remainingJars = 0;
			for (var k = 0; k < jars.length; k++) {
				if (!jars[k].broken) {
					remainingJars++;
				}
			}
			// Level up only when all jars are broken (only 1 remaining = this jar that just broke)
			if (remainingJars <= 1) {
				// Level up!
				currentLevel++;
				jarsBrokenThisLevel = 0;
				levelTxt.setText('Level ' + currentLevel);
				// Flash screen gold for level up
				LK.effects.flashScreen(0xFFD700, 800);
				// Hide ninja temporarily for level transition
				ninja.alpha = 0;
				// Generate new platforms and jars for next level
				LK.setTimeout(function () {
					// Clear existing platforms and jars
					for (var i = platforms.length - 1; i >= 0; i--) {
						platforms[i].destroy();
					}
					for (var j = jars.length - 1; j >= 0; j--) {
						if (!jars[j].broken) {
							jars[j].destroy();
						}
					}
					platforms = [];
					jars = [];
					// Reset ninja position to starting position
					ninja.x = 1024;
					ninja.y = 2500;
					ninja.velocityY = 0;
					ninja.onGround = false;
					// Make platforms and ninja appear together
					generatePlatforms();
					// Fade in ninja with platforms
					tween(ninja, {
						alpha: 1
					}, {
						duration: 800,
						easing: tween.easeInOut
					});
				}, 500);
			}
			// Create multiple jar fragments for breaking effect
			var fragments = [];
			for (var i = 0; i < 4; i++) {
				var fragment = LK.getAsset('jar', {
					anchorX: 0.5,
					anchorY: 0.5,
					scaleX: 0.3,
					scaleY: 0.3,
					tint: 0x8b4513
				});
				fragment.x = self.x + (Math.random() - 0.5) * 20;
				fragment.y = self.y + (Math.random() - 0.5) * 20;
				fragments.push(fragment);
				game.addChild(fragment);
				// Animate each fragment
				var fragmentSpeedX = (Math.random() - 0.5) * 200;
				var fragmentSpeedY = -Math.random() * 150 - 50;
				var fragmentRotation = (Math.random() - 0.5) * 6;
				tween(fragment, {
					x: fragment.x + fragmentSpeedX,
					y: fragment.y + fragmentSpeedY + 100,
					rotation: fragmentRotation,
					alpha: 0,
					scaleX: 0.1,
					scaleY: 0.1
				}, {
					duration: 600,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						fragment.destroy();
					}
				});
			}
			// Main jar breaking animation - shake and fade
			tween(jarGraphics, {
				rotation: 0.3
			}, {
				duration: 50,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					tween(jarGraphics, {
						rotation: -0.3,
						scaleX: 1.2,
						scaleY: 0.8
					}, {
						duration: 50,
						easing: tween.easeInOut,
						onFinish: function onFinish() {
							tween(jarGraphics, {
								scaleX: 0.1,
								scaleY: 0.1,
								alpha: 0,
								rotation: 0
							}, {
								duration: 200,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									self.destroy();
								}
							});
						}
					});
				}
			});
		}
	};
	self.fireAttack = function () {
		if (!self.broken && self.canAttack) {
			var fireProjectile = new FireProjectile();
			fireProjectile.x = self.x;
			fireProjectile.y = self.y + 20;
			fireProjectile.speedX = (Math.random() - 0.5) * 2; // Slight horizontal variation
			fireProjectiles.push(fireProjectile);
			game.addChild(fireProjectile);
			LK.getSound('jarFire').play();
		}
	};
	return self;
});
var Ninja = Container.expand(function () {
	var self = Container.call(this);
	var ninjaGraphics = self.attachAsset('ninja', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.velocityY = 0;
	self.onGround = false;
	self.gravity = 0.8;
	self.jumpPower = -18;
	self.health = 5;
	self.attackCooldown = 0;
	self.update = function () {
		// Apply gravity
		if (!self.onGround) {
			self.velocityY += self.gravity;
		}
		self.y += self.velocityY;
		// Reset ground state
		self.onGround = false;
		// Check platform collisions
		for (var i = 0; i < platforms.length; i++) {
			var platform = platforms[i];
			if (self.intersects(platform) && self.velocityY > 0) {
				var platformTop = platform.y - platform.height / 2;
				var ninjaBottom = self.y + self.height / 2;
				if (ninjaBottom > platformTop - 20) {
					self.y = platformTop - self.height / 2;
					self.velocityY = 0;
					self.onGround = true;
					// Move ninja with platform
					self.x += platform.moveSpeed * platform.moveDirection;
					break;
				}
			}
		}
		// Fall off screen check
		if (self.y > 2800) {
			LK.showGameOver();
		}
		// Reduce attack cooldown
		if (self.attackCooldown > 0) {
			self.attackCooldown--;
		}
	};
	self.jump = function () {
		if (self.onGround) {
			self.velocityY = self.jumpPower;
			self.onGround = false;
			LK.getSound('jump').play();
		}
	};
	self.attack = function (targetX, targetY) {
		if (self.attackCooldown <= 0) {
			var projectile = new Projectile();
			projectile.x = self.x;
			projectile.y = self.y;
			var dx = targetX - self.x;
			var dy = targetY - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			projectile.speedX = dx / distance * 24;
			projectile.speedY = dy / distance * 24;
			projectiles.push(projectile);
			game.addChild(projectile);
			self.attackCooldown = 20;
			LK.getSound('attack').play();
		}
	};
	self.moveLeft = function () {
		self.x -= ninjaSpeed;
		if (self.x < 50) self.x = 50;
		// Flip ninja to face left
		ninjaGraphics.scaleX = -1;
	};
	self.moveRight = function () {
		self.x += ninjaSpeed;
		if (self.x > 1998) self.x = 1998;
		// Flip ninja to face right
		ninjaGraphics.scaleX = 1;
	};
	return self;
});
var Platform = Container.expand(function () {
	var self = Container.call(this);
	var platformGraphics = self.attachAsset('platform', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.moveSpeed = Math.random() * 2 + 1; // Random speed between 1-3
	self.moveDirection = Math.random() < 0.5 ? -1 : 1; // Random initial direction
	self.leftBound = 100;
	self.rightBound = 1948;
	self.update = function () {
		// Move platform horizontally
		self.x += self.moveSpeed * self.moveDirection;
		// Bounce off boundaries
		if (self.x <= self.leftBound || self.x >= self.rightBound) {
			self.moveDirection *= -1;
		}
	};
	return self;
});
var Projectile = Container.expand(function () {
	var self = Container.call(this);
	var projectileGraphics = self.attachAsset('projectile', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedX = 0;
	self.speedY = 0;
	self.lifetime = 0;
	self.update = function () {
		self.x += self.speedX;
		self.y += self.speedY;
		self.lifetime++;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x87ceeb
});
/**** 
* Game Code
****/ 
// Create background
var background = LK.getAsset('background', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	scaleX: 1.0,
	scaleY: 1.0
});
game.addChild(background);
var ninja = new Ninja();
var platforms = [];
var enemies = [];
var projectiles = [];
var jars = [];
var fireProjectiles = [];
var enemySpawnTimer = 0;
var difficultyTimer = 0;
var currentLevel = 1;
var jarsPerLevel = 5;
var jarsBrokenThisLevel = 0;
var touchStartX = 0;
var touchStartY = 0;
var isSwipeMove = false;
var ninjaSpeed = 8;
var ninjaMaxHealth = 5;
var ninjaCurrentHealth = 5;
// Create score display
var scoreTxt = new Text2('0', {
	size: 80,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create level display
var levelTxt = new Text2('Level 1', {
	size: 60,
	fill: 0xFFD700
});
levelTxt.anchor.set(0, 0);
levelTxt.x = 120;
levelTxt.y = 20;
LK.gui.topLeft.addChild(levelTxt);
// Create health display
var healthTxt = new Text2('Health: 5', {
	size: 60,
	fill: 0xff0000
});
healthTxt.anchor.set(1, 0);
healthTxt.x = -20;
healthTxt.y = 20;
LK.gui.topRight.addChild(healthTxt);
// Generate random platforms
function generatePlatforms() {
	platforms = [];
	// Ground platform
	var groundPlatform = new Platform();
	groundPlatform.x = 1024;
	groundPlatform.y = 2600;
	groundPlatform.width = 400;
	// Start platforms invisible for coordinated appearance
	groundPlatform.alpha = 0;
	platforms.push(groundPlatform);
	game.addChild(groundPlatform);
	// Animate ground platform appearance
	tween(groundPlatform, {
		alpha: 1
	}, {
		duration: 600,
		easing: tween.easeInOut
	});
	// Random platforms - increase count with level
	var platformCount = Math.min(8 + currentLevel, 15);
	for (var i = 0; i < platformCount; i++) {
		var platform = new Platform();
		platform.x = Math.random() * 1600 + 200;
		platform.y = 2400 - i * 250 - Math.random() * 100;
		// Make platforms smaller at higher levels for more challenge
		platform.width = Math.max(150 + Math.random() * 100 - currentLevel * 5, 80);
		// Start platforms invisible for coordinated appearance
		platform.alpha = 0;
		platforms.push(platform);
		game.addChild(platform);
		// Animate platform appearance with staggered timing
		tween(platform, {
			alpha: 1
		}, {
			duration: 600,
			delay: i * 100,
			easing: tween.easeInOut
		});
		// Ensure enough jars are available for level completion
		var jarChance = Math.min(0.8, 0.6 + currentLevel * 0.05);
		if (Math.random() < jarChance) {
			var jar = new Jar();
			jar.x = platform.x;
			jar.y = platform.y - platform.height / 2;
			jar.platform = platform; // Assign platform reference to jar
			// Start jars invisible for coordinated appearance
			jar.alpha = 0;
			// Randomly make one jar per few platforms a fire attacker
			jar.canAttack = Math.random() < 0.3; // 30% chance
			if (jar.canAttack) {
				jar.attackTimer = Math.random() * 180 + 60;
			}
			jars.push(jar);
			game.addChild(jar);
			// Animate jar appearance slightly after platform
			tween(jar, {
				alpha: 1
			}, {
				duration: 400,
				delay: i * 100 + 200,
				easing: tween.easeInOut
			});
		}
	}
}
function spawnEnemy() {
	var enemy = new Enemy();
	// Spawn from random edge
	var side = Math.floor(Math.random() * 4);
	switch (side) {
		case 0:
			// Top
			enemy.x = Math.random() * 2048;
			enemy.y = -30;
			break;
		case 1:
			// Right
			enemy.x = 2078;
			enemy.y = Math.random() * 2732;
			break;
		case 2:
			// Bottom
			enemy.x = Math.random() * 2048;
			enemy.y = 2762;
			break;
		case 3:
			// Left
			enemy.x = -30;
			enemy.y = Math.random() * 2732;
			break;
	}
	enemies.push(enemy);
	game.addChild(enemy);
}
// Initialize game elements
generatePlatforms();
ninja.x = 1024;
ninja.y = 2500;
game.addChild(ninja);
// Touch controls
game.down = function (x, y, obj) {
	touchStartX = x;
	touchStartY = y;
	isSwipeMove = false;
};
game.up = function (x, y, obj) {
	if (!isSwipeMove) {
		// If touching near ninja, jump
		var dx = x - ninja.x;
		var dy = y - ninja.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance < 150) {
			ninja.jump();
		} else {
			// Attack in direction of touch
			ninja.attack(x, y);
		}
	}
};
game.move = function (x, y, obj) {
	var swipeDistanceX = x - touchStartX;
	var swipeDistanceY = Math.abs(y - touchStartY);
	// Detect horizontal swipe (minimum 50px horizontal, less than 100px vertical)
	if (Math.abs(swipeDistanceX) > 50 && swipeDistanceY < 100) {
		isSwipeMove = true;
		if (swipeDistanceX > 0) {
			// Swipe right
			ninja.moveRight();
		} else {
			// Swipe left
			ninja.moveLeft();
		}
	}
};
game.update = function () {
	// Spawn enemies
	enemySpawnTimer++;
	difficultyTimer++;
	var spawnRate = Math.max(180 - Math.floor(difficultyTimer / 300), 60);
	if (enemySpawnTimer >= spawnRate) {
		spawnEnemy();
		enemySpawnTimer = 0;
	}
	// Check projectile vs enemy collisions
	for (var p = projectiles.length - 1; p >= 0; p--) {
		var projectile = projectiles[p];
		// Remove old projectiles
		if (projectile.lifetime > 180 || projectile.x < -50 || projectile.x > 2098 || projectile.y < -50 || projectile.y > 2782) {
			projectile.destroy();
			projectiles.splice(p, 1);
			continue;
		}
		// Check enemy hits
		for (var e = enemies.length - 1; e >= 0; e--) {
			var enemy = enemies[e];
			if (projectile.intersects(enemy)) {
				// Hit enemy
				LK.setScore(LK.getScore() + 10);
				scoreTxt.setText(LK.getScore());
				LK.getSound('enemyHit').play();
				LK.effects.flashObject(enemy, 0xffffff, 200);
				enemy.destroy();
				enemies.splice(e, 1);
				projectile.destroy();
				projectiles.splice(p, 1);
				break;
			}
			// Check jar hits
			for (var j = jars.length - 1; j >= 0; j--) {
				var jar = jars[j];
				if (!jar.broken && projectile.intersects(jar)) {
					jar.breakJar();
					jars.splice(j, 1);
					projectile.destroy();
					projectiles.splice(p, 1);
					break;
				}
			}
		}
	}
	// Update jar positions to follow their platforms
	for (var j = 0; j < jars.length; j++) {
		var jar = jars[j];
		if (!jar.broken && jar.platform) {
			jar.x = jar.platform.x;
		}
	}
	// Check ninja vs enemy collisions
	for (var e = enemies.length - 1; e >= 0; e--) {
		var enemy = enemies[e];
		if (ninja.intersects(enemy)) {
			ninja.health--;
			ninjaCurrentHealth = ninja.health;
			healthTxt.setText('Health: ' + ninjaCurrentHealth);
			LK.effects.flashObject(ninja, 0xff0000, 500);
			enemy.destroy();
			enemies.splice(e, 1);
			if (ninja.health <= 0) {
				LK.showGameOver();
			}
		}
	}
	// Update and check fire projectiles
	for (var f = fireProjectiles.length - 1; f >= 0; f--) {
		var fireProjectile = fireProjectiles[f];
		// Remove fire projectiles that are off screen or too old
		if (fireProjectile.lifetime > 300 || fireProjectile.y > 2800 || fireProjectile.x < -50 || fireProjectile.x > 2098) {
			fireProjectile.destroy();
			fireProjectiles.splice(f, 1);
			continue;
		}
		// Check fire projectile vs ninja collision
		if (fireProjectile.intersects(ninja)) {
			ninja.health--;
			ninjaCurrentHealth = ninja.health;
			healthTxt.setText('Health: ' + ninjaCurrentHealth);
			LK.effects.flashObject(ninja, 0xff4500, 500);
			fireProjectile.destroy();
			fireProjectiles.splice(f, 1);
			if (ninja.health <= 0) {
				LK.showGameOver();
			}
		}
	}
	// Keep ninja on screen horizontally
	if (ninja.x < 40) ninja.x = 40;
	if (ninja.x > 2008) ninja.x = 2008;
};
// Play background music
LK.playMusic('ninjai'); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGraphics = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedX = (Math.random() - 0.5) * 3;
	self.speedY = (Math.random() - 0.5) * 3;
	self.health = 1;
	self.update = function () {
		self.x += self.speedX;
		self.y += self.speedY;
		// Bounce off screen edges
		if (self.x < 30 || self.x > 2018) {
			self.speedX *= -1;
		}
		if (self.y < 30 || self.y > 2702) {
			self.speedY *= -1;
		}
	};
	return self;
});
var FireProjectile = Container.expand(function () {
	var self = Container.call(this);
	var fireGraphics = self.attachAsset('fireProjectile', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedX = 0;
	self.speedY = 8; // Downward speed
	self.lifetime = 0;
	self.gravity = 0.3;
	self.update = function () {
		self.x += self.speedX;
		self.y += self.speedY;
		self.speedY += self.gravity; // Fire falls with gravity
		self.lifetime++;
		// Add fire effect with slight flickering
		fireGraphics.alpha = 0.8 + Math.sin(self.lifetime * 0.3) * 0.2;
	};
	return self;
});
var Jar = Container.expand(function () {
	var self = Container.call(this);
	var jarGraphics = self.attachAsset('jar', {
		anchorX: 0.5,
		anchorY: 1.0
	});
	self.broken = false;
	self.jumpTimer = Math.random() * 120 + 60; // Random jump intervals
	self.moveTimer = Math.random() * 180 + 120; // Random movement intervals
	self.moveDirection = Math.random() < 0.5 ? -1 : 1; // Random initial direction
	self.isJumping = false;
	self.originalY = 0; // Store original platform position
	self.update = function () {
		if (!self.broken && self.platform) {
			// Update timers
			self.jumpTimer--;
			self.moveTimer--;
			// Jump behavior
			if (self.jumpTimer <= 0 && !self.isJumping) {
				self.jump();
				self.jumpTimer = Math.random() * 180 + 120; // Reset jump timer
			}
			// Movement behavior
			if (self.moveTimer <= 0) {
				self.moveDirection *= -1; // Change direction
				self.moveTimer = Math.random() * 240 + 180; // Reset move timer
			}
			// Horizontal movement within platform bounds
			var moveAmount = Math.sin(LK.ticks * 0.05) * 2 * self.moveDirection;
			var newX = self.platform.x + moveAmount;
			// Keep jar on platform
			var platformWidth = self.platform.width || 200;
			if (newX >= self.platform.x - platformWidth / 3 && newX <= self.platform.x + platformWidth / 3) {
				self.x = newX;
			} else {
				self.x = self.platform.x;
			}
			// Keep jar positioned on platform
			if (!self.isJumping) {
				self.y = self.platform.y - self.platform.height / 2;
				self.originalY = self.y;
			}
			// Fire attack if this jar can attack
			if (self.canAttack) {
				self.attackTimer--;
				if (self.attackTimer <= 0) {
					self.fireAttack();
					self.attackTimer = Math.random() * 180 + 120; // Random fire intervals
				}
			}
		}
	};
	self.jump = function () {
		if (!self.isJumping && !self.broken) {
			self.isJumping = true;
			var jumpHeight = 80 + Math.random() * 40; // Random jump height
			// Play jar sound when jumping
			LK.getSound('jar').play();
			// Jump up
			tween(self, {
				y: self.originalY - jumpHeight
			}, {
				duration: 400,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					// Fall back down
					tween(self, {
						y: self.originalY
					}, {
						duration: 400,
						easing: tween.easeIn,
						onFinish: function onFinish() {
							self.isJumping = false;
						}
					});
				}
			});
		}
	};
	self.breakJar = function () {
		if (!self.broken) {
			self.broken = true;
			LK.getSound('jarBreak').play();
			LK.setScore(LK.getScore() + 5);
			scoreTxt.setText(LK.getScore());
			// Track jars broken for level progression
			jarsBrokenThisLevel++;
			// Check if all jars are broken (count remaining unbroken jars)
			var remainingJars = 0;
			for (var k = 0; k < jars.length; k++) {
				if (!jars[k].broken) {
					remainingJars++;
				}
			}
			// Level up only when all jars are broken (only 1 remaining = this jar that just broke)
			if (remainingJars <= 1) {
				// Level up!
				currentLevel++;
				jarsBrokenThisLevel = 0;
				levelTxt.setText('Level ' + currentLevel);
				// Flash screen gold for level up
				LK.effects.flashScreen(0xFFD700, 800);
				// Hide ninja temporarily for level transition
				ninja.alpha = 0;
				// Generate new platforms and jars for next level
				LK.setTimeout(function () {
					// Clear existing platforms and jars
					for (var i = platforms.length - 1; i >= 0; i--) {
						platforms[i].destroy();
					}
					for (var j = jars.length - 1; j >= 0; j--) {
						if (!jars[j].broken) {
							jars[j].destroy();
						}
					}
					platforms = [];
					jars = [];
					// Reset ninja position to starting position
					ninja.x = 1024;
					ninja.y = 2500;
					ninja.velocityY = 0;
					ninja.onGround = false;
					// Make platforms and ninja appear together
					generatePlatforms();
					// Fade in ninja with platforms
					tween(ninja, {
						alpha: 1
					}, {
						duration: 800,
						easing: tween.easeInOut
					});
				}, 500);
			}
			// Create multiple jar fragments for breaking effect
			var fragments = [];
			for (var i = 0; i < 4; i++) {
				var fragment = LK.getAsset('jar', {
					anchorX: 0.5,
					anchorY: 0.5,
					scaleX: 0.3,
					scaleY: 0.3,
					tint: 0x8b4513
				});
				fragment.x = self.x + (Math.random() - 0.5) * 20;
				fragment.y = self.y + (Math.random() - 0.5) * 20;
				fragments.push(fragment);
				game.addChild(fragment);
				// Animate each fragment
				var fragmentSpeedX = (Math.random() - 0.5) * 200;
				var fragmentSpeedY = -Math.random() * 150 - 50;
				var fragmentRotation = (Math.random() - 0.5) * 6;
				tween(fragment, {
					x: fragment.x + fragmentSpeedX,
					y: fragment.y + fragmentSpeedY + 100,
					rotation: fragmentRotation,
					alpha: 0,
					scaleX: 0.1,
					scaleY: 0.1
				}, {
					duration: 600,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						fragment.destroy();
					}
				});
			}
			// Main jar breaking animation - shake and fade
			tween(jarGraphics, {
				rotation: 0.3
			}, {
				duration: 50,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					tween(jarGraphics, {
						rotation: -0.3,
						scaleX: 1.2,
						scaleY: 0.8
					}, {
						duration: 50,
						easing: tween.easeInOut,
						onFinish: function onFinish() {
							tween(jarGraphics, {
								scaleX: 0.1,
								scaleY: 0.1,
								alpha: 0,
								rotation: 0
							}, {
								duration: 200,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									self.destroy();
								}
							});
						}
					});
				}
			});
		}
	};
	self.fireAttack = function () {
		if (!self.broken && self.canAttack) {
			var fireProjectile = new FireProjectile();
			fireProjectile.x = self.x;
			fireProjectile.y = self.y + 20;
			fireProjectile.speedX = (Math.random() - 0.5) * 2; // Slight horizontal variation
			fireProjectiles.push(fireProjectile);
			game.addChild(fireProjectile);
			LK.getSound('jarFire').play();
		}
	};
	return self;
});
var Ninja = Container.expand(function () {
	var self = Container.call(this);
	var ninjaGraphics = self.attachAsset('ninja', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.velocityY = 0;
	self.onGround = false;
	self.gravity = 0.8;
	self.jumpPower = -18;
	self.health = 5;
	self.attackCooldown = 0;
	self.update = function () {
		// Apply gravity
		if (!self.onGround) {
			self.velocityY += self.gravity;
		}
		self.y += self.velocityY;
		// Reset ground state
		self.onGround = false;
		// Check platform collisions
		for (var i = 0; i < platforms.length; i++) {
			var platform = platforms[i];
			if (self.intersects(platform) && self.velocityY > 0) {
				var platformTop = platform.y - platform.height / 2;
				var ninjaBottom = self.y + self.height / 2;
				if (ninjaBottom > platformTop - 20) {
					self.y = platformTop - self.height / 2;
					self.velocityY = 0;
					self.onGround = true;
					// Move ninja with platform
					self.x += platform.moveSpeed * platform.moveDirection;
					break;
				}
			}
		}
		// Fall off screen check
		if (self.y > 2800) {
			LK.showGameOver();
		}
		// Reduce attack cooldown
		if (self.attackCooldown > 0) {
			self.attackCooldown--;
		}
	};
	self.jump = function () {
		if (self.onGround) {
			self.velocityY = self.jumpPower;
			self.onGround = false;
			LK.getSound('jump').play();
		}
	};
	self.attack = function (targetX, targetY) {
		if (self.attackCooldown <= 0) {
			var projectile = new Projectile();
			projectile.x = self.x;
			projectile.y = self.y;
			var dx = targetX - self.x;
			var dy = targetY - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			projectile.speedX = dx / distance * 24;
			projectile.speedY = dy / distance * 24;
			projectiles.push(projectile);
			game.addChild(projectile);
			self.attackCooldown = 20;
			LK.getSound('attack').play();
		}
	};
	self.moveLeft = function () {
		self.x -= ninjaSpeed;
		if (self.x < 50) self.x = 50;
		// Flip ninja to face left
		ninjaGraphics.scaleX = -1;
	};
	self.moveRight = function () {
		self.x += ninjaSpeed;
		if (self.x > 1998) self.x = 1998;
		// Flip ninja to face right
		ninjaGraphics.scaleX = 1;
	};
	return self;
});
var Platform = Container.expand(function () {
	var self = Container.call(this);
	var platformGraphics = self.attachAsset('platform', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.moveSpeed = Math.random() * 2 + 1; // Random speed between 1-3
	self.moveDirection = Math.random() < 0.5 ? -1 : 1; // Random initial direction
	self.leftBound = 100;
	self.rightBound = 1948;
	self.update = function () {
		// Move platform horizontally
		self.x += self.moveSpeed * self.moveDirection;
		// Bounce off boundaries
		if (self.x <= self.leftBound || self.x >= self.rightBound) {
			self.moveDirection *= -1;
		}
	};
	return self;
});
var Projectile = Container.expand(function () {
	var self = Container.call(this);
	var projectileGraphics = self.attachAsset('projectile', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedX = 0;
	self.speedY = 0;
	self.lifetime = 0;
	self.update = function () {
		self.x += self.speedX;
		self.y += self.speedY;
		self.lifetime++;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x87ceeb
});
/**** 
* Game Code
****/ 
// Create background
var background = LK.getAsset('background', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	scaleX: 1.0,
	scaleY: 1.0
});
game.addChild(background);
var ninja = new Ninja();
var platforms = [];
var enemies = [];
var projectiles = [];
var jars = [];
var fireProjectiles = [];
var enemySpawnTimer = 0;
var difficultyTimer = 0;
var currentLevel = 1;
var jarsPerLevel = 5;
var jarsBrokenThisLevel = 0;
var touchStartX = 0;
var touchStartY = 0;
var isSwipeMove = false;
var ninjaSpeed = 8;
var ninjaMaxHealth = 5;
var ninjaCurrentHealth = 5;
// Create score display
var scoreTxt = new Text2('0', {
	size: 80,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create level display
var levelTxt = new Text2('Level 1', {
	size: 60,
	fill: 0xFFD700
});
levelTxt.anchor.set(0, 0);
levelTxt.x = 120;
levelTxt.y = 20;
LK.gui.topLeft.addChild(levelTxt);
// Create health display
var healthTxt = new Text2('Health: 5', {
	size: 60,
	fill: 0xff0000
});
healthTxt.anchor.set(1, 0);
healthTxt.x = -20;
healthTxt.y = 20;
LK.gui.topRight.addChild(healthTxt);
// Generate random platforms
function generatePlatforms() {
	platforms = [];
	// Ground platform
	var groundPlatform = new Platform();
	groundPlatform.x = 1024;
	groundPlatform.y = 2600;
	groundPlatform.width = 400;
	// Start platforms invisible for coordinated appearance
	groundPlatform.alpha = 0;
	platforms.push(groundPlatform);
	game.addChild(groundPlatform);
	// Animate ground platform appearance
	tween(groundPlatform, {
		alpha: 1
	}, {
		duration: 600,
		easing: tween.easeInOut
	});
	// Random platforms - increase count with level
	var platformCount = Math.min(8 + currentLevel, 15);
	for (var i = 0; i < platformCount; i++) {
		var platform = new Platform();
		platform.x = Math.random() * 1600 + 200;
		platform.y = 2400 - i * 250 - Math.random() * 100;
		// Make platforms smaller at higher levels for more challenge
		platform.width = Math.max(150 + Math.random() * 100 - currentLevel * 5, 80);
		// Start platforms invisible for coordinated appearance
		platform.alpha = 0;
		platforms.push(platform);
		game.addChild(platform);
		// Animate platform appearance with staggered timing
		tween(platform, {
			alpha: 1
		}, {
			duration: 600,
			delay: i * 100,
			easing: tween.easeInOut
		});
		// Ensure enough jars are available for level completion
		var jarChance = Math.min(0.8, 0.6 + currentLevel * 0.05);
		if (Math.random() < jarChance) {
			var jar = new Jar();
			jar.x = platform.x;
			jar.y = platform.y - platform.height / 2;
			jar.platform = platform; // Assign platform reference to jar
			// Start jars invisible for coordinated appearance
			jar.alpha = 0;
			// Randomly make one jar per few platforms a fire attacker
			jar.canAttack = Math.random() < 0.3; // 30% chance
			if (jar.canAttack) {
				jar.attackTimer = Math.random() * 180 + 60;
			}
			jars.push(jar);
			game.addChild(jar);
			// Animate jar appearance slightly after platform
			tween(jar, {
				alpha: 1
			}, {
				duration: 400,
				delay: i * 100 + 200,
				easing: tween.easeInOut
			});
		}
	}
}
function spawnEnemy() {
	var enemy = new Enemy();
	// Spawn from random edge
	var side = Math.floor(Math.random() * 4);
	switch (side) {
		case 0:
			// Top
			enemy.x = Math.random() * 2048;
			enemy.y = -30;
			break;
		case 1:
			// Right
			enemy.x = 2078;
			enemy.y = Math.random() * 2732;
			break;
		case 2:
			// Bottom
			enemy.x = Math.random() * 2048;
			enemy.y = 2762;
			break;
		case 3:
			// Left
			enemy.x = -30;
			enemy.y = Math.random() * 2732;
			break;
	}
	enemies.push(enemy);
	game.addChild(enemy);
}
// Initialize game elements
generatePlatforms();
ninja.x = 1024;
ninja.y = 2500;
game.addChild(ninja);
// Touch controls
game.down = function (x, y, obj) {
	touchStartX = x;
	touchStartY = y;
	isSwipeMove = false;
};
game.up = function (x, y, obj) {
	if (!isSwipeMove) {
		// If touching near ninja, jump
		var dx = x - ninja.x;
		var dy = y - ninja.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance < 150) {
			ninja.jump();
		} else {
			// Attack in direction of touch
			ninja.attack(x, y);
		}
	}
};
game.move = function (x, y, obj) {
	var swipeDistanceX = x - touchStartX;
	var swipeDistanceY = Math.abs(y - touchStartY);
	// Detect horizontal swipe (minimum 50px horizontal, less than 100px vertical)
	if (Math.abs(swipeDistanceX) > 50 && swipeDistanceY < 100) {
		isSwipeMove = true;
		if (swipeDistanceX > 0) {
			// Swipe right
			ninja.moveRight();
		} else {
			// Swipe left
			ninja.moveLeft();
		}
	}
};
game.update = function () {
	// Spawn enemies
	enemySpawnTimer++;
	difficultyTimer++;
	var spawnRate = Math.max(180 - Math.floor(difficultyTimer / 300), 60);
	if (enemySpawnTimer >= spawnRate) {
		spawnEnemy();
		enemySpawnTimer = 0;
	}
	// Check projectile vs enemy collisions
	for (var p = projectiles.length - 1; p >= 0; p--) {
		var projectile = projectiles[p];
		// Remove old projectiles
		if (projectile.lifetime > 180 || projectile.x < -50 || projectile.x > 2098 || projectile.y < -50 || projectile.y > 2782) {
			projectile.destroy();
			projectiles.splice(p, 1);
			continue;
		}
		// Check enemy hits
		for (var e = enemies.length - 1; e >= 0; e--) {
			var enemy = enemies[e];
			if (projectile.intersects(enemy)) {
				// Hit enemy
				LK.setScore(LK.getScore() + 10);
				scoreTxt.setText(LK.getScore());
				LK.getSound('enemyHit').play();
				LK.effects.flashObject(enemy, 0xffffff, 200);
				enemy.destroy();
				enemies.splice(e, 1);
				projectile.destroy();
				projectiles.splice(p, 1);
				break;
			}
			// Check jar hits
			for (var j = jars.length - 1; j >= 0; j--) {
				var jar = jars[j];
				if (!jar.broken && projectile.intersects(jar)) {
					jar.breakJar();
					jars.splice(j, 1);
					projectile.destroy();
					projectiles.splice(p, 1);
					break;
				}
			}
		}
	}
	// Update jar positions to follow their platforms
	for (var j = 0; j < jars.length; j++) {
		var jar = jars[j];
		if (!jar.broken && jar.platform) {
			jar.x = jar.platform.x;
		}
	}
	// Check ninja vs enemy collisions
	for (var e = enemies.length - 1; e >= 0; e--) {
		var enemy = enemies[e];
		if (ninja.intersects(enemy)) {
			ninja.health--;
			ninjaCurrentHealth = ninja.health;
			healthTxt.setText('Health: ' + ninjaCurrentHealth);
			LK.effects.flashObject(ninja, 0xff0000, 500);
			enemy.destroy();
			enemies.splice(e, 1);
			if (ninja.health <= 0) {
				LK.showGameOver();
			}
		}
	}
	// Update and check fire projectiles
	for (var f = fireProjectiles.length - 1; f >= 0; f--) {
		var fireProjectile = fireProjectiles[f];
		// Remove fire projectiles that are off screen or too old
		if (fireProjectile.lifetime > 300 || fireProjectile.y > 2800 || fireProjectile.x < -50 || fireProjectile.x > 2098) {
			fireProjectile.destroy();
			fireProjectiles.splice(f, 1);
			continue;
		}
		// Check fire projectile vs ninja collision
		if (fireProjectile.intersects(ninja)) {
			ninja.health--;
			ninjaCurrentHealth = ninja.health;
			healthTxt.setText('Health: ' + ninjaCurrentHealth);
			LK.effects.flashObject(ninja, 0xff4500, 500);
			fireProjectile.destroy();
			fireProjectiles.splice(f, 1);
			if (ninja.health <= 0) {
				LK.showGameOver();
			}
		}
	}
	// Keep ninja on screen horizontally
	if (ninja.x < 40) ninja.x = 40;
	if (ninja.x > 2008) ninja.x = 2008;
};
// Play background music
LK.playMusic('ninjai');
 2d anime chibi style ninja hitam jepang. In-Game asset. 2d. High contrast. No shadows
 2d anime image pemandangan gunung fuji jepang zaman kuno di kejauhan. wilayah hutan dan bukit bebatuan dari dekat. langit biru cerah. In-Game asset. 2d. High contrast. No shadows
 2d anime chibi evil hitam jepang. In-Game asset. 2d. High contrast. No shadows
 2d anime image tanah dan bebatuan. In-Game asset. 2d. High contrast. No shadows