这篇文章简单介绍下如何在cocos create里面实现刮刮卡的效果。
首先看该节点的结构目录
ScrapeArea为主节点,控制这个组件的代码防在这个节点上面。这个节点要注意的事项就是本节点的size数值一点要大于texture节点的数值,才能擦除操作。因为这个要完成的点击、触摸等相应的事件。
mask为反向遮罩节点,必须确保大小和位置为(0,0)。
这是实现擦除效果的关键,运用到的就是反向遮罩和绘图先这两个功能。 首先为mask节点添加mask组件,记得将Inverted(即反向遮罩)勾上。
遮罩的含义是在含有mask组件的节点(下面简称mask节点)的子节点中,子节点超出mask范围(即size)的部分不给予显示。反向遮罩的功能正好相反,是子节点在mask节点范围内的部分不给予显示。这正式本方法实现擦除效果的原来,通过绘图,改变mask节点的大小,进而反向遮挡texture节点,露出底层的图片。
textrue为图片节点,就是过一个将要被刮开的图片。
我们来看一下具体代码的实现过程吧
代码里graphics的属性,可以参考cocos的API文档。
cc.Class({
extends: cc.Component,
properties: {
mask: {
default: null,
type: cc.Mask,
tooltip:'需要刮开的'
},
},
// 激活主节点的监听事件
onLoad: function () {
this.node.on(cc.Node.EventType.TOUCH_START, this._onTouchBegin, this);
this.node.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMoved, this);
this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this);
this.node.on(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
},
/**
* 结束刮图的动作监听
*/
endScrape(){
this.node.off(cc.Node.EventType.TOUCH_START, this._onTouchBegin, this);
this.node.off(cc.Node.EventType.TOUCH_MOVE, this._onTouchMoved, this);
this.node.off(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this);
this.node.off(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
},
/**
* 点击开始
* @param {*} event
*/
_onTouchBegin: function (event) {
cc.log('touchBegin');
this.comFun(event);
},
_onTouchMoved: function (event) {
this.comFun(event);
},
_onTouchEnd: function (event) {
cc.log('touchEnd');
this.checkScrape();
this.comFun(event);
},
_onTouchCancel: function (event) {
cc.log('TouchCancel')
this.checkScrape();
},
onDestroy: function () {
this.endScrape();
},
/**
* 获得点击的位置
* @param {事件} e
*/
getPos(e) {
var point = e.touch.getLocation();
point = this.node.convertToNodeSpaceAR(point);
return point;
},
comFun(event) {
var point = this.getPos(event);
this.checkPixelPiont(point);
this._addCircle(point);
},
/**
* 进行刮开的操作
* @param {*} point
*/
_addCircle: function (point) {
var graphics = this.mask._graphics;
//cc.log("xxxx:",graphics)
var color = cc.color(0, 0, 0, 255);
// 绘制椭圆
graphics.ellipse(point.x, point.y, 60, 60);
graphics.lineWidth = 2;
// 填充颜色为透明
graphics.fillColor = color;
// 开始填充颜色
graphics.fill();
},
});
然后将代码拖的主节点上,将mask放入槽中,刮刮卡的基本的功能就实现了。
下面是完整版刮刮卡代码的介绍,增加当擦除到70%的时候所有texture消失,执行回调事件。
本方法是先根据接触点的大小在图片上排列一个点矩阵,每个点矩阵有一个检测范围且只能被检测一次,没次被检测刮开的数都会执行++操作,知道接触点等于目标点(刮开的范围可以自己设置)后,遮罩的图片消失,并执行回调函数。
注:改方法不用设置主节点ScrapeArea节点的大小,在代码会改变它的大小的。
cc.Class({
extends: cc.Component,
properties: {
mask: {
default: null,
type: cc.Mask,
tooltip:'需要刮开的'
},
scrapteRadiusX: {
default: 25.0,
type: cc.Float,
tooltip: '绘制点图形的x轴半径'
},
scrapteRadiusY: {
default: 35.0,
type: cc.Float,
tooltip: '绘制点图形的Y轴半径'
},
scrapteArea: {
default: 0.5,
type: cc.Float,
tooltip: '需要刮开的图层面积的多少'
},
scrapeEvents: {
default: [],
type: [cc.Component.EventHandler],
tooltip: '擦除完成后所触发的事件'
},
},
onLoad: function () {
this.activeMaskNode();
},
activeMaskNode() {
this.getinitNum();
this.node.on(cc.Node.EventType.TOUCH_START, this._onTouchBegin, this);
this.node.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMoved, this);
this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this);
this.node.on(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
},
/**
* 结束刮图的动作监听
*/
endScrape(){
this.node.off(cc.Node.EventType.TOUCH_START, this._onTouchBegin, this);
this.node.off(cc.Node.EventType.TOUCH_MOVE, this._onTouchMoved, this);
this.node.off(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this);
this.node.off(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
},
/**
* 点击开始
* @param {*} event
*/
_onTouchBegin: function (event) {
cc.log('touchBegin');
this.comFun(event);
},
_onTouchMoved: function (event) {
this.comFun(event);
},
_onTouchEnd: function (event) {
cc.log('touchEnd');
this.checkScrape();
this.comFun(event);
},
_onTouchCancel: function (event) {
cc.log('TouchCancel')
this.checkScrape();
},
onDestroy: function () {
this.endScrape();
},
comFun(event) {
var point = this.getPos(event);
this.checkPixelPiont(point);
this._addCircle(point);
},
/**
* 进行刮开的操作
* @param {*} point
*/
_addCircle: function (point) {
var graphics = this.mask._graphics;
//cc.log("xxxx:",graphics)
var color = cc.color(0, 0, 0, 255);
// 绘制椭圆
graphics.ellipse(point.x, point.y, this.scrapteRadiusX * 2, this.scrapteRadiusY * 2);
graphics.lineWidth = 2;
// 填充颜色为透明
graphics.fillColor = color;
// 开始填充颜色
graphics.fill();
},
/**
* 检查是否完成擦除
*/
checkScrape() {
cc.log('目标数是:' + this.achieveNum);
cc.log('现在已经刮开' + this.pixelNum);
if (this.achieveNum < this.pixelNum) {
cc.log("已经刮完图层");
this.achieveScrape();
}
},
/**
* 获得点击的位置
* @param {事件} e
*/
getPos(e) {
var point = e.touch.getLocation();
point = this.node.convertToNodeSpaceAR(point);
return point;
},
/**
* 获取初始值
*/
getinitNum() {
this.pixelNum = 0;
// 记录要擦除多少像素点才能完成擦除操作
this.achieveNum = this.scrapteArea * this.initPixel();
},
/**
* 根据所设计的接触点的大小设置出一个点矩阵,在根据接触点与点矩阵的
* 距离判断当前已经刮开了图像的多少了
*/
initPixel() {
this.scrapeNode = this.mask.node.children[0];
var x = this.scrapeNode.width, y = this.scrapeNode.height;
//根据所设texture的大小来改变主节点的大小
this.node.width = x;
this.node.height = y;
//根据接触点的大小来设置矩阵点多少以及点之间的距离
this.widthWide = x / 2 + 20;
this.heightWide = x / 2 + 20;
var zx = x / 2, zy = y / 2, dx = -zx, dy = -zy, dy1 = dy;
var pixelPiont = [];
var rx = this.scrapteRadiusX * 2;
var ry = this.scrapteRadiusY * 2;
// 开始排列矩阵
for (; dx <= zx; dx += rx) {
for (dy = dy1; dy <= zy; dy += ry) {
var p = [dx, dy];
// 该属性确保每个矩阵点只能有一次的检测操作
// 被检测完后变为false不能被二次检测
p.isTouch = true;
pixelPiont.push(p);
}
}
this.pixelPiont = pixelPiont;
//返回像素点的个数
return pixelPiont.length;
},
/**
* 检查是否画在新的像素点上,若是话在了新的点上,接使刮开数执行++操作
*/
checkPixelPiont(point) {
var pixelPiont = this.pixelPiont;
var x, y;
for (var i in pixelPiont) {
x = Math.abs(point.x - pixelPiont[i][0]);
y = Math.abs(point.y - pixelPiont[i][1]);
if (x <= this.scrapteRadiusX && y <= this.scrapteRadiusY && pixelPiont[i].isTouch) {
// 让该元素不可以响应触摸功能
pixelPiont[i].isTouch = false;
this.pixelNum++;
return;
}
}
},
/**
* 完成刮蹭事件
*/
achieveScrape() {
this.endScrape();
// 执行渐隐效果,卡片消失
this.node.runAction(cc.fadeOut(0.5));
this.scheduleOnce((() => {
// 执行回调事件
cc.Component.EventHandler.emitEvents(this.scrapeEvents, new cc.Event.EventCustom('scrapeEvents'));
//this.node.destroy();
}).bind(this), 0.6);
},
});