October 27, 2024
Chicago 12, Melborne City, USA
javascript

Not being able to see the animations being rendered because the function is inside the game loop


I am quite new to game development. In fact, this is the first ever game I am creating. My game is a simple balloon popping game. The problem is I have a pump asset which inflates the balloon on click. Usually, it takes around 5 clicks to inflate the balloon. But I am caught in a weird logic wherein I have to call the blowBalloon() function [for inflating the balloon] inside the game loop. This causes the function to be rendered 24 times on a single click, resulting in the animations being skipped completely. Please help. Thanks in advance. Please refer to blowBalloon() function.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Alphabet Balloons</title>

    <style>
      body,
      html {
        margin: 0;
        padding: 0;
        overflow: hidden;
        height: 100%;
        width: 100%;
        box-sizing: border-box;
        border: 5px;
        border-radius: 5px;
        border-style: solid;
        cursor: pointer;
      }
      canvas {
        display: block;
      }
    </style>
  </head>
  <body>
    <canvas id="gameCanvas"></canvas>
      <div class="animation-container">
        <img
          src="Assets/BurstAnimation.gif"
          alt="Burst Animation"
          class="burst-animation"
          style="display: none"
        />
      </div>
    </div>
    <script>
      const canvas = document.getElementById("gameCanvas");
      const ctx = canvas.getContext("2d");

      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;

      window.addEventListener("resize", () => {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        drawBackground();
      });

      const backgroundImage = new Image();
      backgroundImage.src = "Assets/Background/backgroundImage.png";

      function drawBackground() {
        ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
      }

      const alphabetArray = [...Array(26).keys()].map((i) => ({
        src: `Assets/GeneralAssets/Alphabets/Alpha${String.fromCharCode(
          65 + i
        )}.png`,
      }));

      const alphabetImages = alphabetArray.map((alphabet) => {
        const img = new Image();
        img.src = alphabet.src;
        return img;
      });

      const balloonArray = [
        "Assets/GeneralAssets/Balloons/BalloonBlue1.png",
        "Assets/GeneralAssets/Balloons/BalloonBlue2.png",
        "Assets/GeneralAssets/Balloons/BalloonGreen1.png",
        "Assets/GeneralAssets/Balloons/BalloonGreen2.png",
        "Assets/GeneralAssets/Balloons/BalloonOrange.png",
        "Assets/GeneralAssets/Balloons/BalloonPink.png",
        "Assets/GeneralAssets/Balloons/BalloonPink2.png",
        "Assets/GeneralAssets/Balloons/BalloonPurple.png",
        "Assets/GeneralAssets/Balloons/BalloonRed.png",
        "Assets/GeneralAssets/Balloons/BalloonYellow.png",
      ].map((src) => {
        const img = new Image();
        img.src = src;
        return img;
      });

      // Importing balloon string
      const balloonString = new Image();
      balloonString.src = "Assets/GeneralAssets/Balloons/BalloonString.png";

      const pump = { x: window.innerWidth - 407, y: window.innerHeight - 407 };
      const pumpParts = [
        { src: "Assets/GeneralAssets/Pump/PumpConnector.png", x: 50, y: 170 },
        { src: "Assets/GeneralAssets/Pump/PumpHandle.png", x: 190, y: 30 },
        { src: "Assets/GeneralAssets/Pump/PumpSymbol.png", x: 190, y: 190 },
      ];

      const pumpImages = pumpParts.map((part) => {
        const img = new Image();
        img.src = part.src;
        return { img, x: part.x, y: part.y };
      });

      let shakeOffsetX = 0;
      let shakeOffsetY = 0;
      let symbolShakeX = 0;
      let symbolShakeY = 0;
      let rotationAngle = 0;
      let scale = 1;
      let handleY = 0;
      let handleMoving = false;
      let handleDirection = 1;
      let connectorShaking = false;
      let symbolShaking = false;

      function applyPumpAnimations() {
        if (connectorShaking) {
          shakeOffsetX = Math.random() * 1 - 0.5;
          shakeOffsetY = Math.random() * 1 - 0.5;
        }
        if (symbolShaking) {
          symbolShakeX = Math.random() * 3 - 1.5;
          symbolShakeY = Math.random() * 3 - 1.5;
        }
        if (handleMoving) {
          handleY += handleDirection * 50;
          if (handleY >= 200) {
            handleDirection = -1;
          } else if (handleY <= 0) {
            handleDirection = 1;
            handleMoving = false;
          }
        }
      }

      function assemblePump() {
        pumpImages.forEach((part, index) => {
          let x = pump.x + part.x,
            y = pump.y + part.y;
          ctx.save();
          if (index === 0 && connectorShaking) {
            // Pump Connector shake
            x += shakeOffsetX;
            y += shakeOffsetY;
          } else if (index === 1 && handleMoving) {
            // Pump Handle up-and-down movement
            y += handleY;
          } else if (index === 2 && symbolShaking) {
            // Pump Symbol vibration
            x += symbolShakeX;
            y += symbolShakeY;
          }
          ctx.drawImage(part.img, x, y, 250, 250);
          ctx.restore();
        });
      }

      // An empty array to keep track of multiple balloons
      const balloons = [];

      // alphabet index keeps track of the alphabet rendered.
      let alphabetIndex = 0;

      function drawBalloons() {
        balloons.forEach((balloon) => {
            ctx.drawImage(
            balloon.balloonImage,
            balloon.x,
            balloon.y,
            balloon.width,
            balloon.height
        );
        const alphabetX = balloon.x + balloon.width / 4,
        alphabetY = balloon.y + balloon.height / 4;
        ctx.drawImage(
            balloon.alphabetImg,
            alphabetX,
            alphabetY,
            balloon.width / 2,
            balloon.height / 2
        );

        // Drawing the string
        const stringX = (balloon.x + balloon.width / 2) - (balloon.balloonString.width / 2) +185;
        const stringY = balloon.y + balloon.height -50;
        ctx.drawImage(
            balloon.balloonString,
            stringX,
            stringY,
            balloon.width,
            balloon.height,
        );
  });
}

      function updateBalloonPositions() {
        balloons.forEach((balloon) => {
          if (!balloon.isGrowing) {
            balloon.x += balloon.speedX;
            balloon.y += balloon.speedY;
            if (balloon.x < 0 || balloon.x + balloon.width > canvas.width)
              balloon.speedX *= -1;
            if (balloon.y < 0 || balloon.y + balloon.height > canvas.height)
              balloon.speedY *= -1;
          }
        });
      }

      function blowBalloon(balloon) {
        if (balloon.isBlowing) return; // Prevent re-triggering
  
        balloon.isBlowing = true; // Set this only once per click
        if (balloon.width < 150 && balloon.height < 150) {
          balloon.width += 5;
          balloon.height += 5;
          balloon.x -= 12;
          balloon.y -= 20;
          console.log("blowBalloon executed");
        } else {
          balloon.isGrowing = false;
          balloon.isBlowing = false;
          console.log("Balloon grown");
        }
      }

      
      let loadedImages = 0,
        totalImages =
          alphabetImages.length + balloonArray.length + pumpImages.length + 2;
      function checkAllImagesLoaded() {
        loadedImages++;
        if (loadedImages === totalImages) gameLoop();
      }

      backgroundImage.onload = checkAllImagesLoaded;
      alphabetImages.forEach((img) => (img.onload = checkAllImagesLoaded));
      pumpImages.forEach((part) => (part.img.onload = checkAllImagesLoaded));
      balloonArray.forEach((img) => (img.onload = checkAllImagesLoaded));
      balloonString.onload = checkAllImagesLoaded;

      function gameLoop() {
        drawBackground();
        assemblePump();

        drawBalloons();
        balloons.forEach((balloon) => {
            balloon.isBlowing = false;
          if (balloon.isGrowing) {
            blowBalloon(balloon);
            applyPumpAnimations();
            console.log("PumpAnimation Executed");
          }
        });
        updateBalloonPositions();
        requestAnimationFrame(gameLoop);
      }

      canvas.addEventListener("click", function (event) {
        const rect = canvas.getBoundingClientRect();
        const x = event.clientX - rect.left;
        const y = event.clientY - rect.top;

        // check if a balloon has been clicked
        for (let i = balloons.length - 1; i >= 0; i--) {
          const balloon = balloons[i];

          if (
            x >= balloon.x &&
            x <= balloon.x + balloon.width &&
            y >= balloon.y &&
            y <= balloon.y + balloon.height
          ) {
            // Playing the burst animation
            const burstAnimation = document.querySelector(".burst-animation");
            burstAnimation.style.display = "block";
            burstAnimation.style.left = `${balloon.x}px`; // Position the GIF
            burstAnimation.style.top = `${balloon.y}px`; // Position the GIF
            console.log("Burst animation played");

            // Remove the balloon from the array
            balloons.splice(i, 1);

            return;
          }
        }

        const pumpX = pump.x;
        const pumpY = pump.y;

        if (x >= pumpX && x <= pumpX + 400 && y >= pumpY && y <= pumpY + 400) {
          // If we've reached the end of the alphabet, stop creating new balloons
          if (alphabetIndex >= alphabetImages.length) {
            return; // No more balloons
          }

          // Apply pump animations
          connectorShaking = true;
          symbolShaking = true;
          handleMoving = true;

          setTimeout(() => {
            connectorShaking = false;
            symbolShaking = false;
          }, 5000); // Stop shaking after 5 second

          const newBalloon = {
            x: pump.x + 100,
            y: pump.y + 200,
            speedX: Math.random() * 4 + 0.3,
            speedY: Math.random() * 1 + 0.3,
            width: 30,
            height: 30,
            isGrowing: true,
            isBlowing: false,
            alphabetImg: alphabetImages[alphabetIndex],
            balloonImage:
              balloonArray[Math.floor(Math.random() * balloonArray.length)],
            balloonString: balloonString,
          };

          balloons.push(newBalloon);
          alphabetIndex++;
        }
      });
    </script>
  </body>
</html>

I tried moving out the function from the game loop and executing it independently outside the game loop expecting that this will solve the issue, but that ended up in the rendering of many balloons all at once.



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video