教你一招:四兩拔千斤
在游戲中實(shí)現(xiàn)節(jié)點(diǎn)的可拖動(dòng)是一個(gè)比較常見情況,比如:可以給小朋友做一個(gè)將果皮投進(jìn)垃圾箱的教學(xué)練習(xí)、角色換裝、物品包裹界面等。
在Cocos Creator中實(shí)現(xiàn)一個(gè)可拖動(dòng)組件,只需對(duì)目標(biāo)節(jié)點(diǎn)拖拽配置就能讓節(jié)點(diǎn)任意移動(dòng),這對(duì)策劃、美術(shù)人員來(lái)說(shuō)是不是很有殺傷力!
1. 創(chuàng)建測(cè)試場(chǎng)景
在實(shí)現(xiàn)一個(gè)組件代碼之前最好新建一個(gè)測(cè)試場(chǎng)景,組件代碼在測(cè)試場(chǎng)景中通過(guò)了基本測(cè)試之后再放入正式環(huán)境使用。
而且在組件完成后,測(cè)試場(chǎng)景最好也不要丟棄了,等我們以后為組件升級(jí)或修改BUG時(shí),可用于快速檢驗(yàn)修改是否正確。
初始化工程
2. 實(shí)現(xiàn)可拖拽組件
我們來(lái)看下組件代碼非常簡(jiǎn)單,就算你不會(huì)編程,根著注釋相信也能明白個(gè)大概
const?{ccclass,?property}?=?cc._decorator;
@ccclass
export?default?class?Dragable?extends?cc.Component?{
????onLoad()?{
????????//注冊(cè)TOUCH_MOVE事件
????????this.node.on(cc.Node.EventType.TOUCH_MOVE,?this.onTouchMove,?this);
????}
????onTouchMove(touchEvent:?cc.Event.EventTouch)?{
????????//獲取觸摸位移增量
????????let?dt?=?touchEvent.getDelta();
????????//設(shè)置節(jié)點(diǎn)位置
????????this.node.x?+=?dt.x;
????????this.node.y?+=?dt.y;
????}
}代碼主要是設(shè)置節(jié)點(diǎn)的觸摸監(jiān)聽,在監(jiān)聽事件中修改節(jié)點(diǎn)的位置。將組件代碼掛載到節(jié)點(diǎn)上,其它什么都不用做,運(yùn)行起來(lái)看看效果:
3. 設(shè)置移動(dòng)目標(biāo)
有了這個(gè)組件,可以控制節(jié)點(diǎn)任意移動(dòng)了,但是很多情況下,需要將節(jié)點(diǎn)移動(dòng)到指定位置,比如將果皮投進(jìn)垃圾箱,我們?cè)鰪?qiáng)一下組件代碼:
const?{ccclass,?property}?=?cc._decorator;
@ccclass
export?default?class?DragToTarget?extends?cc.Component?{
????@property(cc.Node)
????target:?cc.Node?=?null;
????_oldPosition:?cc.Vec3?=?null;
????_oldParent:?cc.Node?=?null;
????onLoad()?{
????????//保存原始父節(jié)點(diǎn)
????????this._oldPosition?=?this.node.position;
????????this._oldParent?=?this.node.parent;
????????
????????//注冊(cè)觸摸開始
????????this.node.on(cc.Node.EventType.TOUCH_START,?this.onTouchStart,?this);
????????//注冊(cè)觸摸移動(dòng)
????????this.node.on(cc.Node.EventType.TOUCH_MOVE,?this.onTouchMove,?this);
????????//注冊(cè)觸摸結(jié)束
????????this.node.on(cc.Node.EventType.TOUCH_END,?this.onTouchEnd,?this);
????}
????private?onTouchStart(touchEvent:?cc.Event.EventTouch)?{
????????let?location?=?touchEvent.getLocation();
????????let?offset?=?this.node.convertToNodeSpaceAR(location);
????????if?(this.node.parent?===?this._oldParent)?{
????????????return;
????????}
????????//保存原始位置
????????this.node.parent?=?this._oldParent;
????????let?point?=?this._oldParent.convertToNodeSpaceAR(location);
????????this.node.position?=?cc.v3(point.x?-?offset.x,?point.y?-?offset.y,?0);
????}
????private?onTouchMove(touchEvent:?cc.Event.EventTouch)?{
????????//移動(dòng)節(jié)點(diǎn)
????????let?dt?=?touchEvent.getDelta();
????????this.node.x?+=?dt.x;
????????this.node.y?+=?dt.y;
????}
????private?onTouchEnd(touchEvent:?cc.Event.EventTouch)?{
????????if?(!this.target)?{
????????????return;
????????}
????????//獲取target節(jié)點(diǎn)在父容器的包圍盒,返回一個(gè)矩形對(duì)象
????????let?rect?=?this.target.getBoundingBox();
????????//使用target容器轉(zhuǎn)換觸摸坐標(biāo)
????????let?location?=?touchEvent.getLocation();
????????let?point?=?this.target.parent.convertToNodeSpaceAR(location);
????????if?(rect.contains(point))?{
????????????//在目標(biāo)矩形內(nèi),修改節(jié)點(diǎn)坐標(biāo)??
????????????point?=?this.target.convertToNodeSpaceAR(location);?
????????????this.node.position?=?cc.v3(point);
????????????//修改父節(jié)點(diǎn)
????????????this.node.parent?=?this.target;
????????????return;
????????}
????????//不在矩形中,還原節(jié)點(diǎn)位置????
????????this.node.position?=?this._oldPosition;
????}
}代碼變復(fù)雜了,簡(jiǎn)單說(shuō)明一下:
是增加了一個(gè)target節(jié)點(diǎn)屬性,他是節(jié)點(diǎn)要移動(dòng)到的目標(biāo) 增加TOUCH_END事件,當(dāng)手指抬起時(shí),檢查當(dāng)前節(jié)點(diǎn)是否在目標(biāo)節(jié)點(diǎn)之中 在目標(biāo)范圍,修改節(jié)點(diǎn)父子關(guān)系 不在目標(biāo)范圍,還原節(jié)點(diǎn)位置(提前緩存節(jié)點(diǎn)原始坐標(biāo))
組件有了鎖定目標(biāo)的功能,現(xiàn)在就可以實(shí)現(xiàn)將果皮投進(jìn)垃圾箱了,當(dāng)然也可以用來(lái)實(shí)現(xiàn)給角色換裝、物品包裹之類的操作,請(qǐng)看下面的演示:
我給目標(biāo)節(jié)點(diǎn)掛載了一個(gè)Layout組件,設(shè)置成GRID模式,實(shí)現(xiàn)自動(dòng)網(wǎng)格排列,很像游戲中的物品包裹功能,這個(gè)組件真的是物超所值哦!
4. 小結(jié)
這次主要運(yùn)用了節(jié)點(diǎn)的觸摸事件監(jiān)聽,在觸摸事件的touchEvent參數(shù)中獲取當(dāng)前觸摸坐標(biāo)點(diǎn)。
同時(shí)還需要對(duì)坐標(biāo)點(diǎn)在不同節(jié)點(diǎn)坐標(biāo)系下進(jìn)行轉(zhuǎn)換,需要理解的是拖動(dòng)節(jié)點(diǎn)的本質(zhì)是:修改節(jié)點(diǎn)在父節(jié)點(diǎn)上的位置,需要使用this.node.parent.convertToNodeSpaceAR進(jìn)行轉(zhuǎn)換。
同時(shí)還有使用了最簡(jiǎn)單的碰撞檢測(cè)函數(shù)rect.contains,檢查一個(gè)坐標(biāo)點(diǎn)是否在矩形內(nèi)。
好了這次的代碼有點(diǎn)多非程序員同學(xué)要好好消化下,發(fā)揮你的想像,可以使用這個(gè)組件做出更有趣的東西。

Creator星球教程文章分類導(dǎo)航 天天996,試用期4個(gè)月,被公司勸退!開發(fā)者太糟心了! 臥槽,爆款了!?。⌒∮螒蜷_發(fā)者,公測(cè)當(dāng)日收益過(guò)千! 我肝了三個(gè)月,這樣學(xué)Creator,零基礎(chǔ)都不怕! CreatorPrimer 30篇教程匯總 盤點(diǎn)Creator星球上的幾大開源工具包
