User prompt
when player is in morphState 0 set it's scale to 0.5
User prompt
add a new property to player 'morphState': 0 - DEFAULT 1 - BIG 2 - FIRE
User prompt
Stop music when play die
Code edit (2 edits merged)
Please save this source code
User prompt
add a simple shadow to player
Code edit (1 edits merged)
Please save this source code
User prompt
during die anim movment loop between playerDieFrame2 & playerDieFrame3
Code edit (2 edits merged)
Please save this source code
User prompt
during die anim movement, make player scale up to x4 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
during die anim, make player scale up to x4 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (4 edits merged)
Please save this source code
User prompt
when playing die anim, play loose sound
Code edit (1 edits merged)
Please save this source code
User prompt
continue die animation after reaching frame 3, animate player move toward top 512px, then toward the bottom until going out of the screen
Code edit (1 edits merged)
Please save this source code
User prompt
when lives reach 0, call un new function in Player that creates a onshot Die animation with 3 frames.
Code edit (1 edits merged)
Please save this source code
User prompt
if (lives < 0) don't update platforms, backgrounds, coins and monsters
User prompt
if (lives < 0) don't update player
Code edit (1 edits merged)
Please save this source code
User prompt
wait 1sec before gameover ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
play hit sound when player is hit
Code edit (1 edits merged)
Please save this source code
User prompt
Stop coins and monsters move when player is hit (exactly like backgrounds)
Code edit (1 edits merged)
Please save this source code
/**** * 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 self.x -= self.speed; // 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 }); 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; }; self.update = function () { self.x -= self.speed; // 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; self.y += self.velocityY; } // Vérifier collision avec le sol if (self.y >= groundLevel) { self.y = groundLevel; 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 }; }; 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 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 if (player && player.isHit) { return; } self.x -= self.speed; 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); 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 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, don't process movement if (self.isHit) { return; } if (self.isJumping) { self.y += self.velocityY; self.velocityY += 2.0; // 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 if (self.y >= groundLevel - 100 && !self.currentPlatform) { // Ground level self.y = groundLevel - 100; 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 tween(self, { scaleX: 1.2, scaleY: 0.8 }, { duration: 100, easing: tween.elasticOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { 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; } }; 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; // Show hit frame self.hitFrame.alpha = 1; // 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); }; 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 if (self.velocityY > 0 && playerBounds.bottom >= platformBounds.top && playerBounds.bottom - self.velocityY < platformBounds.top && playerBounds.right > platformBounds.left && playerBounds.left < platformBounds.right) { // Land on the platform // Utiliser la moitié de la hauteur du joueur pour le positionner correctement sur la plateforme self.y = platform.y - self.playerHeight / 2; 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 tween(self, { scaleX: 1.2, scaleY: 0.8 }, { duration: 100, easing: tween.elasticOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.elasticOut }); } }); return true; } } return false; }; }); // Define StartButton class 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; }); /**** * 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 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 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; // Function to handle background updates function backgroundUpdate() { // Only move backgrounds if player is not hit if (!player || !player.isHit) { // Parallax scrolling bgClose.x -= 4; // Increase speed for close background bgClose2.x -= 4; // Move the duplicate at the same speed bgFar.x -= 2; // Increase speed for far background bgFar2.x -= 2; // 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 -= 10; // Même vitesse que les plateformes ground2.x -= 10; 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 if (player && player.isHit) { 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 { // Player touched enemy from side or bottom - lose a life lives--; // Update lives counter livesCounter.updateLives(lives); // Trigger player hit state player.hitPlayer(); // Flash screen to indicate damage LK.effects.flashScreen(0xff0000, 100); // If no more lives, show game over if (lives <= 0) { LK.showGameOver(); } 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); } } }; // 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 / 4; // 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 = []; // 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); // 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();
/****
* 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
self.x -= self.speed;
// 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
});
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;
};
self.update = function () {
self.x -= self.speed;
// 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;
self.y += self.velocityY;
}
// Vérifier collision avec le sol
if (self.y >= groundLevel) {
self.y = groundLevel;
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
};
};
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 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
if (player && player.isHit) {
return;
}
self.x -= self.speed;
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);
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
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, don't process movement
if (self.isHit) {
return;
}
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += 2.0; // 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
if (self.y >= groundLevel - 100 && !self.currentPlatform) {
// Ground level
self.y = groundLevel - 100;
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
tween(self, {
scaleX: 1.2,
scaleY: 0.8
}, {
duration: 100,
easing: tween.elasticOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
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;
}
};
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;
// Show hit frame
self.hitFrame.alpha = 1;
// 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);
};
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
if (self.velocityY > 0 && playerBounds.bottom >= platformBounds.top && playerBounds.bottom - self.velocityY < platformBounds.top && playerBounds.right > platformBounds.left && playerBounds.left < platformBounds.right) {
// Land on the platform
// Utiliser la moitié de la hauteur du joueur pour le positionner correctement sur la plateforme
self.y = platform.y - self.playerHeight / 2;
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
tween(self, {
scaleX: 1.2,
scaleY: 0.8
}, {
duration: 100,
easing: tween.elasticOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.elasticOut
});
}
});
return true;
}
}
return false;
};
});
// Define StartButton class
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;
});
/****
* 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 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 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;
// Function to handle background updates
function backgroundUpdate() {
// Only move backgrounds if player is not hit
if (!player || !player.isHit) {
// Parallax scrolling
bgClose.x -= 4; // Increase speed for close background
bgClose2.x -= 4; // Move the duplicate at the same speed
bgFar.x -= 2; // Increase speed for far background
bgFar2.x -= 2; // 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 -= 10; // Même vitesse que les plateformes
ground2.x -= 10;
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
if (player && player.isHit) {
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 {
// Player touched enemy from side or bottom - lose a life
lives--;
// Update lives counter
livesCounter.updateLives(lives);
// Trigger player hit state
player.hitPlayer();
// Flash screen to indicate damage
LK.effects.flashScreen(0xff0000, 100);
// If no more lives, show game over
if (lives <= 0) {
LK.showGameOver();
} 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);
}
}
};
// 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 / 4; // 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 = [];
// 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);
// 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();