Code edit (10 edits merged)
Please save this source code
User prompt
when victory, flash the screen green 1sec
Code edit (3 edits merged)
Please save this source code
User prompt
in handleHitImpact, also display a resultText in the top center of the screen with "VICTORY!" or "DEFEAT!"
Code edit (1 edits merged)
Please save this source code
User prompt
replace LK.effects.flashScreen(pictureToShow === 'victoryPicture' ? 0x00FF00 : 0xFF0000, 2000); by adding the asset to the game
User prompt
Please fix the bug: 'Timeout.tick error: LK.showPicture is not a function' in or related to this line: 'LK.showPicture(pictureToShow);' Line Number: 307
Code edit (22 edits merged)
Please save this source code
User prompt
before gameover, show victoryPicture or defeatPicture for 2 sec
Code edit (1 edits merged)
Please save this source code
Code edit (14 edits merged)
Please save this source code
User prompt
in thinkAboutTarget, when going to the other take into account attackDistance self.targetX = other.x; self.targetY = other.y;
User prompt
in mainAIMove, Implement acceleration and deceleration in the AI's movement. The AI could start moving slowly, gradually increase its speed as it moves away from its starting point, and then slow down as it approaches the target. This would add a more natural feel to the movement. Don't alter the other logic, only the movement
User prompt
Please fix the bug: 'TypeError: Math.rancomd is not a function' in or related to this line: 'if (Math.rancomd() < 0.5) {' Line Number: 367
Code edit (1 edits merged)
Please save this source code
Code edit (3 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: self.gard is not a function' in or related to this line: 'self.gard(true);' Line Number: 360
Code edit (9 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: self.gard is not a function' in or related to this line: 'self.gard(true);' Line Number: 352
Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: target is undefined' in or related to this line: 'self.targetX = target.x;' Line Number: 370
User prompt
in thinkAboutTarget, when self.energy < 15, select a corner far from the other player
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: opponent.isPunching is not a function' in or related to this line: 'if (opponent.isPunching(opponent.leftHand.intersects(player.torso) || opponent.rightHand.intersects(player.torso))) {' Line Number: 860
Code edit (1 edits merged)
Please save this source code
/**** 
* Classes
****/ 
/****************************************************************************************** */ 
/************************************* ATHLETE CLASS ************************************** */
/****************************************************************************************** */ 
var Athlete = Container.expand(function (isPlayer) {
	var self = Container.call(this);
	self.isPlayer = isPlayer;
	self.isPunching = false; // Indicates if the athlete is currently punching
	self.isGuarding = false; // Indicates if the athlete is currently punching
	self.isFighting = false;
	self.isHit = false;
	self.isTouched = false;
	self.energy = 100;
	self.guardLevel = 100;
	self.health = 100; // TEMP DEBUG
	self.retreat = false;
	self.basePunchEnergy = 2; // Punch cost in energy
	self.baseGuardLevelDecrease = 5;
	self.currentPunchEnergy = 2; // Punch cost in energy
	self.punchCount = 0; // Initialize punch count
	self.lastPunchTime = 0; // Timestamp of the last punch
	self.lastHitTime = 0; // Timestamp of the last hit
	self.immunityDelayMs = 300; // Timestamp of the last hit
	self.isTargetOther = true;
	self.hasReachedTarget = true;
	self.lastTargetReachTime = 0;
	self.baseStayTimeMs = 3000;
	self.targetStayTimeMs = 3000;
	self.body = new Container();
	game.addChild(self.body);
	var punchDistance = 60; // Define punch distance for punching animation
	var attackDistance = 350;
	self.targetX = self.targetX || 1024; // Default target X
	self.targetY = self.targetY || 1366; // Default target Y
	// Left Arm
	self.leftForearm = self.body.attachAsset('forearm', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: -110,
		y: -125,
		width: 80,
		rotation: -Math.PI * 0.2
	});
	self.leftHand = self.body.attachAsset('hand', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: -100,
		y: -250,
		width: 90,
		height: 180,
		rotation: -Math.PI * 0.05,
		tint: isPlayer ? 0xFFFFFF : 0x33CCFF
	});
	self.leftArm = self.body.attachAsset('arm', {
		anchorX: 0.5,
		anchorY: 0,
		x: -120,
		y: -120
	});
	// Right Arm
	self.rightForearm = self.body.attachAsset('forearm', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 110,
		y: -125,
		scaleX: -1,
		width: 80,
		rotation: Math.PI * 0.2
	});
	self.rightHand = self.body.attachAsset('hand', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 100,
		y: -250,
		scaleX: -1,
		width: 90,
		height: 180,
		rotation: Math.PI * 0.05,
		tint: isPlayer ? 0xFFFFFF : 0x33CCFF
	});
	self.rightArm = self.body.attachAsset('arm', {
		anchorX: 0.5,
		anchorY: 0,
		x: 120,
		y: -120,
		scaleX: -1
	});
	self.torso = self.body.attachAsset('body', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.head = self.body.attachAsset(isPlayer ? 'head' : 'head2', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: -40
	});
	// Player movement speed
	self.speed = 5;
	// Punch function to handle punching action
	self.punch = function (isLeft) {
		if (Date.now() - self.lastHitTime < self.immunityDelayMs) {
			return false;
		}
		if (!self.isPlayer) {
			log("AI PUNCH : isLeft=" + isLeft);
		}
		if (self.isPunching || self.isGuarding || !self.isPlayer && self.retreat) {
			return;
		}
		if (self.energy <= 0) {
			return;
		}
		// Calculate time difference since last punch
		var currentTime = Date.now();
		var timeDiff = currentTime - self.lastPunchTime;
		// If punches are within 1 second, increase punch count, else reset
		if (timeDiff <= 1000) {
			self.punchCount++;
		} else {
			self.punchCount = 1;
			self.currentPunchEnergy = self.basePunchEnergy;
		}
		// Update last punch time
		self.lastPunchTime = currentTime;
		// Adjust currentPunchEnergy based on punchCount
		self.currentPunchEnergy = self.basePunchEnergy * self.punchCount;
		self.energy = Math.max(0, self.energy - self.currentPunchEnergy);
		if (!self.isPlayer && self.energy <= 0) {
			log("AI NO MORE ENERGY !!!");
		}
		//log("self.punchCount => " + self.punchCount, "self.currentPunchEnergy => " + self.currentPunchEnergy);
		if (self.isPlayer) {
			playerEnergyBar.updateEnergy(self.energy);
		}
		var arm = isLeft ? self.leftArm : self.rightArm;
		var forearm = isLeft ? self.leftForearm : self.rightForearm;
		var hand = isLeft ? self.leftHand : self.rightHand;
		// Refactored punch animation logic using deltas method
		self.isPunching = true;
		self.setPosture(idlePosture);
		var deltas = {
			arm: {
				height: punchDistance,
				x: 15 * (isLeft ? 1 : -1),
				y: -punchDistance
			},
			forearm: {
				height: punchDistance,
				x: 22 * (isLeft ? 1 : -1),
				y: -punchDistance * 1.5,
				rotation: isLeft ? 0.6 : -0.6
			},
			hand: {
				x: 80 * (isLeft ? 1 : -1),
				y: -punchDistance * 1.5,
				rotation: isLeft ? 0.4 : -0.4
			},
			head: {
				x: isLeft ? 15 : -15,
				width: -0.05,
				height: 0.05,
				rotation: isLeft ? 0.1 : -0.1
			}
		};
		// Apply deltas for punch animation
		(function (arm, forearm, hand, head) {
			LK.setTimeout(function () {
				if (!self.isPlayer) {
					log("AI PUNCH : applyDeltas...");
				}
				applyDeltas(arm, deltas.arm);
				applyDeltas(forearm, deltas.forearm);
				applyDeltas(hand, deltas.hand);
				applyDeltas(head, deltas.head);
			}, 10);
		})(arm, forearm, hand, self.head);
		(function (arm, forearm, hand, head) {
			LK.setTimeout(function () {
				if (!self.isPlayer) {
					log("AI PUNCH : applyDeltas Reverse...");
				}
				applyDeltas(arm, reverseDeltas(deltas.arm));
				applyDeltas(forearm, reverseDeltas(deltas.forearm));
				applyDeltas(hand, reverseDeltas(deltas.hand));
				applyDeltas(head, reverseDeltas(deltas.head));
				self.isPunching = false;
			}, 200);
		})(arm, forearm, hand, self.head);
		function applyDeltas(element, deltas) {
			for (var key in deltas) {
				element[key] += deltas[key];
			}
		}
		function reverseDeltas(deltas) {
			var reversed = {};
			for (var key in deltas) {
				reversed[key] = -deltas[key];
			}
			return reversed;
		}
	};
	// Guard function to handle guarding action
	self.guard = function (setGuard) {
		if (!self.isPlayer) {
			log("AI GUARD : setGuard=" + setGuard);
		}
		if (!self.isGuarding && !setGuard || self.isGuarding && setGuard) {
			return;
		}
		if (setGuard && self.guardLevel <= 0) {
			self.setPosture(idlePosture);
			self.isGuarding = false;
			return;
		}
		if (setGuard && !self.isGuarding) {
			self.setPosture(idlePosture);
			self.head.height *= 0.95;
		}
		self.isGuarding = setGuard;
		// Simplified adjustments for guarding using symmetrical elements
		var adjustPosition = function adjustPosition(elementPair, deltaX, deltaY, deltaW, deltaH, deltaR, setGuard) {
			elementPair.forEach(function (element, index) {
				var directionH = (index === 0 ? 1 : -1) * (setGuard ? 1 : -1);
				var directionV = setGuard ? 1 : -1;
				element.x += deltaX * directionH;
				element.y += deltaY * directionV; // Add vertical adjustment
				element.rotation += deltaR * directionH;
				element.width += deltaW * directionV; // Add width adjustment
				element.height += deltaH * directionV; // Add height adjustment
			});
		};
		// Pair elements for symmetrical adjustments
		var elementPairs = [[self.leftHand, self.rightHand], [self.leftForearm, self.rightForearm], [self.leftArm, self.rightArm]];
		// Adjustments for Hands, Forearms and Arms
		var adjustments = [{
			deltaX: 65,
			deltaY: 90,
			deltaW: 15,
			deltaH: 15,
			deltaR: 0.35
		}, {
			deltaX: 30,
			deltaY: 60,
			deltaW: 0,
			deltaH: 0,
			deltaR: 0.2
		}, {
			deltaX: 50,
			deltaY: 10,
			deltaW: 0,
			deltaH: 0,
			deltaR: 0.4
		}];
		adjustments.forEach(function (adj, index) {
			if (!self.isPlayer) {
				log("AI GUARD : adjustPositions...");
			}
			return adjustPosition(elementPairs[index], adj.deltaX, adj.deltaY, adj.deltaW, adj.deltaH, adj.deltaR, setGuard);
		});
		if (!setGuard) {
			self.setPosture(idlePosture);
		}
	};
	self.handleHitImpact = function (attacker) {
		if (Date.now() - self.lastHitTime < self.immunityDelayMs) {
			return false;
		}
		self.lastHitTime = Date.now();
		var damage = attacker.punchCount * (self.isGuarding ? 0.01 : 0.5);
		if (!self.isPlayer) {
			log("AI Received damage=" + damage);
		}
		self.health = Math.max(0, self.health - damage);
		(self.isPlayer ? playerHealthBar : opponentHealthBar).updateHealth(self.health);
		if (self.health <= 0) {
			isPlaying = false;
			var isVictory = self.isPlayer ? false : true;
			// Show victory or defeat picture before game over
			var pictureToShow = isVictory ? 'victoryPicture' : 'defeatPicture';
			var victoryOrDefeatPicture = LK.getAsset(pictureToShow, {
				anchorX: 0.5,
				anchorY: 0.5,
				x: game.width / 2,
				y: game.height / 2
			});
			game.addChild(victoryOrDefeatPicture);
			var resultText = new Text2(isVictory ? "VICTORY!" : " DEFEAT!", {
				size: 200,
				fill: "#ffffff",
				weight: 1000,
				dropShadow: true
			});
			resultText.anchor.set(0.5, -2); // Center the text horizontally
			LK.gui.top.addChild(resultText); // Add the text to the top-center of the screen
			LK.effects.flashScreen(0x00FF00, 1000);
			LK.setTimeout(function () {
				LK.showGameOver();
			}, 2000); // Show the picture and text for 2 seconds before game over
		}
		return true;
	};
	// Update player position based on input
	self.update = function () {
		if (isPlaying) {
			self.mainMove();
		}
		if (LK.ticks % 60 == 0) {
			log("===================== TICK =====================");
			if (self.isGuarding) {
				//log("self.isGuarding : self.guardLevel=" + self.guardLevel);
				self.guardLevel = Math.max(0, self.guardLevel - self.baseGuardLevelDecrease);
				if (self.guardLevel <= 0) {
					if (!self.isPlayer) {
						log("AI NO MORE GUARD !!!");
					}
					self.guard(false);
				}
				self.energy = Math.min(100, self.energy + 4);
			} else {
				self.guardLevel = Math.min(100, self.guardLevel + (self.isPunching ? self.punchCount : 2));
			}
			self.energy = Math.min(100, self.energy + 3);
			if (self.isPlayer) {
				playerEnergyBar.updateEnergy(self.energy);
				playerGuardBar.updateEnergy(self.guardLevel);
			}
			// AI Guard Handling
			if (!self.isPlayer) {
				if (self.retreat && !self.isGuarding && self.guardLevel > 0) {
					self.guard(true);
				}
			}
		}
		// Player is idle
		self.miniMove();
		// Update body position and rotation
		self.body.x = self.x;
		self.body.y = self.y;
		// Calculate angle to face the opponent
		var target = self.isPlayer ? opponent : player; // Determine target based on whether self is Player or Opponent
		var angleToOpponent = Math.atan2(target.y - self.y, target.x - self.x) + Math.PI * 0.5;
		self.body.rotation = angleToOpponent;
	};
	self.thinkAboutTarget = function () {
		log((self.isPlayer ? "PLAYER" : "AI") + " Search target..." + self.hasReachedTarget);
		self.hasReachedTarget = false;
		var other = self.isPlayer ? opponent : player;
		// If Guard level < 25% or Energy < 25% retreat to closest ring corner
		if (self.energy < 15) {
			self.retreat = true;
			self.isTargetOther = false;
			if (!self.isPlayer) {
				log("AI RETREAT !!! self.energy=" + self.energy);
			} else {
				log("PLAYER RETREAT !!! self.energy=" + self.energy);
			}
			if (Math.random() < 0.5) {
				if (other.x > 1024) {
					self.targetX = ring.leftCorner;
				} else {
					self.targetX = ring.rightCorner;
				}
				self.targetY = other.targetY == ring.bottomCorner ? ring.topCorner : ring.bottomCorner;
			} else {
				if (other.y > 1044) {
					self.targetY = ring.topCorner;
				} else {
					self.targetY = ring.bottomCorner;
				}
				self.targetX = other.targetX == ring.bottomCorner ? ring.rightCorner : ring.leftCorner;
			}
		} else {
			if (self.isPlayer) {
				log("PLAYER ATTACK !!! self.energy=" + self.energy);
			}
			self.retreat = false;
			self.isTargetOther = true;
			self.targetX = other.x;
			self.targetY = other.y;
		}
	};
	self.mainMove = function () {
		var stayDelay = Date.now() - self.lastTargetReachTime;
		if (self.hasReachedTarget && stayDelay > self.targetStayTimeMs) {
			// Randomize next target stay time
			self.targetStayTimeMs = self.baseStayTimeMs + Math.random() * 1000;
			self.thinkAboutTarget();
		}
		// Check if athlete has reached the target
		if (self.isTargetOther) {
			// Update target if it's the other player
			var other = self.isPlayer ? opponent : player;
			self.targetX = other.x;
			self.targetY = other.y;
		}
		var distanceToTarget = Math.sqrt(Math.pow(self.targetX - self.x, 2) + Math.pow(self.targetY - self.y, 2));
		if (self.isPlayer) {
			log("PLAYER DISTANCE TO " + (self.retreat ? "RETREAT" : "FIGHT") + "  " + self.targetX + "," + self.targetY + " = " + distanceToTarget);
		}
		if (self.retreat) {
			// Going to a corner
			if (distanceToTarget > 20) {
				// Progressively move to the target
				// Calculate acceleration factor based on distance to target
				var accelerationFactor = Math.min(1, distanceToTarget / 500);
				var decelerationDistance = 200; // Distance from target to start decelerating
				var speedModifier = distanceToTarget < decelerationDistance ? distanceToTarget / decelerationDistance : accelerationFactor;
				var adjustedSpeed = self.speed * speedModifier;
				var moveX = (self.targetX - self.x) / distanceToTarget * adjustedSpeed;
				var moveY = (self.targetY - self.y) / distanceToTarget * adjustedSpeed;
				self.x += moveX;
				self.y += moveY;
				if (self.isPlayer) {
					log("PLAYER STILL FAR of Retreat" + self.lastTargetReachTime + " / Moved " + moveX + "," + moveY);
				}
			} else {
				if (!self.hasReachedTarget) {
					self.hasReachedTarget = true;
					self.lastTargetReachTime = Date.now();
				}
				if (self.isPlayer) {
					log("PLAYER REACHED corner at " + self.lastTargetReachTime);
				}
			}
		} else {
			// Going to fight
			if (distanceToTarget < attackDistance) {
				self.isInAttackRange = true;
				if (!self.hasReachedTarget) {
					self.hasReachedTarget = true;
					self.lastTargetReachTime = Date.now();
				}
				if (self.isPlayer) {
					log("PLAYER REACHED fight at " + self.lastTargetReachTime);
				}
				if (!self.isPlayer) {
					self.guard(false);
					self.aiFight();
				}
			} else {
				// Progressively move to the target
				var moveX = (self.targetX - self.x) / distanceToTarget * self.speed;
				var moveY = (self.targetY - self.y) / distanceToTarget * self.speed;
				self.x += moveX;
				self.y += moveY;
				if (self.isPlayer) {
					log((self.isPlayer ? "PLAYER" : "AI") + " STILL FAR of Fight" + self.lastTargetReachTime);
				}
			}
		}
	};
	self.aiFight = function () {
		if (self.retreat) {
			return;
		}
		if (LK.ticks % 2 == 0 && !self.isFighting) {
			self.punch(Math.random() < 0.5);
			// Punch during 4-5sec
			LK.setTimeout(function () {
				self.isFighting = true;
				// Stop durring 2-4 sec
				LK.setTimeout(function () {
					self.isFighting = false;
				}, 2000 - 1000 * Math.random());
			}, 5000 - 1000 * Math.random());
		}
	};
	self.miniMove = function () {
		if (self.isPunching || self.isGuarding || self.isHit) {
			return;
		}
		// Mini head movement with added randomness
		self.head.y = -40 + Math.sin(LK.ticks / 10 + Math.random() * 0.2) * 2;
		// Mini arm and forearm movement with added randomness
		self.leftArm.rotation += Math.sin(LK.ticks / 15 + Math.random() * 0.2) * 0.005;
		self.leftForearm.rotation += Math.sin(LK.ticks / 15 + Math.random() * 0.2) * 0.005; // Add forearm movement
		self.leftHand.x += Math.sin(LK.ticks / 15 + Math.random() * 0.2) * 0.5; // Add hand movement
		self.leftHand.rotation += Math.sin(LK.ticks / 15 + Math.random() * 0.2) * 0.005; // Add hand movement
		self.rightArm.rotation -= Math.sin(LK.ticks / 15 + Math.random() * 0.2) * 0.005;
		self.rightForearm.rotation -= Math.sin(LK.ticks / 15 + Math.random() * 0.2) * 0.005; // Add forearm movement
		self.rightHand.x -= Math.sin(LK.ticks / 15 + Math.random() * 0.2) * 0.5; // Add hand movement
		self.rightHand.rotation -= Math.sin(LK.ticks / 15 + Math.random() * 0.2) * 0.005; // Add hand movement
	};
	self.setPosture = function (targetPosture) {
		if (targetPosture == null) {
			return;
		}
		if (!self.isPlayer) {
			log("AI setPosture: " + targetPosture.name);
		}
		// Torso
		self.torso.x = targetPosture.torso.x;
		self.torso.y = targetPosture.torso.y;
		self.torso.width = targetPosture.torso.w;
		self.torso.height = targetPosture.torso.h;
		self.torso.rotation = targetPosture.torso.r;
		// Head
		self.head.x = targetPosture.head.x;
		self.head.y = targetPosture.head.y;
		self.head.width = targetPosture.head.w;
		self.head.height = targetPosture.head.h;
		self.head.rotation = targetPosture.head.r;
		// Left Arm
		self.leftArm.x = targetPosture.leftArm.x;
		self.leftArm.y = targetPosture.leftArm.y;
		self.leftArm.width = targetPosture.leftArm.w;
		self.leftArm.height = targetPosture.leftArm.h;
		self.leftArm.rotation = targetPosture.leftArm.r;
		// Right Arm
		self.rightArm.x = targetPosture.rightArm.x;
		self.rightArm.y = targetPosture.rightArm.y;
		self.rightArm.width = targetPosture.rightArm.w;
		self.rightArm.height = targetPosture.rightArm.h;
		self.rightArm.rotation = targetPosture.rightArm.r;
		// Left Forearm
		self.leftForearm.x = targetPosture.leftForearm.x;
		self.leftForearm.y = targetPosture.leftForearm.y;
		self.leftForearm.width = targetPosture.leftForearm.w;
		self.leftForearm.height = targetPosture.leftForearm.h;
		self.leftForearm.rotation = targetPosture.leftForearm.r;
		// Right Forearm
		self.rightForearm.x = targetPosture.rightForearm.x;
		self.rightForearm.y = targetPosture.rightForearm.y;
		self.rightForearm.width = targetPosture.rightForearm.w;
		self.rightForearm.height = targetPosture.rightForearm.h;
		self.rightForearm.rotation = targetPosture.rightForearm.r;
		// Left Hand
		self.leftHand.x = targetPosture.leftHand.x;
		self.leftHand.y = targetPosture.leftHand.y;
		self.leftHand.width = targetPosture.leftHand.w;
		self.leftHand.height = targetPosture.leftHand.h;
		self.leftHand.rotation = targetPosture.leftHand.r;
		// Right Hand
		self.rightHand.x = targetPosture.rightHand.x;
		self.rightHand.y = targetPosture.rightHand.y;
		self.rightHand.width = targetPosture.rightHand.w;
		self.rightHand.height = targetPosture.rightHand.h;
		self.rightHand.rotation = targetPosture.rightHand.r;
	};
});
/****************************************************************************************** */ 
/************************************* ENERGY BAR CLASS ********************************** */
/****************************************************************************************** */ 
var EnergyBar = Container.expand(function (maxEnergy, isGuard) {
	var self = Container.call(this);
	self.maxEnergy = maxEnergy;
	self.currentEnergy = maxEnergy;
	// Background of the energy bar
	self.frame = self.attachAsset('energyBarBackground', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.energyGradiant = self.attachAsset('energyBar', {
		anchorX: 0.5,
		anchorY: 1,
		y: self.frame.height / 2 - 30
	});
	// Fill of the energy bar
	self.fill = self.attachAsset('energyBarFill', {
		anchorX: 0.50,
		anchorY: 0,
		x: 0,
		y: -self.frame.height / 2 + 30,
		height: 0,
		visible: true
	});
	// Lightning icon above the energy bar
	self.lightningIcon = self.attachAsset(isGuard ? 'shieldIcon' : 'lightning', {
		anchorX: 0.5,
		anchorY: 1,
		x: 0,
		y: -self.energyGradiant.height / 2 - 50 // Position above the energy bar
	});
	// Update the energy bar display
	self.updateEnergy = function (energy) {
		self.currentEnergy = energy;
		var fillSize = Math.max(0, self.maxEnergy - self.currentEnergy) / self.maxEnergy * (self.energyGradiant.height + 6);
		self.fill.height = fillSize;
	};
});
/****************************************************************************************** */ 
/************************************* GUARD BUTTON CLASS ********************************** */
/****************************************************************************************** */ 
var GuardButton = Container.expand(function () {
	var self = Container.call(this);
	self.buttonAsset = self.attachAsset('guardButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.8
	});
	self.x = 400; // Position button in the bottom center
	self.y = game.height - 350;
	self.down = function (x, y, obj) {
		player.guard(true); // Activate guard state for player
		self.width *= 0.9;
		self.height *= 0.9;
	};
	self.up = function (x, y, obj) {
		player.guard(false);
		self.width = 600;
		self.height = 600;
	};
});
/****************************************************************************************** */ 
/************************************* HEALTH BAR CLASS *********************************** */
/****************************************************************************************** */ 
var HealthBar = Container.expand(function (maxHealth, isPlayer, barColor) {
	var self = Container.call(this);
	self.maxHealth = maxHealth;
	self.currentHealth = maxHealth;
	// Frame of the health bar
	self.frame = self.attachAsset('healthBarFrame', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Fill of the health bar
	self.fill = self.attachAsset('healthBar', {
		anchorX: 0,
		anchorY: 0.5,
		x: -self.frame.width / 2 + 15,
		y: 0,
		width: self.frame.width,
		tint: 0xFF0000
	});
	self.icon = self.attachAsset('healthIcon', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: -self.frame.width / 2 - 40,
		tint: isPlayer ? 0xFF0000 : 0x0E78CA
	});
	// Update the health bar display
	self.updateHealth = function (health) {
		self.currentHealth = health;
		var fillWidth = Math.max(0, self.currentHealth) / self.maxHealth * (self.frame.width - 30);
		self.fill.width = fillWidth;
	};
	self.updateHealth(100);
});
/****************************************************************************************** */ 
/************************************* PUNCH BUTTON CLASS ********************************** */
/****************************************************************************************** */ 
var PunchButton = Container.expand(function () {
	var self = Container.call(this);
	self.buttonAsset = self.attachAsset('punchButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.8
	});
	self.x = game.width - 400; // Position button on the bottom right
	self.y = game.height - 350;
	self.down = function (x, y, obj) {
		// Simulate button press by triggering punch with left arm
		player.punch(Math.random() < 0.5); // Randomly choose left or right arm for punching
		self.width *= 0.9;
		self.height *= 0.9;
	};
	self.up = function (x, y, obj) {
		// Simulate button release by triggering punch with right arm
		self.width = 600;
		self.height = 600;
	};
});
/****************************************************************************************** */ 
/**************************************** RING CLASS ************************************** */
/****************************************************************************************** */ 
var Ring = Container.expand(function () {
	var self = Container.call(this);
	self.leftBorder = 300;
	self.rightBorder = 1800;
	self.topBorder = 200;
	self.bottomBorder = 1750;
	self.leftCorner = 600;
	self.rightCorner = 1500;
	self.topCorner = 500;
	self.bottomCorner = 1500;
	self.ringAsset = self.attachAsset('ring', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.x = 1024; // Center of the screen horizontally
	self.y = 1366 - self.height / 6; // Center of the screen vertically
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 // Init game with black background
});
/**** 
* Game Code
****/ 
/****************************************************************************************** */ 
/************************************** GLOBAL VARIABLES ********************************** */
/****************************************************************************************** */ 
var isPlaying = false;
var ring;
var punchButton;
var guardButton;
var player;
var opponent;
var touchPosition = null;
var swipeStart = null;
var swipeEnd = null;
var playerEnergyBar = null;
var playerGuardBar = null;
var playerHealthBar = null;
var opponentHealthBar = null;
var isDebug = true;
var debugMarker;
/****************************************************************************************** */ 
/************************************** POSTURES ****************************************** */
/****************************************************************************************** */ 
var idlePosture = {
	name: "idlePosture",
	// Left Arm
	leftForearm: {
		x: -110,
		y: -125,
		w: 80,
		h: 120,
		r: -Math.PI * 0.2
	},
	leftHand: {
		x: -110,
		y: -250,
		w: 80,
		h: 180,
		r: -Math.PI * 0.05
	},
	leftArm: {
		x: -120,
		y: -120,
		w: 80,
		h: 150,
		r: 0
	},
	// Right Arm
	rightForearm: {
		x: 110,
		y: -125,
		w: 80,
		h: 120,
		r: Math.PI * 0.2
	},
	rightHand: {
		x: 110,
		y: -250,
		w: 90,
		h: 180,
		r: Math.PI * 0.05
	},
	rightArm: {
		x: 120,
		y: -120,
		w: 80,
		h: 150,
		r: 0
	},
	torso: {
		x: 0,
		y: 0,
		w: 300,
		h: 150,
		r: 0
	},
	head: {
		x: 0,
		y: -40,
		w: 150,
		h: 190,
		r: 0
	}
};
/****************************************************************************************** */ 
/*********************************** UTILITY FUNCTIONS ************************************ */
/****************************************************************************************** */ 
function log() {
	if (isDebug) {
		var _console;
		(_console = console).log.apply(_console, arguments);
	}
}
/****************************************************************************************** */ 
/************************************** INPUT HANDLERS ************************************ */
/****************************************************************************************** */ 
game.down = function (x, y, obj) {
	if (!isPlaying) {
		isPlaying = true;
	}
};
game.move = function (x, y, obj) {};
game.up = function (x, y, obj) {};
/****************************************************************************************** */ 
/************************************ GAME INITIALIZE ************************************* */
/****************************************************************************************** */ 
function gameInitialize() {
	log("Game initialize...");
	// Initialize Ring
	ring = game.addChild(new Ring());
	punchButton = game.addChild(new PunchButton());
	guardButton = game.addChild(new GuardButton());
	// Initialize Player
	player = game.addChild(new Athlete(true));
	player.x = 1024; // Center horizontally
	player.y = game.height * 0.55; // Position towards the bottom
	// Initialize Opponent
	opponent = game.addChild(new Athlete());
	opponent.x = 1024; // Center horizontally
	opponent.y = game.height * 0.2; // Center vertically in the middle of the ring
	opponent.rotation = Math.PI * 0.5;
	// Initialize Energy Bar for Player
	playerEnergyBar = game.addChild(new EnergyBar(100));
	playerEnergyBar.x = game.width - 75; // Position energy bar on the left side
	playerEnergyBar.y = game.height * 0.4; // Position towards the top
	// Initialize Guard Bar for Player
	playerGuardBar = game.addChild(new EnergyBar(100, true));
	playerGuardBar.x = 75; // Position energy bar on the left side
	playerGuardBar.y = game.height * 0.4; // Position towards the top
	// Initialize Player Health bar
	playerHealthBar = game.addChild(new HealthBar(100, true));
	playerHealthBar.x = 1024;
	playerHealthBar.y = 1960;
	// Initialize Opponent Health bar
	opponentHealthBar = game.addChild(new HealthBar(100, false));
	opponentHealthBar.x = 1024; // Center horizontally
	opponentHealthBar.y = 35; // Position at the top of the screen
	if (isDebug) {
		// Debug Marker
		debugMarker = LK.getAsset('debugMarker', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		game.addChild(debugMarker);
		debugMarker.x = 1800;
		debugMarker.y = 1750;
	}
}
/****************************************************************************************** */ 
/************************************* GAME FUNCTIONS ************************************* */
/****************************************************************************************** */ 
function handleHit(attacker, defender) {
	defender.isHit = true;
	defender.isTouched = !defender.isGuarding;
	var backDelta = defender.isGuarding ? 2 : 50;
	var backHeadDelta = defender.isGuarding ? 1 : 4;
	// Player hit reaction: head goes back, flash screen red
	// Calculate defender's current direction and move back accordingly
	var defenderDirection = Math.atan2(defender.y - attacker.y, defender.x - attacker.x);
	// Move defender back
	var newX = defender.x + Math.cos(defenderDirection) * backDelta;
	var newY = defender.y + Math.sin(defenderDirection) * backDelta;
	// Check if newX and newY are within ring's corners
	var withinLimits = newX >= ring.leftCorner && newX <= ring.rightCorner && newY >= ring.topCorner && newY <= ring.bottomCorner;
	//log("Is in ring ?", withinLimits);
	if (withinLimits) {
		defender.x = newX; // Move defender back in the x direction of current movement
		defender.y = newY; // Move defender back in the y direction of current movement
	} else {
		// If out of limits, move attacker back instead
		/* 
		var attackerDirection = Math.atan2(attacker.y - defender.y, attacker.x - defender.x);
		attacker.x += Math.cos(attackerDirection) * backDelta;
		attacker.y += Math.sin(attackerDirection) * backDelta;
		*/ 
	}
	var impacted = defender.handleHitImpact(attacker);
	var flashColor = defender.isGuarding || !impacted ? 0xcccccc : 0xFF0000;
	if (defender.isGuarding) {
		LK.effects.flashObject(defender.leftHand, flashColor, 100); // Flash the defender 
		LK.effects.flashObject(defender.rightHand, flashColor, 100); // Flash the defender 
	} else {
		LK.effects.flashObject(defender.head, flashColor, 100); // Flash the defender 
		LK.effects.flashObject(defender.torso, flashColor, 100); // Flash the defender 
	}
	LK.effects.flashObject(defender.leftArm, flashColor, 100); // Flash the defender 
	LK.effects.flashObject(defender.leftForearm, flashColor, 100); // Flash the defender 
	LK.effects.flashObject(defender.rightArm, flashColor, 100); // Flash the defender 
	LK.effects.flashObject(defender.rightForearm, flashColor, 100); // Flash the defender 
	// Arms back movement
	var members = [];
	if (defender.isGuarding) {
		// Move arms back
		members = [defender.leftArm, defender.leftForearm, defender.rightArm, defender.rightForearm];
	} else {
		// Move head and torso back
		members = [defender.head, defender.torso];
	}
	// Apply movement to all members in the array
	members.forEach(function (member) {
		member.x += Math.cos(defenderDirection) * backHeadDelta;
		member.y += Math.sin(defenderDirection) * backHeadDelta;
	});
	(function (defender, defenderDirection, backHeadDelta, members) {
		LK.setTimeout(function () {
			// Head returns to normal position
			members.forEach(function (member) {
				member.x -= Math.cos(defenderDirection) * backHeadDelta;
				member.y -= Math.sin(defenderDirection) * backHeadDelta;
			});
			/* 
			defender.head.x -= 2.5 * Math.cos(defenderDirection) * backHeadDelta;
			defender.head.y -= 2.5 * Math.sin(defenderDirection) * backHeadDelta;
			defender.torso.x -= Math.cos(defenderDirection) * backHeadDelta;
			defender.torso.y -= Math.sin(defenderDirection) * backHeadDelta;
			*/ 
			defender.isHit = false;
			if (!defender.isGuarding && !defender.isPunching) {
				defender.setPosture(idlePosture);
			}
		}, 500);
	})(defender, defenderDirection, backHeadDelta, members);
}
/****************************************************************************************** */ 
/************************************** MAIN GAME LOOP ************************************ */
/****************************************************************************************** */ 
// Game update function
game.update = function () {
	// This section has been removed to prevent redundant player movement handling.
	// Check for collision between player's hand and opponent's head
	if (Date.now() - opponent.lastHitTime < opponent.immunityDelayMs || Date.now() - player.lastHitTime < player.immunityDelayMs) {
		return;
	}
	if (player.isPunching && (player.leftHand.intersects(opponent.torso) || player.rightHand.intersects(opponent.torso))) {
		handleHit(player, opponent);
	}
	if (opponent.isPunching && (opponent.leftHand.intersects(player.torso) || opponent.rightHand.intersects(player.torso))) {
		handleHit(opponent, player);
	}
};
gameInitialize(); ===================================================================
--- original.js
+++ change.js
@@ -13,9 +13,9 @@
 	self.isHit = false;
 	self.isTouched = false;
 	self.energy = 100;
 	self.guardLevel = 100;
-	self.health = 2; //100; // TEMP DEBUG
+	self.health = 100; // TEMP DEBUG
 	self.retreat = false;
 	self.basePunchEnergy = 2; // Punch cost in energy
 	self.baseGuardLevelDecrease = 5;
 	self.currentPunchEnergy = 2; // Punch cost in energy
@@ -276,25 +276,27 @@
 		self.health = Math.max(0, self.health - damage);
 		(self.isPlayer ? playerHealthBar : opponentHealthBar).updateHealth(self.health);
 		if (self.health <= 0) {
 			isPlaying = false;
+			var isVictory = self.isPlayer ? false : true;
 			// Show victory or defeat picture before game over
-			var pictureToShow = self.isPlayer ? 'defeatPicture' : 'victoryPicture';
+			var pictureToShow = isVictory ? 'victoryPicture' : 'defeatPicture';
 			var victoryOrDefeatPicture = LK.getAsset(pictureToShow, {
 				anchorX: 0.5,
 				anchorY: 0.5,
 				x: game.width / 2,
 				y: game.height / 2
 			});
 			game.addChild(victoryOrDefeatPicture);
-			var resultText = new Text2(self.isPlayer ? "DEFEAT!" : "VICTORY!", {
+			var resultText = new Text2(isVictory ? "VICTORY!" : " DEFEAT!", {
 				size: 200,
 				fill: "#ffffff",
 				weight: 1000,
 				dropShadow: true
 			});
-			resultText.anchor.set(0.5, 0); // Center the text horizontally
+			resultText.anchor.set(0.5, -2); // Center the text horizontally
 			LK.gui.top.addChild(resultText); // Add the text to the top-center of the screen
+			LK.effects.flashScreen(0x00FF00, 1000);
 			LK.setTimeout(function () {
 				LK.showGameOver();
 			}, 2000); // Show the picture and text for 2 seconds before game over
 		}
@@ -315,13 +317,13 @@
 						log("AI NO MORE GUARD !!!");
 					}
 					self.guard(false);
 				}
-				self.energy = Math.min(100, self.energy + 2);
+				self.energy = Math.min(100, self.energy + 4);
 			} else {
 				self.guardLevel = Math.min(100, self.guardLevel + (self.isPunching ? self.punchCount : 2));
 			}
-			self.energy = Math.min(100, self.energy + 2);
+			self.energy = Math.min(100, self.energy + 3);
 			if (self.isPlayer) {
 				playerEnergyBar.updateEnergy(self.energy);
 				playerGuardBar.updateEnergy(self.guardLevel);
 			}
@@ -355,21 +357,21 @@
 			} else {
 				log("PLAYER RETREAT !!! self.energy=" + self.energy);
 			}
 			if (Math.random() < 0.5) {
-				if (other.targetX > 1024 || other.x > 1024) {
+				if (other.x > 1024) {
 					self.targetX = ring.leftCorner;
 				} else {
 					self.targetX = ring.rightCorner;
 				}
-				self.targetY = self.y > 1044 ? ring.topCorner : ring.bottomCorner;
+				self.targetY = other.targetY == ring.bottomCorner ? ring.topCorner : ring.bottomCorner;
 			} else {
-				if (other.targetY > 1044 || other.y > 1044) {
+				if (other.y > 1044) {
 					self.targetY = ring.topCorner;
 				} else {
 					self.targetY = ring.bottomCorner;
 				}
-				self.targetX = self.x > 1024 ? ring.rightCorner : ring.leftCorner;
+				self.targetX = other.targetX == ring.bottomCorner ? ring.rightCorner : ring.leftCorner;
 			}
 		} else {
 			if (self.isPlayer) {
 				log("PLAYER ATTACK !!! self.energy=" + self.energy);
 
 
 clear
 basic light gray convex round button with a red boxing glove icon. UI
 Un gant de boxe bleu vu de dessus. video game
 
 
 basic light round convex gray button with a raised blue shield icon.. UI
 
 un éclair. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
 
 remove
 
 a basic white heart.. game icon
 A boxer has lost the match..
 man boxer with red gloves is KO on the ring..