如何在 canvas 上为带有背景图像的球制作动画?
How can I animate a ball with a background image on the canvas?
我正在创建一个 canvas 游戏,其中的球会相互反弹。
我希望球有自己的皮肤,其中背景图像放在弧形元素上。
当球不弹跳时,图像剪辑得很好并且是圆形的,就像弧线一样。但是,当我开始为球设置动画时,它根本就不会移动,因为剪辑功能不允许重绘图像或弧线。
那时我发现 canvas 中的保存和恢复功能允许在制作动画时使用剪辑方法。
问题是图像的一部分没有正确剪裁。只有一半的动画是圆形的,另一半是矩形的。我试过调整图像的位置,但这并没有达到预期的效果。
我不确定为什么代码会这样,也不知道如何修复它,使它只是一个带有图像背景的动画球。
如果有人对此有所了解并且可能有解决方案,将不胜感激。
下面是代码和片段:
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>
您需要调用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" />
另请注意,对于圆形遮罩,您最好使用合成而不是剪裁,合成处理更好的抗锯齿,并且不需要昂贵的 save/restore。
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" />
我正在创建一个 canvas 游戏,其中的球会相互反弹。 我希望球有自己的皮肤,其中背景图像放在弧形元素上。
当球不弹跳时,图像剪辑得很好并且是圆形的,就像弧线一样。但是,当我开始为球设置动画时,它根本就不会移动,因为剪辑功能不允许重绘图像或弧线。
那时我发现 canvas 中的保存和恢复功能允许在制作动画时使用剪辑方法。
问题是图像的一部分没有正确剪裁。只有一半的动画是圆形的,另一半是矩形的。我试过调整图像的位置,但这并没有达到预期的效果。
我不确定为什么代码会这样,也不知道如何修复它,使它只是一个带有图像背景的动画球。
如果有人对此有所了解并且可能有解决方案,将不胜感激。
下面是代码和片段:
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>
您需要调用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" />
另请注意,对于圆形遮罩,您最好使用合成而不是剪裁,合成处理更好的抗锯齿,并且不需要昂贵的 save/restore。
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" />