Code edit (6 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var distance = obstacles[self.lineIndex][0].x - nextX;' Line Number: 173
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var distance = obstacles[self.lineIndex][0].x - nextX;' Line Number: 171
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (22 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: deltaSpeed is not defined' in or related to this line: 'if (distance > 0 && distance <= 250) {' Line Number: 164
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'globalSpeedPerLine[line] = globalBaseSpeed;' Line Number: 621
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'length')' in or related to this line: 'if (!obstacles[line].length && !finishLine.isCut) {' Line Number: 836
Code edit (1 edits merged)
Please save this source code
Code edit (17 edits merged)
Please save this source code
User prompt
in updateProgress, when (finishLine.isCut) , reduce globalSpeedPerLine[line] to 0 progressievly
Code edit (1 edits merged)
Please save this source code
Code edit (4 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: clearInterval is not a function' in or related to this line: 'clearInterval(cutInterval);' Line Number: 351
Code edit (9 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: setInterval is not a function' in or related to this line: 'var cutInterval = setInterval(function () {' Line Number: 345
User prompt
in FinishLine, make the cut pregressive
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
/**** 
* Classes
****/ 
/****************************************************************************************** */ 
/**************************************** CLASSES ***************************************** */
/****************************************************************************************** */ 
/****************************************************************************************** */ 
/************************************* ATHLETE CLASS ************************************** */
/****************************************************************************************** */ 
var Athlete = Container.expand(function (line) {
	var self = Container.call(this);
	self.speedX = -1 * globalSpeedPerLine[line];
	self.jumpSpeed = -17;
	self.lastJumpTime = 0;
	self.interJumpDelayMs = 500;
	self.gravity = 0.5;
	self.lineIndex = line;
	self.isAi = line > 0;
	self.isOnGround = true;
	self.isRunning = false;
	self.isFalling = false; // Indicates if the athlete is currently falling
	self.currentPosture = ""; // Store the name of the current posture
	self.isChangingPosture = false; // 0 when idle or moving down, 1 when moving up
	self.nextPosture = null;
	self.tint = colorsArray[self.lineIndex % colorsArray.length];
	self.previousX = 0;
	// BODY PARTS
	self.trunk = self.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1,
		scaleY: 1,
		rotation: 0.125,
		tint: 0x000000 //self.tint // TEMP DEBUG
	});
	self.head = self.trunk.attachAsset('head', {
		anchorX: 0.5,
		anchorY: 2,
		scaleX: 1,
		scaleY: 1,
		tint: 0x000000 // self.tint
	});
	self.rightArm = self.trunk.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0,
		scaleX: 1,
		scaleY: 1,
		tint: self.tint
	});
	// Right hand asset attachment removed
	self.leftArm = self.trunk.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0,
		scaleX: 1,
		scaleY: 1,
		tint: self.tint
	});
	// Left hand asset attachment removed
	self.rightLeg = self.trunk.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0,
		scaleX: 1,
		scaleY: 1.0,
		tint: self.tint
	});
	// Right foot asset attachment removed
	self.leftLeg = self.trunk.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0,
		scaleX: 1,
		scaleY: 1.0,
		tint: self.tint
	});
	// Left foot asset attachment removed
	// FUNCTIONS
	self.updatePosture = function () {
		var speed = 0.2; // Speed of transition
		if (!self.targetPosture) {
			//log("no targetPosture.");
			return;
		}
		// Check if the target posture for hands and legs is reached
		//log("self.targetPosture: " + self.targetPosture.name + " :  self.rightHand.x: " + self.rightHand.x, " self.targetPosture.rightHand.x: " + self.targetPosture.rightHand.x);
		var handsAndLegsReached = Math.abs(self.rightLeg.x - self.targetPosture.rightLeg.x) < 1 && Math.abs(self.rightLeg.y - self.targetPosture.rightLeg.y) < 1 && Math.abs(self.leftLeg.x - self.targetPosture.leftLeg.x) < 1 && Math.abs(self.leftLeg.y - self.targetPosture.leftLeg.y) < 1 && Math.abs(self.head.x - self.targetPosture.head.x) < 1 && Math.abs(self.head.y - self.targetPosture.head.y) < 1;
		if (handsAndLegsReached) {
			log("handsAndLegsReached !");
			// Update currentPosture to the name of the targetPosture when hands and legs posture is reached
			self.currentPosture = self.targetPosture.name;
			self.targetPosture = null;
			self.isChangingPosture = false;
			if (self.nextPosture) {
				self.setPosture(self.nextPosture);
			}
			return;
		} else {
			self.isChangingPosture = true;
		}
		if (self.targetPosture && self.targetPosture.head) {
			self.head.x += (self.targetPosture.head.x - self.head.x) * speed;
		}
		self.trunk.rotation += (self.targetPosture.trunk.r - self.trunk.rotation) * speed;
		self.head.y += (self.targetPosture.head.y - self.head.y) * speed;
		self.rightArm.x += (self.targetPosture.rightArm.x - self.rightArm.x) * speed;
		self.rightArm.y += (self.targetPosture.rightArm.y - self.rightArm.y) * speed;
		self.rightArm.rotation += (self.targetPosture.rightArm.r - self.rightArm.rotation) * speed;
		//log("Posture rightArm.rotation=" + self.rightArm.rotation);
		// Right hand updates removed due to hand assets being removed
		self.leftArm.x += (self.targetPosture.leftArm.x - self.leftArm.x) * speed;
		self.leftArm.y += (self.targetPosture.leftArm.y - self.leftArm.y) * speed;
		self.leftArm.rotation += (self.targetPosture.leftArm.r - self.leftArm.rotation) * speed;
		// Left hand updates removed due to hand assets being removed
		self.trunk.x += (self.targetPosture.trunk.x - self.trunk.x) * speed;
		self.trunk.y += (self.targetPosture.trunk.y - self.trunk.y) * speed;
		self.rightLeg.x += (self.targetPosture.rightLeg.x - self.rightLeg.x) * speed;
		self.rightLeg.y += (self.targetPosture.rightLeg.y - self.rightLeg.y) * speed;
		// Right foot updates removed due to foot assets being removed
		self.leftLeg.x += (self.targetPosture.leftLeg.x - self.leftLeg.x) * speed;
		self.leftLeg.y += (self.targetPosture.leftLeg.y - self.leftLeg.y) * speed;
	};
	self.update = function () {
		if (!self.isFalling) {
			if (self.isOnGround) {
				self.leftLeg.height = 200;
				self.leftArm.height = 200;
				self.trunk.rotation = 0.125;
				if (self.isRunning) {
					self.runAnim();
				}
			} else {
				if (self.lineIndex == 3) {
					log("Current pultiplier=" + Math.abs(globalSpeedPerLine[self.lineIndex] / 10));
				}
				self.speedY += self.gravity * Math.abs(globalSpeedPerLine[self.lineIndex] / 10); //self.lineIndex
				self.y += self.speedY * Math.abs(globalSpeedPerLine[self.lineIndex] / 10); //self.lineIndex
				//log("self.speedY=" + self.speedY, " / self.y=" + self.y);
				if (self.y >= linesGroundLevels[self.lineIndex]) {
					self.y = linesGroundLevels[self.lineIndex];
					self.isOnGround = true;
					self.speedY = 0;
				} else {
					self.jumpAnim();
				}
			}
		} else {
			self.y += 5;
			if (self.y >= linesGroundLevels[self.lineIndex] + 200) {
				self.y = linesGroundLevels[self.lineIndex] + 200;
				self.isOnGround = true;
				self.speedY = 0;
			}
		}
		self.updatePosture();
		/* ********************************************************** ATHLETE AI **************************************************** */
		if (self.isAi) {
			var nextX = self.x;
			if (!self.isFalling) {
				if (athlete.isFalling) {
					if (self.lineIndex == 3) {
						log("Player falls add=" + self.speedX);
					}
					//nextX += self.speedX;
					nextX -= globalSpeedPerLine[self.lineIndex] * 1.5;
				} else {
					//nextX += globalSpeedPerLine[self.lineIndex] * 0.5 * Math.random();
				}
				if (!athlete.isFalling && !athlete.isOnGround) {
					// Little advance when player plays jumping
					if (self.lineIndex == 3) {
						log("Player jumping add=" + self.speedX * 0.1);
					}
					//nextX += self.speedX * 0.1;
				}
			}
			// Auto jump hurdles in obstacles[self.lineIndex]
			if (self.isOnGround) {
				if (globalSlowDownAfterJump) {
					if (self.lineIndex == 3) {
						log("globalSlowDownAfterJump SET=-10");
					}
					globalSpeedPerLine[self.lineIndex] = -10;
				}
				if (obstacles[self.lineIndex].length) {
					var distance = obstacles[self.lineIndex][0].x - nextX;
					if (self.lineIndex == 3) {
						log("distance=" + distance);
					}
					if (distance > 0 && distance <= 250 + self.speedX) {
						self.jump();
					}
				}
			}
			self.x = nextX;
			self.previousX = self.x;
		}
	};
	self.jump = function () {
		if (Date.now() - self.lastJumpTime > self.interJumpDelayMs) {
			if (self.isOnGround) {
				self.isOnGround = false;
				self.speedY = self.jumpSpeed;
				self.lastJumpTime = Date.now();
				//globalSpeedPerLine[self.lineIndex] = globalSpeedPerLine[self.lineIndex] * 1.1;
				if (self.lineIndex == 3) {
					log("--------------- JUMP --------------------");
				}
			}
		}
	};
	self.runAnim = function () {
		var ocsilDelay = 5;
		var armsAmplitude = 0.5;
		var legsAmplitude = 0.5;
		// Simulate running by continuously balancing the arms and legs
		var runningArmAngle = Math.sin(LK.ticks / ocsilDelay) * armsAmplitude; // Oscillate arm angle to simulate running faster
		var runningLegAngle = Math.sin(LK.ticks / ocsilDelay) * legsAmplitude; // Oscillate leg angle to simulate running faster
		var armSwitchProgress = (Math.sin(LK.ticks / 5) + 0) / 2; // Normalize between 0 and 1
		self.rightArm.x = 10 * (1 - armSwitchProgress) - 5 * armSwitchProgress;
		self.leftArm.x = -15 * (1 - armSwitchProgress) + 20 * armSwitchProgress;
		self.rightLeg.x = 5 * (1 - armSwitchProgress) - 5 * armSwitchProgress;
		self.leftLeg.x = -10 * (1 - armSwitchProgress) + 10 * armSwitchProgress;
		//log("Run rightArm.rotation=" + runningArmAngle);
		self.rightArm.rotation = runningArmAngle;
		self.leftArm.rotation = -runningArmAngle;
		self.rightLeg.rotation = -runningLegAngle;
		self.leftLeg.rotation = runningLegAngle;
		self.trunk.width = 30 - 10 * (runningArmAngle * Math.PI * 0.5);
		self.head.width = 50 - 10 * (runningArmAngle * Math.PI * 0.5);
	};
	self.jumpAnim = function () {
		var ocsilDelay = 50;
		var armsAmplitude = 1;
		// Simulate running by continuously balancing the arms and legs
		var runningArmAngle = Math.sin(LK.ticks / ocsilDelay) * armsAmplitude; // Oscillate arm angle to simulate running faster
		var armSwitchProgress = (Math.sin(LK.ticks / 5) + 0) / 2; // Normalize between 0 and 1
		self.rightArm.x = 10 * (1 - armSwitchProgress) - 5 * armSwitchProgress;
		self.leftArm.x = -15 * (1 - armSwitchProgress) + 20 * armSwitchProgress;
		self.rightLeg.x = 5 * (1 - armSwitchProgress) - 5 * armSwitchProgress;
		self.leftLeg.x = -10 * (1 - armSwitchProgress) + 10 * armSwitchProgress;
		self.trunk.width = 30 - 10 * (runningArmAngle * Math.PI * 0.5); //armSwitchProgress; // + 10 * Math.abs(runningArmAngle);
		self.trunk.rotation = 0.333; //armSwitchProgress; // + 10 * Math.abs(runningArmAngle);
		var rotationSpeed = 0.05; // Speed of rotation change
		if (self.speedY > 0) {
			self.rightArm.rotation += (0 - self.rightArm.rotation) * rotationSpeed % (Math.PI * 2);
			self.leftArm.rotation += (0 - self.leftArm.rotation) * rotationSpeed % (Math.PI * 2);
			// Return legs to initial rotation when descending
			self.rightLeg.rotation += (0 - self.rightLeg.rotation) * rotationSpeed;
			self.leftLeg.rotation += (0 - self.leftLeg.rotation) * rotationSpeed;
			self.leftLeg.height -= 30 * rotationSpeed;
			self.leftArm.height -= 20 * rotationSpeed;
		} else {
			//log("self.rightArm.rotation=" + self.rightArm.rotation, " + " + -Math.PI * 3 * rotationSpeed % (Math.PI * 2));
			self.rightArm.rotation += -Math.PI * 3 * rotationSpeed % (Math.PI * 2);
			self.leftArm.rotation += Math.PI * 1.75 * rotationSpeed % (Math.PI * 2);
			// Continue with jump animation adjustments
			self.rightLeg.rotation += (-2.6 - self.rightLeg.rotation) * rotationSpeed;
			self.leftLeg.rotation += (1 - self.leftLeg.rotation) * rotationSpeed;
			self.leftLeg.height -= 0 * rotationSpeed;
			self.leftArm.height -= 35 * rotationSpeed;
		}
	};
	self.fallAnim = function () {
		var fallSpeed = 0.1; // Speed of fall animation
		// Adjust body parts to simulate falling
		self.trunk.rotation += (Math.PI / 2 - self.trunk.rotation) * fallSpeed;
		self.rightArm.rotation += (Math.PI / 2 - self.rightArm.rotation) * fallSpeed;
		self.leftArm.rotation += (Math.PI / 2 - self.leftArm.rotation) * fallSpeed;
		self.rightLeg.rotation += (Math.PI / 2 - self.rightLeg.rotation) * fallSpeed;
		self.leftLeg.rotation += (Math.PI / 2 - self.leftLeg.rotation) * fallSpeed;
	};
	self.setPosture = function (newPosture) {
		log("Set posture: " + newPosture.name);
		self.targetPosture = newPosture;
	};
	self.restore = function () {
		log("restore...");
		self.x = self.previousX || 400 + 100 * self.lineIndex;
		self.y = linesGroundLevels[self.lineIndex];
		self.speedY = 0;
		self.trunk.rotation = 0;
		self.rightArm.rotation = idlePosture.rightArm.r;
		self.leftArm.rotation = 0;
		self.rightLeg.rotation = 0;
		self.leftLeg.rotation = 0;
		self.setPosture(idlePosture);
		self.isFalling = false;
		self.isOnGround = true;
		self.hasFlashed = false;
		self.hasFlashedGround = false;
		self.isRunning = true;
	};
});
/****************************************************************************************** */ 
/************************************** FINISH LINE CLASS ************************************ */
/****************************************************************************************** */ 
var FinishLine = Container.expand(function () {
	var self = Container.call(this);
	self.isCut = false;
	self.rightRod = self.attachAsset('obstacle', {
		anchorX: 0.5,
		anchorY: 0.0,
		x: 355,
		y: -1120
	});
	self.centralRodRight = self.attachAsset('finishLine', {
		anchorX: 0.5,
		anchorY: 1,
		y: -200,
		rotation: Math.PI * 0.125,
		tint: 0xFF0000
	});
	self.centralRodLeft = self.attachAsset('finishLine', {
		anchorX: 0.5,
		anchorY: 0,
		x: 355,
		y: -1060,
		rotation: Math.PI * 2.125,
		tint: 0xFF0000,
		height: 450
	});
	self.leftRod = self.attachAsset('obstacle', {
		anchorX: 0.5,
		anchorY: 1.0 // Anchor at the bottom for collision detection
	});
	self.speedX = globalSpeedPerLine[0];
	self.update = function () {
		self.speedX = globalSpeedPerLine[0];
		self.x += self.speedX;
	};
	self.cut = function () {
		var cutHeight = 50; // Amount to reduce the height each frame
		var cutDuration = 5000; // Duration of the cut in milliseconds
		var cutRate = cutDuration / (60 * (self.centralRodRight.height / cutHeight)); // Calculate how often to cut based on 60 FPS and total height
		var cutCounter = 0;
		var cutInterval = LK.setInterval(function () {
			if (cutCounter < cutRate) {
				self.centralRodRight.height -= cutHeight;
				self.centralRodLeft.height -= cutHeight;
				cutCounter++;
			} else {
				LK.clearInterval(cutInterval);
			}
		}, 1000 / 60); // Execute at roughly 60 FPS
	};
});
/****************************************************************************************** */ 
/************************************** OBSTACLE CLASS ************************************ */
/****************************************************************************************** */ 
// Obstacle class
var Obstacle = Container.expand(function (line) {
	var self = Container.call(this);
	self.lineIndex = line;
	self.leftRod = self.attachAsset('obstacle', {
		anchorX: 0.5,
		anchorY: 1.0 // Anchor at the bottom for collision detection
	});
	self.centralRod = self.attachAsset('obstacle', {
		anchorX: 0.5,
		anchorY: 1,
		y: -200,
		rotation: Math.PI * 0.125,
		tint: 0xffff00 // Apply a yellow tint for glow effect
	});
	self.rightRod = self.attachAsset('obstacle', {
		anchorX: 0.5,
		anchorY: 0.0,
		x: 95,
		y: -460
	});
	self.speedX = globalSpeedPerLine[0];
	self.update = function () {
		self.speedX = globalSpeedPerLine[0];
		self.x += self.speedX;
	};
});
/****************************************************************************************** */ 
/************************************** TRACK CLASS ************************************ */
/****************************************************************************************** */ 
var Track = Container.expand(function (index) {
	var self = Container.call(this);
	self.speedX = globalSpeedPerLine[0]; // Use global speed for track movement
	// Attach track asset
	self.trackAsset = self.attachAsset(index % 2 ? 'track' : 'trackOdd', {
		anchorX: 0.0,
		anchorY: 0.0
	});
	// Method to update track position
	self.update = function () {
		self.speedX = globalSpeedPerLine[0];
		self.x += self.speedX;
		// Reset position to create a continuous track effect
		if (self.x <= -2048 - self.speedX * 2) {
			self.x = 2048 + self.speedX * 2;
		}
	};
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x87CEEB // Light blue background to represent the sky
});
/**** 
* Game Code
****/ 
// Enumeration for game states
/****************************************************************************************** */ 
/************************************** GLOBAL VARIABLES ********************************** */
/****************************************************************************************** */ 
var GAME_STATE = {
	INIT: 'INIT',
	MENU: 'MENU',
	HELP: 'HELP',
	STARTING: 'STARTING',
	NEW_ROUND: 'NEW_ROUND',
	PLAYING: 'PLAYING',
	SCORE: 'SCORE'
};
var gameState = GAME_STATE.INIT;
var athlete;
var opponents = [];
var numberOfOpponents = 3; // Adjust based on the actual number of opponents in the game
var groundLevel = 2732 - 200; // Ground level set 200px from the bottom
var linesGroundLevels = []; // Ground level set 200px from the bottom
var numberOfLines = 1 + numberOfOpponents;
var numberOfObstacles = 20; // Total number of hurdles
var obstacles = [[]];
var obstacleSpawnTicker = 0;
var obstacleSpawnDistanceRate = 1.5; // Ratio of screen width between obstacles
var obstacleJustPassed = false;
var finishLine;
var stadium;
var stadiumOdd;
var field;
var fieldOdd;
var farfield;
var farfieldOdd;
var track;
var track2;
var track3;
var track4;
var scoreTxt;
var globalSpeedBase = -20;
var globalSpeedIncreaseStep = 0; //5; TEMP DEBUG
var globalSlowDownAfterJump = false;
var globalSpeedPerLine = []; // Global speed for tracks and obstacles default -10 / min = -4
var colorsArray = [0x1188FF, 0xFF0000, 0x00FF00, 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFFFFF, 0xFF8811];
var isDebug = true;
var debugMarker;
// UI
var startText;
var startButton;
/****************************************************************************************** */ 
/************************************** POSTURES ****************************************** */
/****************************************************************************************** */ 
var idlePosture = {
	name: "idlePosture",
	trunk: {
		x: 0,
		y: 0,
		r: 0.125
	},
	head: {
		x: 0,
		y: 0
	},
	rightArm: {
		x: 20,
		y: -80,
		r: 0 //Math.PI * 2 * 0.0
	},
	leftArm: {
		x: -20,
		y: -80,
		r: 0 //Math.PI * 2 * 0.125
	},
	rightLeg: {
		x: 5,
		y: 100
	},
	leftLeg: {
		x: -5,
		y: 100
	}
};
/****************************************************************************************** */ 
/*********************************** UTILITY FUNCTIONS ************************************ */
/****************************************************************************************** */ 
function log() {
	if (isDebug) {
		var _console;
		(_console = console).log.apply(_console, arguments);
	}
}
/****************************************************************************************** */ 
/************************************** INPUT HANDLERS ************************************ */
/****************************************************************************************** */ 
// Touch event to make the athlete jump
game.on('down', function () {
	switch (gameState) {
		case GAME_STATE.MENU:
			// Handle menu logic here
			break;
		case GAME_STATE.STARTING:
			// Handle game starting logic here
			break;
		case GAME_STATE.PLAYING:
			gamePlayingDown();
			break;
		case GAME_STATE.SCORE:
			// Handle score display logic here
			break;
	}
});
function gamePlayingDown() {
	// Make the athlete jump
	athlete.jump();
}
/****************************************************************************************** */ 
/************************************* AI FUNCTIONS *************************************** */
/****************************************************************************************** */ 
/****************************************************************************************** */ 
/************************************* GAME STATES **************************************** */
/****************************************************************************************** */ 
function gameInitialize() {
	log("Game initialize...");
	// Add background asset
	scoreTxt = new Text2('0', {
		size: 100,
		fill: "#ffffff" // White color for better visibility
	});
	scoreTxt.anchor.set(1.1, 0.15); // Center the score text horizontally
	LK.gui.topRight.addChild(scoreTxt); // Add the score text to the GUI overlay at the top center
	var background = LK.getAsset('background', {
		anchorX: 0.0,
		anchorY: 0.0,
		y: -256,
		visible: true
	});
	game.addChild(background);
	field = LK.getAsset('field', {
		anchorX: 0.0,
		anchorY: 0.0,
		y: 2732 - 1024 - 600
	});
	game.addChild(field);
	fieldOdd = LK.getAsset('fieldOdd', {
		anchorX: 0.0,
		anchorY: 0.0,
		x: 2048,
		y: 2732 - 1024 - 600
	});
	game.addChild(fieldOdd);
	farField = LK.getAsset('farField', {
		anchorX: 0.0,
		anchorY: 0.0,
		y: 2732 - 1024 - 600 - 512
	});
	game.addChild(farField);
	farFieldOdd = LK.getAsset('farFieldOdd', {
		anchorX: 0.0,
		anchorY: 0.0,
		x: 2048,
		y: 2732 - 1024 - 600 - 512
	});
	game.addChild(farFieldOdd);
	stadium = LK.getAsset('stadium', {
		anchorX: 0.0,
		anchorY: 0.0,
		x: 0,
		y: 150
	});
	game.addChild(stadium);
	stadiumOdd = LK.getAsset('stadiumOdd', {
		anchorX: 0.0,
		anchorY: 0.0,
		x: 2048,
		y: 150
	});
	game.addChild(stadiumOdd);
	// Initialize track using Track class
	track = game.addChild(new Track(0));
	track.x = 0;
	track.y = 2732 - 512;
	// Second track instance for continuous effect
	track2 = game.addChild(new Track(1));
	track2.x = 2048; // Position the second track right after the first one
	track2.y = 2732 - 512;
	// Second line track 1
	track3 = game.addChild(new Track(2));
	track3.x = 0;
	track3.y = 2732 - 1024;
	// Second line track 2
	track4 = game.addChild(new Track(3));
	track4.x = 2048;
	track4.y = 2732 - 1024;
	// Initialize ground levels & speeds
	for (var line = 0; line < numberOfLines; line++) {
		linesGroundLevels[line] = groundLevel - 200 - 220 * line;
		if (typeof globalBaseSpeed !== 'undefined') {
			globalSpeedPerLine[line] = globalBaseSpeed;
		} else {
			console.error('globalBaseSpeed is not defined');
		}
	}
	// Add Button in the center of the screen
	startButton = LK.getAsset('button', {
		anchorX: 0.5,
		// Center the button horizontally
		anchorY: 0.5,
		// Center the button vertically
		x: 2048 / 2,
		// Position horizontally in the center
		y: 2732 / 2 // Position vertically above the start text
	});
	game.addChild(startButton);
	startButton.on('down', function () {
		cleanMenuState();
		initPlayingState();
	});
	// Add Start Text in the center of the screen
	startText = new Text2('START', {
		size: 200,
		fill: "#ffffff" // White color for better visibility
	});
	startText.anchor.set(0.5, 0.5); // Center the text horizontally and vertically
	startText.x = 2048 / 2; // Center horizontally
	startText.y = 2732 / 2; // Center vertically
	game.addChild(startText);
	gameState = GAME_STATE.MENU;
	if (isDebug) {
		// Debug Marker
		debugMarker = LK.getAsset('debugMarker', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		game.addChild(debugMarker);
		debugMarker.x = 0;
		debugMarker.y = groundLevel;
	}
}
function gamePlaying() {
	//log("Game playing...");
	// Update fields
	updateFields();
	// Update obstacles
	updateObstacles();
	// Update tracks
	updateTracks();
	// Update Progress
	updateProgress();
	// Update opponents
	for (var i = numberOfOpponents - 1; i >= 0; i--) {
		opponents[i].update();
		game.addChild(opponents[i]);
	}
	// Update athlete
	athlete.update();
	game.addChild(athlete);
	// Check for collisions
	checkForCollisions();
}
function cleanMenuState() {
	game.removeChild(startText);
	game.removeChild(startButton);
}
function initPlayingState() {
	// Spawn obstacles
	spawnObstacles();
	// Initialize opponents
	for (var i = numberOfOpponents - 1; i >= 0; i--) {
		opponents[i] = game.addChild(new Athlete(i + 1));
		opponents[i].restore();
	}
	// Initialize athlete
	athlete = game.addChild(new Athlete(0));
	athlete.restore();
	gameState = GAME_STATE.PLAYING;
}
/****************************************************************************************** */ 
/************************************** GAME FUNCTIONS ************************************ */
/****************************************************************************************** */ 
function updateFields() {
	if (!(athlete.isFalling && athlete.isOnGround)) {
		field.x += globalSpeedPerLine[0];
		// Reset position to create a continuous effect
		if (field.x <= -2048 - globalSpeedPerLine[0]) {
			field.x = 2048 + globalSpeedPerLine[0];
		}
		fieldOdd.x += globalSpeedPerLine[0];
		// Reset position to create a continuous effect
		if (fieldOdd.x <= -2048 - globalSpeedPerLine[0]) {
			fieldOdd.x = 2048 + globalSpeedPerLine[0];
		}
		// Far field
		farField.x += globalSpeedPerLine[0] * 0.8;
		// Reset position to create a continuous effect
		if (farField.x <= -2048 - globalSpeedPerLine[0]) {
			farField.x = 2048 + globalSpeedPerLine[0];
		}
		farFieldOdd.x += globalSpeedPerLine[0] * 0.8;
		// Reset position to create a continuous effect
		if (farFieldOdd.x <= -2048 - globalSpeedPerLine[0]) {
			farFieldOdd.x = 2048 + globalSpeedPerLine[0];
		}
		stadium.x += globalSpeedPerLine[0] * 0.4;
		// Reset position to create a continuous effect
		if (stadium.x <= -2048 - globalSpeedPerLine[0]) {
			stadium.x = 2048 + globalSpeedPerLine[0];
		}
		stadiumOdd.x += globalSpeedPerLine[0] * 0.4;
		// Reset position to create a continuous effect
		if (stadiumOdd.x <= -2048 - globalSpeedPerLine[0]) {
			stadiumOdd.x = 2048 + globalSpeedPerLine[0];
		}
	}
}
function updateTracks() {
	if (!(athlete.isFalling && athlete.isOnGround)) {
		track.update();
		track2.update();
		track3.update();
		track4.update();
	}
}
function spawnObstacles() {
	// Set obstacles for line 0
	obstacles[0] = [];
	for (var i = 0; i < numberOfObstacles; i++) {
		// 3 obstacles per line
		var newObstacle = new Obstacle(0);
		newObstacle.x = 2048 * obstacleSpawnDistanceRate * (i + 1); // Start from the right edge      
		//log("Obstacle "+ 0+","+i+" +> x="+ newObstacle.x);
		newObstacle.y = groundLevel + 200;
		obstacles[0].push(newObstacle);
		game.addChild(newObstacle);
	}
	// Set obstacles for other lines
	for (var line = 1; line < numberOfLines; line++) {
		obstacles[line] = [];
		for (var i = 0; i < numberOfObstacles; i++) {
			// 3 obstacles per line
			var newObstacle = new Obstacle(line);
			newObstacle.x = obstacles[0][i].x + 100 * line; // Start from the right edge      
			//log("Obstacle "+ line+","+i+" +> x="+ newObstacle.x);
			newObstacle.y = groundLevel + 200 - 220 * line;
			obstacles[line].push(newObstacle);
			game.addChild(newObstacle);
		}
	}
	finishLine = new FinishLine();
	finishLine.x = 2048 * obstacleSpawnDistanceRate * (numberOfObstacles + 1); // Start from the right edge      
	finishLine.y = groundLevel + 200;
	game.addChild(finishLine);
}
function updateObstacles() {
	// Update obstacles
	for (var line = 0; line < numberOfLines; line++) {
		obstacles[line] = obstacles[line] || [];
		for (var i = obstacles[line].length - 1; i >= 0; i--) {
			obstacles[line][i].update();
			// Remove obstacle if it moves off-screen and increase global speed
			if (obstacles[line][i].x < -100) {
				// Assuming obstacle width is less than 100px
				obstacles[line][i].destroy();
				obstacles[line].splice(i, 1);
				if (line == 0) {
					obstacleJustPassed = true;
				}
			}
		}
	}
	finishLine.update();
}
function updateProgress() {
	if (obstacleJustPassed && !finishLine.isCut) {
		// Update Progress
		obstacleJustPassed = false;
		LK.setScore(LK.getScore() + 1); // Add 1 to score for each hurdle passed only if not falling
		scoreTxt.setText(LK.getScore()); // Update score text with prefix
		// Increase global speed after each obstacle passed and add 1 to score only if not falling
		for (var line = 0; line < numberOfLines; line++) {
			globalSpeedPerLine[line] -= globalSpeedIncreaseStep;
			if (line == 3) {
				log("new Speed :" + globalSpeedPerLine[line]);
			}
		}
	}
	if (finishLine.isCut) {
		for (var line = 0; line < numberOfLines; line++) {
			// Ensure a smooth transition to 0 speed
			if (globalSpeedPerLine[line] < -0.25) {
				globalSpeedPerLine[line] += 0.25; // Decrement speed gradually
			} else if (globalSpeedPerLine[line] > 0.25) {
				globalSpeedPerLine[line] -= 0.25; // Increment speed gradually if somehow above 0
			} else {
				globalSpeedPerLine[line] = 0; // Set to 0 if very close to it
				if (athlete.isRunning) {
					athlete.isRunning = false;
					athlete.setPosture(idlePosture);
					opponents.forEach(function (opponent) {
						opponent.isRunning = false;
						opponent.setPosture(idlePosture);
					});
				}
			}
		}
	}
}
function checkForCollisions() {
	if (finishLine.isCut) {
		return;
	}
	for (var line = 0; line < numberOfLines; line++) {
		obstacles[line] = obstacles[line] || [];
		if (obstacles[line].length) {
			var obstacle = obstacles[line][0]; // Check only the first obstacle in the line
			if (line === 0) {
				if (athlete.intersects(obstacle.centralRod)) {
					athlete.isFalling = true;
					athlete.isOnGround = false;
					athlete.fallAnim(); // Call fall animation before game over
				}
			} else {
				if (opponents[line - 1].intersects(obstacle.centralRod)) {
					log("Line " + line + " : opponent " + opponents[line - 1].lineIndex + " collided with obstacle " + obstacle.lineIndex);
					opponents[line - 1].isFalling = true;
					opponents[line - 1].isOnGround = false;
					opponents[line - 1].fallAnim(); // Call fall animation before game over
				}
			}
		}
	}
	handleFallEvent();
	if (!obstacles[0].length && !finishLine.isCut) {
		var isReached = athlete.intersects(finishLine.centralRodRight);
		// opponents.forEach(function (opponent) {
		// 	isReached |= opponent.intersects(finishLine.centralRodRight);
		// });
		if (isReached) {
			finishLine.isCut = true;
			finishLine.cut();
		}
	}
}
function handleFallEvent() {
	if (athlete.isFalling && !athlete.hasFlashed) {
		LK.effects.flashScreen(0xaaaaaa, 500); // Flash screen red for half a second
		athlete.hasFlashed = true;
		globalSpeedPerLine[0] /= 1.5;
		// TEMP TEST FIX AI SPEED
		/*opponents.forEach(function (opponent) {
				globalSpeedPerLine[opponent.lineIndex] /= 1.5;
		});
		=> OK but make AI FALL
		*/
		globalSlowDownAfterJump = true;
		// TEMP TEST FIX AI SPEED
	}
	if (athlete.hasFlashed && !athlete.hasFlashedGround && athlete.isFalling && athlete.isOnGround) {
		LK.effects.flashScreen(0xff0000, 500); // Flash screen red for half a second
		athlete.hasFlashedGround = true;
		globalSpeedPerLine[0] = 0;
		LK.setTimeout(function () {
			globalSpeedPerLine[0] = globalBaseSpeed;
			globalSlowDownAfterJump = false;
			athlete.restore();
		}, 1000); // Delay game over to allow fall animation to be seen
	}
	opponents.forEach(function (opponent, index) {
		if (opponent.isFalling && !opponent.hasFlashed && !opponent.isOnGround) {
			opponent.hasFlashed = true;
			LK.setTimeout(function () {
				globalSpeedPerLine[opponent.lineIndex] = globalBaseSpeed;
				opponent.restore();
			}, 2000);
		}
	});
}
/****************************************************************************************** */ 
/************************************** MAIN GAME LOOP ************************************ */
/****************************************************************************************** */ 
LK.on('tick', function () {
	switch (gameState) {
		case GAME_STATE.MENU:
			// Handle menu logic here
			break;
		case GAME_STATE.STARTING:
			// Handle game starting logic here
			break;
		case GAME_STATE.PLAYING:
			gamePlaying();
			break;
		case GAME_STATE.SCORE:
			// Handle score display logic here
			break;
	}
});
gameInitialize(); ===================================================================
--- original.js
+++ change.js
@@ -116,21 +116,8 @@
 		// Right foot updates removed due to foot assets being removed
 		self.leftLeg.x += (self.targetPosture.leftLeg.x - self.leftLeg.x) * speed;
 		self.leftLeg.y += (self.targetPosture.leftLeg.y - self.leftLeg.y) * speed;
 	};
