/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var BrokenPlatform = Container.expand(function () {
	var self = Container.call(this);
	var platformGraphics = self.attachAsset('brokenPlatform', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.isBroken = false;
	self.breakTimer = 0;
	self.fallSpeed = 8;
	self["break"] = function () {
		if (!self.isBroken) {
			self.isBroken = true;
			// Flash red to indicate breaking
			LK.effects.flashObject(self, 0xff0000, 300);
		}
	};
	self.update = function () {
		if (self.isBroken) {
			self.breakTimer++;
			// Start falling after a short delay
			if (self.breakTimer > 20) {
				self.y += self.fallSpeed;
			}
		}
	};
	return self;
});
//Library for using the camera (the background becomes the user's camera video feed) and the microphone. It can access face coordinates for interactive play, as well detect microphone volume / voice interactions
// var facekit = LK.import('@upit/facekit.v1'); // Not needed for this game
var Hero = Container.expand(function () {
	var self = Container.call(this);
	var heroGraphics = self.attachAsset('hero', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedY = 0;
	self.gravity = 1;
	self.isJumping = false; // Track if the hero is currently jumping
	self.heroGraphics = heroGraphics; // Reference to the graphics for animation
	self.jump = function () {
		self.speedY = -30; // Jump strength
		LK.getSound('jump').play();
		self.isJumping = true; // Set jumping state to true
	};
	self.update = function () {
		self.speedY += self.gravity;
		self.y += self.speedY;
		// Check if the hero has landed on a platform (speedY becomes 0 after collision)
		if (self.speedY === 0 && self.isJumping) {
			self.isJumping = false; // Hero is no longer jumping
		}
		// If hero falls off the bottom, trigger game over.
		if (self.y > 2732) {
			LK.getSound('hit').play();
			LK.showGameOver();
			return; // Stop updating if game over
		}
		// Keep hero within horizontal bounds
		if (self.x < self.width / 2) {
			self.x = self.width / 2;
		} else if (self.x > 2048 - self.width / 2) {
			self.x = 2048 - self.width / 2;
		}
		// Change hero graphic based on jumping state
		if (self.isJumping) {
			self.heroGraphics.texture = LK.getAsset('hero2', {}).texture; // Use hero2 texture
		} else {
			self.heroGraphics.texture = LK.getAsset('hero', {}).texture; // Use hero texture
		}
	};
	return self;
});
var Obstacle = Container.expand(function () {
	var self = Container.call(this);
	var obstacleGraphics = self.attachAsset('obstacle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedY = 5; // Obstacle falling speed
	self.update = function () {
		self.y += self.speedY;
	};
	return self;
});
var Platform = Container.expand(function () {
	var self = Container.call(this);
	var platformGraphics = self.attachAsset('platform', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 // Init game with black background
});
/**** 
* Game Code
****/ 
// Initialize assets used in this game. Scale them according to what is needed for the game.
// Initialize music
//We have access to the following plugins. (Note that the variable names used are mandetory for each plugin)
//Only include the plugins you need to create the game.
//Minimalistic tween library which should be used for animations over time, including tinting / colouring an object, scaling, rotating, or changing any game object property.
//Storage library which should be used for persistent game data
game.setBackgroundColor(0x87ceeb); // Change background color to sky blue
var hero;
var platforms = [];
var obstacles = [];
var scoreTxt;
var score = 0;
var platformSpawnTimer = 0;
var obstacleSpawnTimer = 0;
var heroLastY = 0; // To track vertical progress for scoring
var highestY = 0; // Initialize the highest point reached globally
var highestLevel = 0; // Track the highest level reached for scoring
//Declare method for handling move events on game.
//Favor using a single event handler in the game scope, rather than a per class event handler
//Mouse or touch move on game object. LK returns complex event objects. Please be aware of this.
game.move = function (x, y, obj) {
	if (hero) {
		// Move hero horizontally based on touch/mouse x position
		hero.x = x;
	}
};
//Mouse or touch down on game object
game.down = function (x, y, obj) {
	if (hero) {
		hero.jump();
	}
};
// Initialize game elements
function startGame() {
	// Clear existing elements
	if (hero) hero.destroy();
	for (var i = platforms.length - 1; i >= 0; i--) platforms[i].destroy();
	for (var i = obstacles.length - 1; i >= 0; i--) obstacles[i].destroy();
	platforms = [];
	obstacles = [];
	platformSpawnTimer = 0;
	obstacleSpawnTimer = 0;
	hero = game.addChild(new Hero());
	// Add initial platform
	var initialPlatform = new Platform();
	initialPlatform.x = 2048 / 2; // Keep centered horizontally for the first platform
	initialPlatform.y = 2732 - initialPlatform.height / 2 - hero.height / 2; // Position just above the bottom
	platforms.push(initialPlatform);
	game.addChild(initialPlatform);
	// Position hero at the top of the first platform
	hero.x = initialPlatform.x;
	hero.y = initialPlatform.y - initialPlatform.height / 2 - hero.height / 2;
	heroLastY = hero.y;
	highestY = hero.y; // Initialize the highest point reached
	highestLevel = 0; // Reset level tracking for new game
	score = 0; // Reset score for new game
	LK.setScore(0); // Ensure LK score is also reset for equal progression
	scoreTxt = new Text2('0', {
		size: 150,
		fill: 0xFFFFFF
	});
	LK.gui.top.addChild(scoreTxt);
	// Create several starting platforms at different positions
	for (var i = 0; i < 5; i++) {
		// Create 5 additional platforms
		var platform = new Platform();
		platform.x = Math.random() * (2048 - platform.width) + platform.width / 2; // Random X position
		// Position platforms stacked above the initial one
		platform.y = initialPlatform.y - (i + 1) * 300; // Adjust vertical spacing between platforms
		platforms.push(platform);
		game.addChild(platform);
	}
	LK.playMusic('gameMusic');
}
startGame(); // Call startGame to initialize the game
// Ask LK engine to update game every game tick
game.update = function () {
	// Update hero
	if (hero) hero.update();
	// Platforms and obstacles move at their own fixed speeds
	// Update platforms and check for collision
	for (var i = platforms.length - 1; i >= 0; i--) {
		var platform = platforms[i];
		// Update platform (for broken platforms to handle falling)
		if (platform.update) {
			platform.update();
		}
		// Platforms now move only downwards at their own speed, not affected by scrollSpeed
		platform.y += 3; // Fixed downward speed for platforms
		// Check for hero landing on platform
		if (hero && hero.speedY > 0 && hero.intersects(platform) && hero.y < platform.y - platform.height / 2 + hero.speedY) {
			hero.y = platform.y - platform.height / 2 - hero.height / 2;
			hero.speedY = 0;
			// Break the platform if it's a broken platform
			if (platform["break"]) {
				platform["break"]();
			}
		}
		// Remove platforms that are off-screen below
		if (platform.y > 2732 + platform.height) {
			platform.destroy();
			platforms.splice(i, 1);
		}
	}
	// Update obstacles and check for collision
	for (var i = obstacles.length - 1; i >= 0; i--) {
		var obstacle = obstacles[i];
		obstacle.y += obstacle.speedY; // Move obstacle down at its own speed
		// Check for collision with hero
		if (hero && hero.intersects(obstacle)) {
			// Hero hit by obstacle - Game Over
			LK.getSound('hit').play();
			LK.effects.flashScreen(0xff0000, 500);
			LK.showGameOver();
			// No need to destroy elements here, LK.showGameOver will reset the game
			return; // Stop updating if game over
		}
		// Update score based on highest level reached
		if (hero && hero.y < highestY) {
			highestY = hero.y;
			// Calculate current level based on height with better distribution
			// Use 250 pixels per level for more even scoring progression
			var currentLevel = Math.floor((2732 - highestY) / 250);
			// Award 10 points for each new level reached
			if (currentLevel > highestLevel) {
				highestLevel = currentLevel;
				score = highestLevel * 10; // Score equals 10 times the highest level reached
				LK.setScore(score); // Update LK score system
				scoreTxt.setText(score);
			}
		}
		// Remove obstacles that are off-screen below
		if (obstacle.y > 2732 + obstacle.height) {
			obstacle.destroy();
			obstacles.splice(i, 1);
		}
	}
	// Spawn platforms
	platformSpawnTimer++;
	if (platformSpawnTimer >= 60) {
		// Spawn a platform roughly every second
		var newPlatform;
		// 30% chance to spawn a broken platform
		if (Math.random() < 0.3) {
			newPlatform = new BrokenPlatform();
		} else {
			newPlatform = new Platform();
		}
		// Position platform off-screen at the top
		newPlatform.x = Math.random() * (2048 - newPlatform.width) + newPlatform.width / 2; // Random X position within screen width
		// Find the highest existing platform
		var highestPlatformY = Infinity;
		for (var i = 0; i < platforms.length; i++) {
			if (platforms[i].y < highestPlatformY) {
				highestPlatformY = platforms[i].y;
			}
		}
		// Position the new platform just above the highest existing one
		newPlatform.y = highestPlatformY - 300; // Adjust vertical spacing as needed
		platforms.push(newPlatform);
		game.addChild(newPlatform);
		platformSpawnTimer = 0;
	}
	// Spawn obstacles
	obstacleSpawnTimer++;
	if (obstacleSpawnTimer >= 90) {
		// Spawn an obstacle roughly every 1.5 seconds
		var newObstacle = new Obstacle();
		// Position obstacle off-screen at the top
		newObstacle.x = Math.random() * (2048 - newObstacle.width) + newObstacle.width / 2;
		newObstacle.y = -newObstacle.height / 2;
		obstacles.push(newObstacle);
		game.addChild(newObstacle);
		obstacleSpawnTimer = 0;
	}
	// Prevent hero from falling off the top (if somehow possible with gravity)
	if (hero && hero.y < -hero.height) {
		// This shouldn't happen with normal gameplay, but as a safeguard:
		// Treat as game over if the hero goes too far off the top
		LK.getSound('hit').play();
		LK.showGameOver();
		return;
	}
	// Check if hero has fallen off the bottom of the screen
	if (hero && hero.y > 2732) {
		LK.getSound('hit').play();
		LK.showGameOver();
		return; // Stop updating if game over
	}
}; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var BrokenPlatform = Container.expand(function () {
	var self = Container.call(this);
	var platformGraphics = self.attachAsset('brokenPlatform', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.isBroken = false;
	self.breakTimer = 0;
	self.fallSpeed = 8;
	self["break"] = function () {
		if (!self.isBroken) {
			self.isBroken = true;
			// Flash red to indicate breaking
			LK.effects.flashObject(self, 0xff0000, 300);
		}
	};
	self.update = function () {
		if (self.isBroken) {
			self.breakTimer++;
			// Start falling after a short delay
			if (self.breakTimer > 20) {
				self.y += self.fallSpeed;
			}
		}
	};
	return self;
});
//Library for using the camera (the background becomes the user's camera video feed) and the microphone. It can access face coordinates for interactive play, as well detect microphone volume / voice interactions
// var facekit = LK.import('@upit/facekit.v1'); // Not needed for this game
var Hero = Container.expand(function () {
	var self = Container.call(this);
	var heroGraphics = self.attachAsset('hero', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedY = 0;
	self.gravity = 1;
	self.isJumping = false; // Track if the hero is currently jumping
	self.heroGraphics = heroGraphics; // Reference to the graphics for animation
	self.jump = function () {
		self.speedY = -30; // Jump strength
		LK.getSound('jump').play();
		self.isJumping = true; // Set jumping state to true
	};
	self.update = function () {
		self.speedY += self.gravity;
		self.y += self.speedY;
		// Check if the hero has landed on a platform (speedY becomes 0 after collision)
		if (self.speedY === 0 && self.isJumping) {
			self.isJumping = false; // Hero is no longer jumping
		}
		// If hero falls off the bottom, trigger game over.
		if (self.y > 2732) {
			LK.getSound('hit').play();
			LK.showGameOver();
			return; // Stop updating if game over
		}
		// Keep hero within horizontal bounds
		if (self.x < self.width / 2) {
			self.x = self.width / 2;
		} else if (self.x > 2048 - self.width / 2) {
			self.x = 2048 - self.width / 2;
		}
		// Change hero graphic based on jumping state
		if (self.isJumping) {
			self.heroGraphics.texture = LK.getAsset('hero2', {}).texture; // Use hero2 texture
		} else {
			self.heroGraphics.texture = LK.getAsset('hero', {}).texture; // Use hero texture
		}
	};
	return self;
});
var Obstacle = Container.expand(function () {
	var self = Container.call(this);
	var obstacleGraphics = self.attachAsset('obstacle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedY = 5; // Obstacle falling speed
	self.update = function () {
		self.y += self.speedY;
	};
	return self;
});
var Platform = Container.expand(function () {
	var self = Container.call(this);
	var platformGraphics = self.attachAsset('platform', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 // Init game with black background
});
/**** 
* Game Code
****/ 
// Initialize assets used in this game. Scale them according to what is needed for the game.
// Initialize music
//We have access to the following plugins. (Note that the variable names used are mandetory for each plugin)
//Only include the plugins you need to create the game.
//Minimalistic tween library which should be used for animations over time, including tinting / colouring an object, scaling, rotating, or changing any game object property.
//Storage library which should be used for persistent game data
game.setBackgroundColor(0x87ceeb); // Change background color to sky blue
var hero;
var platforms = [];
var obstacles = [];
var scoreTxt;
var score = 0;
var platformSpawnTimer = 0;
var obstacleSpawnTimer = 0;
var heroLastY = 0; // To track vertical progress for scoring
var highestY = 0; // Initialize the highest point reached globally
var highestLevel = 0; // Track the highest level reached for scoring
//Declare method for handling move events on game.
//Favor using a single event handler in the game scope, rather than a per class event handler
//Mouse or touch move on game object. LK returns complex event objects. Please be aware of this.
game.move = function (x, y, obj) {
	if (hero) {
		// Move hero horizontally based on touch/mouse x position
		hero.x = x;
	}
};
//Mouse or touch down on game object
game.down = function (x, y, obj) {
	if (hero) {
		hero.jump();
	}
};
// Initialize game elements
function startGame() {
	// Clear existing elements
	if (hero) hero.destroy();
	for (var i = platforms.length - 1; i >= 0; i--) platforms[i].destroy();
	for (var i = obstacles.length - 1; i >= 0; i--) obstacles[i].destroy();
	platforms = [];
	obstacles = [];
	platformSpawnTimer = 0;
	obstacleSpawnTimer = 0;
	hero = game.addChild(new Hero());
	// Add initial platform
	var initialPlatform = new Platform();
	initialPlatform.x = 2048 / 2; // Keep centered horizontally for the first platform
	initialPlatform.y = 2732 - initialPlatform.height / 2 - hero.height / 2; // Position just above the bottom
	platforms.push(initialPlatform);
	game.addChild(initialPlatform);
	// Position hero at the top of the first platform
	hero.x = initialPlatform.x;
	hero.y = initialPlatform.y - initialPlatform.height / 2 - hero.height / 2;
	heroLastY = hero.y;
	highestY = hero.y; // Initialize the highest point reached
	highestLevel = 0; // Reset level tracking for new game
	score = 0; // Reset score for new game
	LK.setScore(0); // Ensure LK score is also reset for equal progression
	scoreTxt = new Text2('0', {
		size: 150,
		fill: 0xFFFFFF
	});
	LK.gui.top.addChild(scoreTxt);
	// Create several starting platforms at different positions
	for (var i = 0; i < 5; i++) {
		// Create 5 additional platforms
		var platform = new Platform();
		platform.x = Math.random() * (2048 - platform.width) + platform.width / 2; // Random X position
		// Position platforms stacked above the initial one
		platform.y = initialPlatform.y - (i + 1) * 300; // Adjust vertical spacing between platforms
		platforms.push(platform);
		game.addChild(platform);
	}
	LK.playMusic('gameMusic');
}
startGame(); // Call startGame to initialize the game
// Ask LK engine to update game every game tick
game.update = function () {
	// Update hero
	if (hero) hero.update();
	// Platforms and obstacles move at their own fixed speeds
	// Update platforms and check for collision
	for (var i = platforms.length - 1; i >= 0; i--) {
		var platform = platforms[i];
		// Update platform (for broken platforms to handle falling)
		if (platform.update) {
			platform.update();
		}
		// Platforms now move only downwards at their own speed, not affected by scrollSpeed
		platform.y += 3; // Fixed downward speed for platforms
		// Check for hero landing on platform
		if (hero && hero.speedY > 0 && hero.intersects(platform) && hero.y < platform.y - platform.height / 2 + hero.speedY) {
			hero.y = platform.y - platform.height / 2 - hero.height / 2;
			hero.speedY = 0;
			// Break the platform if it's a broken platform
			if (platform["break"]) {
				platform["break"]();
			}
		}
		// Remove platforms that are off-screen below
		if (platform.y > 2732 + platform.height) {
			platform.destroy();
			platforms.splice(i, 1);
		}
	}
	// Update obstacles and check for collision
	for (var i = obstacles.length - 1; i >= 0; i--) {
		var obstacle = obstacles[i];
		obstacle.y += obstacle.speedY; // Move obstacle down at its own speed
		// Check for collision with hero
		if (hero && hero.intersects(obstacle)) {
			// Hero hit by obstacle - Game Over
			LK.getSound('hit').play();
			LK.effects.flashScreen(0xff0000, 500);
			LK.showGameOver();
			// No need to destroy elements here, LK.showGameOver will reset the game
			return; // Stop updating if game over
		}
		// Update score based on highest level reached
		if (hero && hero.y < highestY) {
			highestY = hero.y;
			// Calculate current level based on height with better distribution
			// Use 250 pixels per level for more even scoring progression
			var currentLevel = Math.floor((2732 - highestY) / 250);
			// Award 10 points for each new level reached
			if (currentLevel > highestLevel) {
				highestLevel = currentLevel;
				score = highestLevel * 10; // Score equals 10 times the highest level reached
				LK.setScore(score); // Update LK score system
				scoreTxt.setText(score);
			}
		}
		// Remove obstacles that are off-screen below
		if (obstacle.y > 2732 + obstacle.height) {
			obstacle.destroy();
			obstacles.splice(i, 1);
		}
	}
	// Spawn platforms
	platformSpawnTimer++;
	if (platformSpawnTimer >= 60) {
		// Spawn a platform roughly every second
		var newPlatform;
		// 30% chance to spawn a broken platform
		if (Math.random() < 0.3) {
			newPlatform = new BrokenPlatform();
		} else {
			newPlatform = new Platform();
		}
		// Position platform off-screen at the top
		newPlatform.x = Math.random() * (2048 - newPlatform.width) + newPlatform.width / 2; // Random X position within screen width
		// Find the highest existing platform
		var highestPlatformY = Infinity;
		for (var i = 0; i < platforms.length; i++) {
			if (platforms[i].y < highestPlatformY) {
				highestPlatformY = platforms[i].y;
			}
		}
		// Position the new platform just above the highest existing one
		newPlatform.y = highestPlatformY - 300; // Adjust vertical spacing as needed
		platforms.push(newPlatform);
		game.addChild(newPlatform);
		platformSpawnTimer = 0;
	}
	// Spawn obstacles
	obstacleSpawnTimer++;
	if (obstacleSpawnTimer >= 90) {
		// Spawn an obstacle roughly every 1.5 seconds
		var newObstacle = new Obstacle();
		// Position obstacle off-screen at the top
		newObstacle.x = Math.random() * (2048 - newObstacle.width) + newObstacle.width / 2;
		newObstacle.y = -newObstacle.height / 2;
		obstacles.push(newObstacle);
		game.addChild(newObstacle);
		obstacleSpawnTimer = 0;
	}
	// Prevent hero from falling off the top (if somehow possible with gravity)
	if (hero && hero.y < -hero.height) {
		// This shouldn't happen with normal gameplay, but as a safeguard:
		// Treat as game over if the hero goes too far off the top
		LK.getSound('hit').play();
		LK.showGameOver();
		return;
	}
	// Check if hero has fallen off the bottom of the screen
	if (hero && hero.y > 2732) {
		LK.getSound('hit').play();
		LK.showGameOver();
		return; // Stop updating if game over
	}
};