HTML5画布动画留下痕迹

时间:2019-06-19 22:38:41

标签: javascript html css canvas html5-canvas

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

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

Flappy Bird

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

就像这样:

https://i.stack.imgur.com/xu0Vzm.png

一个简单的解决方法是按照本文中的说明清除画布:

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>

希望这确实有意义!

谢谢!

2 个答案:

答案 0 :(得分:2)

在将要保持屏幕外的画布上绘制背景,然后在绘制运动部件之前在可见的每一帧上绘制此画布。

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>

答案 1 :(得分:0)

我认为您可以在绘制循环中调用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);
};

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