如何在画布上为带有背景图像的球设置动画?

时间:2019-02-20 03:44:29

标签: javascript animation html5-canvas prototype javascript-objects

我正在创建一个画布游戏,其中的球会相互反弹。 我希望这些球具有自己的皮肤,在弧形元素上放置背景图像。

当球不弹跳时,图像剪辑得很好并且像弧线一样是圆形的。但是,当我开始为球设置动画时,它根本不会移动,因为剪辑功能不允许重绘图像或弧线。

那是我在画布中发现保存和恢复功能时允许在动画时使用clip方法的时候。

此问题是图像的一部分无法正确裁剪。动画中只有一半是圆形的,另一半是矩形图像。我尝试过调整图像的位置,但是并没有达到预期的效果。

我不确定代码为什么会这样,以及如何修复它,使其只是具有图像背景的动画球。

如果有人对此有所了解,甚至可能对解决方案有所了解,将不胜感激。

这是下面的代码和摘录:

  const x = document.getElementById('canvas');
  const ctx = x.getContext('2d');
  let slide = 0;
  class Balls {
    constructor(xPos, yPos, radius) {
      this.xPos = xPos;
      this.yPos = yPos;
      this.radius = radius;
      this.imgX = this.xPos - this.radius;
    }
  }
  const img = document.createElement('img');
  img.src = 'https://geology.com/google-earth/google-earth.jpg';
  Balls.prototype.render = function() {
    ctx.save();
    ctx.arc(this.xPos, this.yPos, this.radius, 0, Math.PI * 2);
    ctx.clip();
    ctx.drawImage(img, this.imgX, this.yPos - this.radius, this.radius * 2, this.radius * 2);

  };
  Balls.prototype.motion = function() {
    this.imgX = this.imgX + 1;
    this.xPos = this.xPos + 1;
  }
  let object = new Balls(100, 100, 25);
  const animate = () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    object.render();
    object.motion();
    ctx.restore();
  }
  setInterval(animate, 50);
body {
  background-color: grey;
}

#canvas {
  background-color: white;
}

#mod {
  border-radius: 100%
}
<!DOCTYPE html>
<html>
<head>
  <title>Page Title</title>
  <script src='practice.js'></script>
  <link rel="stylesheet" type="text/css" href="practice.css">
</head>
<body>
  <canvas id="canvas" height="200" width="800" />
</body>
</html>

1 个答案:

答案 0 :(得分:2)

您需要调用ctx.beginPath(),否则,每次对arc()的调用都会添加到相同且唯一的子路径中。这意味着最后,您将剪切由许多弧线组成的怪异路径:5帧后路径的ASCII表示形式:((((( )

const x = document.getElementById('canvas');
const ctx = x.getContext('2d');
let slide = 0;
class Balls {
  constructor(xPos, yPos, radius) {
    this.xPos = xPos;
    this.yPos = yPos;
    this.radius = radius;
    this.imgX = this.xPos - this.radius;
  }
}
const img = document.createElement('img');
img.src = 'https://geology.com/google-earth/google-earth.jpg';
Balls.prototype.render = function() {
  ctx.save();
  // begin a  new sub-path
  ctx.beginPath();
  ctx.arc(this.xPos, this.yPos, this.radius, 0, Math.PI * 2);
  ctx.clip();
  ctx.drawImage(img, this.imgX, this.yPos - this.radius, this.radius * 2, this.radius * 2);

};
Balls.prototype.motion = function() {
  this.imgX = this.imgX + 1;
  this.xPos = this.xPos + 1;
}
let object = new Balls(100, 100, 25);
const animate = () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  object.render();
  object.motion();
  ctx.restore();
  requestAnimationFrame(animate);
}
animate();
body {
  background-color: grey;
}

#canvas {
  background-color: white;
}

#mod {
  border-radius: 100%
}
<canvas id="canvas" height="200" width="800" />

还请注意,对于圆形蒙版,使用合成比剪切更好,合成可以更好地消除锯齿,并且不需要昂贵的保存/恢复。

const x = document.getElementById('canvas');
const ctx = x.getContext('2d');
let slide = 0;
class Balls {
  constructor(xPos, yPos, radius) {
    this.xPos = xPos;
    this.yPos = yPos;
    this.radius = radius;
    this.imgX = this.xPos - this.radius;
  }
}
const img = document.createElement('img');
img.src = 'https://geology.com/google-earth/google-earth.jpg';
Balls.prototype.render = function() {
  // begin a  new sub-path
  ctx.beginPath();
  ctx.arc(this.xPos, this.yPos, this.radius, 0, Math.PI * 2);
  ctx.fill();
  ctx.globalCompositeOperation = 'source-in';
  ctx.drawImage(img, this.imgX, this.yPos - this.radius, this.radius * 2, this.radius * 2);
  ctx.globalCompositeOperation = 'source-over';
};
Balls.prototype.motion = function() {
  this.imgX = this.imgX + 1;
  this.xPos = this.xPos + 1;
}
let object = new Balls(100, 100, 25);
const animate = () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  object.render();
  object.motion();
  requestAnimationFrame(animate);
}
animate();
body {
  background-color: grey;
}

#canvas {
  background-color: white;
}

#mod {
  border-radius: 100%
}
<canvas id="canvas" height="200" width="800" />