JavaScript

Step 1: Supercharge Your JS

Guess what? Your JavaScript (JS) file wants some love too. Remember where you saved it? Open it up! And just like before, select everything, press Delete, and clear the stage for something awesome.

Step 2: The Magical Finale

Copy the new and exciting JS code we have for you. You know the drill: paste it into your JS file, and hit Ctrl and S to save everything.

And That’s It!

You’re now ready to see your game in action. Fire it up, and watch your characters dash across the screen. You’re a coding wizard in the making! If you ever need help, remember to reach out. Happy coding! ?

document.addEventListener('DOMContentLoaded', function () {
  // Get the start button element
  var startButton = document.querySelector('.start-button');
  // Get the logo element
  var logoElement = document.querySelector('.game-logo');
  // Get the platform container element
  const platformContainer = document.getElementById('platform-container');
  const player = document.getElementById('player');
  const enemy = document.querySelector('.enemy');
  
  const playableScreenWidth = platformContainer.offsetWidth;
  const playerWidth = player.offsetWidth;
  const playerHeight = player.offsetHeight; // Get the player's height
  const enemyWidth = enemy.offsetWidth;
  const enemyHeight = enemy.offsetHeight;
  
  let playerLeft = 0;
  let playerBottom = 10;
  let screenLeft = 0;
  let groundWidth = playableScreenWidth; // Initial width of the ground
  
  // Declare a flag to track if a projectile is currently active
  let projectileActive = false;
  
  // Initial speed values
  const initialPlayerSpeed = 5; // Initial speed of the player
  const initialEnemySpeed = 5; // Initial speed of the enemy
  let playerSpeed = initialPlayerSpeed; // The speed of the player
  let enemySpeed = initialEnemySpeed; // The speed of the player
  const jumpHeight = 150; // Maximum jump height
  const gravity = 10; // Gravity value
  let isJumping = false;
  let isMovingLeft = false;
  let isMovingRight = false;
  let enemyLeft = playableScreenWidth; // Initial position of the enemy
  let enemyMoveRequestId; // Declare the variable to hold the request ID for the enemy movement animation frame
  let projectileDirection = 1; // 1 for right, -1 for left
  // Add a variable to track the player's direction
  let playerDirection = 'right';

  const maxPlayerRight = playableScreenWidth * 0.7; // Maximum distance player can move to the right (70% of playable area)
  const backgroundScrollSpeed = 1; // Adjusted background scroll speed
  let isGameActive = false; // Flag to indicate if the game is active or not
  
  let playerMoveInterval; // Declare the player movement interval variable
  let screenMoveInterval; // Declare the screen movement interval variable
  let enemyMoveInterval;

  // Define the stopCheckingCollision flag
  let stopCheckingCollision = false;
  
  // Declare a variable to track the score at the beginning of your JavaScript code
  const initialscore = 0;
  let score = initialscore;

  // Add a variable to track player's health
  let initialPlayerHealth = 100;
  let playerHealth = initialPlayerHealth;
  let healthBar = document.querySelector('.health');

  // Variables for energy
  let initialPlayerEnergy = 100;
  let playerEnergy = initialPlayerEnergy;
  let energyBar = document.querySelector('.energy');
  let scoreElement = document.querySelector('.score');

  // Get the audio element
  const bgMusic = document.getElementById('bg-music');
  
  // Function to move the screen and the player
  function moveScreen() {
    // Move the screen by the player's speed
    if (isMovingLeft && playerLeft > 0) {
      screenLeft -= playerSpeed;
    } else if (isMovingRight) {
      screenLeft += playerSpeed;
    }
    
    // Move the screen (background)
    document.body.style.backgroundPositionX = '${-screenLeft * backgroundScrollSpeed}px';
    
    // Adjust the width of the ground based on the player's position
    groundWidth = Math.max(groundWidth, playerLeft + playerWidth);
    platformContainer.style.width = '${groundWidth}px';
  }
  
  // Function to apply gravity to the player
  function applyGravity() {
// Check if playerBottom position is more than the bottom platform height, if so apply gravity. When this was set to 0 it was pulling the player down past the platform height to the absolute bottom of the board/screen.
    if (playerBottom > 10 ) {
      playerBottom -= gravity;
      movePlayer();
    } else {
      player.style.bottom = playerBottom + 'px';
      isJumping = false;
    }
  }
  
  // Function to handle key down events
  function handleKeyDown(event) {
    if (!isGameActive) return; // Prevent player movement during game reset
    
    if (event.key === 'ArrowLeft') {
      // Move player to the left within the playable area
      if (playerLeft > 0) {
        playerLeft -= playerSpeed;
        movePlayer();
      }
      isMovingLeft = true;
      playerDirection = 'left'; // Update player direction
      //projectileDirection = -1; // Set the projectile direction to left
    } else if (event.key === 'ArrowRight') {
      // Move player to the right within the playable area
      playerLeft += playerSpeed;
      isMovingRight = true;
      playerDirection = 'right'; // Update player direction
      //projectileDirection = 1; // Set the projectile direction to right
      moveScreen(); // Move the screen immediately when the right arrow is pressed
    } else if (event.key === 'ArrowUp') {
      // Jump
      jump();
    }
else if (event.key === ' ') {
      shootProjectile();
      // console.log('shooting');
    }
  }
  
  // Function to handle key up events
  function handleKeyUp(event) {
    if (event.key === 'ArrowLeft') {
      isMovingLeft = false;
    } else if (event.key === 'ArrowRight') {
      isMovingRight = false;
    }
  }
  
  // Function to move the player
  function movePlayer() {
    // Get the maximum visible position of the player on the screen
    const maxVisiblePlayerRight = playableScreenWidth - playerWidth;
    
    // Restrict player movement within the visible screen area
    if (playerLeft > maxVisiblePlayerRight) {
      playerLeft = maxVisiblePlayerRight;
    } else if (playerLeft > maxPlayerRight) {
      playerLeft = maxPlayerRight;
    }
    
    // Update the player's position
    player.style.left = playerLeft + 'px';
    player.style.bottom = playerBottom + 'px';
    
    // Horizontal flip when moving to the left
    player.style.transform = isMovingLeft ? 'scaleX(-1)' : 'scaleX(1)';
  }

  // Function to handle player jumping
  function jump() {
    if (!isJumping) {
      isJumping = true;
      let jumpInterval = setInterval(() => {
        if (playerBottom < jumpHeight) {
          playerBottom += gravity;
          movePlayer();
        } else {
          clearInterval(jumpInterval);
          let fallInterval = setInterval(() => {
            applyGravity();
            if (!isJumping) {
              clearInterval(fallInterval);
            }
          }, 30);
        }
      }, 30);
    }
  }

// Function to shoot a projectile
function shootProjectile() {
  if (playerEnergy >= 5) {
    playerEnergy -= 5; // Subtract energy when shooting
    updateEnergyBar(); // Update the energy bar display
  
    // Play the shoot sound effect
    const shootSound = document.getElementById('shootSound');
    shootSound.currentTime = 0; // Rewind the sound to the beginning
    shootSound.play();
    
    projectileActive = true;
    
    // Calculate the initial top position of the projectile
    let projectileTop = player.offsetTop + playerHeight / 2;
    
    // Calculate the initial left position of the projectile
    let projectileLeft = playerLeft + playerWidth / 2;
    
    // Store the initial shooting direction
    projectileDirection = playerDirection === 'right' ? 1 : -1;
    
    // Create a new projectile element
    const projectile = document.createElement('div');
    projectile.classList.add('projectile');
    
    projectile.style.top = projectileTop + 'px'; // Set the initial top position
    projectile.style.left = projectileLeft + 'px'; // Set the initial left position
    
    platformContainer.appendChild(projectile); // Append to the platform container
    
    // Move the projectile using requestAnimationFrame
    let projectileMoveInterval = null; // Declare projectile move interval variable
    
    function moveProjectile() {
      projectileLeft += 10 * projectileDirection; // Adjust projectile speed as needed
      projectile.style.left = projectileLeft + 'px';
      
      // Inside the moveProjectile function after updating the projectile position
      checkProjectileEnemyCollision(projectile);
      
      // Check if the projectile is out of bounds
      if (projectileLeft < 0 || projectileLeft > playableScreenWidth) {
        // Remove the projectile when out of bounds
        clearInterval(projectileMoveInterval); // Clear the interval
        projectile.remove();
      }
    }
    
    // Start moving the projectile and store the interval ID
    projectileMoveInterval = setInterval(moveProjectile, 30);
  }
}

function resetPlayer() {
// Reset player position and speed
    playerLeft = 0;
    player.style.bottom = playerBottom + 'px';
    player.style.left = playerLeft + 'px';
    isMovingLeft = false;
    isMovingRight = false;
    playerSpeed = initialPlayerSpeed; // Set the player speed back to its initial value
	playerHealth = initialPlayerHealth; // Set the player health back to its initial value
	playerEnergy = initialPlayerEnergy; // Set the energy health back to its initial value
}

// Declare a flag to track enemy jump state
let isEnemyJumping = false;

// Function to move the enemy
function moveEnemy() {
  if (isGameActive) {
    // Move the enemy horizontally
    enemyLeft -= initialEnemySpeed;
    enemy.style.left = enemyLeft + 'px';
    
    // Check if the enemy has moved off the screen and reset its position
    if (enemyLeft + enemyWidth < 0) {
      resetEnemy();
    }
  }
  
  // Check enemy proximity to the player
  const distanceToPlayer = Math.abs(playerLeft - enemyLeft);
  const isNearPlayer = distanceToPlayer < 150; // Adjust the proximity threshold as needed
  
  if (!isEnemyJumping) {
    // Randomly decide if the enemy should jump, considering proximity to the player
    const shouldJump = Math.random() < 0.02 || (isNearPlayer && Math.random() < 0.5);
    
    if (shouldJump) {
      // Set the jump flag to true
      isEnemyJumping = true;
      
      // Calculate the jump duration based on the distance
      const jumpDuration = Math.min(400, distanceToPlayer * 2); // Limit jump duration to 400 milliseconds
      
      // Calculate the jump height
      const jumpHeight = 100; // Adjust the jump height as needed
      
      // Apply jump animation
      enemy.style.transition = 'bottom ${jumpDuration}ms ease-in-out';
      enemy.style.bottom = '${jumpHeight}px';
      
      // After the jump, initiate the falling animation
      setTimeout(() => {
        // Apply falling animation
        enemy.style.transition = 'bottom ${jumpDuration}ms ease-in-out';
        enemy.style.bottom = '10px'; // Reset the enemy's bottom position
        
        // After the fall animation, reset the transition property and jump flag
        setTimeout(() => {
          enemy.style.transition = 'none';
          isEnemyJumping = false;
          
          // Check if the enemy has moved off the screen and reset its position
          if (enemyLeft + enemyWidth < 0) {
            resetEnemy();
          }
        }, jumpDuration);
      }, jumpDuration);
    }
  }
  
  // Request the next animation frame
  enemyMoveRequestId = requestAnimationFrame(moveEnemy);
}

function playEnemyDefeatedSound() {
  const enemyDefeatedSound = document.getElementById('enemy-defeated-sound');
  enemyDefeatedSound.currentTime = 0; // Reset the audio to the beginning
  enemyDefeatedSound.play();
}

// Function to defeat the enemy
function defeatEnemy() {
  // Apply squishing effect
  enemy.style.transition = 'all 0.1s ease-in-out'; // Disable transition to make the squishing instant
  enemy.style.height = '0px'; // Reduce the enemy's height to make it appear squished
  // enemy.style.bottom = '10px'; // Move the enemy to the bottom of the container
  
  // Play the enemy defeated sound effect
  playEnemyDefeatedSound();
  
  // Stop checking collision temporarily
  stopCheckingCollision = true;
  
  // Make the enemy visible again after a short delay
  setTimeout(() => {
    enemy.style.transition = 'none';
    // Reset the enemy's height to its original value
    enemy.style.height = ''; // Set height to an empty string to unset the height property
    // Reappear at the right side of the screen
    resetEnemy();
    stopCheckingCollision = false;
  }, 100); // Adjust the delay as needed
  
  // Start moving the enemy again
  moveEnemy();
}

// RESETTING THE ENEMY POSITION ****
/* You're absolutely right! Moving the cancelAnimationFrame(enemyMoveRequestId); from the startGame function to the resetEnemy function indeed fixes the increasing enemy speed after an enemy defeat.
By canceling the previous animation frame request before resetting the enemy's position and speed, we prevent the animation frame loop from stacking up, which was causing the enemy's speed to increase.*/
function resetEnemy() {
    // Reset enemy position to its original starting point
    enemyLeft = playableScreenWidth;
    enemy.style.left = enemyLeft + 'px';
	enemySpeed = initialEnemySpeed;
    // Reset the enemy's movement animation frame request ID
    cancelAnimationFrame(enemyMoveRequestId);
}

// Function to update health bar
function updateHealthBar() {
    if (playerHealth === 0){
	// console.log(playerHealth)
        healthBar.style.width = 0 + 'px';	
	}
	else {
	// console.log(playerHealth)
        healthBar.style.width = '${playerHealth}%';
	}
}

// Function to update energy bar
function updateEnergyBar() {
    if (energyBar) {
        if (playerEnergy === 0) {
            energyBar.style.width = 0 + 'px';
        } else {
            energyBar.style.width = '${playerEnergy}%';
        }
    }
}

// Function to update the score display
function updateScoreDisplay() {
  if (score === 0) {
     scoreElement.textContent = 0; // Reset the score display to 0
  }
  else {
	scoreElement.textContent = score * 10; // Multiply the score by 10 for display
  }
}

function stopBackgroundMusic() {
  bgMusic.pause();
  bgMusic.currentTime = 0; // Reset the audio to the beginning
}

  // Function to reset the game state
  function resetGame() {

    // Stop the game
    isGameActive = false;

    // Clear all existing intervals to avoid stacking up
    clearInterval(playerMoveInterval);
    clearInterval(screenMoveInterval);
    clearInterval(enemyMoveInterval);
    
    // Remove event listeners for key events
    document.removeEventListener('keydown', handleKeyDown);
    document.removeEventListener('keyup', handleKeyUp);
    
    // Reset player position and stats
    resetPlayer();
	playerHealth = initialPlayerHealth;
	updateHealthBar();
	playerEnergy = initialPlayerEnergy;
	updateEnergyBar();
    
    // Reset the score variable
    score = initialscore;
	updateScoreDisplay();
    
    // Reset enemy position and speed
    resetEnemy();
}

  // Function to end the game
  function endGame() {
  // Show the logo element
  logoElement.style.display = 'block';

  // Stop the background music
  stopBackgroundMusic();
  
  // Reset the game
  resetGame();

  // Add the 'ready-to-play' class back to the body element
  document.body.classList.remove('ready-to-play');

  // Reset the opacity of the body ::before pseudo-element
  document.body.style.setProperty('--before-opacity', '1');

  // Fade in the body ::before pseudo-element
  var bodyBeforeOpacity = 0;
  var fadeInInterval = setInterval(function () {
    if (bodyBeforeOpacity >= 1) {
      clearInterval(fadeInInterval);
    } else {
      bodyBeforeOpacity += 0.1;
      document.body.style.setProperty('--before-opacity', bodyBeforeOpacity);
    }
  }, 100);
}

// Function to check collision between player and enemy
function checkCollision() {
  if (isGameActive && !stopCheckingCollision) {
    // Calculate player and enemy positions
    const playerRight = playerLeft + playerWidth;
    const playerTop = playerBottom + player.offsetHeight;
    const enemyRight = enemyLeft + enemyWidth;
    const enemyTop = parseInt(getComputedStyle(enemy).bottom, 10) + enemy.offsetHeight;

    // Check for collision
    if (
      playerRight > enemyLeft &&
      playerLeft < enemyRight &&
      playerTop > enemyTop &&
      playerBottom < enemyTop
    ) {
      // Collision detected, check if player collides from the top or side
      if (playerBottom < enemyTop - playerSpeed) {
        // Collision from the side
        // Subtract health points
        playerHealth -= 15;
        if (playerHealth <= 0) {
          // Player's health is less than or equal to 0, end the game
          playerHealth = 0;
          updateHealthBar();
          endGame();
        } else {
          // Update health bar
          updateHealthBar();
          defeatEnemy();
          // Wait for a short delay before resuming collision detection
          setTimeout(() => {
            stopCheckingCollision = false;
          }, 500); // Adjust the delay as needed
        }
      } else {
          // Collision from the top
          // Increment the score only if the enemy is defeated by top collision.
          playerEnergy += 5; // Subtract energy when shooting
          updateEnergyBar(); // Update the energy bar display
          score += 1;
          updateScoreDisplay();
          defeatEnemy();
      }
    }
  }

  requestAnimationFrame(checkCollision);
}

function checkProjectileEnemyCollision(projectile) {
  const projectileRight = parseInt(projectile.style.left, 10) + projectile.offsetWidth;
  const projectileLeft = parseInt(projectile.style.left, 10);
  const enemyRight = enemyLeft + enemyWidth;

  if (
    projectileRight > enemyLeft &&
    projectileLeft < enemyRight &&
    projectile.offsetTop > enemy.offsetTop &&
    projectile.offsetTop < enemy.offsetTop + enemy.offsetHeight
  ) {
    // Collision detected between projectile and enemy
    score += 1;
    updateScoreDisplay();
    defeatEnemy();
    projectile.remove(); // Remove the projectile
    // console.log('collision detected');
  }
}

  // Function to start the game
  function startGame() {
    // Clear previous intervals, if any
    clearInterval(playerMoveInterval);
    clearInterval(screenMoveInterval);
    clearInterval(enemyMoveInterval);

    // Reset player position and stats
    resetPlayer();

    // Reset enemy position to its original starting point
    resetEnemy();

    // Set the game as active
    isGameActive = true;

    // Start playing the background music
    bgMusic.play();

    // Hide the logo element
    logoElement.style.display = 'none';

    // Add event listeners for key events
    document.addEventListener('keydown', handleKeyDown);
    document.addEventListener('keyup', handleKeyUp);

    // Update player position
    playerMoveInterval = setInterval(() => {
      if (isMovingLeft && playerLeft > 0) {
        playerLeft -= playerSpeed;
        movePlayer();
      } else if (isMovingRight && playerLeft < maxPlayerRight) {
        playerLeft += playerSpeed;
        movePlayer();
      }
    }, 30);

    // Update screen position
    screenMoveInterval = setInterval(() => {
      if (isGameActive) {
        moveScreen();
      }
    }, 30);

    // Reset the stopCheckingCollision flag
    stopCheckingCollision = false;

    // Start the collision detection loop
    requestAnimationFrame(checkCollision);

    // Start moving the enemy
    moveEnemy();
  }

    // Add a click event listener to the start button
    startButton.addEventListener('click', function () {
    // Add the 'ready-to-play' class to the body element
    document.body.classList.add('ready-to-play');

    // Hide the logo element
    logoElement.style.display = 'none';

    // Fade out the body ::before pseudo-element
    var bodyBefore = getComputedStyle(document.body, '::before');
    var bodyBeforeOpacity = parseFloat(bodyBefore.getPropertyValue('opacity'));

    var fadeOutInterval = setInterval(function () {
      if (bodyBeforeOpacity <= 0) {
        clearInterval(fadeOutInterval);
        document.body.style.overflow = 'visible'; // Optional: Show content outside body bounds if necessary

        // Start the game once the fade-out animation is complete
        startGame();
      } else {
        bodyBeforeOpacity -= 0.1;
        document.body.style.setProperty('--before-opacity', bodyBeforeOpacity);
      }
    }, 100); // Adjust the fade-out interval as needed
  });

});