遮罩
遮罩的场景很广泛,合理的使用可以完成很多不同的效果,我们先看看一个简单的例子:
// 创建一个容器
var container = new Tiny.Container();
// 创建一个精灵
var sprite = Tiny.Sprite.fromImage('https://gw.alipayobjects.com/as/g/tiny/resources/1.0.0/images/logo.png');
// 创建一个圆
var g = new Tiny.Graphics();
g.lineStyle(0);
g.beginFill(0xFFFFFF);
// x: 60, y: 150, 直径:60
g.drawCircle(60, 150, 60);
g.endFill();
// 设置精灵的遮罩是这个圆形
sprite.mask = g;
// 将精灵添加到容器 container 中
container.addChild(sprite);
// 切换场景为这个 container
app.replaceScene(container);
效果如下:
使用位图
说到位图,我们可能会追溯到像素阵列,特殊时候,用透明背景的图片可以快速达到某种形态的效果,比如下图:
然后我们想要用这个透明 png 图片来做遮罩,应该如何做?
1、首先,将位图转化为像素值(注意:这里会用到插件 tinyjs-plugin-extract
):
// 使用静态方法 fromImage 创建纹理
var texture = Tiny.Texture.fromImage('https://gw.alipayobjects.com/as/g/tiny/resources/1.0.0/images/mokey.png');
// 使用纹理创建精灵
var mokey = new Tiny.Sprite(texture);
// 只有等图片加载完成才能获取到像素值
texture.on('update', function () {
// 使用插件 tinyjs-plugin-extract 的方法 pixels 将精灵转换成像素值
var pixels = app.renderer.plugins.extract.pixels(mokey);
console.log(pixels);
//=> Uint8Array(1166400) [0, 0, 0, 0, 0, 0, 0, 0, ...]
});
2、然后我们解析一下这个 pixels,这是一个 Uint8Array
的数组,排列的规则是自左向右、自上而下对应到位图上的像素点,每四个一组(RGBA值),理解之后再分解一下:
var arr = [];
for (var i = 0, len1 = pixels.length; i < len1; i++) {
if (i % 4 === 0) {
var rgba = [];
for (var c = 0; c < 4; c++) {
rgba.push(pixels[i + c]);
}
arr.push(rgba);
}
}
console.log(arr);
//=> (291600) [Array(4), Array(4), Array(4), ...]
这样,我们就拿到位图的像素矩阵,因为是 png 的透明图,所以我们找“形状”就直接判断 A
值(即 alpha
通道)是否为 0 即可(当然,如果是边缘模糊,也可以以中间值来判断)。
var pos = [];
for (var j = 0, len2 = arr.length; j < len2; j++) {
if (arr[j][3] !== 0) {
pos.push([j % width, ~~(j / height)]);
}
}
console.log(pos);
//=> (98640) [Array(2), Array(2), Array(2), ...]
这样,我们就拿到了有像素值的坐标了,以这些坐标用 Graphics
的画 1 像素的矩形就成“形状”了:
var g = new Tiny.Graphics();
g.beginFill(0x000000);
pos.forEach((p) => {
g.drawRect(p[0], p[1], 1, 1);
});
g.endFill();
结果如下:
3、最后创建一个背景,并将它的遮罩设置成转化后的图形:
var sprite = Tiny.Sprite.fromImage('https://gw.alipayobjects.com/as/g/tiny/resources/1.0.0/images/bg/pic1.jpg');
// 转化的方法 pixels2graphics 见篇尾
sprite.mask = pixels2graphics(pixels, mokey.width, mokey.height);
结果如下:
注意
- 遮罩的位移(
setPosition
)请慎用浮点数,最好强制转化成整数。- 请不要过于依赖此姿势,使用过多或影响性能,特殊时候适当使用。
附上像素转化代码:
/**
* 像素转化为图形
*
* @param {Array} pixels - 位图像素值
* @param {Number} width - 位图真实宽度
* @param {Number} height - 位图真实高度
* @return {Tiny.Graphics}
*/
function pixels2graphics(pixels, width, height) {
var arr = [];
var pos = [];
for (var i = 0, len1 = pixels.length; i < len1; i++) {
if (i % 4 === 0) {
var rgba = [];
for (var c = 0; c < 4; c++) {
rgba.push(pixels[i + c]);
}
arr.push(rgba);
}
}
for (var j = 0, len2 = arr.length; j < len2; j++) {
if (arr[j][3] !== 0) {
pos.push([j % width, ~~(j / height)]);
}
}
var g = new Tiny.Graphics();
g.beginFill(0x000000);
pos.forEach((p) => {
g.drawRect(p[0], p[1], 1, 1);
});
g.endFill();
return g;
}