Code edit (3 edits merged)
Please save this source code
User prompt
pass a callback to drownAnim to act when anim is finished
User prompt
in drownAnim, instead of `var animLoop = true;` use a public property like self.isDrownAnimPlaying
User prompt
Now Mushrooms should only spawn on the middle of platforms
Code edit (1 edits merged)
Please save this source code
User prompt
when Clearing water holes, move back the left most ground to hide the gap left by the removed water hole
User prompt
extract all the code of drown anim end into a resetRun() function
User prompt
at end of drownAnim, remove all current coins, monsters and waterHoles to start again on a fresh screen
Code edit (1 edits merged)
Please save this source code
User prompt
When drownAnim end restore player correctly : - add a wite flash - hide playerDieFrame1 and 2 - restore player at its base position and in running state
User prompt
hide die frames when resatoring player
User prompt
in drownAnim, after player is out of screen replace it at initial position if lives > 0 and unpause game movments
User prompt
in drownPlayer() pause all movements (backgrounds, coins, monsters...) ; use a global var for that;
User prompt
in drownAnim() ,animate player drown by alterning between 'playerDieFrame2' and 'playerDieFrame3' and make player fall vertically until going out of screen bottom ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
in drownPlayer() call new empty function drownAnim() and remove playerHit() call
Code edit (1 edits merged)
Please save this source code
User prompt
fix WaterHoleManager.checkPlayerCollision() because playerBounds is in format: { left: self.x - 75, right: self.x + 75, top: self.y - 100, bottom: self.y + 100 } not x,y,w,h
Code edit (1 edits merged)
Please save this source code
User prompt
add logs to checkPlayerCollision because it doesn't work
User prompt
extract `playerBounds.x - playerBounds.width / 2 < holeX + waterHole.boundingBox.width / 2 && playerBounds.x + playerBounds.width / 2 > holeX - waterHole.boundingBox.width / 2 && playerBounds.y + playerBounds.height / 2 > groundLevel - 150` in a dedicated function
Code edit (1 edits merged)
Please save this source code
Code edit (3 edits merged)
Please save this source code
User prompt
dans WaterHoleManager, quand player touche l'eau, appeler une nouvelle fonction player.drownPlayer() qui contiendra ``` if (lives > 0) { // Lose a life lives--; // Update lives counter livesCounter.updateLives(lives); // Player hit animation or die if no lives left if (lives <= 0) { player.die(); // Show game over after animation LK.setTimeout(function () { LK.showGameOver(); }, 4000); } else { player.hitPlayer(); } } ```
User prompt
if faut corriger ``` return { left: self.x - 75, right: self.x + 75, top: self.y - 100, bottom: self.y + 100 }; ``` pour utiliser le dimesions de self.boundingBox au lieu de valeurs fixes
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Define a class for coins with 8-frame animation var Coin = Container.expand(function () { var self = Container.call(this); // Create and attach all 8 coin frames self.frames = [self.attachAsset('coinFrame1', { anchorX: 0.5, anchorY: 0.5, alpha: 1 // First frame visible initially }), self.attachAsset('coinFrame2', { anchorX: 0.5, anchorY: 0.5, alpha: 0 // Hidden initially }), self.attachAsset('coinFrame3', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('coinFrame4', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('coinFrame5', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('coinFrame6', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('coinFrame7', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('coinFrame8', { anchorX: 0.5, anchorY: 0.5, alpha: 0 })]; self.currentFrame = 0; self.speed = 10; // Horizontal movement speed self.collected = false; self.animationSpeed = 4; // Frames to wait before changing animation frame // Method to reset coin for reuse from pool self.reset = function (x, y) { self.x = x; self.y = y; self.collected = false; self.alpha = 1; // Reset animation state self.currentFrame = 0; // Show first frame, hide others for (var i = 0; i < self.frames.length; i++) { self.frames[i].alpha = i === 0 ? 1 : 0; } self.animationTimer = 0; }; // Initialize animation self.startAnimation = function () { // No need to call animate directly, it will be called via update self.animationTimer = 0; }; self.animate = function () { // Hide current frame self.frames[self.currentFrame].alpha = 0; // Move to next frame self.currentFrame = (self.currentFrame + 1) % self.frames.length; // Show next frame self.frames[self.currentFrame].alpha = 1; }; self.getBounds = function () { return { left: self.x - 40, right: self.x + 40, top: self.y - 40, bottom: self.y + 40 }; }; self.update = function () { // Handle animation timing with frame counter self.animationTimer += 1; if (self.animationTimer >= 6) { // 6 frames ≈ 100ms at 60fps self.animate(); self.animationTimer = 0; } // Move coin from right to left only if player is not hit and lives >= 0 if (!player || !player.isHit && lives >= 0) { self.x -= self.speed * globalSpeed; } // Remove coin when it goes off-screen if (self.x < -100) { // Remove from coins array before returning to pool var coinIndex = coins.indexOf(self); if (coinIndex > -1) { coins.splice(coinIndex, 1); } // Return to pool instead of destroying if (self.parent) { self.parent.removeChild(self); } self.visible = false; coinPool.push(self); } // Check if player collected the coin (intersection with player) // Only allow collection if player can jump (start button was pressed) if (!self.collected && player && player.getBounds && player.canJump) { var coinBounds = self.getBounds(); var playerBounds = player.getBounds(); if (playerBounds.left < coinBounds.right && playerBounds.right > coinBounds.left && playerBounds.top < coinBounds.bottom && playerBounds.bottom > coinBounds.top) { self.collected = true; // Play coin sound when collected LK.getSound('coin').play(); // Increment score immediately LK.setScore(LK.getScore() + 10); if (scoreText) { scoreText.setText(LK.getScore()); } // Update coin counter immediately - increment coins by 1 (independent from score) if (coinCounter) { coinCount++; // Increment coin count coinCounter.updateCount(coinCount); } // Coin collection animation tween(self, { y: self.y - 100, alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Remove from coins array before returning to pool var coinIndex = coins.indexOf(self); if (coinIndex > -1) { coins.splice(coinIndex, 1); } // Return to pool instead of destroying if (self.parent) { self.parent.removeChild(self); } self.visible = false; coinPool.push(self); } }); } } }; // Start the animation when created self.startAnimation(); return self; }); // Define a class for the coin counter display var CoinCounter = Container.expand(function () { var self = Container.call(this); // Create and attach coin icon var coinIcon = self.attachAsset('coinFrame1', { anchorX: 0.5, anchorY: 0.5, x: 220, y: 50, width: 96, height: 96 }); // Create 3-digit display (hundreds, tens, units) self.hundreds = new Text2('0', { size: 100, fill: 0xFFFFFF }); self.hundreds.anchor.set(0.5); self.hundreds.x = 0; self.hundreds.y = 50; self.addChild(self.hundreds); self.tens = new Text2('0', { size: 100, fill: 0xFFFFFF }); self.tens.anchor.set(0.5); self.tens.x = 60; self.tens.y = 50; self.addChild(self.tens); self.units = new Text2('0', { size: 100, fill: 0xFFFFFF }); self.units.anchor.set(0.5); self.units.x = 120; self.units.y = 50; self.addChild(self.units); // Method to update the counter display self.updateCount = function (count) { // Ensure count is between 0-999 count = Math.min(999, Math.max(0, count)); // Calculate digits var h = Math.floor(count / 100); var t = Math.floor(count % 100 / 10); var u = count % 10; // Update text display self.hundreds.setText(h.toString()); self.tens.setText(t.toString()); self.units.setText(u.toString()); }; // Initialize with 0 self.updateCount(0); return self; }); // Define a class for enemies var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); // Add pulsing animation self.startAnimation = function () { // Create a subtle x-axis pulse animation with faster timing tween(self, { scaleX: 1.15 }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { scaleX: 0.9 }, { duration: 200, easing: tween.easeInOut, onFinish: self.startAnimation }); } }); }; self.speed = 15; // Plus rapide que le sol (10) pour qu'ils avancent vers la gauche self.velocityY = 0; self.gravity = 0.7; // Même gravité que le joueur self.currentPlatform = null; // Plateforme actuelle sur laquelle l'ennemi se trouve // Reset method to reuse enemy self.reset = function (x, y) { self.x = x; self.y = y; self.velocityY = 0; self.currentPlatform = null; self.passed = false; // Start the animation when enemy is reset self.startAnimation(); }; self.update = function () { // Only move if player is not hit and lives >= 0 if (player && player.isHit || lives < 0) { return; } self.x -= self.speed * globalSpeed; // Vérifier si l'ennemi est toujours sur sa plateforme actuelle if (self.currentPlatform) { var enemyBounds = self.getBounds(); var platformBounds = { left: self.currentPlatform.x - 500, right: self.currentPlatform.x + 500 }; // Si l'ennemi sort de la plateforme, il commence à tomber if (enemyBounds.left > platformBounds.right || enemyBounds.right < platformBounds.left) { self.currentPlatform = null; } } // Appliquer la gravité si l'ennemi n'est pas sur une plateforme if (!self.currentPlatform) { self.velocityY += self.gravity * globalSpeed; self.y += self.velocityY * globalSpeed; } // Vérifier collision avec le sol // Adjust Y position to account for enemy's height (anchor is 0.5), similar to player offset var enemyVisualBottomOffset = 75; // Half of enemy height (150 / 2) if (self.y >= groundLevel - enemyVisualBottomOffset) { self.y = groundLevel - enemyVisualBottomOffset; // Set enemy bottom to ground level self.velocityY = 0; self.currentPlatform = null; // L'ennemi est sur le sol, pas sur une plateforme } // Vérifier collision avec les plateformes seulement si l'ennemi tombe if (self.velocityY > 0) { for (var i = 0; i < platforms.length; i++) { var platform = platforms[i]; var enemyBounds = self.getBounds(); var platformBounds = { left: platform.x - 500, right: platform.x + 500, top: platform.y - 50, bottom: platform.y + 50 }; // Si l'ennemi atterrit sur une plateforme if (enemyBounds.bottom >= platformBounds.top && enemyBounds.bottom - self.velocityY < platformBounds.top && enemyBounds.right > platformBounds.left && enemyBounds.left < platformBounds.right) { self.y = platform.y - 75; self.velocityY = 0; self.currentPlatform = platform; // Mémoriser la plateforme actuelle break; } } } if (self.x < -50) { // Instead of destroying, return to pool if (self.parent) { self.parent.removeChild(self); } // Remove from enemies array var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } // Add to pool for reuse self.visible = false; enemyPool.push(self); } }; self.getBounds = function () { return { left: self.x - 50, right: self.x + 50, top: self.y - 50, bottom: self.y + 50 }; }; // Start animation when enemy is created self.startAnimation(); return self; }); // Define a class for lives counter display var LivesCounter = Container.expand(function () { var self = Container.call(this); // Create heart icons for lives self.hearts = []; // Number of heart icons to create var maxHearts = 3; // Create heart icons using coin assets (since we don't have heart assets) for (var i = 0; i < maxHearts; i++) { var heart = self.attachAsset('playerRunFrame2', { anchorX: 0.5, anchorY: 0.5, x: i * 70, // Space hearts horizontally y: 0, width: 60, height: 60 }); self.hearts.push(heart); } // Method to update lives display self.updateLives = function (livesCount) { // Ensure lives count is between 0-3 livesCount = Math.min(maxHearts, Math.max(0, livesCount)); // Show or hide hearts based on current lives for (var i = 0; i < maxHearts; i++) { self.hearts[i].visible = i < livesCount; } }; // Initialize with 3 lives self.updateLives(3); return self; }); // Define StartButton class // Define Mushroom class for power-up var Mushroom = Container.expand(function () { var self = Container.call(this); // Create and attach mushroom asset var mushroomGraphics = self.attachAsset('mushroom', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; // Same speed as platforms self.collected = false; // Method to reset mushroom for reuse from pool self.reset = function (x, y) { self.x = x; self.y = y; self.collected = false; self.alpha = 1; }; self.getBounds = function () { return { left: self.x - 50, right: self.x + 50, top: self.y - 45, bottom: self.y + 45 }; }; self.update = function () { // Move mushroom from right to left only if player is not hit and lives >= 0 if (!player || !player.isHit && lives >= 0) { self.x -= self.speed * globalSpeed; } // Remove mushroom when it goes off-screen if (self.x < -100) { // Remove from mushrooms array before returning to pool var mushroomIndex = mushrooms.indexOf(self); if (mushroomIndex > -1) { mushrooms.splice(mushroomIndex, 1); } // Return to pool instead of destroying if (self.parent) { self.parent.removeChild(self); } self.visible = false; mushroomPool.push(self); } // Check if player collected the mushroom if (!self.collected && player && player.getBounds && player.canJump) { var mushroomBounds = self.getBounds(); var playerBounds = player.getBounds(); if (playerBounds.left < mushroomBounds.right && playerBounds.right > mushroomBounds.left && playerBounds.top < mushroomBounds.bottom && playerBounds.bottom > mushroomBounds.top) { self.collected = true; // Change player morph state if currently in DEFAULT state if (player.morphState === 0) { // Play mushroom eat sound when player is in DEFAULT state LK.getSound('mushroomEat').play(); player.morphState = 1; player.updateRefScale(); } // Add 100 points LK.setScore(LK.getScore() + 100); if (scoreText) { scoreText.setText(LK.getScore()); } // Collection animation tween(self, { y: self.y - 100, alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Remove from mushrooms array before returning to pool var mushroomIndex = mushrooms.indexOf(self); if (mushroomIndex > -1) { mushrooms.splice(mushroomIndex, 1); } // Return to pool instead of destroying if (self.parent) { self.parent.removeChild(self); } self.visible = false; mushroomPool.push(self); } }); } } }; return self; }); // Define a class for platforms var Platform = Container.expand(function () { var self = Container.call(this); var platformGraphics = self.attachAsset('platform', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.passed = false; self.update = function () { // Only move if player is not hit and lives >= 0 if (player && player.isHit || lives < 0) { return; } self.x -= self.speed * globalSpeed; if (self.x < -500) { // Instead of destroying, remove from parent and add to pool if (self.parent) { self.parent.removeChild(self); } // Remove from platforms array var index = platforms.indexOf(self); if (index > -1) { platforms.splice(index, 1); } // Add to pool for reuse self.visible = false; platformPool.push(self); } }; return self; }); // Define a class for the player character var Player = Container.expand(function () { var self = Container.call(this); // Add morphState property to track player state // 0 - DEFAULT, 1 - BIG, 2 - FIRE self.morphState = 0; // Add reference scale properties self.refScaleX = 0.5; self.refScaleY = 0.5; // Initialize player with appropriate scale based on morphState self.init = function () { self.updateRefScale(); }; // Update player reference scale based on morphState self.updateRefScale = function () { // Set player scale based on morphState // Store current scale before updating var oldScaleY = self.refScaleY; // Calculate current offset from ground var visualBottomOffset = self.playerHeight * oldScaleY / 2; if (self.morphState === 0) { self.refScaleX = 0.5; self.refScaleY = 0.5; } else { self.refScaleX = 1.0; self.refScaleY = 1.0; } // Calculate new offset for the updated scale var newVisualBottomOffset = self.playerHeight * self.refScaleY / 2; // Adjust player position based on current position if (!self.isJumping) { if (self.currentPlatform) { // Adjust position on platform self.y = self.currentPlatform.y - newVisualBottomOffset; } else { // Adjust position on ground self.y = groundLevel - newVisualBottomOffset; } } tween(self.scale, { x: self.refScaleX, y: self.refScaleY }, { duration: 1000, // Animation duration in milliseconds easing: tween.easeOut }); }; // Add shadow beneath player self.shadow = self.attachAsset('shadow', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5, scaleX: 2.0, scaleY: 0.4, tint: 0x000000, y: 200 // Position shadow below player }); self.runFrames = [self.attachAsset('playerRunFrame1', { anchorX: 0.5, anchorY: 0.5, alpha: 1 }), self.attachAsset('playerRunFrame2', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('playerRunFrame', { anchorX: 0.5, anchorY: 0.5, alpha: 0 })]; self.currentRunFrame = 0; self.speed = 5; self.jumpHeight = 35; // Réduire légèrement la hauteur de saut self.isJumping = false; self.velocityY = 0; self.isFalling = false; self.currentPlatform = null; self.playerHeight = 400; // Hauteur du sprite du joueur self.canJump = false; // Flag to control if player can jump (only after start button is clicked) self.isHit = false; // Track if player is in hit state // Add bounding box for collision detection visualization self.boundingBox = self.attachAsset('boundingBox', { anchorX: 0.5, anchorY: 0.5, width: 150, height: 380, alpha: isDebug ? 0.5 : 0 }); self.hitFrame = self.attachAsset('playerHitFrame1', { anchorX: 0.5, anchorY: 0.5, alpha: 0 // Hidden initially }); self.jumpFrame = self.attachAsset('playerJumpFrame', { anchorX: 0.5, anchorY: 0.5, alpha: 0 // Hide the jump frame by setting alpha to 0 }); self.getBounds = function () { return { left: self.x - 75, right: self.x + 75, top: self.y - 100, bottom: self.y + 100 }; }; self.update = function () { // If player is in hit state or lives are less than zero, don't process movement if (self.isHit || lives < 0) { return; } // Update shadow position based on player's height from the ground if (self.isJumping) { // Reduce shadow opacity based on height and make it smaller when jumping var height = Math.min(1, (groundLevel - self.y) / 300); self.shadow.alpha = 0.5 - height * 0.3; self.shadow.scaleX = 2.0 - height; self.shadow.scaleY = 0.5 - height * 0.2; } else { // Reset shadow when on ground self.shadow.alpha = 0.5; self.shadow.scaleX = 2.0; self.shadow.scaleY = 0.5; } if (self.isJumping) { self.y += self.velocityY * globalSpeed; self.velocityY += 2.0 * globalSpeed; // Increase gravity for faster fall without changing jump height self.isFalling = self.velocityY > 0; self.jumpFrame.alpha = 1; // While jumping, switch to the jump frame self.runFrames[self.currentRunFrame].alpha = 0; // Hide the player asset when jumping // Check for platform collision self.checkPlatformCollision(); // Check for ground collision // Use visual bottom offset for correct ground alignment based on scale var visualBottomOffset = self.playerHeight * self.refScaleY / 2; if (self.y >= groundLevel - visualBottomOffset && !self.currentPlatform) { // Ground level - adjust y based on current scale self.y = groundLevel - visualBottomOffset; self.isJumping = false; self.velocityY = 0; self.jumpFrame.alpha = 0; // When not jumping, switch back to the normal frame self.runFrames[self.currentRunFrame].alpha = 1; // Show the player asset when not jumping // Add a bounce effect relative to refScale tween(self, { scaleX: self.refScaleX * 1.2, scaleY: self.refScaleY * 0.8 }, { duration: 100, easing: tween.elasticOut, onFinish: function onFinish() { tween(self, { scaleX: self.refScaleX, scaleY: self.refScaleY }, { duration: 500, easing: tween.elasticOut }); } }); } } else { // Check if player is still on the platform if (self.currentPlatform) { var platformBounds = { left: self.currentPlatform.x - 500, right: self.currentPlatform.x + 500 }; var playerBounds = self.getBounds(); // If player is no longer on the platform, start falling if (playerBounds.left > platformBounds.right || playerBounds.right < platformBounds.left) { self.isJumping = true; self.velocityY = 0.1; // Start with a small downward velocity self.isFalling = true; self.currentPlatform = null; self.jumpFrame.alpha = 1; self.runFrames[self.currentRunFrame].alpha = 0; } } // Handle running animation if (LK.ticks % 5 === 0) { // Fine-tuned interval for balanced and natural pace // Adjusted interval for balanced pace self.runFrames[self.currentRunFrame].alpha = 0; // Hide current frame self.currentRunFrame = (self.currentRunFrame + 1) % self.runFrames.length; // Switch to next frame self.runFrames[self.currentRunFrame].alpha = 1; // Show next frame } } }; self.jump = function () { if (!self.isJumping && self.canJump) { self.isJumping = true; self.velocityY = -self.jumpHeight * 1.5; // Increase initial jump velocity for a faster jump self.jumpFrame.alpha = 1; // Make jump frame visible LK.getSound('jump').play(); // Play jump sound self.currentPlatform = null; } }; // Add die animation frames self.dieFrames = [self.attachAsset('playerDieFrame1', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('playerDieFrame2', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('playerDieFrame3', { anchorX: 0.5, anchorY: 0.5, alpha: 0 })]; self.die = function () { // Hide all other frames for (var i = 0; i < self.runFrames.length; i++) { self.runFrames[i].alpha = 0; } self.jumpFrame.alpha = 0; self.hitFrame.alpha = 0; // Hide shadow during die animation self.shadow.alpha = 0; // Play loose sound when die animation starts LK.getSound('loose').play(); LK.getSound('loose2').play(); // Stop background music LK.stopMusic(); // Play die animation sequence var currentFrame = 0; function showNextFrame() { // Hide previous frame if exists if (currentFrame > 0) { self.dieFrames[currentFrame - 1].alpha = 0; } // Show current frame self.dieFrames[currentFrame].alpha = 1; currentFrame++; // After last frame, start movement animation if (currentFrame < self.dieFrames.length) { LK.setTimeout(showNextFrame, 100); } else { // After last frame, start movement animation startDeathMovement(); } } // Start death movement animation function startDeathMovement() { // Start looping animation between frames 2 and 3 var animLoop = true; var loopFrame = 1; // Start with frame 2 (index 1) function loopDieFrames() { // Hide all frames for (var i = 0; i < self.dieFrames.length; i++) { self.dieFrames[i].alpha = 0; } // Show current frame self.dieFrames[loopFrame].alpha = 1; // Toggle between frames 2 and 3 (index 1 and 2) loopFrame = loopFrame === 1 ? 2 : 1; // Continue loop if animation is active if (animLoop) { LK.setTimeout(loopDieFrames, 120); } } // Start the loop animation loopDieFrames(); // First tween: move player up to y=512 with bounce effect and scale up to 4x tween(self, { y: self.y - 1024, scaleX: 5, scaleY: 5 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Second tween: move player down out of screen tween(self, { y: 4000 // Beyond screen bottom }, { duration: 1200, easing: tween.easeIn, onFinish: function onFinish() { // Stop the animation loop when player is off screen animLoop = false; } }); } }); } // Start animation showNextFrame(); }; self.hitPlayer = function () { if (self.isHit) { return; } // Already in hit state // Set hit state self.isHit = true; // Hide all other frames for (var i = 0; i < self.runFrames.length; i++) { self.runFrames[i].alpha = 0; } self.jumpFrame.alpha = 0; if (self.morphState === 0) { // Player touched enemy from side or bottom - lose a life lives--; // Update lives counter livesCounter.updateLives(lives); } // Show hit frame self.hitFrame.alpha = 1; if (lives <= 0) { // Call die animation instead of returning self.die(); return; } // Check if player is in BIG state (morphState 1) if (self.morphState === 1) { // Play hit sound LK.getSound('hit').play(); // Transform player back to DEFAULT state instead of losing a life self.morphState = 0; self.updateRefScale(); // Set a timeout to reset player after hit animation LK.setTimeout(function () { // Hide hit frame self.hitFrame.alpha = 0; // Show appropriate frame based on state if (self.isJumping) { self.jumpFrame.alpha = 1; } else { self.runFrames[self.currentRunFrame].alpha = 1; } // Reset hit state self.isHit = false; }, 330); } else { // Normal hit behavior for DEFAULT state // Play hit sound LK.getSound('hitSmall').play(); // Set a timeout to reset player after 600ms LK.setTimeout(function () { // Hide hit frame self.hitFrame.alpha = 0; // Show appropriate frame based on state if (self.isJumping) { self.jumpFrame.alpha = 1; } else { self.runFrames[self.currentRunFrame].alpha = 1; } // Reset hit state self.isHit = false; }, 330); } }; // Method to handle drowning in water holes self.drownAnim = function () { // Hide all other frames for (var i = 0; i < self.runFrames.length; i++) { self.runFrames[i].alpha = 0; } self.jumpFrame.alpha = 0; self.hitFrame.alpha = 0; // Hide shadow during drowning animation self.shadow.alpha = 0; // Start alternating between frames 2 and 3 var animLoop = true; var loopFrame = 1; // Start with frame 2 (index 1) function loopDrownFrames() { // Hide all frames for (var i = 0; i < self.dieFrames.length; i++) { self.dieFrames[i].alpha = 0; } // Show current frame self.dieFrames[loopFrame].alpha = 1; // Toggle between frames 2 and 3 (index 1 and 2) loopFrame = loopFrame === 1 ? 2 : 1; // Continue loop if animation is active if (animLoop) { LK.setTimeout(loopDrownFrames, 120); } } // Start the loop animation loopDrownFrames(); // Fall vertically to bottom of screen tween(self, { y: 4000 // Beyond screen bottom }, { duration: 1500, easing: tween.easeIn, onFinish: function onFinish() { // Stop the animation loop when player is off screen animLoop = false; } }); }; self.drownPlayer = function () { self.drownAnim(); if (lives > 0) { // Lose a life lives--; // Update lives counter livesCounter.updateLives(lives); // Player hit animation or die if no lives left if (lives <= 0) { player.die(); // Show game over after animation LK.setTimeout(function () { LK.showGameOver(); }, 4000); } } }; self.checkPlatformCollision = function () { for (var i = 0; i < platforms.length; i++) { var platform = platforms[i]; var platformBounds = { left: platform.x - 500, right: platform.x + 500, top: platform.y - 50, bottom: platform.y + 50 }; var playerBounds = self.getBounds(); // Check if player is above the platform and falling // Adjust collision detection for high globalSpeed values var adjustedVelocity = self.velocityY * globalSpeed; if (self.velocityY > 0 && playerBounds.bottom >= platformBounds.top && playerBounds.bottom - adjustedVelocity < platformBounds.top && playerBounds.right > platformBounds.left && playerBounds.left < platformBounds.right) { // Land on the platform // Adjust player Y based on current scale to ensure visual bottom aligns with platform top var visualBottomOffset = self.playerHeight * self.refScaleY / 2; self.y = platform.y - visualBottomOffset; self.velocityY = 0; self.isJumping = false; self.isFalling = false; self.currentPlatform = platform; self.jumpFrame.alpha = 0; self.runFrames[self.currentRunFrame].alpha = 1; // Add a bounce effect relative to refScale tween(self, { scaleX: self.refScaleX * 1.2, scaleY: self.refScaleY * 0.8 }, { duration: 100, easing: tween.elasticOut, onFinish: function onFinish() { tween(self, { scaleX: self.refScaleX, scaleY: self.refScaleY }, { duration: 500, easing: tween.elasticOut }); } }); return true; } } return false; }; self.init(); }); var StartButton = Container.expand(function () { var self = Container.call(this); // Create and attach start button asset var buttonGraphics = self.attachAsset('startButton', { anchorX: 0.5, anchorY: 0.5, width: 1024, height: 1024 }); // Add pulsing animation effect self.animate = function () { // Initialize scale object if it doesn't exist if (!self.scale) { self.scale = { x: 1, y: 1 }; } tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 800, easing: tween.easeInOut, onFinish: self.animate }); } }); }; // Handle button press self.down = function (x, y, obj) { // Play sound effect when button is pressed LK.getSound('start').play(); // Trigger button pressed animation tween(self, { scale: 0.9 }, { duration: 100, easing: tween.easeOut }); }; // Handle button release self.up = function (x, y, obj) { // Play start sound when button is clicked // Hide the button with a scale animation tween(self, { scale: 0, alpha: 0 }, { duration: 300, easing: tween.elasticIn, onFinish: function onFinish() { // Remove button after animation if (self.parent) { self.parent.removeChild(self); } // Start enemy spawning enemySpawnCounter = 0; // Allow player to jump now if (player) { player.canJump = true; } } }); }; return self; }); // Define a class for water hole with 8-frame animation var WaterHole = Container.expand(function () { var self = Container.call(this); // Create and attach all 8 water hole frames self.frames = [self.attachAsset('waterHoleFrame1', { anchorX: 0.5, anchorY: 0.5, alpha: 1 // First frame visible initially }), self.attachAsset('waterHoleFrame2', { anchorX: 0.5, anchorY: 0.5, alpha: 0 // Hidden initially }), self.attachAsset('waterHoleFrame3', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('waterHoleFrame4', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('waterHoleFrame5', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('waterHoleFrame6', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('waterHoleFrame7', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }), self.attachAsset('waterHoleFrame8', { anchorX: 0.5, anchorY: 0.5, alpha: 0 })]; // Add bounding box for collision detection visualization self.boundingBox = self.attachAsset('boundingBox', { anchorX: 0.5, anchorY: 0.5, width: 256, height: 1024, alpha: isDebug ? 0.5 : 0 }); self.leftBorder = self.attachAsset('waterHoleBorder', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, x: -230 }); self.leftBorder = self.attachAsset('waterHoleBorder', { anchorX: 0.5, anchorY: 0.5, scaleX: -1.0, x: 230 }); self.currentFrame = 0; self.speed = groundSpeedBase; // Use base ground speed for synchronization // Method to reset water hole for reuse self.reset = function (x, y) { self.x = x; self.y = y; self.alpha = 1; // Reset animation state self.currentFrame = 0; // Show first frame, hide others for (var i = 0; i < self.frames.length; i++) { self.frames[i].alpha = i === 0 ? 1 : 0; } self.animationTimer = 0; }; // Initialize animation self.startAnimation = function () { // No need to call animate directly, it will be called via update self.animationTimer = 0; }; self.animate = function () { // Hide current frame self.frames[self.currentFrame].alpha = 0; // Move to next frame self.currentFrame = (self.currentFrame + 1) % self.frames.length; // Show next frame self.frames[self.currentFrame].alpha = 1; }; self.update = function () { // Handle animation timing with frame counter self.animationTimer += 1; if (self.animationTimer >= 6) { // 6 frames ≈ 100ms at 60fps self.animate(); self.animationTimer = 0; } // Move water hole from right to left only if player is not hit and lives >= 0 if (!player || !player.isHit && lives >= 0) { self.x -= self.speed * globalSpeed; } }; // Start the animation when created self.startAnimation(); return self; }); // Define WaterHoleManager class to handle water hole spawning and pooling var WaterHoleManager = Container.expand(function () { var self = Container.call(this); // Properties to manage water holes self.waterHoles = []; // Active water holes self.waterHolePool = []; // Pool for reuse self.spawnInterval = 200; // Base spawn interval self.spawnCounter = 0; // Counter for spawn timing // Function to check if player is colliding with water hole self.checkPlayerCollision = function (playerBounds, waterHole) { var holeX = waterHole.x; // Log player and water hole positions and dimensions console.log("Player bounds:", { left: playerBounds.left, right: playerBounds.right, top: playerBounds.top, bottom: playerBounds.bottom }); console.log("Water hole:", { x: holeX, boundingBoxWidth: waterHole.boundingBox.width, groundLevel: groundLevel }); // Log individual collision conditions var condition1 = playerBounds.left < holeX + waterHole.boundingBox.width / 2; var condition2 = playerBounds.right > holeX - waterHole.boundingBox.width / 2; var condition3 = playerBounds.bottom > groundLevel - 150; console.log("Collision conditions:", { horizontalOverlap1: condition1, horizontalOverlap2: condition2, belowThreshold: condition3, allConditions: condition1 && condition2 && condition3 }); // Simple AABB collision check using player's boundingBox in the right format return condition1 && condition2 && condition3; }; // Initialize the manager self.init = function () { self.waterHoles = []; self.waterHolePool = []; self.spawnCounter = 0; }; // Spawn a new water hole self.spawnWaterHole = function () { // Determine the spawn position based on the rightmost ground piece var spawnX; var rightmostGround; if (ground && ground2) { if (ground.x > ground2.x) { rightmostGround = ground; } else { rightmostGround = ground2; } // Calculate the X position for the water hole: the start of the rightmost ground piece + half the gap width var gapStartX = rightmostGround.x; // Position before offset spawnX = gapStartX + 256; // Center of the 512 gap } if (!spawnX || spawnX < 2304) { return; } // Apply 512px offset to the rightmost ground piece AFTER calculating spawnX rightmostGround.x += 512; var waterHole; // Try to reuse from pool first var wasReused = false; if (self.waterHolePool.length > 0) { waterHole = self.waterHolePool.pop(); waterHole.visible = true; wasReused = true; } else { waterHole = new WaterHole(); } // Position water hole waterHole.x = spawnX; // Position water hole vertically. Its visual top should align with groundLevel. // Anchor is 0.5, 0.5 and height is 1024. Center should be at groundLevel + 512. waterHole.y = groundLevel + 512; // If water hole was reused from pool, reset its state if (wasReused) { waterHole.reset(waterHole.x, waterHole.y); } //{ax} // Keep original comment ID for context // Add to tracking array and game container self.waterHoles.push(waterHole); // Only add to container if not already a child if (!waterHole.parent) { middlegroundContainer.addChild(waterHole); } // Note: The ground offset logic is now integrated above, before positioning the water hole. // The block below is no longer needed here. //{aC} // Keep original comment ID for context // Randomize next spawn interval self.spawnInterval = Math.floor(Math.random() * 300) + 200; self.spawnCounter = 0; }; // Update all water holes self.update = function () { // Don't spawn if player is hit or game over if (player && player.isHit || lives < 0) { return; } // Increment spawn counter self.spawnCounter++; // Check if it's time to spawn a new water hole if (self.waterHoles.length < 3 && self.spawnCounter >= self.spawnInterval) { self.spawnWaterHole(); } // Process all active water holes for (var i = self.waterHoles.length - 1; i >= 0; i--) { var waterHole = self.waterHoles[i]; // Check if water hole is off-screen if (waterHole.x < -300) { // Return to pool if (waterHole.parent) { waterHole.parent.removeChild(waterHole); } self.waterHoles.splice(i, 1); waterHole.visible = false; self.waterHolePool.push(waterHole); } // Check collision with player if (player && player.getBounds) { var playerBounds = player.getBounds(); // Use the extracted collision check function if (self.checkPlayerCollision(playerBounds, waterHole)) { // Only trigger once if (!waterHole.triggered) { waterHole.triggered = true; // If player can jump (game started), handle deadly water if (player.canJump) { // Player dies in water player.drownPlayer(); } else { // Game not started yet - make player jump over waterhole player.jump(); // player.isJumping = true; // player.velocityY = -player.jumpHeight * 1.5; // player.jumpFrame.alpha = 1; // Make jump frame visible // LK.getSound('jump').play(); // Play jump sound // player.currentPlatform = null; } } } else { waterHole.triggered = false; } } } }; // Initialize the manager self.init(); return self; }); /**** * Initialize Game ****/ // Initialize game var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ /**** * Global Variables ****/ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) { return t; } var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) { return i; } throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var isDebug = true; // Global debug flag var level1Height; var level2Height; var game; var background; var player; var enemies; var enemySpawnInterval; var enemySpawnCounter; var startButton; // Variable for start button var coins = []; // Initialize an empty array for tracking active coins var coinPool = []; // Initialize coin pool for reusing instances var mushrooms = []; // Initialize array for tracking active mushrooms var mushroomPool = []; // Initialize mushroom pool for reusing instances var mushroomSpawnInterval = 500; // Control how often mushrooms spawn var scoreText; var coinCounter; var coinCount = 0; // Add global coin count variable var lives = 3; // Add global lives counter var backgroundContainer; var middlegroundContainer; var foregroundContainer; var bgClose; var bgClose2; var bgFar; var bgFar2; var platforms; var ground; var ground2; var groundLevel; var groundSpeedBase = 10; // Base speed for ground elements var globalSpeed = 1.0; // Control the overall game speed (1.0 = normal) var waterHoleManager; // Manager for water holes // Function to handle background updates function backgroundUpdate() { // Only move backgrounds if player is not hit and lives >= 0 if ((!player || !player.isHit) && lives >= 0) { // Parallax scrolling bgClose.x -= 4 * globalSpeed; // Increase speed for close background bgClose2.x -= 4 * globalSpeed; // Move the duplicate at the same speed bgFar.x -= 2 * globalSpeed; // Increase speed for far background bgFar2.x -= 2 * globalSpeed; // Move the duplicate at the same speed // Repeat backgrounds infinitely if (bgClose.x <= -bgClose.width) { bgClose.x = bgClose2.x + bgClose2.width; } if (bgClose2.x <= -bgClose2.width) { bgClose2.x = bgClose.x + bgClose.width; } if (bgFar.x <= -bgFar.width) { bgFar.x = bgFar2.x + bgFar2.width; } if (bgFar2.x <= -bgFar2.width) { bgFar2.x = bgFar.x + bgFar.width; } // Scroll ground ground.x -= groundSpeedBase * globalSpeed; // Use base ground speed ground2.x -= groundSpeedBase * globalSpeed; // Use base ground speed if (ground.x <= -ground.width) { ground.x = ground2.x + ground2.width; } if (ground2.x <= -ground2.width) { ground2.x = ground.x + ground.width; } } } // Function to handle platform updates function platformsUpdate() { // Only process platforms if player is not hit and lives >= 0 if (player && player.isHit || lives < 0) { return; } // Update platforms for (var i = platforms.length - 1; i >= 0; i--) { // Ne pas appeler update() car il est déjà appelé automatiquement par le moteur // platforms[i].update(); // Remove platforms that are destroyed if (platforms[i].destroyed) { platforms.splice(i, 1); } } // Check if we need to spawn a new platform if (platforms.length > 0) { var lastPlatform = platforms[platforms.length - 1]; if (lastPlatform.x < 2048 + 500) { // Spawn a new platform spawnPlatform(); } } } // Handle game updates game.update = function () { // Call background update function backgroundUpdate(); // Call platform update function platformsUpdate(); // Spawn enemies only after start button is clicked (when enemySpawnCounter is not 9999) if (enemySpawnCounter !== 9999) { enemySpawnCounter++; if (enemySpawnCounter >= enemySpawnInterval) { var enemy; // Try to reuse an enemy from the pool if (enemyPool.length > 0) { enemy = enemyPool.pop(); enemy.visible = true; } else { enemy = new Enemy(); } enemy.x = 2500; // Plus loin à droite que 2048 // Décider si l'ennemi apparaît sur le sol ou sur une plateforme var spawnOnPlatform = Math.random() < 0.5 && platforms.length > 0; if (spawnOnPlatform) { // Trouver une plateforme visible à l'écran ou proche de l'écran var visiblePlatforms = []; for (var p = 0; p < platforms.length; p++) { if (platforms[p].x > 2200 && platforms[p].x < 2700) { visiblePlatforms.push(platforms[p]); } } // S'il y a des plateformes visibles, placer l'ennemi sur l'une d'elles if (visiblePlatforms.length > 0) { var randomPlatform = visiblePlatforms[Math.floor(Math.random() * visiblePlatforms.length)]; // Placer l'ennemi sur la plateforme en utilisant la même logique que pour le joueur enemy.y = randomPlatform.y - 150; } else { // Sinon, placer l'ennemi sur le sol (même position Y que le joueur au repos) enemy.y = player.y; } } else { // Placer l'ennemi sur le sol (même position Y que le joueur au repos) enemy.y = player.y; } // If enemy was from pool, use reset method if (enemyPool.indexOf(enemy) > -1) { enemy.reset(enemy.x, enemy.y); } enemies.push(enemy); // Only add to container if not already a child if (!enemy.parent) { middlegroundContainer.addChild(enemy); } // Randomize the spawn interval for the next enemy enemySpawnInterval = Math.floor(Math.random() * 150) + 50; enemySpawnCounter = 0; } } // Check collisions with enemies var playerBounds = player.getBounds(); // Calculate once per frame for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (!enemy.visible) { continue; } // Skip invisible enemies (in pool) var enemyBounds = enemy.getBounds(); // Check if player intersects with enemy if (playerBounds.left < enemyBounds.right && playerBounds.right > enemyBounds.left && playerBounds.top < enemyBounds.bottom && playerBounds.bottom > enemyBounds.top) { // Check if player is falling on top of the enemy if (player.isFalling && player.velocityY > 0 && playerBounds.bottom > enemyBounds.top && playerBounds.bottom - player.velocityY < enemyBounds.top) { // Player jumped on enemy - return to pool if (enemy.parent) { enemy.parent.removeChild(enemy); } enemies.splice(j, 1); enemy.visible = false; enemyPool.push(enemy); // Play enemy stomp sound LK.getSound('enemyStomp').play(); // Give player a small bounce after killing enemy player.velocityY = -15; // Increment score when killing enemy LK.setScore(LK.getScore() + 5); scoreText.setText(LK.getScore()); } else { if (lives < 0) { return; } // Trigger player hit state player.hitPlayer(); // Flash screen to indicate damage LK.effects.flashScreen(0xff0000, 150); // If no more lives, show game over after a short delay if (lives <= 0) { // Wait 1 second before showing game over LK.setTimeout(function () { LK.showGameOver(); }, 4000); } else { // Remove enemy that caused damage if (enemy.parent) { enemy.parent.removeChild(enemy); } enemies.splice(j, 1); enemy.visible = false; enemyPool.push(enemy); } } } else if (player.x > enemy.x && !enemy.passed) { // Player passed enemy without touching it enemy.passed = true; LK.setScore(LK.getScore() + 1); scoreText.setText(LK.getScore()); } } // Use coins array to track how many active coins we have // Spawn coins with random timing, but limit the maximum number if (coins.length < 10 && LK.ticks % Math.floor(Math.random() * 100 + 50) === 0) { var coin; // Try to reuse a coin from the pool if (coinPool.length > 0) { coin = coinPool.pop(); coin.visible = true; } else { coin = new Coin(); } coin.x = 2500; // Start off-screen to the right // Randomly position the coin at one of three heights var randomHeight = Math.random(); if (randomHeight < 0.33) { // On ground level coin.y = groundLevel - 100; } else if (randomHeight < 0.66) { // On level 1 coin.y = level1Height - 100; } else { // On level 2 coin.y = level2Height - 100; } // If coin was from pool, use reset method if (coinPool.indexOf(coin) > -1) { coin.reset(coin.x, coin.y); } // Add coin to both the coins array and the middle ground coins.push(coin); // Only add to container if not already a child if (!coin.parent) { middlegroundContainer.addChild(coin); } } // Spawn mushrooms occasionally (much less frequently than coins) if (mushrooms.length < 2 && LK.ticks % mushroomSpawnInterval === 0) { var mushroom; // Try to reuse a mushroom from the pool if (mushroomPool.length > 0) { mushroom = mushroomPool.pop(); mushroom.visible = true; } else { mushroom = new Mushroom(); } mushroom.x = 2500; // Start off-screen to the right // Randomly position the mushroom at one of three heights var randomMushroomHeight = Math.random(); if (randomMushroomHeight < 0.33) { // On ground level mushroom.y = groundLevel - 100; } else if (randomMushroomHeight < 0.66) { // On level 1 mushroom.y = level1Height - 100; } else { // On level 2 mushroom.y = level2Height - 100; } // If mushroom was from pool, use reset method if (mushroomPool.indexOf(mushroom) > -1) { mushroom.reset(mushroom.x, mushroom.y); } // Add mushroom to both the mushrooms array and the middle ground mushrooms.push(mushroom); // Only add to container if not already a child if (!mushroom.parent) { middlegroundContainer.addChild(mushroom); } // Reset spawn interval to a random value between 500 and 1000 mushroomSpawnInterval = Math.floor(Math.random() * 500) + 500; } }; // Handle player jump game.down = function (x, y, obj) { player.jump(); }; function initializeGame() { // Initialize containers backgroundContainer = new Container(); middlegroundContainer = new Container(); foregroundContainer = new Container(); // Add containers to game in proper order game.addChild(backgroundContainer); game.addChild(middlegroundContainer); game.addChild(foregroundContainer); // Define fixed platform heights for two levels groundLevel = 2732 / 2 + 450; // Descendre le niveau du sol de 450 pixels // Add background bgFar = LK.getAsset('bgFar', { anchorX: 0, anchorY: 0 }); bgFar.x = 0; bgFar.y = 0; bgFar.width = 2732; backgroundContainer.addChild(bgFar); // Add second background for infinite scrolling bgFar2 = LK.getAsset('bgFar', { anchorX: 0, anchorY: 0 }); bgFar2.x = bgFar.width; bgFar2.y = 0; bgFar2.width = 2732; backgroundContainer.addChild(bgFar2); // Initialize parallax backgrounds bgClose = LK.getAsset('bgClose', { anchorX: 0, anchorY: 0 }); bgClose.x = 0; bgClose.y = 0; bgClose.width = 2732; // Set correct width to match the actual image width backgroundContainer.addChild(bgClose); // Create a duplicate of bgClose for seamless scrolling bgClose2 = LK.getAsset('bgClose', { anchorX: 0, anchorY: 0 }); bgClose2.x = bgClose.width; bgClose2.y = 0; bgClose2.width = 2732; backgroundContainer.addChild(bgClose2); // Add ground that scrolls ground = LK.getAsset('ground', { anchorX: 0, anchorY: 0 }); ground.x = 0; ground.y = groundLevel; // Placer le haut du sol exactement au niveau du sol ground.width = 2048; middlegroundContainer.addChild(ground); // Add second ground piece for infinite scrolling ground2 = LK.getAsset('ground', { anchorX: 0, anchorY: 0 }); ground2.x = ground.width; ground2.y = groundLevel; // Placer le haut du sol exactement au niveau du sol ground2.width = 2048; middlegroundContainer.addChild(ground2); // Initialize player player = new Player(); player.x = 2048 / 6; // Adjust the player's initial position to be more to the left player.y = groundLevel - 100; // Mario légèrement au-dessus du sol foregroundContainer.addChild(player); // Initialize enemies enemies = []; enemyPool = []; // Reset enemy pool on game init enemySpawnInterval = 100; enemySpawnCounter = 9999; // Set to a large value so enemies won't spawn until start button is pressed // Create and add start button startButton = new StartButton(); startButton.x = 2048 / 2; // Center horizontally startButton.y = 2732 / 2; // Center vertically startButton.scale = { x: 0, y: 0 }; // Initialize scale properly as an object foregroundContainer.addChild(startButton); startButton.animate(); // Start the pulsing animation // Make sure the start button is visible startButton.visible = true; // Initialize player with jumping disabled until start button is clicked player.canJump = false; // Reset lives counter lives = 3; // Clear the global coins array and coin pool coins = []; coinPool = []; // Clear mushrooms array and pool mushrooms = []; mushroomPool = []; // Initialize platforms platforms = []; level1Height = groundLevel - 450; // Niveau 1 à 450 pixels au-dessus du sol level2Height = level1Height - 450; // Niveau 2 à 450 pixels au-dessus du niveau 1 // Create initial platforms for (var i = 0; i < 2; i++) { var platform = new Platform(); if (i === 0) { platform.x = player.x + 800; // Start the first platform further away platform.y = level1Height; // Première plateforme toujours au niveau 1 } else { // Deuxième plateforme au niveau 2, mais plus proche horizontalement platform.x = platforms[i - 1].x + 1200; // Plus espacé platform.y = level2Height; } platforms.push(platform); middlegroundContainer.addChild(platform); } // Create a new Text2 object to display the score scoreText = new Text2('0', { size: 100, fill: 0xFFFFFF }); // Add the score text to the game GUI at the top center of the screen LK.gui.top.addChild(scoreText); scoreText.x = 2048 / 2; scoreText.y = 0; // Create the coin counter and add it to the GUI coinCounter = new CoinCounter(); // Position coin counter properly in the top right corner // Note: GUI coordinates work differently than game coordinates coinCounter.x = -300; // Negative X moves it left from the right edge coinCounter.y = 30; // Some space from the top LK.gui.topRight.addChild(coinCounter); // Create the lives counter and add it to the GUI livesCounter = new LivesCounter(); // Position lives counter in the top left corner with offset livesCounter.x = 250; // Offset from left edge livesCounter.y = 80; // Some space from the top LK.gui.topLeft.addChild(livesCounter); // Initialize lives counter livesCounter.updateLives(lives); // Create and initialize water hole manager waterHoleManager = new WaterHoleManager(); middlegroundContainer.addChild(waterHoleManager); // Play background music LK.playMusic('bgMusic'); } // Platform object pool var platformPool = []; // Enemy object pool var enemyPool = []; // Function to spawn a new platform function spawnPlatform() { var platform; // Try to reuse a platform from the pool if (platformPool.length > 0) { platform = platformPool.pop(); platform.visible = true; } else { platform = new Platform(); } var lastPlatform = platforms[platforms.length - 1]; var lastHeight = lastPlatform.y; // Déterminer la hauteur de la nouvelle plateforme if (lastHeight === level1Height) { // Si la dernière plateforme était au niveau 1, la nouvelle sera au niveau 2 platform.y = level2Height; platform.x = lastPlatform.x + 1200; // Plus espacé } else { // Si la dernière plateforme était au niveau 2, la nouvelle sera au niveau 1 platform.y = level1Height; platform.x = lastPlatform.x + 1500; // Encore plus espacé après une plateforme de niveau 2 } // Ajouter une chance de ne pas générer de plateforme (20%) if (Math.random() < 0.2) { // Si on décide de ne pas générer cette plateforme, on augmente la distance pour la prochaine lastPlatform.x += 500; // Return platform to pool if we decided not to use it if (platform.parent) { platform.parent.removeChild(platform); } platformPool.push(platform); return; } platforms.push(platform); middlegroundContainer.addChild(platform); } // Call initializeGame at the end of the file initializeGame();
===================================================================
--- original.js
+++ change.js
@@ -836,9 +836,46 @@
}
};
// Method to handle drowning in water holes
self.drownAnim = function () {
- // Empty function for now
+ // Hide all other frames
+ for (var i = 0; i < self.runFrames.length; i++) {
+ self.runFrames[i].alpha = 0;
+ }
+ self.jumpFrame.alpha = 0;
+ self.hitFrame.alpha = 0;
+ // Hide shadow during drowning animation
+ self.shadow.alpha = 0;
+ // Start alternating between frames 2 and 3
+ var animLoop = true;
+ var loopFrame = 1; // Start with frame 2 (index 1)
+ function loopDrownFrames() {
+ // Hide all frames
+ for (var i = 0; i < self.dieFrames.length; i++) {
+ self.dieFrames[i].alpha = 0;
+ }
+ // Show current frame
+ self.dieFrames[loopFrame].alpha = 1;
+ // Toggle between frames 2 and 3 (index 1 and 2)
+ loopFrame = loopFrame === 1 ? 2 : 1;
+ // Continue loop if animation is active
+ if (animLoop) {
+ LK.setTimeout(loopDrownFrames, 120);
+ }
+ }
+ // Start the loop animation
+ loopDrownFrames();
+ // Fall vertically to bottom of screen
+ tween(self, {
+ y: 4000 // Beyond screen bottom
+ }, {
+ duration: 1500,
+ easing: tween.easeIn,
+ onFinish: function onFinish() {
+ // Stop the animation loop when player is off screen
+ animLoop = false;
+ }
+ });
};
self.drownPlayer = function () {
self.drownAnim();
if (lives > 0) {