【问题标题】:Html5 canvas animation leaves a trailHtml5画布动画留下痕迹
【发布时间】:2023-04-05 11:15:01
【问题描述】:

我正在尝试制作一个小游戏来玩画布。我决定选择Flappy Bird,因为网上有很多例子。我的目标是让游戏对所有设备都“响应”。如果您在手机或任何屏幕中打开它,您应该可以正常播放它。

为此,我在画布中绘制了一个背景图像,它将使高度适应屏幕的高度,并在 x 轴上重复。

我遇到的问题是,当我为这只鸟设置动画时,它会在它身后留下一条痕迹。

就像这样:

                                         

如本文所述,一个简单的解决方法是清除画布:

Canvas image leaves weird trail when moving left

但这是不可能的,因为我绘制背景的方式(我绘制一次,如果调整大小则重新绘制)。

问题

如何避免这种带有静态背景的图像轨迹?是否有可能拥有不需要重新绘制的虚假静态背景?

我显然想在画布中做,而不需要在 html 中有图像。

这是主要功能的代码,你可以看看:

const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");

cvs.style.height = "100vh";
cvs.style.width = "100vw";

var bird = new Image();
var bg = new Image();

bird.src = "https://lh3.googleusercontent.com/prntPuix7QxlhKXx6IBtTxv7PrdEJtmzFJ4mopScNS1_klze86BVNy3PqHbQn2UQ4JyJdix3XQ=w128-h128-e365";
bg.src = "https://opengameart.org/sites/default/files/bg_5.png";

let gravity = 1;
birdPositionY = 10;
birdPositionX = 50;

const draw = () => {
  ctx.drawImage(bird, birdPositionX, birdPositionY);

  birdPositionY += gravity;
  birdPositionX += 3;

  requestAnimationFrame(draw);
};

const resizeCanvas = () => {
  const {
    width,
    height
  } = cvs.getBoundingClientRect();
  cvs.height = height;
  cvs.width = width;

  let x = 0,
    y = 0;
  while (x < cvs.width && y < cvs.height) {
    ctx.drawImage(bg, x, y, 360, cvs.height);
    x += bg.width;
  }
};

bg.onload = () => {
  resizeCanvas();
};

window.addEventListener("resize", resizeCanvas, false);

draw();
<!DOCTYPE html>
<html>

<head>
  <title>Flappy Bird</title>
  <meta name="viewport" content="width=device-width, user-scalable=no" />
  <style>
    html {
      overflow: hidden;
    }
    
    body {
      margin: 0;
    }
    
    canvas {
      width: 100vw;
      height: 100vh;
    }
  </style>
</head>

<body>
  <canvas id="canvas"></canvas>
  <script src="index.js"></script>
</body>

</html>

希望它确实有意义!

提前致谢!

【问题讨论】:

    标签: javascript html css canvas html5-canvas


    【解决方案1】:

    在您将远离屏幕的画布上绘制背景,然后在绘制移动部件之前,在可见帧上的每一帧都绘制此画布。

    const cvs = document.getElementById("canvas");
    const ctx = cvs.getContext("2d");
    // our backround canvas that we won't append in the doc ("off-screen")
    const background = cvs.cloneNode();
    const bg_ctx = background.getContext('2d');
    
    cvs.style.height = "100vh";
    cvs.style.width = "100vw";
    
    var bird = new Image();
    var bg = new Image();
    
    bird.src = "https://lh3.googleusercontent.com/prntPuix7QxlhKXx6IBtTxv7PrdEJtmzFJ4mopScNS1_klze86BVNy3PqHbQn2UQ4JyJdix3XQ=w128-h128-e365";
    bg.src = "https://opengameart.org/sites/default/files/bg_5.png";
    
    let gravity = 1;
    birdPositionY = 10;
    birdPositionX = 50;
    
    const draw = () => {
      // first draw the background canvas
      ctx.drawImage(background, 0,0);
      // then your persona
      ctx.drawImage(bird, birdPositionX, birdPositionY);
    
      birdPositionY += gravity;
      birdPositionX += 3;
    
      requestAnimationFrame(draw);
    };
    
    const resizeCanvas = () => {
      const {
        width,
        height
      } = cvs.getBoundingClientRect();
      // resize both canvases
      cvs.height = background.height = height;
      cvs.width = background.width = width;
    
      let x = 0,
        y = 0;
      while (x < cvs.width && y < cvs.height) {
        // draw on the off-screen canvas
        bg_ctx.drawImage(bg, x, y, 360, cvs.height);
        x += bg.width;
      }
    };
    
    bg.onload = () => {
      resizeCanvas();
      draw();
    };
    
    window.addEventListener("resize", resizeCanvas, false);
    <!DOCTYPE html>
    <html>
    
    <head>
      <title>Flappy Bird</title>
      <meta name="viewport" content="width=device-width, user-scalable=no" />
      <style>
        html {
          overflow: hidden;
        }
        
        body {
          margin: 0;
        }
        
        canvas {
          width: 100vw;
          height: 100vh;
        }
      </style>
    </head>
    
    <body>
      <canvas id="canvas"></canvas>
      <script src="index.js"></script>
    </body>
    
    </html>

    【讨论】:

    • 这正是我想要的!非常感谢@Kaiido
    【解决方案2】:

    我认为您可以在绘制循环中调用 resizeCanvas 来重绘背景。

    编辑:显然这不起作用。另一种选择是像这样在绘图循环中绘制它:

    const draw = () => {
      ctx.clearRect(0, 0, cvs.width, cvs.height)
      let x = 0, y = 0;
      while (x < cvs.width && y < cvs.height) {
        ctx.drawImage(bg, x, y, 360, cvs.height);
        x += bg.width;
      }
    
      ctx.drawImage(bird, birdPositionX, birdPositionY);
    
      birdPositionY += gravity;
      birdPositionX += 3;
    
      requestAnimationFrame(draw);
    };
    

    编辑:那也不起作用。另一种选择是制作两张画布并将它们重叠在一起,一张画背景,一张画鸟。

    【讨论】:

    • 它没有,我也试过了,但它会冻结屏幕
    • 这是完全相同的代码,但在另一个地方,所以结果是一样的。你可以在sn-p中测试一下
    • 对不起。另一种选择可能是创建两个画布,一个画背景,另一个画鸟。
    猜你喜欢
    • 2013-12-14
    • 2019-06-09
    • 2011-12-30
    • 2019-04-16
    • 1970-01-01
    • 2012-05-11
    • 2010-11-04
    • 2018-05-13
    • 1970-01-01
    相关资源
    最近更新 更多