User prompt
create 3 different killers instead of 1
User prompt
add an index to Killer constructor that allow asset selection
User prompt
create a global array for killers
Code edit (3 edits merged)
Please save this source code
User prompt
find a way to avoid values like 0.7999999999999999
Code edit (1 edits merged)
Please save this source code
User prompt
in updateGoalForLevel, show the text for 2sec then hide it
Code edit (1 edits merged)
Please save this source code
User prompt
call updateGoalForLevel(1); when start button is pressed
Code edit (12 edits merged)
Please save this source code
User prompt
create a function updateGoalForLevel $10 for level 1 $100 for level 2 $1 000 000 for level 3
Code edit (4 edits merged)
Please save this source code
User prompt
increase goalText weight
Code edit (3 edits merged)
Please save this source code
User prompt
add a global goalText variable containing a Text with text : "COLLECT\r\n$10"
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
In ObstacleManager, find a way to switch obstacles assets depending on level
Code edit (1 edits merged)
Please save this source code
User prompt
Add obstacles assets switch depending on level. The logic should be in ObstacleManager
Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: self is undefined' in or related to this line: 'self.updateForLevel = function (level) {' Line Number: 1474
User prompt
Add obstacles assets switch depending on level.
Code edit (11 edits merged)
Please save this source code
User prompt
if (currentLevel === 1) { self.assetIndex = Math.floor(Math.random() * 3); // Select from 0 to 2 } else if (currentLevel === 2) { self.assetIndex = Math.floor(Math.random() * 3) + 3; // Select from 3 to 5 } else if (currentLevel === 3) { self.assetIndex = Math.floor(Math.random() * 3) + 6; // Select from 6 to 8 } could be simplified
/**** 
* Classes
****/ 
var Background = Container.expand(function () {
	var self = Container.call(this);
	var backgroundGraphics1 = self.attachAsset('background_1', {
		anchorX: 0.5,
		anchorY: 0.5,
		visible: true
	});
	var backgroundGraphics2 = self.attachAsset('background_2', {
		anchorX: 0.5,
		anchorY: 0.5,
		visible: false
	});
	var backgroundGraphics3 = self.attachAsset('background_3', {
		anchorX: 0.5,
		anchorY: 0.5,
		visible: false
	});
	self.updateForLevel = function (level) {
		backgroundGraphics1.visible = level === 1;
		backgroundGraphics2.visible = level === 2;
		backgroundGraphics3.visible = level === 3;
	};
});
// Assets will be automatically created and loaded during gameplay
// Coin class
var Coin = Container.expand(function (index) {
	var self = Container.call(this);
	self.index = index;
	var coinGraphics = self.attachAsset('coin1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var coinGraphics2 = self.attachAsset('coin2', {
		//'dollarsBundle'
		anchorX: 0.5,
		anchorY: 0.5,
		visible: false
	});
	var coinGraphics3 = self.attachAsset('dollarsBundle', {
		//'dollarsBundle'
		anchorX: 0.5,
		anchorY: 0.5,
		visible: false
	});
	var speed = 5;
	var startY = roadTop + 50;
	var endY = startY + roadHeight;
	var leftStartX = 1024 - 100;
	var leftEndX = 1024 - 650;
	var rightStartX = 1024 + 100;
	var rightEndX = 1024 + 650;
	var startSize = 2;
	var endSize = 140;
	coinGraphics.width = startSize;
	coinGraphics.height = startSize;
	coinGraphics2.width = startSize;
	coinGraphics2.height = startSize;
	coinGraphics3.width = startSize;
	coinGraphics3.height = startSize;
	self.pathIndex = 0;
	self.update = function () {
		// Road should animate even if the game hasn't started
		if (!isPlaying || isKilled) {
			return;
		}
		;
		obstacleManager.updateObstacles();
		self.progress = Math.max(0, self.y - startY) / (endY - startY); // Update progress property
		coinGraphics.width = startSize + (endSize - startSize) * self.progress;
		coinGraphics.height = startSize + (endSize - startSize) * self.progress;
		coinGraphics2.width = startSize + (endSize - startSize) * self.progress;
		coinGraphics2.height = startSize + (endSize - startSize) * self.progress;
		coinGraphics3.width = startSize + (endSize - startSize) * self.progress;
		coinGraphics3.height = startSize + (endSize - startSize) * self.progress;
		var newSpeed = currentSpeed; // + 10 * self.progress;
		var tempSpeed = currentSpeed * 0.05 + currentSpeed * (self.progress * 3);
		newSpeed = tempSpeed;
		self.y += newSpeed;
		// Move innerLineLeft x progressively to innerLeftLineEndX
		if (self.pathIndex == 0 && self.x != leftEndX) {
			self.x = leftStartX + (leftEndX - leftStartX) * self.progress;
		}
		if (self.pathIndex == 2 && self.x != rightEndX) {
			self.x = rightStartX + (rightEndX - rightStartX) * self.progress;
		}
		if (self.y > endY + endSize / 2) {
			self.reset();
		}
		// Check for collision with player
		if (!player.isJumping && self.y > 2500 && self.y < 2732 && player.shadow.intersects(self)) {
			updateScore(false);
			// coinsCollected increment moved to increaseScore function
			LK.effects.flashObject(player, 0x00ff00, 500); // Flash green for 0.5 seconds
			self.reset();
			// Increase speed every 3 coins collected
			/* 
			if (coinsCollected % nextCoinTypeThreshold === 0 && currentSpeed < maxSpeed) {
				currentSpeed += 3; // Increase speed by 3
			}
			*/
		}
	};
	self.reset = function () {
		self.y = startY;
		self.progress = 0; // Initialize progress property
		coinGraphics.width = startSize;
		coinGraphics.height = startSize;
		coinGraphics2.width = startSize;
		coinGraphics2.height = startSize;
		coinGraphics3.width = startSize;
		coinGraphics3.height = startSize;
		self.pathIndex = Math.floor(Math.random() * 3);
		if (self.pathIndex === 0) {
			self.x = leftStartX;
		} else if (self.pathIndex === 2) {
			self.x = rightStartX;
		} else {
			self.x = 1024;
		}
	};
	self.updateForLevel = function (level) {
		coinGraphics.visible = level === 1;
		coinGraphics2.visible = level === 2;
		coinGraphics3.visible = level === 3;
	};
});
// CoinAnimation class
var CoinAnimation = Container.expand(function () {
	var self = Container.call(this);
	var coinGraphics = self.attachAsset('coin1', {
		anchorX: 0.5,
		anchorY: 0.5,
		visible: currentCoinType == 0
	});
	var coinGraphics2 = self.attachAsset('coin2', {
		anchorX: 0.5,
		anchorY: 0.5,
		visible: currentCoinType == 1
	});
	// Initialize velocity and gravity
	self.vx = (Math.random() < 0.5 ? -1 : 1) * 5; // Random horizontal velocity
	self.vy = -15; // Initial vertical velocity
	self.gravity = 0.5; // Gravity effect
	self.update = function () {
		self.vy += self.gravity; // Apply gravity to vertical velocity
		self.x += self.vx; // Update horizontal position
		self.y += self.vy; // Update vertical position
		self.alpha -= 0.0035; // Fade out the coin
		if (currentCoinType == 0) {
			coinGraphics.alpha = 1;
			coinGraphics2.alpha = 0;
		} else if (currentCoinType == 1) {
			coinGraphics.alpha = 0;
			coinGraphics2.alpha = 1;
		}
		if (self.alpha <= 0) {
			self.destroy(); // Remove the coin when it becomes invisible
		}
	};
});
// Decoration class
var Decoration = Container.expand(function (decoIndex) {
	var self = Container.call(this);
	self.index = decoIndex;
	var assets = ['decoration_1_1', 'decoration_1_2', 'decoration_1_3', 'decoration_2_1', 'decoration_2_2', 'decoration_2_3', 'decoration_3_1', 'decoration_3_2', 'decoration_3_3'];
	self.assets = assets.map(function (assetId) {
		return self.attachAsset(assetId, {
			anchorX: 0.5,
			anchorY: 0.5,
			visible: false
		});
	});
	self.ready = false;
	var speed = 5;
	var startY = roadTop + 50;
	var endY = startY + roadHeight;
	var xOffset = 1024;
	var baseLeftStartX = 780;
	var rand = Math.random();
	self.leftStartX = baseLeftStartX; // - rand * xOffset;
	self.leftEndX = self.leftStartX - xOffset * (1.5 + rand);
	var baseRightStartX = 1280;
	self.rightStartX = baseRightStartX; // + rand * xOffset / 2;
	self.rightEndX = self.rightStartX + xOffset * (1.5 + rand);
	self.assetWidthRatios = [100 / 300, 1, 1, 1, 1, 1, 1, 1];
	self.endSizes = [600, 600, 600, 600, 600, 600, 600, 600, 600];
	var startSize = 1;
	self.assetIndex = Math.floor(Math.random() * 3) + (currentLevel - 1) * 3;
	mainGraphics = self.assets[self.assetIndex];
	mainGraphics.width = startSize;
	mainGraphics.height = startSize;
	self.pathIndex = 0;
	self.update = function () {
		if (isKilled) {
			return;
		}
		var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf;
		//mainGraphics.tint = newTint;
		var tempSpeed = currentSpeed * 0.055 + currentSpeed * (self.progress * 3);
		var newSpeed = currentSpeed; // + 10 * self.progress;
		newSpeed = tempSpeed * 1; // TEMP DEBUG !!!
		self.y += newSpeed;
		self.progress = Math.max(0, self.y - startY) / (endY - startY); // Update progress property
		// Move innerLineLeft x progressively to innerLeftLineEndX
		if (self.index == 7) {
			//log("Decoration " + self.index + " update - p=", self.progress, "x:", Math.round(self.x), "y:", Math.round(self.y));
			//log(self.progress);
		}
		if (self.pathIndex == 0 && self.x > self.leftEndX) {
			self.x = self.leftStartX + (self.leftEndX - self.leftStartX) * self.progress * 3;
		}
		if (self.pathIndex == 1 && self.x < self.rightEndX) {
			self.x = self.rightStartX + (self.rightEndX - self.rightStartX) * self.progress * 3;
		}
		if (self.y > endY + self.endSizes[self.assetIndex] / 2) {
			//self.y = -startSize; // Move obstacle back to the top
			self.reset();
		}
		//mainGraphics = self.assets[self.assetIndex];
		mainGraphics.height = startSize + (self.endSizes[self.assetIndex] - startSize) * self.progress * 2;
		mainGraphics.width = mainGraphics.height * self.assetWidthRatios[self.assetIndex];
		if (self.index == 8 && mainGraphics.width > 200) {
			//log("Decoration " + self.index + " update - assetIndex:", self.assetIndex, "width:", mainGraphics.width, "x:", Math.round(self.x), "y:", Math.round(self.y));
		}
		if (self.index == 7 && mainGraphics.width > 200) {
			//log("Decoration " + self.index + " update - assetIndex:", self.assetIndex, "width:", mainGraphics.width, "x:", Math.round(self.x), "y:", Math.round(self.y));
		}
		if (!self.ready) {
			//log("Decoration " + self.index + " ready =" + self.ready);
		}
		//log("Decoration " + self.index + " update width:", Math.round(mainGraphics.width), "x:", Math.round(self.x), "y:", Math.round(self.y));
	};
	self.reset = function () {
		self.ready = false;
		//log("Decoration reset" + self.index);
		self.y = startY;
		self.progress = 0; // Initialize progress property
		rand = Math.random();
		self.assetIndex = Math.floor(Math.random() * 3) + (currentLevel - 1) * 3;
		self.assets.forEach(function (asset, index) {
			asset.visible = index === self.assetIndex;
		});
		mainGraphics = self.assets[self.assetIndex];
		mainGraphics.height = startSize;
		mainGraphics.width = mainGraphics.height * self.assetWidthRatios[self.assetIndex];
		if (self.index == 1 && mainGraphics.width > 200) {
			//log("=== Decoration " + self.index + " reset - assetIndex:", self.assetIndex, "width:", mainGraphics.width, "y:", self.y, " ===");
		}
		self.leftStartX = baseLeftStartX; // - rand * xOffset;
		self.leftEndX = self.leftStartX - xOffset * (1 + rand);
		self.rightStartX = baseRightStartX; // + rand * xOffset;
		self.rightEndX = self.rightStartX + xOffset * (1 + rand);
		if (self.index == 1) {
			//log("=== Decoration " + self.index);
			//log("Left StartX:", self.leftStartX, "Left EndX:", self.leftEndX);
			//log("Right StartX:", self.rightStartX, "Right EndX:", self.rightEndX);
		}
		self.pathIndex = Math.floor(rand * 2);
		if (self.pathIndex === 0) {
			self.x = self.leftStartX;
		} else {
			self.x = self.rightStartX;
		}
		self.ready = true;
	};
});
var Killer = Container.expand(function () {
	var self = Container.call(this);
	var assets = ['killer3'];
	self.assetIndex = Math.floor(Math.random() * assets.length);
	var randomAsset = assets[self.assetIndex];
	var killerGraphics = self.attachAsset(randomAsset, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var speed = 5;
	var startY = roadTop - 20;
	var endY = startY + roadHeight;
	var leftStartX = 1024 - 100;
	var leftEndX = 1024 - 650;
	var rightStartX = 1024 + 100;
	var rightEndX = 1024 + 650;
	var startSize = 1;
	var endSize = 800;
	var assetHeightRatio = 500 / 400;
	killerGraphics.width = startSize;
	killerGraphics.height = startSize;
	self.pathIndex = 0;
	self.inactive = true;
	self.inactiveStartTime = Date.now();
	self.update = function () {
		if (!isPlaying) {
			return;
		}
		var currentTime = Date.now();
		if (self.inactive) {
			if (currentTime - self.inactiveStartTime >= killerDelay) {
				self.inactive = false;
			}
			return;
		}
		if (!isKilled && player && self.y > 2500 && self.y < 2732 && player.shadow.intersects(self)) {
			isKilled = true;
			player.visible = false;
			LK.effects.flashScreen(0xff0000, 2000);
			// Spawn MurderShape at player's last position
			var murderShape = new MurderShape();
			murderShape.x = player.x;
			murderShape.y = playerBaseY;
			murderShape.fixPosition();
			game.addChildAt(murderShape, game.getChildIndex(road) + 1);
			return;
		}
		self.progress = Math.max(0, self.y - startY) / (endY - startY);
		killerGraphics.width = startSize + (endSize - startSize) * self.progress;
		debugTxt.setText(self.progress.toFixed(2));
		killerGraphics.height = assetHeightRatio * killerGraphics.width;
		var tempSpeed = currentSpeed * 0.5 + currentSpeed * (self.progress * 3);
		var newSpeed = currentSpeed * 3;
		newSpeed = tempSpeed * 1;
		self.y += newSpeed;
		if (self.pathIndex == 0 && self.x != leftEndX) {
			self.x = leftStartX + (leftEndX - leftStartX) * self.progress;
		}
		if (self.pathIndex == 2 && self.x != rightEndX) {
			self.x = rightStartX + (rightEndX - rightStartX) * self.progress;
		}
		if (self.y > endY + endSize / 2) {
			self.reset();
		}
	};
	self.reset = function () {
		self.y = startY;
		self.progress = 0;
		killerGraphics.width = startSize;
		killerGraphics.height = startSize;
		self.pathIndex = Math.floor(Math.random() * 3);
		if (self.pathIndex === 0) {
			self.x = leftStartX;
		} else if (self.pathIndex === 2) {
			self.x = rightStartX;
		} else {
			self.x = 1024;
		}
		self.inactive = true;
		self.inactiveStartTime = Date.now();
	};
});
var Landscape = Container.expand(function () {
	var self = Container.call(this);
	var landscapeGraphics = self.attachAsset('landscape_1', {
		anchorX: 0.5,
		anchorY: 0.0
	});
	var landscapeGraphics2 = self.attachAsset('landscape_2', {
		anchorX: 0.5,
		anchorY: 0.0,
		visible: false
	});
	var landscapeGraphics3 = self.attachAsset('landscape_3', {
		anchorX: 0.5,
		anchorY: 0.0,
		visible: false
	});
	var gradientGraphics = self.attachAsset('gradient', {
		anchorX: 0.5,
		anchorY: 0.0,
		scaleY: -1,
		y: 1024,
		blendMode: 2,
		alpha: 0.5,
		tint: 0xFEFEFE,
		height: 15
	});
	self.x = 2048 / 2; // Center horizontally
	self.y = 0; // Position at the top
	self.update = function () {
		var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf;
		landscapeGraphics.tint = newTint; // Apply reduced tint to the road based on the intensity
	};
	self.updateForLevel = function (level) {
		landscapeGraphics.visible = level === 1;
		landscapeGraphics2.visible = level === 2;
		landscapeGraphics3.visible = level === 3;
	};
});
var MurderShape = Container.expand(function () {
	var self = Container.call(this);
	var murderShapeGraphics = self.attachAsset('murderShape', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.update = function () {
		// MurderShape does not need to update its position or behavior
	};
	self.fixPosition = function () {
		if (self.x < 600) {
			self.x += 150;
		} else if (self.x > 1400) {
			self.x -= 150;
		}
	};
});
// Obstacle class
var Obstacle = Container.expand(function (index) {
	var self = Container.call(this);
	self.active = true;
	self.index = index;
	var assets = [];
	if (currentLevel === 1) {
		assets = ['obstacle_1_1', 'obstacle_1_2', 'obstacle_1_3'];
	} else if (currentLevel === 2) {
		assets = ['obstacle_2_1', 'obstacle_2_2', 'obstacle_2_3'];
	} else if (currentLevel === 3) {
		assets = ['obstacle_3_1', 'obstacle_3_2', 'obstacle_3_3'];
	}
	self.assetIndex = Math.floor(Math.random() * assets.length);
	var randomAsset = assets[self.assetIndex];
	var obstacleGraphics = self.attachAsset(randomAsset, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var speed = 5;
	var startY = roadTop + 50;
	var endY = startY + roadHeight;
	var leftStartX = 1024 - 100;
	var leftEndX = 1024 - 650;
	var rightStartX = 1024 + 100;
	var rightEndX = 1024 + 650;
	var innerLeftLineStartX = -150;
	var innerLeftLineEndX = -390;
	var startSize, endSize;
	if (self.assetIndex == 0) {
		startSize = 3;
		endSize = 350;
	} else if (self.assetIndex == 1) {
		startSize = 1;
		endSize = 350;
	} else if (self.assetIndex == 2) {
		startSize = 2;
		endSize = 350;
	}
	obstacleGraphics.width = startSize;
	obstacleGraphics.height = startSize;
	self.pathIndex = 0;
	self.update = function () {
		if (!isPlaying || isKilled) {
			return;
		}
		// coinsCollected increment moved to updateScore function
		var currentTime = Date.now();
		if (currentTime - lastObstacleHitTime > immunityDelay && player && !player.isJumping && self.y > 2500 && self.y < 2732 && player.shadow.intersects(self)) {
			lastObstacleHitTime = currentTime; // Update the last hit time
			// Make player flash red for 1 second
			LK.effects.flashObject(player, 0xff0000, 1000);
			// Add coin animation only if score is greater than 0
			if (score > 0) {
				var coinAnimation = new CoinAnimation();
				coinAnimation.x = player.x;
				coinAnimation.y = player.y;
				game.addChild(coinAnimation);
			}
			// Reduce score by 1
			updateScore(true);
			//log("Obstacle y:", self.y);
			// Reduce currentSpeed by a factor (e.g., 0.8)
			//log("Old speed :", currentSpeed);
			//currentSpeed = Math.max(10, Math.min(20, Math.round(currentSpeed * 0.8)));
			//log("New speed :", currentSpeed);
		}
		self.progress = Math.max(0, self.y - startY) / (endY - startY); // Update progress property
		obstacleGraphics.width = startSize + (endSize - startSize) * self.progress;
		obstacleGraphics.height = startSize + (endSize - startSize) * self.progress;
		var tempSpeed = currentSpeed * 0.05 + currentSpeed * (self.progress * 3);
		var newSpeed = currentSpeed; // + 10 * self.progress;
		newSpeed = tempSpeed * 1; // TEMP DEBUG !!!
		self.y += newSpeed;
		// Move innerLineLeft x progressively to innerLeftLineEndX
		if (self.pathIndex == 0 && self.x != leftEndX) {
			self.x = leftStartX + (leftEndX - leftStartX) * self.progress;
		}
		if (self.pathIndex == 2 && self.x != rightEndX) {
			self.x = rightStartX + (rightEndX - rightStartX) * self.progress;
		}
		if (self.y > endY + endSize / 2) {
			self.reset();
		}
	};
	self.reset = function () {
		obstacleManager.freePath(self.pathIndex); // Mark the path as unoccupied
		self.active = false;
		self.y = startY;
		self.progress = 0; // Initialize progress property
		obstacleGraphics.width = startSize;
		obstacleGraphics.height = startSize;
	};
	self.setPath = function (newPathIndex) {
		self.pathIndex = newPathIndex; //Math.floor(Math.random() * 3);
		if (self.pathIndex === 0) {
			self.x = leftStartX;
		} else if (self.pathIndex === 2) {
			self.x = rightStartX;
		} else {
			self.x = 1024;
		}
	};
	self.updateForLevel = function (level) {
		log("Obstacle updateForLevel", level);
		var assets = [];
		if (level === 1) {
			assets = ['obstacle_1_1', 'obstacle_1_2', 'obstacle_1_3'];
		} else if (level === 2) {
			assets = ['obstacle_2_1', 'obstacle_2_2', 'obstacle_2_3'];
		} else if (level === 3) {
			assets = ['obstacle_3_1', 'obstacle_3_2', 'obstacle_3_3'];
		}
		self.assetIndex = Math.floor(Math.random() * assets.length);
		var randomAsset = assets[self.assetIndex];
		log("Obstacle asset =>", randomAsset);
		obstacleGraphics.destroy();
		obstacleGraphics = self.attachAsset(randomAsset, {
			anchorX: 0.5,
			anchorY: 0.5
		});
		self.reset();
	};
});
var ObstacleManager = Container.expand(function () {
	var self = Container.call(this);
	self.obstacles = [];
	self.occupiedPaths = [false, false, false];
	self.addObstacle = function (obstacle) {
		self.obstacles.push(obstacle);
	};
	self.resetObstacles = function () {
		self.occupiedPaths = [false, false, false];
		self.obstacles.forEach(function (obstacle) {
			obstacle.reset();
		});
	};
	self.updateObstacles = function () {
		self.obstacles.forEach(function (obstacle) {
			if (!obstacle.active) {
				obstacle.reset();
			}
		});
	};
	self.update = function () {
		if (!isPlaying || isKilled) {
			return;
		}
		// Activate obstacles regularly in random path
		var currentTime = Date.now();
		log("ObstacleManager update...");
		if (currentTime - lastObstacleSpawnTime > baseObstacleSpawnDelay) {
			log("Attempting to spawn obstacle. Current time:", currentTime, "Last spawn time:", lastObstacleSpawnTime);
			var availablePaths = self.occupiedPaths.map(function (occupied, index) {
				return occupied ? null : index;
			}).filter(function (index) {
				return index !== null;
			});
			log("Available paths for obstacle activation:", availablePaths);
			if (availablePaths.length > 0) {
				var randomPathIndex = availablePaths[Math.floor(Math.random() * availablePaths.length)];
				var inactiveObstacles = self.obstacles.filter(function (obstacle) {
					return !obstacle.active;
				});
				log("Inactive obstacles available for activation:", inactiveObstacles.length);
				if (inactiveObstacles.length > 0) {
					var obstacleToActivate = inactiveObstacles[Math.floor(Math.random() * inactiveObstacles.length)];
					log("Activating obstacle in path:", randomPathIndex);
					obstacleToActivate.setPath(randomPathIndex);
					log("Obstacle activated:", obstacleToActivate);
					obstacleToActivate.active = true;
					self.setPathOccupied(randomPathIndex, true);
					log("Path occupied status updated. Path:", randomPathIndex, "Occupied:", self.isPathOccupied(randomPathIndex));
					lastObstacleSpawnTime = currentTime; // Update the last spawn time
				}
			}
		}
	};
	self.isPathOccupied = function (pathIndex) {
		return self.occupiedPaths[pathIndex];
	};
	self.setPathOccupied = function (pathIndex, occupied) {
		self.occupiedPaths[pathIndex] = occupied;
	};
	self.freePath = function (pathIndex) {
		self.setPathOccupied(pathIndex, false);
	};
	self.updateForLevel = function (level) {
		self.obstacles.forEach(function (obstacle) {
			obstacle.updateForLevel(level);
		});
	};
});
// Player class
var Player = Container.expand(function () {
	var self = Container.call(this);
	self.shadow = self.attachAsset('shadow', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.isJumping = false; // Initialize isJumping to false
	self.shadow.alpha = 0.5; // Make the shadow semi-transparent
	self.shadow.y = 270; // Offset the shadow slightly below the player
	var playerGraphics1_1 = self.attachAsset('player_1_1', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: -5
	});
	var playerGraphics1_2 = self.attachAsset('player_1_2', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 5
	});
	var playerGraphics2_1 = self.attachAsset('player_2_1', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: -5,
		visible: false // Initially hide player2_1 asset
	});
	var playerGraphics2_2 = self.attachAsset('player_2_2', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 5,
		visible: false // Initially hide player2_2 asset
	});
	var playerGraphics3_1 = self.attachAsset('player_3_1', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: -5,
		visible: false // Initially hide player3_1 asset
	});
	var playerGraphics3_2 = self.attachAsset('player_3_2', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 5,
		visible: false // Initially hide player3_2 asset
	});
	var frame = 0;
	self.update = function () {
		if (!self.isJumping) {
			frame += Math.min(currentSpeed, 20); // Add a max limit to avoid optical effects
			if (frame >= 100) {
				frame = 0;
				// Swap frames every 10 game ticks
				if (currentLevel <= 1) {
					var visible = playerGraphics1_1.visible;
					playerGraphics1_1.visible = !visible;
					playerGraphics1_2.visible = visible;
				}
				if (currentLevel === 2) {
					var visible = playerGraphics2_1.visible;
					playerGraphics2_1.visible = !visible;
					playerGraphics2_2.visible = visible;
				}
				if (currentLevel === 3) {
					var visible = playerGraphics3_1.visible;
					playerGraphics3_1.visible = !visible;
					playerGraphics3_2.visible = visible;
				}
			}
		}
	};
	self.updateForLevel = function (level) {
		playerGraphics1_1.visible = level === 1;
		playerGraphics1_2.visible = level === 1;
		playerGraphics2_1.visible = level === 2;
		playerGraphics2_2.visible = level === 2;
		playerGraphics3_1.visible = level === 3;
		playerGraphics3_2.visible = level === 3;
	};
	self.jump = function () {
		if (!self.isJumping) {
			self.isJumping = true;
			var initialY = self.y;
			var initialShadowY = self.shadow.y;
			var jumpHeight = 300;
			var jumpDuration = 30;
			var jumpStep = jumpHeight / jumpDuration;
			var fallStep = jumpHeight / jumpDuration;
			var jumpStartTime = Date.now();
			var jumpInterval = LK.setInterval(function () {
				var elapsed = Date.now() - jumpStartTime;
				var progress = elapsed / (jumpDuration * 1000 / 60);
				if (progress < 1) {
					var easeProgress = Math.sin(progress * Math.PI / 2);
					self.y = initialY - jumpHeight * easeProgress;
					self.shadow.y = initialShadowY + jumpHeight * easeProgress; // Move shadow inversely
					self.shadow.width = 240 * (1 - 0.5 * easeProgress); // Reduce shadow width
					self.shadow.height = 100 * (1 - 0.5 * easeProgress); // Reduce shadow height
				} else {
					LK.clearInterval(jumpInterval);
					var fallStartTime = Date.now();
					var fallInterval = LK.setInterval(function () {
						var elapsed = Date.now() - fallStartTime;
						var progress = elapsed / (jumpDuration * 1000 / 60);
						if (progress < 1) {
							var easeProgress = Math.sin(progress * Math.PI / 2);
							self.y = initialY - jumpHeight + jumpHeight * easeProgress;
							self.shadow.y = initialShadowY + jumpHeight - jumpHeight * easeProgress; // Move shadow inversely
							self.shadow.width = 120 + 120 * easeProgress; // Reset shadow width
							self.shadow.height = 50 + 50 * easeProgress; // Reset shadow height
						} else {
							self.y = initialY;
							self.shadow.y = initialShadowY; // Reset shadow position
							self.isJumping = false;
							LK.clearInterval(fallInterval);
						}
					}, 1000 / 60);
				}
			}, 1000 / 60);
		}
	};
});
// Road class
var Road = Container.expand(function () {
	var self = Container.call(this);
	var baseY = 750;
	var roadGraphics = self.attachAsset('triangle', {
		tint: 0x555555,
		// Initialize tint to white
		anchorX: 0.5,
		anchorY: 0,
		width: 2048,
		height: roadHeight,
		y: baseY
	});
	var speed = 5;
	var lineOffset = -150;
	// Inner lines
	var innerLineStartY = roadTop;
	var innerLineEndY = roadTop + roadHeight + 200;
	// Left
	var innerLeftLineStartX = -50;
	var innerLeftLineEndX = -412;
	var innerLeftLineStartW = 3;
	var innerLeftLineEndW = 80;
	var innerLeftLineStartH = 3;
	var innerLeftLineEndH = 500;
	var innerLeftLineStartR = 0.22; //0.075;
	var innerLeftLineEndR = 0.275;
	// Right
	var innerRightLineStartX = 50;
	var innerRightLineEndX = 412;
	var innerRightLineStartW = 3;
	var innerRightLineEndW = 80;
	var innerRightLineStartH = 3;
	var innerRightLineEndH = 500;
	var innerRightLineStartR = -0.22;
	var innerRightLineEndR = -0.275;
	// Lamp posts 
	// Left Lamp
	var leftLampStartX = -130;
	var leftLampEndX = -1600;
	var leftLampStartY = roadTop;
	var leftLampEndY = roadTop + roadHeight + 0; // Define leftLampEndY variable
	var leftLampStartH = 2;
	var leftLampEndH = 900;
	var leftLampWRatio = 1 / 3;
	// Right Lamp
	var rightLampStartX = 130;
	var rightLampEndX = 1600;
	var rightLampStartY = roadTop;
	var rightLampEndY = roadTop + roadHeight + 0; // Define leftLampEndY variable
	var rightLampStartH = 2;
	var rightLampEndH = 900;
	var rightLampWRatio = 1 / 3;
	var nbInnerLines = 6;
	var leftLine = self.attachAsset('triangle', {
		anchorX: 0.5,
		anchorY: 0,
		width: 100,
		height: 1950,
		rotation: 0.45
	});
	leftLine.x = lineOffset; // Position the left line on the left side of the road
	leftLine.y = roadTop + 45; // Center the left line vertically
	var rightLine = self.attachAsset('triangle', {
		anchorX: 0.5,
		anchorY: 0,
		width: 100,
		height: 1950,
		rotation: -0.45
	});
	rightLine.x = -lineOffset; // Position the right line on the right side of the road
	rightLine.y = roadTop + 45; // Center the right line vertically
	self.innerLeftLines = [];
	self.innerRightLines = [];
	self.leftLampPosts = [];
	self.rightLampPosts = [];
	// Define arrays to store assets for each level
	var leftLampPostAssets = ['lampPost_1',
	// Level 1 asset
	'lampPost_2',
	// Level 2 asset
	'lampPost_3' // Level 3 asset
	];
	var rightLampPostAssets = ['lampPost_1',
	// Level 1 asset
	'lampPost_2',
	// Level 2 asset
	'lampPost_3' // Level 3 asset
	];
	for (var i = 0; i < nbInnerLines; i++) {
		var innerLineLeft = self.attachAsset('line', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: innerLeftLineStartW,
			height: innerLeftLineStartH,
			rotation: innerLeftLineStartR,
			alpha: 1
		});
		innerLineLeft.x = innerLeftLineStartX;
		innerLineLeft.y = innerLineStartY - 0.1 * i * roadHeight / nbInnerLines;
		//log(i + " : " + innerLineStartY + " + " + i * roadHeight / nbInnerLines + " => " + innerLineLeft.y);
		innerLineLeft.progress = 0; // Initialize progress property
		self.innerLeftLines.push(innerLineLeft);
		var innerLineRight = self.attachAsset('line', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: innerRightLineStartW,
			height: innerRightLineStartH,
			rotation: innerRightLineStartR,
			alpha: 1
		});
		innerLineRight.x = innerRightLineStartX;
		innerLineRight.y = innerLineStartY - 0.1 * i * roadHeight / nbInnerLines;
		innerLineRight.progress = 0; // Initialize progress property
		self.innerRightLines.push(innerLineRight);
		if (i % 2 == 0) {
			continue;
		}
		var leftLampPost = self.attachAsset(leftLampPostAssets[currentLevel - 1], {
			anchorX: 0.5,
			anchorY: 0.5,
			height: leftLampStartH,
			width: leftLampStartH * leftLampWRatio
		});
		var leftLampShadow = self.attachAsset('shadow', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: leftLampPost.width * 0.8,
			height: leftLampPost.height * 0.1,
			y: leftLampPost.height * 0.5 + 10 // Offset shadow slightly below the lamp post
		});
		leftLampPost.addChild(leftLampShadow);
		leftLampPost.x = leftLampStartX;
		leftLampPost.y = leftLampStartY - (i - 1) * 40;
		self.addChild(leftLampPost);
		self.leftLampPosts.push(leftLampPost);
		var rightLampPost = self.attachAsset(rightLampPostAssets[currentLevel - 1], {
			anchorX: 0.5,
			anchorY: 0.5,
			scaleX: -1,
			height: rightLampStartH,
			width: rightLampStartH * rightLampWRatio
		});
		var rightLampShadow = self.attachAsset('shadow', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: rightLampPost.width * 0.8,
			height: rightLampPost.height * 0.1,
			y: rightLampPost.height * 0.5 + 10 // Offset shadow slightly below the lamp post
		});
		rightLampPost.addChild(rightLampShadow);
		rightLampPost.x = rightLampStartX;
		rightLampPost.y = rightLampStartY - (i - 1) * 40;
		self.addChild(rightLampPost);
		self.rightLampPosts.push(rightLampPost);
	}
	self.update = function () {
		if (isKilled) {
			return;
		}
		var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf;
		//roadGraphics.tint = newTint; // Apply reduced tint to the road based on the intensity
		leftLine.tint = newTint;
		rightLine.tint = newTint;
		// Add any update logic for the road if needed
		for (var i = 0; i < self.innerLeftLines.length; i++) {
			innerLineLeft = self.innerLeftLines[i];
			innerLineLeft.tint = newTint;
			if (innerLineLeft.y > innerLineEndY) {
				self.resetInnerLine(innerLineLeft, true);
			} else {
				innerLineLeft.progress = Math.max(0, innerLineLeft.y - innerLineStartY) / (innerLineEndY - innerLineStartY); // Update progress property
			}
			var tempSpeed = currentSpeed * 0.05 + currentSpeed * (innerLineLeft.progress * 3);
			var newSpeed = currentSpeed; // + 10 * self.progress;
			newSpeed = tempSpeed * 1; // TEMP DEBUG !!!
			innerLineLeft.y += newSpeed;
			// Move innerLineLeft x progressively to innerLeftLineEndX
			if (innerLineLeft.x != innerLeftLineEndX) {
				innerLineLeft.x = innerLeftLineStartX + (innerLeftLineEndX - innerLeftLineStartX) * innerLineLeft.progress;
			}
			// Move innerLineLeft x progressively 
			if (innerLineLeft.rotation != innerLeftLineEndR) {
				//innerLineLeft.rotation = innerLeftLineStartR + (innerLeftLineEndR - innerLeftLineStartR) * innerLineLeft.progress;
			}
			// Move innerLineLeft x progressively 
			if (innerLineLeft.width != innerLeftLineEndW) {
				innerLineLeft.width = innerLeftLineStartW + (innerLeftLineEndW - innerLeftLineStartW) * innerLineLeft.progress;
			}
			// Move innerLineLeft x progressively
			if (innerLineLeft.height != innerLeftLineEndH) {
				innerLineLeft.height = innerLeftLineStartH + (innerLeftLineEndH - innerLeftLineStartH) * innerLineLeft.progress;
			}
		}
		for (var i = 0; i < self.innerRightLines.length; i++) {
			innerLineRight = self.innerRightLines[i];
			innerLineRight.tint = newTint;
			if (innerLineRight.y > innerLineEndY) {
				self.resetInnerLine(innerLineRight, false);
			} else {
				innerLineRight.progress = Math.max(0, innerLineRight.y - innerLineStartY) / (innerLineEndY - innerLineStartY);
			}
			var tempSpeed = currentSpeed * 0.05 + currentSpeed * (innerLineRight.progress * 3);
			var newSpeed = currentSpeed; // + 10 * self.progress;
			newSpeed = tempSpeed * 1; // TEMP DEBUG !!!
			innerLineRight.y += newSpeed;
			// Move innerLineRight x progressively to innerRightLineEndX
			if (innerLineRight.x != innerRightLineEndX) {
				innerLineRight.x = innerRightLineStartX + (innerRightLineEndX - innerRightLineStartX) * innerLineRight.progress;
			}
			// Move innerLineRight x progressively 
			if (innerLineRight.rotation != innerRightLineEndR) {
				//innerLineRight.rotation = innerRightLineStartR + (innerRightLineEndR - innerRightLineStartR) * innerLineRight.progress;
			}
			// Move innerLineRight x progressively 
			if (innerLineRight.width != innerRightLineEndW) {
				innerLineRight.width = innerRightLineStartW + (innerRightLineEndW - innerRightLineStartW) * innerLineRight.progress;
			}
			// Move innerLineRight x progressively 
			if (innerLineRight.height != innerRightLineEndH) {
				innerLineRight.height = innerRightLineStartH + (innerRightLineEndH - innerRightLineStartH) * innerLineRight.progress;
			}
		}
		// Lamp posts
		for (var i = 0; i < self.leftLampPosts.length; i++) {
			var leftLampPost = self.leftLampPosts[i];
			//leftLampPost.tint = newTint;
			var tempProgress = Math.max(0, leftLampPost.y - leftLampStartY) / (leftLampEndY - leftLampStartY);
			var tempSpeed = currentSpeed * 0.05 + currentSpeed * (tempProgress * 3);
			leftLampPost.y += tempSpeed;
			//leftLampPost.visible = currentLevel !== 1; // Make lampPost not visible when level is 1
			if (leftLampPost.y > leftLampEndY) {
				leftLampPost.y = leftLampStartY;
				leftLampPost.x = leftLampStartX;
				leftLampPost.height = leftLampStartH;
			}
			leftLampPost.progress = Math.max(0, leftLampPost.y - leftLampStartY) / (leftLampEndY - leftLampStartY); // Update progress property
			leftLampPost.alpha = 0.75 + Math.min(0.25, leftLampPost.progress);
			if (i == 0) {
				//debugTxt.setText(leftLampPost.progress.toFixed(2));
			}
			if (leftLampPost.x != leftLampEndX) {
				leftLampPost.x = leftLampStartX + (leftLampEndX - leftLampStartX) * Math.min(1, leftLampPost.progress * 1);
			}
			if (leftLampPost.height != leftLampEndH) {
				leftLampPost.height = Math.min(1, leftLampPost.progress * 2) * leftLampEndH; // leftLampStartH + (leftLampEndH - leftLampStartH) * Math.min(1, leftLampPost.progress * 1);
				leftLampPost.width = leftLampPost.height * leftLampWRatio;
			}
		}
		for (var i = 0; i < self.rightLampPosts.length; i++) {
			var rightLampPost = self.rightLampPosts[i];
			var tempProgress = Math.max(0, rightLampPost.y - rightLampStartY) / (rightLampEndY - rightLampStartY);
			var tempSpeed = currentSpeed * 0.05 + currentSpeed * (tempProgress * 3);
			rightLampPost.y += tempSpeed;
			//rightLampPost.visible = currentLevel !== 1; // Make right lampPost not visible when level is 1
			if (rightLampPost.y > rightLampEndY) {
				rightLampPost.y = rightLampStartY;
				rightLampPost.x = rightLampStartX;
				rightLampPost.height = rightLampStartH;
			}
			rightLampPost.progress = Math.max(0, rightLampPost.y - rightLampStartY) / (rightLampEndY - rightLampStartY);
			rightLampPost.alpha = 0.75 + Math.min(0.25, rightLampPost.progress);
			if (rightLampPost.x != rightLampEndX) {
				rightLampPost.x = rightLampStartX + (rightLampEndX - rightLampStartX) * rightLampPost.progress;
			}
			if (rightLampPost.height != leftLampEndH) {
				rightLampPost.height = rightLampStartH + (rightLampEndH - rightLampStartH) * Math.min(1, rightLampPost.progress * 2);
				rightLampPost.width = rightLampPost.height * rightLampWRatio;
			}
		}
	};
	self.updateForLevel = function (level) {
		// Iterate through left lamp posts
		for (var i = 0; i < self.leftLampPosts.length; i++) {
			var leftLampPost = self.leftLampPosts[i];
			var newLeftLampPost = self.attachAsset(leftLampPostAssets[level - 1], {
				anchorX: 0.5,
				anchorY: 0.5,
				height: leftLampPost.height,
				width: leftLampPost.width
			});
			newLeftLampPost.visible = leftLampPost.visible;
			newLeftLampPost.x = leftLampPost.x;
			newLeftLampPost.y = leftLampPost.y;
			self.leftLampPosts[i] = newLeftLampPost;
			leftLampPost.destroy();
		}
		for (var i = 0; i < self.rightLampPosts.length; i++) {
			var rightLampPost = self.rightLampPosts[i];
			rightLampPost.children.forEach(function (child) {
				child.visible = false;
			});
			var newRightLampPost = self.attachAsset(rightLampPostAssets[level - 1], {
				anchorX: 0.5,
				anchorY: 0.5,
				scaleX: -1,
				height: rightLampPost.height,
				width: rightLampPost.width
			});
			newRightLampPost.visible = rightLampPost.visible;
			newRightLampPost.x = rightLampPost.x;
			newRightLampPost.y = rightLampPost.y;
			self.rightLampPosts[i] = newRightLampPost;
			rightLampPost.destroy();
		}
	};
	self.resetInnerLine = function (innerLine, isLeft) {
		if (isLeft) {
			innerLine.x = innerLeftLineStartX;
			innerLine.rotation = innerLeftLineStartR;
			innerLine.width = innerLeftLineStartW;
			innerLine.height = innerLeftLineStartH;
		} else {
			innerLine.x = innerRightLineStartX;
			innerLine.rotation = innerRightLineStartR;
			innerLine.width = innerRightLineStartW;
			innerLine.height = innerRightLineStartH;
		}
		innerLine.y = innerLineStartY - 0.2 * roadHeight / nbInnerLines;
		innerLine.progress = 0; // Reset progress property
	};
});
var StartButton = Container.expand(function () {
	var self = Container.call(this);
	var buttonGraphics = self.attachAsset('startButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.interactive = true;
	self.buttonMode = true;
	self.on('down', function () {
		self.visible = false;
		isPlaying = true;
		scoreTxt.visible = true;
		updateGoalForLevel(1); // Call updateGoalForLevel(1) when start button is pressed
	});
});
var Stripe = Container.expand(function () {
	var self = Container.call(this);
	self.stripeGraphics = self.attachAsset('stripe_1', {
		anchorX: 0,
		anchorY: 1,
		height: 1
	});
	self.stripeGraphics2 = self.attachAsset('stripe_2', {
		anchorX: 0,
		anchorY: 1,
		height: 1,
		visible: false
	});
	self.stripeGraphics3 = self.attachAsset('stripe_3', {
		anchorX: 0,
		anchorY: 1,
		height: 1,
		visible: false
	});
	self.progress = 0; // Initialize progress property
	self.update = function () {
		if (isKilled) {
			return;
		}
		self.progress = Math.max(0, self.y - roadTop) / roadHeight; // Update progress property
		var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf;
		self.stripeGraphics.tint = newTint;
		self.stripeGraphics2.tint = newTint;
		self.stripeGraphics3.tint = newTint;
		var tempSpeed = currentSpeed * 0.05 + currentSpeed * (self.progress * 3);
		self.y += tempSpeed;
		self.stripeGraphics.height = 400 * self.progress; // Adjust height based on progress
		self.stripeGraphics2.height = 400 * self.progress; // Adjust height based on progress
		self.stripeGraphics3.height = 400 * self.progress; // Adjust height based on progress
		if (self.y > roadTop + roadHeight) {
			self.y = roadTop;
			self.stripeGraphics.height = 0; // Reset height to initial value
			self.stripeGraphics.tint = 0xFFFFFF; // Reset tint to initial value
			self.stripeGraphics2.height = 0;
			self.stripeGraphics2.tint = 0xFFFFFF;
			self.stripeGraphics3.height = 0;
			self.stripeGraphics3.tint = 0xFFFFFF;
		}
	};
	self.updateForLevel = function (level) {
		self.stripeGraphics.visible = level === 1;
		self.stripeGraphics2.visible = level === 2;
		self.stripeGraphics3.visible = level === 3;
	};
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 // Init game with black background
});
/**** 
* Game Code
****/ 
function updateGoalForLevel(level) {
	if (level === 1) {
		goalText.setText('COLLECT\r\n$10');
	} else if (level === 2) {
		goalText.setText('COLLECT\r\n$100');
	} else if (level === 3) {
		goalText.setText('COLLECT\r\n$1 000 000');
	}
	goalText.visible = true;
	LK.setTimeout(function () {
		goalText.visible = false;
	}, goalAnnounceDelay);
}
var moneyLost = 0; // Initialize global moneyLost variable
var isDebug = true; // Define global isDebug variable
var occupiedPaths = [false, false, false]; // Initialize an array to track occupied paths
var baseObstacleSpawnDelay = 2000; // Define global baseObstacleSpawnDelay
var obstacleManager; // Define obstacleManager in the global scope
var lastObstacleSpawnTime = 0; // Track the last time an obstacle was spawned
var levelConfigs = [{}, {
	name: "Level 1",
	backgroundTint: 0xeda716,
	coinValue: 0.10,
	baseSpeed: 10
}, {
	name: "Level 2",
	backgroundTint: 0x2faf1d,
	coinValue: 1,
	baseSpeed: 15
}, {
	name: "Level 3",
	backgroundTint: 0x6c6060,
	coinValue: 100,
	baseSpeed: 20
}];
var stripes = [];
var nbDecorations = 10;
var decorations = [];
// Initialize arrays and variables
var currentLevel = 1;
var road = new Road();
var nextLevelCoinThreshold = 10;
var isPlaying = false;
var isKilled = false;
var killerDelay = 10000; // Delay in milliseconds before updating killer
var lastKillerUpdate = 0; // Timestamp of the last killer update
var currentCoinType = 0;
var nextCoinTypeThreshold = 100;
var isNight = false;
var roadHeight = 2000;
var roadTop = 1000; // ~= road.height/2 - baseY
var background;
var landscape;
var nbStripes = 33;
var baseNbCoins = 10;
var baseNbObstacles = 10;
var coins = [];
var obstacles = [];
var road;
var score = 0;
var scoreTxt;
var goalText;
var goalAnnounceDelay = 3000;
var startX = 0;
var startY = 0;
var endX = 0;
var endY = 0;
var intensity = 0;
var intensityHalf = 0;
var leftLampPosts = [];
var rightLampPosts = [];
var leftDecorations = [];
var rightDecorationss = [];
var maxSpeed = 70; // Define a maximum speed limit
var currentSpeed = 15; //20; // Initialize currentSpeed
var coinsCollected = 0; // Initialize coins collected counter
var isIntersectingObstacle = false; // Flag to track if the player is currently intersecting an obstacle
var lastObstacleHitTime = 0; // Timestamp of the last obstacle hit
var immunityDelay = 500; // Immunity delay in milliseconds
var playerPositionIndex = 1; // Initialize player position index
var playerBaseY = 2732 - 300;
// Define the three fixed x positions for the player
var playerPositions = [2048 / 5, 2048 / 2, 4 * 2048 / 5];
// Create player
var player;
var debugMarker;
var debugText;
var debugTxt;
/****************************************************************************************** */ 
/************************************** GAME FUNCTIONS ************************************ */
/****************************************************************************************** */ 
function updateScore() {
	var negative = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
	if (negative) {
		if (score > 0) {
			moneyLost += Math.min(levelConfigs[currentLevel].coinValue || 1, score);
		}
		score -= levelConfigs[currentLevel].coinValue || 1;
		score = parseFloat(score.toFixed(1));
		score = Math.max(0, score); // Ensure score doesn't go below 0
	} else {
		score += levelConfigs[currentLevel].coinValue || 1;
		score = parseFloat(score.toFixed(1));
		coinsCollected += 1; // Increment coins collected counter
	}
	if (coinsCollected >= nextLevelCoinThreshold * currentLevel) {
		changeLevel(currentLevel + 1);
	}
	// Format score
	log("score=", score, " => ", (score * 100).toFixed(0) + "¢");
	if (score < 1) {
		scoreTxt.setText((score * 100).toFixed(0) + "¢");
	} else if (score < 10) {
		scoreTxt.setText("$" + score.toFixed(2));
	} else {
		scoreTxt.setText("$" + Math.floor(score));
	}
}
// Function to change the level
function changeLevel(newLevel) {
	obstacleManager.updateForLevel(currentLevel);
	log("changeLevel:", newLevel);
	newLevel = Math.max(1, Math.min(levelConfigs.length, newLevel));
	currentLevel = newLevel;
	currentSpeed = levelConfigs[currentLevel].baseSpeed;
	nextLevelCoinThreshold = levelConfigs[currentLevel].coinValue * 10; // Example threshold calculation
	console.log("Level changed to:", currentLevel);
	// Add a big white flash effect
	LK.effects.flashScreen(0xFFFFFF, 1000); // Flash white for 1 second
	// Change background tint using levelConfig
	background.updateForLevel(currentLevel);
	// Update stripe graphics visibility based on the level
	stripes.forEach(function (stripe) {
		stripe.updateForLevel(currentLevel);
	});
	// Update landscape based on the level
	landscape.updateForLevel(currentLevel);
	// Update player graphics based on the level
	player.updateForLevel(currentLevel);
	if (road) {
		road.updateForLevel(currentLevel);
	}
	coins.forEach(function (coin) {
		coin.updateForLevel(currentLevel);
	});
	updateGoalForLevel(currentLevel);
}
function easeInOutQuad(t) {
	return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}
function updateBackgroundColor() {
	var time = 1000 + new Date().getTime() * 0.0002;
	intensity = Math.sin(time) * 127 + 128;
	var baseColor = levelConfigs[currentLevel].backgroundTint;
	var r = (baseColor >> 16 & 0xFF) + intensity;
	var g = (baseColor >> 8 & 0xFF) + intensity;
	var b = (baseColor & 0xFF) + intensity;
	r = Math.min(255, Math.max(0, r));
	g = Math.min(255, Math.max(0, g));
	b = Math.min(255, Math.max(0, b));
	var color = r << 16 | g << 8 | b;
	background.tint = color;
	isNight = intensity < 128;
	intensityHalf = 128 + Math.floor(intensity * 0.5);
}
function log() {
	if (isDebug) {
		var _console;
		(_console = console).log.apply(_console, arguments);
	}
}
/****************************************************************************************** */ 
/************************************** INPUT HANDLERS ************************************ */
/****************************************************************************************** */ 
// Handle move events
game.down = function (x, y, obj) {
	if (!isPlaying) {
		return;
	}
	startX = x;
	startY = y;
};
game.up = function (x, y, obj) {
	if (isKilled) {
		LK.setTimeout(function () {
			LK.showGameOver();
		}, 500);
		return;
	}
	if (!isPlaying) {
		return;
	}
	endX = x;
	endY = y;
	var deltaX = endX - startX;
	var deltaY = endY - startY;
	if (Math.abs(deltaX) > Math.abs(deltaY)) {
		if (deltaX > 0) {
			// Swipe right
			if (playerPositionIndex < 2) {
				playerPositionIndex++;
			}
		} else {
			// Swipe left
			if (playerPositionIndex > 0) {
				playerPositionIndex--;
			}
		}
	} else {
		if (deltaY < 0) {
			// Swipe up
			player.jump();
		}
	}
	// Make the player move progressively to the next path
	var targetX = playerPositions[playerPositionIndex];
	var initialX = player.x;
	var moveDuration = 30;
	var moveStartTime = Date.now();
	var moveInterval = LK.setInterval(function () {
		var elapsed = Date.now() - moveStartTime;
		var progress = elapsed / (moveDuration * 1000 / 60);
		if (progress < 1) {
			var easeProgress = easeInOutQuad(progress);
			player.x = initialX + (targetX - initialX) * easeProgress;
		} else {
			player.x = targetX;
			LK.clearInterval(moveInterval);
		}
	}, 1000 / 60);
};
// Update game every tick
game.update = function () {
	updateBackgroundColor();
	if (!isPlaying || isKilled) {
		return;
	}
};
// Initialize game
function gameInitialize() {
	// Initialize arrays and variables
	// Attach the background asset to the game
	background = game.addChild(new Background());
	background.updateForLevel(currentLevel);
	// Add a series of Stripe instances to cover the bottom half of the screen
	for (var i = 0; i < nbStripes; i++) {
		var stripe = new Stripe();
		stripe.y = i === 0 ? roadTop : stripes[i - 1].y + stripes[i - 1].stripeGraphics.height; // Position stripe under the previous one using previous stripe y and height
		stripe.progress = Math.max(0, stripe.y - roadTop) / roadHeight; // Calculate progress
		stripes.push(stripe);
		game.addChild(stripe);
		stripe.stripeGraphics.height = 1 + 400 * stripe.progress; // Adjust height based on progress
		//log("Stripe ", i, " y=", stripe.y, " h=", stripe.stripeGraphics.height, " p=", stripe.progress);
	}
	for (var i = 0; i < stripes.length; i++) {
		stripes[i].update();
	}
	// Create and attach decoration instances to the game
	for (var i = 0; i < nbDecorations; i++) {
		var newDecoration = new Decoration(i);
		newDecoration.reset();
		decorations.push(newDecoration);
		game.addChild(newDecoration);
	}
	// Create and attach the road instance to the game
	road = game.addChild(new Road());
	road.x = 2048 / 2;
	road.y = 0;
	if (road) {
		//road.updateForLevel(currentLevel);
	}
	score = 0;
	scoreTxt = new Text2('0¢', {
		size: 150,
		fill: "#ffffff",
		dropShadow: true,
		dropShadowColor: "#000000",
		dropShadowBlur: 5,
		dropShadowDistance: 5
	});
	scoreTxt.anchor.set(0.5, 0);
	scoreTxt.visible = false;
	goalText = new Text2('', {
		size: 150,
		fill: "#ffffff",
		dropShadow: true,
		dropShadowColor: "#111111",
		dropShadowBlur: 10,
		dropShadowDistance: 10,
		align: 'center',
		weight: 1000
	});
	goalText.anchor.set(0.5, 1);
	LK.gui.center.addChild(goalText);
	//goalText.x = 2048 / 2;
	//goalText.y = 100;
	//goalText.visible = true;
	LK.gui.top.addChild(scoreTxt);
	coins = [];
	for (var i = 0; i < baseNbCoins; i++) {
		var newCoin = new Coin(i);
		newCoin.reset();
		newCoin.y = roadTop - i * 50;
		coins.push(newCoin);
		game.addChild(newCoin);
	}
	// Create a variable to store the current player position index
	playerPositionIndex = 1;
	// Create and attach obstacle instances to the game
	obstacleManager = new ObstacleManager();
	var numObstacles = Math.floor(Math.random() * baseNbObstacles) + 1; // Randomize number of obstacles (1 to baseNbObstacles)
	for (var i = 0; i < numObstacles; i++) {
		var newObstacle = new Obstacle(i);
		obstacleManager.addObstacle(newObstacle);
		game.addChild(newObstacle);
	}
	obstacleManager.resetObstacles();
	game.addChild(obstacleManager);
	// Create and attach the killer instance to the game
	var newKiller = new Killer();
	newKiller.reset();
	obstacles.push(newKiller);
	game.addChild(newKiller);
	// Create player
	player = game.addChild(new Player());
	player.frame = 0;
	player.x = playerPositions[playerPositionIndex]; // Start at the center position
	player.y = playerBaseY;
	// Create and attach the landscape instance to the game
	landscape = game.addChild(new Landscape());
	var startButton = game.addChild(new StartButton());
	startButton.x = 2048 / 2;
	startButton.y = 2732 / 4;
	// TEMP DEBUG !!!
	startButton.width = 100;
	startButton.height = 100;
	// Attach a debugMarker asset to the game at position (1000, 0)
	debugMarker = game.attachAsset('debugMarker', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	debugMarker.x = 1280;
	debugMarker.y = roadTop;
	debugTxt = new Text2('Debug Info', {
		size: 50,
		fill: "#ff0000"
	});
	debugTxt.anchor.set(1, 1); // Set anchor to the bottom right corner
	LK.gui.bottomRight.addChild(debugTxt);
	isPlaying = false;
}
gameInitialize();
// DEVLOG:
// Add obstacles assets switch depending on level and a goal text to inform of collect goal ===================================================================
--- original.js
+++ change.js
@@ -1116,12 +1116,14 @@
 * Game Code
 ****/ 
 function updateGoalForLevel(level) {
 	if (level === 1) {
-		goalText.setText('COLLECT\r\n$0.10');
-		goalText.setText('COLLECT\r\n$1.00');
-		goalText.setText('COLLECT\r\n$100.00');
-	} else if (level === 2) {} else if (level === 3) {}
+		goalText.setText('COLLECT\r\n$10');
+	} else if (level === 2) {
+		goalText.setText('COLLECT\r\n$100');
+	} else if (level === 3) {
+		goalText.setText('COLLECT\r\n$1 000 000');
+	}
 	goalText.visible = true;
 	LK.setTimeout(function () {
 		goalText.visible = false;
 	}, goalAnnounceDelay);
@@ -1134,22 +1136,19 @@
 var lastObstacleSpawnTime = 0; // Track the last time an obstacle was spawned
 var levelConfigs = [{}, {
 	name: "Level 1",
 	backgroundTint: 0xeda716,
-	coinValue: 10,
-	// Value in cents
+	coinValue: 0.10,
 	baseSpeed: 10
 }, {
 	name: "Level 2",
 	backgroundTint: 0x2faf1d,
-	coinValue: 100,
-	// Value in cents
+	coinValue: 1,
 	baseSpeed: 15
 }, {
 	name: "Level 3",
 	backgroundTint: 0x6c6060,
-	coinValue: 10000,
-	// Value in cents
+	coinValue: 100,
 	baseSpeed: 20
 }];
 var stripes = [];
 var nbDecorations = 10;
@@ -1210,27 +1209,29 @@
 function updateScore() {
 	var negative = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
 	if (negative) {
 		if (score > 0) {
-			moneyLost += Math.min(Math.round((levelConfigs[currentLevel].coinValue || 1) * 100), score);
+			moneyLost += Math.min(levelConfigs[currentLevel].coinValue || 1, score);
 		}
-		score -= Math.round((levelConfigs[currentLevel].coinValue || 1) * 100);
+		score -= levelConfigs[currentLevel].coinValue || 1;
+		score = parseFloat(score.toFixed(1));
 		score = Math.max(0, score); // Ensure score doesn't go below 0
 	} else {
-		score += Math.round((levelConfigs[currentLevel].coinValue || 1) * 100);
+		score += levelConfigs[currentLevel].coinValue || 1;
+		score = parseFloat(score.toFixed(1));
 		coinsCollected += 1; // Increment coins collected counter
 	}
 	if (coinsCollected >= nextLevelCoinThreshold * currentLevel) {
 		changeLevel(currentLevel + 1);
 	}
 	// Format score
-	log("score=", score, " => ", score + "¢");
-	if (score < 100) {
-		scoreTxt.setText(score + "¢");
-	} else if (score < 1000) {
-		scoreTxt.setText("$" + (score / 100).toFixed(2));
+	log("score=", score, " => ", (score * 100).toFixed(0) + "¢");
+	if (score < 1) {
+		scoreTxt.setText((score * 100).toFixed(0) + "¢");
+	} else if (score < 10) {
+		scoreTxt.setText("$" + score.toFixed(2));
 	} else {
-		scoreTxt.setText("$" + Math.floor(score / 100));
+		scoreTxt.setText("$" + Math.floor(score));
 	}
 }
 // Function to change the level
 function changeLevel(newLevel) {
@@ -1238,9 +1239,9 @@
 	log("changeLevel:", newLevel);
 	newLevel = Math.max(1, Math.min(levelConfigs.length, newLevel));
 	currentLevel = newLevel;
 	currentSpeed = levelConfigs[currentLevel].baseSpeed;
-	nextLevelCoinThreshold = levelConfigs[currentLevel].coinValue * 10 / 100; // Example threshold calculation
+	nextLevelCoinThreshold = levelConfigs[currentLevel].coinValue * 10; // Example threshold calculation
 	console.log("Level changed to:", currentLevel);
 	// Add a big white flash effect
 	LK.effects.flashScreen(0xFFFFFF, 1000); // Flash white for 1 second
 	// Change background tint using levelConfig
@@ -1384,9 +1385,9 @@
 	road.y = 0;
 	if (road) {
 		//road.updateForLevel(currentLevel);
 	}
-	score = 0; // Initialize score as an integer representing cents
+	score = 0;
 	scoreTxt = new Text2('0¢', {
 		size: 150,
 		fill: "#ffffff",
 		dropShadow: true,
:quality(85)/https://cdn.frvr.ai/66cb777cc36bc8152d8f8031.png%3F3) 
 Directly overhead, plumb view of a beggar heading top (we see his back).. Zenith view, directly overhead, plumb view. NOT PERSPECTIVE! Fantasy theme. Pixel art
:quality(85)/https://cdn.frvr.ai/66ccf14b9c4e45d382d11309.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66ce18e5423e03c81f87a015.png%3F3) 
 a traffic cone. video game sprite
:quality(85)/https://cdn.frvr.ai/66ce2581423e03c81f87a053.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66ce25c4423e03c81f87a056.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d0bbac423e03c81f87a179.png%3F3) 
 face view of a big start button in the shape of a dollar bill. video game style
:quality(85)/https://cdn.frvr.ai/66d1fc0e4c0bfbf86463ae2d.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d428c01a40feadd85fc2ad.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d42e241a40feadd85fc2e9.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d43f291a40feadd85fc37b.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d490b11a40feadd85fc4af.png%3F3) 
 a tree. video game style
:quality(85)/https://cdn.frvr.ai/66d4d0c367ce33ddda304025.png%3F3) 
 a black garbage bag. video game style
:quality(85)/https://cdn.frvr.ai/66d4de00401d2c2487b96f5a.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d4e47c651049126fa096cc.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d4e4be401d2c2487b96f78.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d555bd651049126fa096f0.png%3F3) 
 Dollar bill. Perspective. video game sprite
:quality(85)/https://cdn.frvr.ai/66d6f447a3e8b4a4a4829fb3.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d844022a19586325bec80d.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d844362a19586325bec810.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d8c2645c7c6fbac545d122.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66d9373598ec289fd45d77b2.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66dd38dddaaa27ee3942c131.png%3F3) 
 perspective of a simple snake rolled up on itself.. video game sprite
:quality(85)/https://cdn.frvr.ai/66dd3a2bdaaa27ee3942c13e.png%3F3) 
 Ball of dry desert bushes. video game sprite
:quality(85)/https://cdn.frvr.ai/66dd3c02daaa27ee3942c154.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66ddb2e9bf754a83aa523fb1.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66ddb7aecc485d4eb466960b.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66de8560d88e3b2f9d0d34dd.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66e0a42193e17031e44d9902.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66e0a8f4ccaaa6aa21e29430.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66e2701b2345adf8f56be232.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66e271832345adf8f56be236.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66e271d62345adf8f56be241.png%3F3) 
 tractor. high definition video game sprite
:quality(85)/https://cdn.frvr.ai/66e272f12345adf8f56be257.png%3F3) 
 street ad billboard with 1 or 2 posts with "Get rich!" on it. high definition video game sprite
:quality(85)/https://cdn.frvr.ai/66e278682345adf8f56be29e.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66e27f5a2345adf8f56be2fe.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66e35a3953e2dd7786ae56f8.png%3F3) 
 a dog sleeping on a street. video game sprite
:quality(85)/https://cdn.frvr.ai/66e35caa53e2dd7786ae571a.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66e887ca939ae2c335f047d6.png%3F3) 
 desert bush. video game sprite
:quality(85)/https://cdn.frvr.ai/66f09079353aeac5eb1686c0.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66f09358353aeac5eb1686cc.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66f0985a353aeac5eb168728.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66f09a6c353aeac5eb16875a.png%3F3) 
 profile view of an empty motorcycle helmet. black with a white vertical central band and another thiner orange band on the center. NOT PERSPECTIVE!. Pixel art high definition
:quality(85)/https://cdn.frvr.ai/66f09bc6353aeac5eb16879c.png%3F3) 
 simple red and white magnet. video game style
:quality(85)/https://cdn.frvr.ai/66f0f3e0673e5ef9433cb9ac.png%3F3) 
 gold sign with a "X" and a "2". video game style
:quality(85)/https://cdn.frvr.ai/66f14bbd07176eca63330db8.png%3F3) 
 bgMusic
Music
coin_1
Sound effect
hit_1
Sound effect
hit_2
Sound effect
hit_3
Sound effect
levelWin_1
Sound effect
car_1
Sound effect
police_1
Sound effect
ambulance_1
Sound effect
accident_1
Sound effect
killed_1
Sound effect
jump_1
Sound effect
rip_1
Sound effect
bonus_take
Sound effect
bonus_approaching
Sound effect