我有这张png sprite云片。我完全有能力切割spritesheet,并将单个云放入画布上下文中。但是,如果我想修改该云的图像呢? 如果我想在左边用黄色着色怎么办?具有某种径向梯度。那些东西应该是可能的,对吧?径向渐变仅影响白云像素,但仅影响透明度。 这个叫什么?我需要做什么?
答案 0 :(得分:1)
这称为compositing,是的,Canvas2D API非常可行,它提供了globalCompositeOperation
属性,有几种不同的模式。
这是一个使用fully white + alpha sprite的简单ES6示例,我们将在其上绘制一个radialGradient。
(async() => {
const ctx = c.getContext('2d');
const clouds = getCloudsObjects(30);
const sheet = await loadImage('https://i.stack.imgur.com/Gvewl.png');
ctx.filter = 'blur(2px)';
const cloud_grad = initGrad('yellow', 'red');
const sky_grad = initGrad('#300c46', 'green');
anim();
function anim() {
ctx.clearRect(0, 0, c.width, c.height);
clouds.forEach(updateAndDrawSprite);
// draw only on non transparent pixels, keeping the alpha info
ctx.globalCompositeOperation = 'source-atop';
drawGrad(cloud_grad);
if (bg.checked) {
// draw behind everything ?
ctx.globalCompositeOperation = 'destination-over';
drawGrad(sky_grad);
}
// reset gCO
ctx.globalCompositeOperation = 'source-over';
requestAnimationFrame(anim);
}
function initGrad(col1, col2) {
const grad = ctx.createRadialGradient(0, c.height, 0, 0, c.height, c.width * 1.6);
grad.addColorStop(0, col1);
grad.addColorStop(0.7, col2);
return grad;
}
function drawGrad(grad) {
ctx.fillStyle = grad;
ctx.fillRect(0, 0, c.width, c.height);
}
function updateAndDrawSprite(obj) {
obj.update();
ctx.drawImage(sheet, obj.ox, obj.oy, obj.ow, obj.oh, obj.x, obj.y, obj.w, obj.h);
}
function getCloudsObjects(nbOfClouds) {
const arr = [];
const W = 64,
h = 16,
w = 16,
max = w / W;
for (let i = 0; i < nbOfClouds; i++) {
let s = Math.random() * (c.height / h);
arr[i] = {
ox: Math.floor(Math.random() * 4) * w,
oy: 0,
oh: h,
ow: w,
x: Math.random() * c.width,
y: Math.random() * c.height,
w: s * w,
h: s * h,
speed: Math.random() - .5,
update: function() {
this.x += this.speed;
this.y += this.speed / 2;
if (this.x > c.width)
this.x = -this.w;
if (this.y > c.height)
this.y = -this.h;
if (this.x < -this.w)
this.x = c.width;
if (this.y < -this.h)
this.y = c.height;
}
};
}
return arr;
}
function loadImage(url) {
return new Promise((res, rej) => {
const img = new Image();
img.onload = e => res(img);
img.onerror = e => rej(img);
img.src = url;
});
}
})();
label {
display: block
}
<canvas id="c" width="500"></canvas>
<label>draw background <input type="checkbox" id="bg"></label>