Code edit (6 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: self is undefined' in or related to this line: 'self.setWinnerFace = function () {' Line Number: 2127
User prompt
in athlete class, add a setWinnerFace function
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
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
Code edit (11 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: groundLevels is not defined' in or related to this line: 'self.shadow.y = groundLevels[0] - self.y - self.trunk.y;' Line Number: 366
Code edit (1 edits merged)
Please save this source code
Code edit (21 edits merged)
Please save this source code
User prompt
Using the following instructions, add shadows to the athletes, you would modify the Athlete class to include a shadow asset for each athlete instance. Here's a conceptual outline of the code changes you would make, described in human language: 1. **Define a Shadow Asset in the Athlete Class Initialization:** - Within the Athlete class constructor, after initializing the athlete's body parts (like the trunk, head, arms, and legs), you would attach a new asset to represent the shadow. This could be done using the `self.attachAsset` method similar to how other body parts are attached. - The shadow asset could be a simple ellipse or a custom shape that resembles the shadow cast by an athlete. You would set its color to a dark gray or black with reduced alpha to make it semi-transparent, mimicking a real shadow. - Position the shadow asset directly below the athlete, offsetting its `x` and `y` properties to ensure it appears right under the athlete's feet. The `y` offset might be slightly larger than the athlete's height to place it on the ground, and you might need to adjust the `scaleX` and `scaleY` properties to stretch the shadow horizontally to make it look more realistic. 2. **Update Shadow Position in the Athlete's Update Method:** - In the Athlete class's update method (`self._update_migrated`), along with updating the athlete's position and handling animations, you would also update the shadow's position to follow the athlete. This ensures that the shadow remains correctly positioned under the athlete as they move. - If the athlete jumps, you could optionally adjust the shadow's `scaleX` and `scaleY` to make the shadow grow or shrink, simulating the shadow's behavior in real life as the athlete moves away from or closer to the ground. 3. **Adjust Shadow Visibility Based on Athlete's State:** - You might want to adjust the shadow's visibility or opacity based on the athlete's state. For example, if the athlete is jumping, the shadow could become fainter or slightly larger to reflect the increased distance from the ground. - When the athlete is falling or has collided with an obstacle, you could temporarily hide the shadow or make it more prominent based on the game's visual feedback requirements.
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
when isReached and athlete had won, show the confettis
Code edit (14 edits merged)
Please save this source code
User prompt
add a confetti class to celebrate player victory
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: 'ReferenceError: messageTextBig is not defined' in or related to this line: 'messageTextBig.visible = false;' Line Number: 548
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.isRunning = false; self.isBlocked = false; self.nextHurdleSpeedX = 0; self.jumpSpeedDefault = -20; // -17; self.jumpSpeedBonus = -40; self.jumpSpeed = self.jumpSpeedDefault; 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 = currentRoundColors[line]; self.previousX = 0; self.justTookBonus = false; self.isWaiting = true; // Player at speed 0 self.nbJumps = 0; // BODY PARTS self.trunk = self.attachAsset('bodyPart', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1, rotation: 0.125, tint: 0x000000 }); self.head = self.trunk.attachAsset('head', { anchorX: 0.5, anchorY: 2, scaleX: 1, scaleY: 1, tint: 0x000000 }); 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) { if (self.lineIndex == 1) { 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; } 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.head.rotation += (self.targetPosture.head.r - self.head.rotation) * 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; self.rightLeg.rotation += (self.targetPosture.rightLeg.r - self.rightLeg.rotation) * speed; self.rightLeg.height += (self.targetPosture.rightLeg.h - self.rightLeg.height) * 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.leftLeg.rotation += (self.targetPosture.leftLeg.r - self.leftLeg.rotation) * speed; self.leftLeg.height += (self.targetPosture.leftLeg.h - self.leftLeg.height) * speed; }; self._update_migrated = function () { /* ********************************************************** AI ATHLETE **************************************************** */ if (self.isAi) { // AI Athlete var nextX = self.x; self.previousX = self.x; if (self.isRunning) { var deltaSpeed = Math.abs(globalSpeedPerLine[self.lineIndex]) - Math.abs(globalSpeedPerLine[0]); nextX += deltaSpeed; if (!self.isFalling) { // Normal running if (self.isOnGround) { // Running self.leftLeg.height = 200; self.leftArm.height = 200; if (self.isRunning) { self.trunk.rotation = 0.125; self.runAnim(); } // Auto jump first hurdle of the line if (obstacles[self.lineIndex].length) { var distance = obstacles[self.lineIndex][0].x - nextX; if (self.lineIndex == 1) { //log((self.isOnGround ? 'On ground' : 'In air 1') + " / x=" + self.x + " / y=" + self.y + " / DeltaY=" + (obstacles[self.lineIndex][0].y - obstacles[self.lineIndex][0].centralRod.y - self.y) + " / distance=" + distance); } if (self.x > aiJumpLeftLimit && self.x < aiJumpRightLimit && distance > 0 && distance <= 300) { self.jump(); } else { // Reduce advance when out of screen var normalize = self.nextHurdleSpeedX; normalize = self.x < -200 ? Math.abs(normalize) : normalize; normalize = self.x > 2100 ? -10 + Math.random() * 2 : normalize; normalize = self.x > 3000 ? -20 : normalize; nextX += normalize; } } } else { if (obstacles[self.lineIndex].length) { var distance = obstacles[self.lineIndex][0].x - nextX; if (self.lineIndex == 1) { //log((self.isOnGround ? 'On ground' : 'In air 2') + " / x=" + self.x + " / y=" + self.y + " / DeltaY=" + (obstacles[self.lineIndex][0].y - obstacles[self.lineIndex][0].centralRod.y - self.y) + " / distance=" + distance); } } // Jumping - if not running, finish the jump self.speedY += self.gravity * Math.abs(globalSpeedPerLine[self.lineIndex] / 10) + (!self.isRunning ? 0.5 : 0); self.y += self.speedY * Math.abs(globalSpeedPerLine[self.lineIndex] / 10) + (!self.isRunning ? self.speedY : 0); if (self.y >= linesGroundLevels[self.lineIndex]) { // Reached the ground self.isOnGround = true; self.speedY = 0; self.y = linesGroundLevels[self.lineIndex]; // Define speed for next hurdle => Defines the Difficulty //self.nextHurdleSpeedX = -1 + (-5 + 10 * Math.random()); // Level 1/3 //self.nextHurdleSpeedX = 0 + (-5 + 15 * Math.random()); // Level 2/3 self.nextHurdleSpeedX = -2 * Math.min(0, 2 - difficultyLevel) + (-5 + 10 * Math.random() * (1 + 0.5 * (difficultyLevel - 1))); // Level n if (difficultyLevel == 1 && obstacles[self.lineIndex].length <= 3 && self.x > athlete.x) { self.nextHurdleSpeedX = -2 - 1 * Math.abs(self.nextHurdleSpeedX); // Level 1/3 } } else { self.jumpAnim(); } } } else { // Falling self.y += 5; if (self.y >= linesGroundLevels[self.lineIndex]) { self.isOnGround = true; self.speedY = 0; self.y = linesGroundLevels[self.lineIndex]; } else { self.fallAnim(); } } } else { if (self.lineIndex == 1) { //log("WAITING / x=" + self.x + " / y=" + self.y + " / globalSpeedPerLine[0]=" + globalSpeedPerLine[0]); } if (self.finishPosition == 1) { self.victoryAnim(); } if (athlete.isRunning && !self.isBlocked) { nextX += -1 * globalSpeedPerLine[0]; } if (self.isBlocked) { nextX += globalSpeedPerLine[0]; } } // Update athlete position self.x = nextX; self.previousX = self.x; } else { // Player Athlete /* ********************************************************** PLAYER ATHLETE **************************************************** */ if (self.isRunning) { if (!self.isFalling) { // Normal running if (self.isOnGround) { // Running self.leftLeg.height = 200; self.leftArm.height = 200; self.trunk.rotation = 0.125; self.runAnim(); /* if (globalSpeedPerLine[0] != 0) { self.isWaiting = false; self.trunk.rotation = 0.125; self.runAnim(); } else { if (!self.isWaiting) { log("NOW Player Waiting..."); self.isWaiting = true; self.trunk.rotation = 0.0; self.setPosture(idlePosture); } } */ } else { // Jumping self.speedY += self.gravity * 2; self.y += self.speedY * 2; if (self.y >= linesGroundLevels[self.lineIndex]) { // Reached the ground self.isOnGround = true; self.speedY = 0; self.y = linesGroundLevels[self.lineIndex]; if (self.justTookBonus) { log("Restore previous Speed..." + self.speedBeforeBonus); globalSpeedPerLine[self.lineIndex] = self.speedBeforeBonus; self.speedBeforeBonus = 0; } // Restore pos if (globalSpeedPerLine[0] != 0) { self.isWaiting = false; self.trunk.rotation = 0.125; self.runAnim(); } else { if (!self.isWaiting) { self.isWaiting = true; self.trunk.rotation = 0.0; self.setPosture(idlePosture); } } } else { if (self.justTookBonus) { log("Apply Bonus Speed..."); if (!self.speedBeforeBonus) { log("Save previous Speed..." + globalSpeedPerLine[self.lineIndex]); self.speedBeforeBonus = globalSpeedPerLine[self.lineIndex]; } globalSpeedPerLine[self.lineIndex] = self.speedBeforeBonus * 2; } self.jumpAnim(); } } // Update athlete speed if (self.isOnGround && !finishLine.isCut && Date.now() - lastRunTime > 1000) { // Decelerate when not pressing button speedGauge = Math.max(0, speedGauge - 0.02 * (Date.now() - lastRunTime) / 1000); globalSpeedPerLine[0] = globalBaseSpeed * speedGauge; } } else { // Falling self.y += 5; self.fallAnim(); if (self.y >= linesGroundLevels[self.lineIndex] + 200) { // 200 for horizontal trunk offset self.isOnGround = true; self.speedY = 0; self.y = linesGroundLevels[self.lineIndex] + 200; } } } else { if (self.finishPosition == 1) { self.victoryAnim(); } } } self.updatePosture(); }; self.jump = function () { if (self.isAi || Date.now() - self.lastJumpTime > self.interJumpDelayMs) { if (self.isOnGround) { self.isOnGround = false; // Handle jump bonus if (!self.isAi && self.justTookBonus) { self.nbJumps++; if (self.nbJumps > nbBonusJumps) { log("JUMPS FINISHED " + self.nbJumps); self.justTookBonus = false; self.jumpSpeed = self.jumpSpeedDefault; self.speedBeforeBonus = 0; self.nbJumps = 0; globalSpeedPerLine[self.lineIndex] = globalBaseSpeed * speedGauge; bonusManager.endBonus(); } } self.speedY = self.jumpSpeed; self.lastJumpTime = Date.now(); //globalSpeedPerLine[self.lineIndex] = globalSpeedPerLine[self.lineIndex] * 1.1; if (self.lineIndex == 1) { log("--------------- JUMP -------------------- speedY :" + self.speedY); } } } }; self.runAnim = function () { if (self.lineIndex == 1) { log("runAnim #1...self.rightArm.rotation=" + self.rightArm.rotation); } if (!self.isAi && speedGauge < 0.2) { return; } if (self.lineIndex == 1) { log("runAnim #1...go anim!"); } var ocsilDelay = 5 * (self.isAi ? 1 : 2 - speedGauge); 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 () { if (self.lineIndex == 1) { log("jumpAnim #1..."); } var ocsilDelay = 5; var armsAmplitude = 1; var runningArmAngle = Math.sin(LK.ticks / ocsilDelay) * armsAmplitude; // Oscillate arm angle to simulate running faster var armSwitchProgress = Math.sin(LK.ticks / 5) * 0.5; // 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); self.trunk.rotation = 0.333; var rotationSpeed = 0.001; //0.05; // Speed of rotation change if (self.speedY > 0) { var rr = self.rightArm.rotation - self.rightArm.rotation * rotationSpeed; // % (Math.PI * 2); self.rightArm.rotation = rr; var lr = self.leftArm.rotation - self.leftArm.rotation * rotationSpeed; // % (Math.PI * 2); self.leftArm.rotation = lr; //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)); var rr = -Math.PI * 0.5; //self.rightArm.rotation - Math.PI * 3 * rotationSpeed; // % (Math.PI * 2); self.rightArm.rotation = rr; var lr = Math.PI * 0.2; //self.leftArm.rotation + Math.PI * 1.75 * rotationSpeed; // % (Math.PI * 2); self.leftArm.rotation = lr; //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 = -Math.PI * 0.6; //+= -0.55 - self.rightLeg.rotation * rotationSpeed; self.leftLeg.rotation = Math.PI * 0.2; //+= (1 - self.leftLeg.rotation) * rotationSpeed; //self.leftLeg.height -= 0 * rotationSpeed; //self.leftArm.height -= 35 * rotationSpeed; } }; self.fallAnim = function () { if (self.lineIndex == 1) { //log("Check finish for #3 at x=" + opponents[line - 1].x + " vs " + (finishLine.x + 512)); } 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.victoryAnim = function () { if (self.lineIndex == 1) { log("Victory #1"); } var jumpHeight = 10; var waveSpeed = 0.1; var armWaveAmplitude = 0.5; // Make the athlete do little jumps if (self.isOnGround) { self.speedY = -10; // Jump a little self.isOnGround = false; } else { self.speedY += self.gravity; self.y += self.speedY; if (self.y >= linesGroundLevels[self.lineIndex]) { self.y = linesGroundLevels[self.lineIndex]; self.isOnGround = true; } } // Wave arms self.rightArm.rotation = Math.max(-armWaveAmplitude, Math.min(armWaveAmplitude, Math.sin(LK.ticks * waveSpeed) * armWaveAmplitude)) + Math.PI; self.leftArm.rotation = Math.max(-armWaveAmplitude, Math.min(armWaveAmplitude, -Math.sin(LK.ticks * waveSpeed) * armWaveAmplitude * 0.5)); }; self.setPosture = function (newPosture) { log("Set posture: " + newPosture.name); self.targetPosture = newPosture; }; self.restore = function () { log("restore..."); self.stop(); self.hasFlashed = false; self.hasFlashedGround = false; self.isRunning = true; }; self.stop = function () { log("stop..."); self.x = self.previousX || startX + 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.useBonus = function () { log("Player useBonus...", self.justTookBonus); if (self.justTookBonus) { return; } self.justTookBonus = true; self.jumpSpeed = self.jumpSpeedBonus; // Adjust jumpSpeed for bonus }; }); /****************************************************************************************** */ /************************************** BILLBOARD CLASS ************************************ */ /****************************************************************************************** */ var Billboard = Container.expand(function () { var self = Container.call(this); self.billboardGraphics = self.attachAsset('billboard', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 612 }); // Add a message text to the billboard self.welcomeMessage = "WELCOME TO\r\n \r\n "; self.messageText = new Text2("", { // \r\n\r\n AthleSticks!\r\n\r\n Level 1 : Juniors size: 80, fill: "#ffffff" // White color for better visibility }); self.messageText.anchor.set(0.5, 0.5); // Center the text horizontally and vertically self.messageText.x = 1024; // Center horizontally relative to the billboard self.messageText.y = 200; self.addChild(self.messageText); self.messageTextBig = new Text2("AthleSticks!", { size: 150, fill: "#ffffff" // White color for better visibility }); self.messageTextBig.anchor.set(0.5, 0.5); // Center the text horizontally and vertically self.messageTextBig.x = 1024; // Center horizontally relative to the billboard self.messageTextBig.y = 450; self.addChild(self.messageTextBig); self.speedX = globalSpeedPerLine[0]; self._update_migrated = function () { self.speedX = globalSpeedPerLine[0]; self.x += self.speedX; if (self.x < -2048 && finishLine) { self.x = finishLine.x + 256; self.setMessage(""); } }; self.setMessage = function (newMessage, bigMessage) { var nbLineFeeds = (newMessage.match(/\r\n|\r|\n/g) || []).length; self.messageText.y = 220 + 42 * nbLineFeeds; self.messageText.setText(newMessage); if (bigMessage && bigMessage.length > 0) { self.messageTextBig.visible = true; self.messageTextBig.setText(bigMessage); } else { self.messageTextBig.visible = false; } }; self.setLevelMessage = function (go) { var newMessage = ""; switch (difficultyLevel) { case 2: newMessage = "Level 2: Amateurs\r\n \r\n \r\n "; break; case 3: newMessage = "Level 3: Pros\r\n \r\n \r\n"; break; case 4: newMessage = "Level 4: Super Heroes\r\n \r\n \r\n "; break; default: newMessage = "Level 1: Juniors\r\n \r\n \r\n "; break; } newMessage += go ? "" : "GET READY!"; billboard.setMessage(newMessage, go ? " GO!" : ""); }; self.setMessage(self.welcomeMessage, "AthleSticks!"); }); /****************************************************************************************** */ /********************************** BLOCKER CLASS ********************************** */ /****************************************************************************************** */ var Blocker = Container.expand(function (athleteX, groundLevelY) { var self = Container.call(this); self.blockerGraphics = self.attachAsset('blocker01', { anchorX: 0.5, anchorY: 0.0, x: athleteX + 2048 + 512, y: groundLevelY + 75 }); self.speedX = globalSpeedPerLine[0]; self._update_migrated = function () { self.speedX = globalSpeedPerLine[0]; self.x += self.speedX; }; }); /****************************************************************************************** */ /********************************** BONUS CLASS ********************************** */ /****************************************************************************************** */ var BonusManager = Container.expand(function () { var self = Container.call(this); self.isUsed = false; self.alphaDirection = -1; // Bonus asset self.bonusGraphics = self.attachAsset('bonus1', { anchorX: 0.5, anchorY: 0.5, width: 100, height: 100, x: game.width - 150, y: 75, visible: false }); // Update method for animations or effects over time self._update_migrated = function () { if (!self.isUsed) { return; } if (LK.ticks % 120) { self.bonusGraphics.alpha += self.alphaDirection * 0.1; if (self.bonusGraphics.alpha <= 0 || self.bonusGraphics.alpha >= 1) { self.alphaDirection *= -1; } } }; self.useBonus = function () { log("BonusManager useBonus..."); if (self.isUsed) { log("Alredy used ..."); return; } self.isUsed = true; drone.useBonus(); athlete.useBonus(); self.bonusGraphics.visible = true; }; self.endBonus = function () { log("BonusManager endBonus..."); self.bonusGraphics.visible = false; self.isUsed = false; }; }); var Confetti = Container.expand(function () { var self = Container.call(this); self.particles = []; for (var i = 0; i < 100; i++) { var particle = self.attachAsset('bonus1', { anchorX: 0.5, anchorY: 0.5, scaleX: Math.random() * 0.5 + 0.5, scaleY: Math.random() * 0.5 + 0.5, x: Math.random() * 2048, y: Math.random() * -2732, rotation: Math.random() * Math.PI * 2, tint: Math.random() * 0xFFFFFF }); self.particles.push(particle); } self._update_migrated = function () { self.particles.forEach(function (particle) { particle.y += 10; // Speed of falling particle.rotation += 0.1; // Rotation speed if (particle.y > 2732) { // Reset if it goes below the screen particle.y = Math.random() * -2732; } }); }; }); /****************************************************************************************** */ /************************************** DRONE CLASS ************************************ */ /****************************************************************************************** */ var DeliveryDrone = Container.expand(function () { var self = Container.call(this); self.speedX = 0; self.packetSpeed = 0; self.entered = false; self.enterTime = 0; self.packetDropped = false; self.packetFalling = false; self.movePacket = false; self.droneLeaving = false; // Create layers for packets and drones self.packetLayer = new Container(); self.droneLayer = new Container(); game.addChild(self.packetLayer); game.addChild(self.droneLayer); self.packet = self.packetLayer.attachAsset('packet1', { anchorX: 0.5, anchorY: 0.5, y: 75 }); self.bonus = self.packetLayer.attachAsset('bonus1', { anchorX: 0.5, anchorY: 0.5, y: 75, visible: false, isUsed: false }); self.drone1 = self.droneLayer.attachAsset('drone', { anchorX: 0.5, anchorY: 0.5 }); self.drone2 = self.droneLayer.attachAsset('drone2', { anchorX: 0.5, anchorY: 0.5 }); self.drone1.visible = true; self.drone2.visible = false; self.dropPacket = function () { if (!self.packetDropped) { // Make packet fall to the ground self.packetDropped = true; self.packetFalling = true; log("THROW PACKET! self.packet.y < groundLevel : " + self.packet.y + " < " + groundLevel); } }; self.packetLayer.down = function (x, y, obj) { self.dropPacket(); }; // Down works on last layer only ? self.droneLayer.down = function (x, y, obj) { self.dropPacket(); }; self._update_migrated = function () { self.x += self.speedX; // Reverse direction at screen edges if (self.x < 2048 - 300) { self.speedX = 0; } if (self.x > 2048 + 512) { self.speedX = 0; } // Toggle visibility every 120 ticks (2 seconds) if (LK.ticks % 2 == 0) { self.drone1.visible = !self.drone1.visible; self.drone2.visible = !self.drone2.visible; } // Update packet1 position to simulate falling if (self.packetFalling && self.packet.y < groundLevel - self.packet.height / 2) { // Ensure packet stops at ground level self.packetSpeed += 1; self.packet.y += self.packetSpeed; // Adjust speed as necessary if (self.packet.y >= groundLevel - self.packet.height / 2) { self.packet.y = groundLevel - self.packet.height / 2; game.removeChild(self.packet); self.packet.destroy(); // Open the packet self.packet = self.packetLayer.attachAsset('packet2', { anchorX: 0.5, anchorY: 0.5, y: groundLevel - self.packet.height / 2 }); self.packetFalling = false; self.movePacket = true; self.droneLeaving = true; // Show the bonus self.bonus = self.packetLayer.attachAsset('bonus1', { anchorX: 0.5, anchorY: 0.5, visible: true, y: groundLevel - self.packet.height * 1.5, isUsed: false }); } } self.packetLayer.x = self.x; self.packetLayer.y = self.y; self.droneLayer.x = self.x; self.droneLayer.y = self.y; if (self.movePacket && self.x + self.packet.x > -512 && athlete.isRunning) { self.packet.x += globalSpeedPerLine[0]; self.bonus.x += globalSpeedPerLine[0]; } if (self.droneLeaving) { if (self.drone1.x < 2048 + 512) { self.drone1.x += 5; self.drone2.x += 5; if (!self.packetDropped) { self.packet.x += 5; self.bonus.x += 5; } } else { self.droneLeaving = false; } } if (self.entered && Date.now() - self.enterTime > droneStaySeconds * 1000) { self.droneLeaving = true; } }; self.prepare = function () { self.x = 2048 + 300; self.y = 128; self.packetSpeed = 0; game.removeChild(self.packet); self.packet.destroy(); self.packet = self.packetLayer.attachAsset('packet1', { anchorX: 0.5, anchorY: 0.5, y: 75 }); self.visible = false; }; self.enter = function () { if (!self.entered) { self.visible = true; self.speedX = -4; self.enterTime = Date.now(); self.entered = true; } }; self.useBonus = function () { log("Drone useBonus..."); if (self.bonus && !self.bonus.isUsed) { self.bonus.isUsed = true; self.bonus.visible = false; game.removeChild(self.bonus); self.bonus.destroy(); } }; }); /****************************************************************************************** */ /************************************** FINISH LINE CLASS ************************************ */ /****************************************************************************************** */ var FinishLine = Container.expand(function () { var self = Container.call(this); self.isCut = false; self.rightRod = self.attachAsset('finishFlag', { anchorX: 0.5, anchorY: 0.0, x: 580, y: -1540 }); self.centralRodRight = self.attachAsset('finishLine', { anchorX: 0.5, anchorY: 1, y: -200, rotation: Math.PI * 0.125, tint: 0xC80000, height: 600 }); self.centralRodLeft = self.attachAsset('finishLine', { anchorX: 0.5, anchorY: 0, x: 455, y: -1300, rotation: Math.PI * 2.125, tint: 0xC80000, height: 600 }); self.leftRod = self.attachAsset('finishFlag', { anchorX: 0.1, anchorY: 1.0, y: 100 }); self.speedX = globalSpeedPerLine[0]; self._update_migrated = function () { self.speedX = globalSpeedPerLine[0]; self.x += self.speedX; }; self.cut = function () { var cutHeight = 30; var cutInterval = LK.setInterval(function () { if (self.centralRodRight.height > 0) { var newHeight = Math.max(0, self.centralRodRight.height - cutHeight); self.centralRodRight.height = newHeight; self.centralRodLeft.height = newHeight; } else { LK.clearInterval(cutInterval); } }, 25); finishLine.isCut = true; }; }); /****************************************************************************************** */ /************************************** 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, tint: 0x999999 }); self.rightRod = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.0, x: 95, y: -445, //-460 tint: 0x999999 }); self.centralRod = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 1, y: -200, width: 20, rotation: Math.PI * 0.125, tint: 0xFFFFFF //0xffff00 // Apply a yellow tint for glow effect }); self.speedX = globalSpeedPerLine[0]; self._update_migrated = function () { self.speedX = globalSpeedPerLine[0]; self.x += self.speedX; }; }); /****************************************************************************************** */ /********************************** STARTING BLOCK CLASS ********************************** */ /****************************************************************************************** */ var StartingBlocks = Container.expand(function (athleteX, groundLevelY, line) { var self = Container.call(this); self.lines = self.attachAsset('startingBlocks', { anchorX: 0.5, anchorY: 0.0, x: athleteX - 100 - 50, // Position slightly behind the athlete y: groundLevelY + 75, height: 200, rotation: Math.PI * 0.25 }); self.block1 = self.attachAsset('startingBlocks', { anchorX: 0.5, anchorY: 1.0, x: athleteX - 100 - 90, y: groundLevelY + 105, width: 60, height: 30, rotation: Math.PI * 0.5 }); self.block2 = self.attachAsset('startingBlocks', { anchorX: 0.5, anchorY: 1.0, x: athleteX - 100 - 170, y: groundLevelY + 170, width: 60, height: 30, rotation: Math.PI * 0.5 }); // Pointer self.pointer = self.attachAsset('pointer', { anchorX: 0.5, anchorY: 0.5, x: athleteX - 440, y: groundLevelY + 145, rotation: 0.03, visible: line == 0 && currentRoundNumber == 1 }); /* x: 150, y: 2732 - 115, */ self.speedX = globalSpeedPerLine[0]; self._update_migrated = function () { self.speedX = globalSpeedPerLine[0]; self.x += self.speedX; }; }); /****************************************************************************************** */ /************************************** TRACK CLASS ************************************ */ /****************************************************************************************** */ var Track = Container.expand(function () { var self = Container.call(this); // Attach track asset self.trackAsset = self.attachAsset('track', { anchorX: 0.0, anchorY: 0.0 }); }); /**** * 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 = 4; // 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 = 2; //20; // Total number of hurdles var obstacles = [[]]; var obstacleSpawnTicker = 0; var obstacleSpawnDistanceRate = 1.5; // Ratio of screen width between obstacles var obstacleJustPassed = false; var nbBonusJumps = 3; var startingBlocks = []; var blockers = []; var startX = 600; var lastRunTime = 0; var aiJumpLeftLimit = -350; var aiJumpRightLimit = 2048 + 512; var finishLine; var stadium; var stadiumOdd; var field; var fieldOdd; var farField; var farFieldOdd; var track; var scoreTxt; var drone; var bonusManager; var currentFinishPosition = 1; var difficultyLevel = 1; var difficultyLevelMax = 4; var globalBaseSpeed = -20 - 3 * difficultyLevel * difficultyLevel; var globalSpeedPerLine = []; // Global speed for tracks and obstacles default -10 / min = -4 var speedGauge = 0; var raceFinishTime = 0; var raceStartTime = 0; var currentRoundNumber = 1; var droneEnrtyObstacleNumber = 5; var droneStaySeconds = 3; var colorsArray = [0x1188FF, // Blue 0xFF0000, // Red 0x00FF00, // Green 0xFFFF00, // Yellow 0xFF00FF, // Magenta 0x00FFFF, // Cyan 0x800000, // Maroon 0x808000, // Olive 0x800080, // Purple 0x008080 // Teal; ]; var currentRoundColors = []; var isDebug = true; var debugMarker; // UI var hintMobileText; var startText; var startButton; var runButton; var jumpButton; var runButtonHelpText; var jumpButtonHelpText; var billboard; /****************************************************************************************** */ /************************************** POSTURES ****************************************** */ /****************************************************************************************** */ var idlePosture = { name: "idlePosture", trunk: { x: 0, y: 0, r: 0 }, head: { x: 0, y: 0, r: 0 }, rightArm: { x: 20, y: -80, r: Math.PI * 2 * -0.025 }, leftArm: { x: -20, y: -80, r: Math.PI * 2 * 0.025 }, rightLeg: { x: 5, y: 100, h: 200, r: Math.PI * 2 * -0.025 }, leftLeg: { x: -5, y: 100, h: 200, r: Math.PI * 2 * 0.025 } }; var startingBlockPosture = { name: "startingBlockPosture", trunk: { x: 0, y: 0, r: Math.PI * 0.35 }, head: { x: 20, y: 20, r: Math.PI * -0.10 }, rightArm: { x: 15, y: -60, r: Math.PI * 2 * -0.15 }, leftArm: { x: -15, y: -60, r: Math.PI * 2 * -0.15 }, rightLeg: { x: 10, y: 80, h: 150, r: Math.PI * 2 * -0.15 }, leftLeg: { x: -10, y: 80, h: 200, r: Math.PI * 2 * -0.05 } }; /****************************************************************************************** */ /*********************************** 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 (x, y, obj) { switch (gameState) { case GAME_STATE.MENU: gameMenuDown(x, y, obj); break; case GAME_STATE.STARTING: gameStartingDown(x, y, obj); break; case GAME_STATE.PLAYING: gamePlayingDown(x, y, obj); break; case GAME_STATE.SCORE: // Handle score display logic here break; } }); function gameMenuDown(x, y, obj) { log("gameMenuDown..."); cleanMenuState(); initStartingState(); } function gameStartingDown(x, y, obj) { cleanStartingState(); initPlayingState(); } function gamePlayingDown(x, y, obj) { log("gamePlayingDown ..."); if (!finishLine.isCut) { if (athlete.isRunning && !athlete.isFalling) { var speedGaugeDelta = 0; if (x < game.width / 2) { lastRunTime = Date.now(); // Make the athlete run speedGaugeDelta = speedGauge ? 0.1 : 0.6; speedGauge = Math.min(1.1, speedGauge + speedGaugeDelta); globalSpeedPerLine[0] = globalBaseSpeed * speedGauge; animateButtonPress(runButton); } else { speedGaugeDelta = speedGauge ? 0.05 : 0.1; speedGauge = Math.min(1.1, speedGauge + speedGaugeDelta); globalSpeedPerLine[0] = globalBaseSpeed * speedGauge; // Make the athlete jump athlete.jump(); animateButtonPress(jumpButton); } } } else { log("gamePlayingDown : raceFinishTime : " + raceFinishTime + " => " + (Date.now() - raceFinishTime)); if (Date.now() - raceFinishTime > 1000) { // Next round cleanPlayingState(); initMenuState(); } } } /****************************************************************************************** */ /************************************* AI FUNCTIONS *************************************** */ /****************************************************************************************** */ /****************************************************************************************** */ /************************************* GAME STATES **************************************** */ /****************************************************************************************** */ // GAME INITIALIZE function gameInitialize() { log("Game initialize..."); // Add background asset var background = LK.getAsset('background', { anchorX: 0.0, anchorY: 0.0, y: -256, visible: true }); game.addChild(background); var fieldBackground = LK.getAsset('fieldBackground', { anchorX: 0.0, anchorY: 0.0, x: 0, y: 898 }); game.addChild(fieldBackground); field = LK.getAsset('field', { anchorX: 0.0, anchorY: 0.0, x: -50, y: 2732 - 1024 - 600 }); game.addChild(field); fieldOdd = LK.getAsset('fieldOdd', { anchorX: 0.0, anchorY: 0.0, x: 2048 + 50, y: 2732 - 1024 - 600 }); game.addChild(fieldOdd); farField = LK.getAsset('farField', { anchorX: 0.0, anchorY: 0.0, x: -50, y: 2732 - 1024 - 600 - 512 }); game.addChild(farField); farFieldOdd = LK.getAsset('farFieldOdd', { anchorX: 0.0, anchorY: 0.0, x: 2048 + 50, y: 2732 - 1024 - 600 - 512 }); game.addChild(farFieldOdd); stadium = LK.getAsset('stadium', { anchorX: 0.0, anchorY: 0.0, x: -50, y: 150 }); game.addChild(stadium); stadiumOdd = LK.getAsset('stadiumOdd', { anchorX: 0.0, anchorY: 0.0, x: 2048 + 50, y: 150 }); game.addChild(stadiumOdd); // Initialize track using Track class track = game.addChild(new Track()); track.x = -50; track.y = 2732 - 1024; // Track lines for (var i = 0; i < 6; i++) { var trackLine = LK.getAsset('trackLine', { anchorX: 0.0, anchorY: 0.0, x: 0, y: groundLevel + 400 - 215 * i }); game.addChild(trackLine); } billboard = game.addChild(new Billboard()); bonusManager = game.addChild(new BonusManager()); hintMobileText = new Text2('Best on Mobile', { size: 90, fill: "#FFFFFF" }); hintMobileText.anchor.set(0.5, 0.5); // Center the text horizontally and vertically hintMobileText.x = 2048 / 2; // Center horizontally hintMobileText.y = 2732 - 120; // Center vertically hintMobileText.rotation = -0.2; game.addChild(hintMobileText); gameState = GAME_STATE.MENU; initMenuState(); if (isDebug) { // Debug Marker debugMarker = LK.getAsset('debugMarker', { anchorX: 0.5, anchorY: 0.5 }); game.addChild(debugMarker); debugMarker.x = 0; debugMarker.y = groundLevel; } } // GAME MENU function initMenuState() { log("initMenuState..."); // Add Button in the center of the screen startButton = LK.getAsset('button', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); game.addChild(startButton); // 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); // Reset fields and stadium field.x = -50; fieldOdd.x = 2048 + 50; farField.x = -50; farFieldOdd.x = 2048 + 50; stadium.x = -50; stadiumOdd.x = 2048 + 50; setRoundColors(); gameState = GAME_STATE.MENU; } function menuHandling() { if (drone) { drone._update_migrated(); } } function cleanMenuState() { game.removeChild(startText); startText.destroy(); game.removeChild(startButton); startButton.destroy(); if (hintMobileText) { game.removeChild(hintMobileText); hintMobileText.destroy(); hintMobileText = null; } } // STARTING function initStartingState() { log("initStartingState..."); // Initialize ground levels & speeds for (var line = 0; line < numberOfLines; line++) { linesGroundLevels[line] = groundLevel - 200 - 220 * line; globalSpeedPerLine[line] = globalBaseSpeed * (line ? 1.0 : speedGauge); } // Spawn obstacles spawnObstacles(); // Add starting blocks to each athlete's starting position for (var i = 0; i <= numberOfOpponents; i++) { startingBlocks[i] = new StartingBlocks(startX + 10 + 100 * i, linesGroundLevels[i] + 145, i); game.addChild(startingBlocks[i]); } // Initialize opponents for (var i = numberOfOpponents - 1; i >= 0; i--) { opponents[i] = game.addChild(new Athlete(i + 1)); opponents[i].restore(); opponents[i].isRunning = false; opponents[i].setPosture(startingBlockPosture); opponents[i].y += 120; } // Initialize athlete athlete = game.addChild(new Athlete(0)); athlete.restore(); athlete.isRunning = false; athlete.setPosture(startingBlockPosture); athlete.y += 120; runButton = LK.getAsset('runButton', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 4, y: 2732 / 3, alpha: 0.7, tint: 0xcccccc, visible: false }); game.addChild(runButton); // Add second semi-transparent runButton in the upper half of the screen jumpButton = LK.getAsset('runButton', { anchorX: 0.5, anchorY: 0.5, x: 2048 * 3 / 4, y: 2732 / 3, alpha: 0.7, tint: 0xcccccc, rotation: -1 * Math.PI / 2, visible: false }); game.addChild(jumpButton); // Buttons help texts runButtonHelpText = new Text2('Run', { size: 100, fill: "#333333" }); runButtonHelpText.anchor.set(0.5, 0.5); runButtonHelpText.x = -365; runButtonHelpText.y = -80; LK.gui.center.addChild(runButtonHelpText); jumpButtonHelpText = new Text2('Jump', { size: 100, fill: "#333333" }); jumpButtonHelpText.anchor.set(0.5, 0.5); jumpButtonHelpText.x = 365; jumpButtonHelpText.y = -80; LK.gui.center.addChild(jumpButtonHelpText); showRunButtons(); billboard.setLevelMessage(); gameState = GAME_STATE.STARTING; } function cleanStartingState() { for (var i = numberOfOpponents - 1; i >= 0; i--) { opponents[i].setPosture(idlePosture); opponents[i].isRunning = true; } athlete.setPosture(idlePosture); athlete.isRunning = true; runButtonHelpText.visible = false; jumpButtonHelpText.visible = false; } function gameStarting() { //log("gameStarting..."); for (var i = 0; i <= numberOfOpponents; i++) { var athletes = [athlete].concat(opponents); athletes[i]._update_migrated(); } if (drone) { drone._update_migrated(); } } // PLAYING function initPlayingState() { scoreTxt = new Text2("0/" + numberOfObstacles.toString(), { size: 80, fill: "#FFFFFF" }); scoreTxt.anchor.set(0.25, 0.125); // Center the score text horizontally LK.gui.top.addChild(scoreTxt); // Add the score text to the GUI overlay at the top center currentFinishPosition = 1; // Remove starting blocks offset for (var i = numberOfOpponents - 1; i >= 0; i--) { opponents[i].y -= 120; } athlete.y -= 120; speedGauge = 0.6; globalSpeedPerLine[0] = globalBaseSpeed * speedGauge; drone = new DeliveryDrone(); // false for odd drone graphic drone.prepare(); bonusManager.endBonus(); game.addChild(drone); raceStartTime = Date.now(); billboard.setLevelMessage(true); gameState = GAME_STATE.PLAYING; } function gamePlaying() { //log("Game playing..."); // Update fields updateFields(); // Update obstacles updateObstacles(); // Update Progress updateProgress(); // Update opponents for (var i = numberOfOpponents - 1; i >= 0; i--) { opponents[i]._update_migrated(); game.addChild(opponents[i]); } // Update athlete athlete._update_migrated(); game.addChild(athlete); // Check for collisions checkForCollisions(); // Update drone drone._update_migrated(); bonusManager._update_migrated(); } function cleanPlayingState() { // Increment round number currentRoundNumber++; // Increase difficulty if the athlete has won the race if (athlete.finishPosition == 1) { difficultyLevel++; if (difficultyLevel > difficultyLevelMax) { // TODO SWITCH TO SCORE STATE LK.showGameOver(); } globalBaseSpeed = -20 - 3 * difficultyLevel * difficultyLevel; } // Set level message billboard.setLevelMessage(); // Remove Opponents & Athlete for (var i = numberOfOpponents - 1; i >= 0; i--) { game.removeChild(opponents[i]); opponents[i].destroy(); } game.removeChild(athlete); athlete.destroy(); // Remove Obstacles for (var i = 0; i < numberOfLines; i++) { for (var j = 0; j < obstacles[i].length; j++) { if (obstacles[i][j]) { game.removeChild(obstacles[i][j]); obstacles[i][j].destroy(); } } } // Remove Finish Line game.removeChild(finishLine); finishLine.destroy(); // Remove Score Text LK.gui.top.removeChild(scoreTxt); scoreTxt.destroy(); } /****************************************************************************************** */ /************************************** GAME FUNCTIONS ************************************ */ /****************************************************************************************** */ function updateFields() { if (!(athlete.isFalling && athlete.isOnGround)) { field.x += globalSpeedPerLine[0]; var offset = 20; //log("Field Decalage :" + globalSpeedPerLine[0]); // Reset position to create a continuous effect if (field.x <= -2048 - offset) { field.x = 2048 + offset; } fieldOdd.x += globalSpeedPerLine[0]; // Reset position to create a continuous effect if (fieldOdd.x <= -2048 - offset) { fieldOdd.x = 2048 + offset; } // Far field farField.x += globalSpeedPerLine[0] * 0.8; // Reset position to create a continuous effect if (farField.x <= -2048 - offset) { farField.x = 2048 + offset; } farFieldOdd.x += globalSpeedPerLine[0] * 0.8; // Reset position to create a continuous effect if (farFieldOdd.x <= -2048 - offset) { farFieldOdd.x = 2048 + offset; } stadium.x += globalSpeedPerLine[0] * 0.4; // Reset position to create a continuous effect if (stadium.x <= -2048 - offset) { stadium.x = 2048 + offset; } stadiumOdd.x += globalSpeedPerLine[0] * 0.4; // Reset position to create a continuous effect if (stadiumOdd.x <= -2048 - offset) { stadiumOdd.x = 2048 + offset; } } } 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 - 212 * line; //- 220 * line; obstacles[line].push(newObstacle); game.addChild(newObstacle); } } finishLine = new FinishLine(); finishLine.x = 2048 * obstacleSpawnDistanceRate * (numberOfObstacles + 1) + 1024; // 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_migrated(); // 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; } } } } for (var i = 0; i <= numberOfOpponents; i++) { startingBlocks[i]._update_migrated(); if (startingBlocks[i].x < -1024) { game.removeChild(startingBlocks[i]); startingBlocks[i].destroy(); } } for (var line = 0; line < numberOfLines; line++) { if (blockers[line]) { blockers[line]._update_migrated(); } } finishLine._update_migrated(); billboard._update_migrated(); } 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(numberOfObstacles - obstacles[0].length + "/" + numberOfObstacles); // Update score text with prefix } for (var line = 0; line < numberOfLines; line++) { if (line == 0 && !athlete.finishPosition && athlete.x > finishLine.x) { athlete.finishPosition = getFinishPosition(); log("Finish athlete => #" + athlete.finishPosition); } if (line > 0 && opponents[line - 1].x > finishLine.x) { if (!opponents[line - 1].finishPosition) { opponents[line - 1].finishPosition = getFinishPosition(); log("Finish opponent " + line + "=> #" + opponents[line - 1].finishPosition); opponents[line - 1].finishStandingOffset = 512 * Math.random(); } // Don't go to far after finish var finishStandingPosition = finishLine.x + 2048 - 200 - (opponents[line - 1].finishStandingOffset || 0); opponents[line - 1].x = Math.min(finishStandingPosition, opponents[line - 1].x); if (opponents[line - 1].x >= finishStandingPosition) { // Stop running when reach final position opponents[line - 1].isRunning = false; } } } if (finishLine.isCut) { for (var line = 0; line < numberOfLines; line++) { if (line > 0 && opponents[line - 1].x < finishLine.x + 512) { continue; } // Handle stoping slowly when AI is late if (globalSpeedPerLine[line] < -1) { globalSpeedPerLine[line] += 0.5 + 0.5 * Math.random(); // Decrement speed gradually } else if (globalSpeedPerLine[line] > 1) { globalSpeedPerLine[line] -= 0.5 + 0.5 * Math.random(); // Increment speed gradually if somehow above 0 } else { globalSpeedPerLine[line] = 0; // Set to 0 if very close to it if (line == 0 && athlete.isRunning) { athlete.isRunning = false; athlete.stop(); } if (line > 0 && opponents[line - 1].isRunning) { log("Opop #" + line + " stopping at " + opponents[line - 1].x); opponents[line - 1].isRunning = false; opponents[line - 1].stop(); } } } } else if (finishLine.x - athlete.x > 2048) { // Handle stoping when AI has big advance for (var line = 1; line < numberOfLines; line++) { if (line == 1) { //log("Check finish for #3 at x=" + opponents[line - 1].x + " vs " + (finishLine.x + 512)); } if (opponents[line - 1].x > finishLine.x + 512 && opponents[line - 1].isRunning) { if (line == 1) { log("OK #3 Passed the line !"); } // stop opponents at finish log("Stoping #" + line + " at " + opponents[line - 1].x + " > " + finishLine.x); opponents[line - 1].isRunning = false; opponents[line - 1].stop(); globalSpeedPerLine[line] = 0; } } } if (drone && !drone.entered && difficultyLevel > 1 && numberOfObstacles - obstacles[0].length > droneEnrtyObstacleNumber) { drone.enter(); } } 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; } } else { if (opponents[line - 1].x > aiJumpLeftLimit && opponents[line - 1].x < aiJumpRightLimit && 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; } if (blockers[line] && opponents[line - 1].isRunning && opponents[line - 1].head.intersects(blockers[line])) { var blocker = blockers[line]; log("Line " + line + " : opponent " + opponents[line - 1].lineIndex + " collided with Blocker ", blocker); LK.effects.flashScreen(0xff0000, 500); // Flash screen red for half a second opponents[line - 1].isRunning = false; opponents[line - 1].isBlocked = true; (function (line) { LK.setTimeout(function () { log("Line " + line + " : opponent " + opponents[line - 1].lineIndex + " Restore after block"); game.removeChild(blockers[line]); blockers[line].destroy(); blockers.splice(line, 1); opponents[line - 1].isRunning = true; opponents[line - 1].isBlocked = false; opponents[line - 1].restore(); }, 2000); // Delay game over to allow fall animation to be seen })(line); } } } } handleFallEvent(); if (!obstacles[0].length && !finishLine.isCut) { var isReached = athlete.x > finishLine.x; if (isReached) { raceFinishTime = Date.now(); var raceTime = (raceFinishTime - raceStartTime) / 1000; if (raceTime >= 100) { raceTime = 99.99; } var raceTimeText = raceTime.toFixed(2) + " sec"; raceTimeText = raceTime < 10 ? "0" + raceTimeText : raceTimeText; var rankText = "Rank: #" + athlete.finishPosition + "\r\n"; rankText = athlete.finishPosition == 1 ? " " + rankText + "QUALIFIED!" : " " + rankText + "Not qualified"; scoreTxt.setText(""); finishLine.isCut = true; finishLine.cut(); billboard.setMessage(rankText, raceTimeText); bonusManager.endBonus(); hideRunButtons(); } } // Take Bonus if (drone && drone.bonus && !drone.bonus.isUsed && athlete.trunk.intersects(drone.bonus)) { log("bonusManager useBonus..."); bonusManager.useBonus(); } } 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; globalSlowDownAfterJump = true; } 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 * speedGauge; 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); } }); } function getFinishPosition() { return currentFinishPosition++; } function setRoundColors() { currentRoundColors = [0x1188FF]; // Fixed color for the player var usedColors = [0x1188FF]; // Initialize with player's color to avoid repetition for (var i = 1; i <= numberOfOpponents; i++) { var color; do { color = colorsArray[Math.floor(Math.random() * colorsArray.length)]; } while (usedColors.includes(color)); // Ensure unique color selection currentRoundColors.push(color); usedColors.push(color); } } function showRunButtons() { runButton.visible = true; jumpButton.visible = true; if (currentRoundNumber == 1) { // show help texts only 1st time runButtonHelpText.visible = true; jumpButtonHelpText.visible = true; } else { runButtonHelpText.visible = false; jumpButtonHelpText.visible = false; } } function hideRunButtons() { runButton.visible = false; jumpButton.visible = false; runButtonHelpText.visible = false; jumpButtonHelpText.visible = false; } function animateButtonPress(button) { // Animate runButton to simulate a button press button.width = 512 * 0.95; button.height = 512 * 0.95; button.alpha = 0.8; LK.setTimeout(function () { button.width = 512; button.height = 512; button.alpha = 0.6; }, 100); } /****************************************************************************************** */ /************************************** MAIN GAME LOOP ************************************ */ /****************************************************************************************** */ LK.on('tick', function () { switch (gameState) { case GAME_STATE.MENU: menuHandling(); break; case GAME_STATE.STARTING: gameStarting(); break; case GAME_STATE.PLAYING: gamePlaying(); break; case GAME_STATE.SCORE: // Handle score display logic here break; } }); gameInitialize();
===================================================================
--- original.js
+++ change.js
@@ -497,9 +497,8 @@
self.messageText.x = 1024; // Center horizontally relative to the billboard
self.messageText.y = 200;
self.addChild(self.messageText);
self.messageTextBig = new Text2("AthleSticks!", {
- // \r\n\r\n AthleSticks!\r\n\r\n Level 1 : Juniors
size: 150,
fill: "#ffffff" // White color for better visibility
});
self.messageTextBig.anchor.set(0.5, 0.5); // Center the text horizontally and vertically
@@ -514,16 +513,21 @@
self.x = finishLine.x + 256;
self.setMessage("");
}
};
- self.setMessage = function (newMessage) {
+ self.setMessage = function (newMessage, bigMessage) {
var nbLineFeeds = (newMessage.match(/\r\n|\r|\n/g) || []).length;
self.messageText.y = 220 + 42 * nbLineFeeds;
self.messageText.setText(newMessage);
+ if (bigMessage && bigMessage.length > 0) {
+ self.messageTextBig.visible = true;
+ self.messageTextBig.setText(bigMessage);
+ } else {
+ self.messageTextBig.visible = false;
+ }
};
self.setLevelMessage = function (go) {
var newMessage = "";
- self.messageTextBig.visible = false;
switch (difficultyLevel) {
case 2:
newMessage = "Level 2: Amateurs\r\n \r\n \r\n ";
break;
@@ -536,12 +540,12 @@
default:
newMessage = "Level 1: Juniors\r\n \r\n \r\n ";
break;
}
- newMessage += go ? "GO!" : "GET READY!";
- billboard.setMessage(newMessage);
+ newMessage += go ? "" : "GET READY!";
+ billboard.setMessage(newMessage, go ? " GO!" : "");
};
- self.setMessage(self.welcomeMessage);
+ self.setMessage(self.welcomeMessage, "AthleSticks!");
});
/****************************************************************************************** */
/********************************** BLOCKER CLASS ********************************** */
/****************************************************************************************** */
@@ -604,8 +608,35 @@
self.bonusGraphics.visible = false;
self.isUsed = false;
};
});
+var Confetti = Container.expand(function () {
+ var self = Container.call(this);
+ self.particles = [];
+ for (var i = 0; i < 100; i++) {
+ var particle = self.attachAsset('bonus1', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: Math.random() * 0.5 + 0.5,
+ scaleY: Math.random() * 0.5 + 0.5,
+ x: Math.random() * 2048,
+ y: Math.random() * -2732,
+ rotation: Math.random() * Math.PI * 2,
+ tint: Math.random() * 0xFFFFFF
+ });
+ self.particles.push(particle);
+ }
+ self._update_migrated = function () {
+ self.particles.forEach(function (particle) {
+ particle.y += 10; // Speed of falling
+ particle.rotation += 0.1; // Rotation speed
+ if (particle.y > 2732) {
+ // Reset if it goes below the screen
+ particle.y = Math.random() * -2732;
+ }
+ });
+ };
+});
/****************************************************************************************** */
/************************************** DRONE CLASS ************************************ */
/****************************************************************************************** */
var DeliveryDrone = Container.expand(function () {
@@ -773,18 +804,18 @@
anchorX: 0.5,
anchorY: 1,
y: -200,
rotation: Math.PI * 0.125,
- tint: 0x1188FF,
+ tint: 0xC80000,
height: 600
});
self.centralRodLeft = self.attachAsset('finishLine', {
anchorX: 0.5,
anchorY: 0,
x: 455,
y: -1300,
rotation: Math.PI * 2.125,
- tint: 0x1188FF,
+ tint: 0xC80000,
height: 600
});
self.leftRod = self.attachAsset('finishFlag', {
anchorX: 0.1,
@@ -1688,11 +1719,19 @@
var isReached = athlete.x > finishLine.x;
if (isReached) {
raceFinishTime = Date.now();
var raceTime = (raceFinishTime - raceStartTime) / 1000;
- scoreTxt.setText(raceTime.toFixed(2) + " sec");
+ if (raceTime >= 100) {
+ raceTime = 99.99;
+ }
+ var raceTimeText = raceTime.toFixed(2) + " sec";
+ raceTimeText = raceTime < 10 ? "0" + raceTimeText : raceTimeText;
+ var rankText = "Rank: #" + athlete.finishPosition + "\r\n";
+ rankText = athlete.finishPosition == 1 ? " " + rankText + "QUALIFIED!" : " " + rankText + "Not qualified";
+ scoreTxt.setText("");
finishLine.isCut = true;
finishLine.cut();
+ billboard.setMessage(rankText, raceTimeText);
bonusManager.endBonus();
hideRunButtons();
}
}
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.