-	self.jump = function () {
-		if (Date.now() - self.lastJumpTime > self.interJumpDelayMs) {
-			if (self.isOnGround) {
-				self.isOnGround = false;
-				self.speedY = self.jumpSpeed;
-				self.lastJumpTime = Date.now();
-				globalSpeedPerLine[self.lineIndex] = globalSpeedPerLine[self.lineIndex] * 0.9;
-				if (self.lineIndex == 3) {
-					log("--------------- JUMP --------------------");
-				}
-			}
-		}
-	};
 	self.update = function () {
 		if (!self.isFalling) {
 			if (self.isOnGround) {
 				self.leftLeg.height = 200;
@@ -139,8 +126,11 @@
 				if (self.isRunning) {
 					self.runAnim();
 				}
 			} else {
+				if (self.lineIndex == 3) {
+					log("Current pultiplier=" + Math.abs(globalSpeedPerLine[self.lineIndex] / 10));
+				}
 				self.speedY += self.gravity * Math.abs(globalSpeedPerLine[self.lineIndex] / 10); //self.lineIndex
 				self.y += self.speedY * Math.abs(globalSpeedPerLine[self.lineIndex] / 10); //self.lineIndex
 				//log("self.speedY=" + self.speedY, " / self.y=" + self.y);
 				if (self.y >= linesGroundLevels[self.lineIndex]) {
@@ -168,26 +158,32 @@
 					if (self.lineIndex == 3) {
 						log("Player falls add=" + self.speedX);
 					}
 					//nextX += self.speedX;
-					nextX -= globalSpeedPerLine[self.lineIndex];
+					nextX -= globalSpeedPerLine[self.lineIndex] * 1.5;
 				} else {
-					nextX += globalSpeedPerLine[self.lineIndex] * 0.05 * Math.random();
+					//nextX += globalSpeedPerLine[self.lineIndex] * 0.5 * Math.random();
 				}
 				if (!athlete.isFalling && !athlete.isOnGround) {
 					// Little advance when player plays jumping
 					if (self.lineIndex == 3) {
 						log("Player jumping add=" + self.speedX * 0.1);
 					}
-					nextX += self.speedX * 0.1;
+					//nextX += self.speedX * 0.1;
 				}
 			}
 			// Auto jump hurdles in obstacles[self.lineIndex]
 			if (self.isOnGround) {
+				if (globalSlowDownAfterJump) {
+					if (self.lineIndex == 3) {
+						log("globalSlowDownAfterJump SET=-10");
+					}
+					globalSpeedPerLine[self.lineIndex] = -10;
+				}
 				if (obstacles[self.lineIndex].length) {
 					var distance = obstacles[self.lineIndex][0].x - nextX;
 					if (self.lineIndex == 3) {
-						//log("distance=" + distance);
+						log("distance=" + distance);
 					}
 					if (distance > 0 && distance <= 250 + self.speedX) {
 						self.jump();
 					}
@@ -196,8 +192,21 @@
 			self.x = nextX;
 			self.previousX = self.x;
 		}
 	};
+	self.jump = function () {
+		if (Date.now() - self.lastJumpTime > self.interJumpDelayMs) {
+			if (self.isOnGround) {
+				self.isOnGround = false;
+				self.speedY = self.jumpSpeed;
+				self.lastJumpTime = Date.now();
+				//globalSpeedPerLine[self.lineIndex] = globalSpeedPerLine[self.lineIndex] * 1.1;
+				if (self.lineIndex == 3) {
+					log("--------------- JUMP --------------------");
+				}
+			}
+		}
+	};
 	self.runAnim = function () {
 		var ocsilDelay = 5;
 		var armsAmplitude = 0.5;
 		var legsAmplitude = 0.5;
@@ -263,9 +272,9 @@
 		self.targetPosture = newPosture;
 	};
 	self.restore = function () {
 		log("restore...");
-		self.x = self.previousX || 400;
+		self.x = self.previousX || 400 + 100 * self.lineIndex;
 		self.y = linesGroundLevels[self.lineIndex];
 		self.speedY = 0;
 		self.trunk.rotation = 0;
 		self.rightArm.rotation = idlePosture.rightArm.r;
@@ -414,12 +423,12 @@
 var numberOfOpponents = 3; // Adjust based on the actual number of opponents in the game
 var groundLevel = 2732 - 200; // Ground level set 200px from the bottom
 var linesGroundLevels = []; // Ground level set 200px from the bottom
 var numberOfLines = 1 + numberOfOpponents;
-var numberOfObstacles = 1;
+var numberOfObstacles = 20; // Total number of hurdles
 var obstacles = [[]];
 var obstacleSpawnTicker = 0;
-var obstacleSpawnDistanceRate = 0.3; //1.5; // Spawn an obstacle 1 screen * 1.5
+var obstacleSpawnDistanceRate = 1.5; // Ratio of screen width between obstacles
 var obstacleJustPassed = false;
 var finishLine;
 var stadium;
 var stadiumOdd;
@@ -431,9 +440,11 @@
 var track2;
 var track3;
 var track4;
 var scoreTxt;
-var globalSpeedIncreaseStep = 5;
+var globalSpeedBase = -20;
+var globalSpeedIncreaseStep = 0; //5; TEMP DEBUG
+var globalSlowDownAfterJump = false;
 var globalSpeedPerLine = []; // Global speed for tracks and obstacles default -10 / min = -4
 var colorsArray = [0x1188FF, 0xFF0000, 0x00FF00, 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFFFFF, 0xFF8811];
 var isDebug = true;
 var debugMarker;
@@ -586,9 +597,13 @@
 	track4.y = 2732 - 1024;
 	// Initialize ground levels & speeds
 	for (var line = 0; line < numberOfLines; line++) {
 		linesGroundLevels[line] = groundLevel - 200 - 220 * line;
-		globalSpeedPerLine[line] = -10;
+		if (typeof globalBaseSpeed !== 'undefined') {
+			globalSpeedPerLine[line] = globalBaseSpeed;
+		} else {
+			console.error('globalBaseSpeed is not defined');
+		}
 	}
 	// Add Button in the center of the screen
 	startButton = LK.getAsset('button', {
 		anchorX: 0.5,
@@ -780,19 +795,24 @@
 			} else if (globalSpeedPerLine[line] > 0.25) {
 				globalSpeedPerLine[line] -= 0.25; // Increment speed gradually if somehow above 0
 			} else {
 				globalSpeedPerLine[line] = 0; // Set to 0 if very close to it
-				athlete.isRunning = false;
-				athlete.setPosture(idlePosture);
-				opponents.forEach(function (opponent) {
-					opponent.isRunning = false;
-					opponent.setPosture(idlePosture);
-				});
+				if (athlete.isRunning) {
+					athlete.isRunning = false;
+					athlete.setPosture(idlePosture);
+					opponents.forEach(function (opponent) {
+						opponent.isRunning = false;
+						opponent.setPosture(idlePosture);
+					});
+				}
 			}
 		}
 	}
 }
 function checkForCollisions() {
+	if (finishLine.isCut) {
+		return;
+	}
 	for (var line = 0; line < numberOfLines; line++) {
 		obstacles[line] = obstacles[line] || [];
 		if (obstacles[line].length) {
 			var obstacle = obstacles[line][0]; // Check only the first obstacle in the line
@@ -828,26 +848,34 @@
 	if (athlete.isFalling && !athlete.hasFlashed) {
 		LK.effects.flashScreen(0xaaaaaa, 500); // Flash screen red for half a second
 		athlete.hasFlashed = true;
 		globalSpeedPerLine[0] /= 1.5;
+		// TEMP TEST FIX AI SPEED
+		/*opponents.forEach(function (opponent) {
+				globalSpeedPerLine[opponent.lineIndex] /= 1.5;
+		});
+		=> OK but make AI FALL
+		*/
+		globalSlowDownAfterJump = true;
+		// TEMP TEST FIX AI SPEED
 	}
 	if (athlete.hasFlashed && !athlete.hasFlashedGround && athlete.isFalling && athlete.isOnGround) {
 		LK.effects.flashScreen(0xff0000, 500); // Flash screen red for half a second
 		athlete.hasFlashedGround = true;
 		globalSpeedPerLine[0] = 0;
 		LK.setTimeout(function () {
-			//LK.showGameOver(); // Show game over screen
-			globalSpeedPerLine[0] = -10;
+			globalSpeedPerLine[0] = globalBaseSpeed;
+			globalSlowDownAfterJump = false;
 			athlete.restore();
 		}, 1000); // Delay game over to allow fall animation to be seen
 	}
 	opponents.forEach(function (opponent, index) {
 		if (opponent.isFalling && !opponent.hasFlashed && !opponent.isOnGround) {
 			opponent.hasFlashed = true;
 			LK.setTimeout(function () {
-				globalSpeedPerLine[opponent.lineIndex] = -10;
+				globalSpeedPerLine[opponent.lineIndex] = globalBaseSpeed;
 				opponent.restore();
-			}, 1000);
+			}, 2000);
 		}
 	});
 }
 /****************************************************************************************** */ 
 Elongated elipse with black top half and white bottom half.
 
 
 full close and front view of empty stands. retro gaming style
 
 delete
 
 
 delete
 
 
 Basquettes à ressort futuriste. vue de profile. Retro gaming style
 a blue iron man style armor flying. Retro gaming style
 a blue iron man style armor flying horizontally. Retro gaming style
 
 
 round button with a big "up" arrow icon and a small line under it. UI
 A big black horizontal arrow pointing left with centred text 'YOU' in capital letters, painted on an orange floor.. horizontal and pointing left
 remove
 
 gold athletics medal with ribbon. retro gaming style
 
 
 
 
 
 a black oval with a crying smiley face.