游戲開(kāi)獎(jiǎng)功能組件《刮刮卡》特效實(shí)現(xiàn)
一、?需求分析
【1】實(shí)現(xiàn)手指觸摸刮開(kāi)效果;【2】?jī)?yōu)化:判斷刮開(kāi)與否(能否正常看到獎(jiǎng)項(xiàng))。
二、?游戲場(chǎng)景可視化編輯

三、?手指觸摸刮刮卡動(dòng)態(tài)刮開(kāi)效果的實(shí)現(xiàn)

Mask為反向遮罩節(jié)點(diǎn),必須確保大小和位置為(0,0)。
運(yùn)用反向遮罩和繪圖來(lái)實(shí)現(xiàn)。 首先為Mask節(jié)點(diǎn)添加Mask組件。記得將Inverted(即反向遮罩)勾上。
原理:類(lèi)似于PS中的遮罩,或者沙畫(huà),比如你在玻璃上寫(xiě)了幾個(gè)字,但是我在你玻璃上鋪上了一層灰色的沙子(MaskBg),在沙子上撒了一點(diǎn)特侖蘇,留下了“刮獎(jiǎng)區(qū)”三個(gè)字。你想把下面的東西顯示出來(lái),只能拿到Mask節(jié)點(diǎn)上面的那把刷子,將沙子掃開(kāi)。
新建GameMgr.js,并掛載到Canvas節(jié)點(diǎn)上。代碼如下:
onLoad () {
// 獲取遮罩子節(jié)點(diǎn),再獲取其上面的Mask遮罩組件
this.mask =?this.node.getChildByName("Mask").getComponent(cc.Mask);
this.node.on(cc.Node.EventType.TOUCH_START,?this.onTouchStart,?this);
this.node.on(cc.Node.EventType.TOUCH_MOVE,?this.onTouchMove,?this);
this.node.on(cc.Node.EventType.TOUCH_END,?this.onTouchEnd,?this);
this.node.on(cc.Node.EventType.TOUCH_CANCEL,?this.onTouchCancel,?this);
},
onTouchStart(e){
this.scratch(e);
},
onTouchMove(e){
this.scratch(e);
},
onTouchEnd(e){
this.scratch(e);
},
onTouchCancel(e){
},
// 刮開(kāi)操作
scratch(e){
// 【1】獲取觸摸點(diǎn)相對(duì)于當(dāng)前節(jié)點(diǎn)的錨點(diǎn)的坐標(biāo)
var pos =?this.getPos(e);
// 【2】根據(jù)觸摸點(diǎn)位置刮開(kāi)圖層,添加一個(gè)形狀
this.addShape(pos);
},
getPos(e){
return?this.node.convertToNodeSpaceAR(e.getLocation());
},
addShape(pos){
var graphics =?this.mask._graphics;
graphics.fillRect(pos.x, pos.y, 50, 30);
},
四、?隨機(jī)刮開(kāi)獎(jiǎng)項(xiàng)
在GameMgr.js中增加如下代碼即可:
start () {
var res = Math.floor(Math.random()*4);
this.initPrize(res);
},
initPrize(res){
this.prizeInfo = ["一等獎(jiǎng)\n胖妞一枚","二等獎(jiǎng)\n白鵝一只","三等獎(jiǎng)\n小三一位","再來(lái)一次!"];
this.prizeItemLabel = cc.find("Canvas/PrizeRoot/PrizeItem").getComponent(cc.Label);
this.prizeItemLabel.string =?this.prizeInfo[res];
},
五、?刮開(kāi)面積計(jì)算與刮開(kāi)結(jié)果后的回調(diào)處理
增加當(dāng)擦除到70%的時(shí)候所有texture消失,執(zhí)行回調(diào)事件。
本方法是先根據(jù)接觸點(diǎn)的大小在圖片上排列一個(gè)點(diǎn)矩陣,每個(gè)點(diǎn)矩陣有一個(gè)檢測(cè)范圍且只能被檢測(cè)一次,每次被檢測(cè)刮開(kāi)的數(shù)都會(huì)執(zhí)行++操作,直到接觸點(diǎn)等于目標(biāo)點(diǎn)(刮開(kāi)的范圍可以自己設(shè)置)后,遮罩的圖片消失,并執(zhí)行回調(diào)函數(shù)。
注:該方法不用設(shè)置主節(jié)點(diǎn)Mask節(jié)點(diǎn)的大小,在代碼會(huì)改變它的大小的。
1. 初始化遮罩層的記錄點(diǎn)數(shù)組
properties: {
maskBg:{type:cc.Node, default:null,tooltip:"刮層節(jié)點(diǎn)",},
scratchRadiuX:{type:cc.Float, default:20,tooltip:"每次刮開(kāi)大小的寬度半徑"},
scratchRadiuY:{type:cc.Float, default:10,tooltip:"每次刮開(kāi)大小的高度半徑"},
},
initMaskPoints(){
var rows = Math.floor(this.maskBg.height/(this.scratchRadiuY*2));
var cols = Math.floor(this.maskBg.width/(this.scratchRadiuY*2));
rows = Math.ceil(rows/2);
cols = Math.ceil(cols/2);
this.hidePoints = []; // 隱藏的數(shù)據(jù)點(diǎn)數(shù)組
for(let i=-rows; i<=rows; i++){
for(let j=-cols; j<=cols; j++){
this.hidePoints.push({"x":j, "y":i});
}
}
// 隱藏的數(shù)據(jù)點(diǎn)數(shù)量
this.hidePointsNum =?this.hidePoints.length;
console.log("this.hidePoints",this.hidePoints,"數(shù)量:",this.hidePointsNum);
},
onLoad () {
this.initMaskPoints(); // 初始化遮罩點(diǎn)

2. 刮出面積計(jì)算
// 刮開(kāi)操作
scratch(e){
// 【1】獲取觸摸點(diǎn)相對(duì)于當(dāng)前節(jié)點(diǎn)的錨點(diǎn)的坐標(biāo)
var pos =?this.getPos(e);
// 【2】根據(jù)觸摸點(diǎn)位置刮開(kāi)圖層,添加一個(gè)形狀
this.addShape(pos);
// 【3】刮開(kāi)面積計(jì)算
this.calcScratchArea(pos);
},
calcScratchArea(pos){
var x = Math.floor(pos.x/(this.scratchRadiuX));
var y = Math.floor(pos.y/(this.scratchRadiuY));
for(let i=0; i<this.hidePoints.length; i++){
if(x===this.hidePoints[i].x && y===this.hidePoints[i].y){
this.hidePoints.splice(i, 1);
break;
}
}
},
3. 回調(diào)處理
添加一個(gè)對(duì)話框,隱藏,當(dāng)刮開(kāi)面積達(dá)到一定比例后,說(shuō)明用戶(hù)已經(jīng)刮開(kāi)獎(jiǎng)項(xiàng)了,可以彈出對(duì)話框提示領(lǐng)取方式等。

if(this.hidePoints.length/this.hidePointsNum<0.6){
this.showDialog();
}
},
showDialog(){
var prompt =?this.resultDialog.getChildByName("bg").getChildByName("info");
prompt.getComponent(cc.Label).string =?this.prizeItemLabel.string;
this.resultDialog.active = true;
// 添加對(duì)話框動(dòng)態(tài)效果
this.resultDialog.opacity = 0;
this.resultDialog.runAction(cc.fadeTo(0.3, 255));
},
4. 思考:只刮開(kāi)周邊區(qū)域沒(méi)看到文字也彈出不合理
方法一:縮放maskBg即可(如果獎(jiǎng)項(xiàng)沒(méi)有顯示在中央則會(huì)不合理)

方法二:如下,添加覆蓋獎(jiǎng)項(xiàng)的節(jié)點(diǎn),調(diào)整位置、大小和透明度。



之后,運(yùn)行結(jié)果如下(即使周邊全部刮開(kāi),內(nèi)容沒(méi)顯示,也不會(huì)彈出兌獎(jiǎng)方式):


六、?小結(jié)
1、做游戲開(kāi)發(fā),首先要學(xué)會(huì)將任務(wù)拆解,其次要設(shè)計(jì)好游戲中的主要算法,考慮好采用的數(shù)據(jù)結(jié)構(gòu),之后,逐步實(shí)現(xiàn)步步為營(yíng)。
2、有問(wèn)題的朋友,可以聯(lián)系我們獲取本節(jié)課完整視頻。