无法看到正在渲染的动画,因为该函数位于游戏循环内

问题描述 投票:0回答:1

我对游戏开发还很陌生。事实上,这是我创建的第一个游戏。我的游戏是一个简单的气球爆破游戏。问题是我有一个泵资产,可以在点击时使气球膨胀。通常,大约需要点击 5 次才能给气球充气。但我陷入了一个奇怪的逻辑,其中我必须在游戏循环内调用blowBalloon()函数[用于给气球充气]。这会导致该函数在单击一次时渲染 24 次,从而导致动画被完全跳过。请帮忙。提前致谢。请参考blowBalloon()函数。

<!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>

我尝试将函数从游戏循环中移出,并在游戏循环之外独立执行它,希望这能解决问题,但最终导致同时渲染许多气球。

javascript html css canvas game-development
1个回答
0
投票

从gameLoop()中删除blowBalloon(balloon)调用

更改单击事件侦听器,以便仅在最后一个气球的 isGrowing 为 true 时才创建新气球。否则请调用blowBalloon()。

  if (x >= pumpX && x <= pumpX + 400 && y >= pumpY && y <= pumpY + 400) {
    if( balloons.length && balloons[balloons.length-1].isGrowing ) {
      blowBalloon(balloons[balloons.length-1]);
    }
    else {
      NOTE: Move your pump animation settings and balloon creation code into this else block
    }
  }
© www.soinside.com 2019 - 2024. All rights reserved.