现在很多微信小游戏或宣传能赚钱的app游戏、以及合成塔防游戏,都用到了拖动合成升级的操作方式。所以我在也尝试做了一个这功能。
思路很简单:1、实现触摸道具并拖动时,道具跟随触摸点位置移动;2、在触摸事件中检查移动的道具与其他道具是矩形相交,即简单的碰撞检查功能;3、如果发生碰撞,则判断是否同级道具,如果是则调用方法删除或隐藏移动的道具和被碰撞的道具,生成新道具(高一级道具);
上面就是简单的实现方法,当然还有不同等级的位置交换或空位置的移动,最大等级判断和重现碰撞检测等问题需要一起解决,比较简单。
具体的实现步骤,用下面截图和代码简单说明:
首先要创建并初始化放置道具的位置节点并编号和列表保存,如图
然后,第1步:实现触摸道具并拖动时,道具跟随触摸点位置移动。
挂载到具道具prefab上的脚本,实现跟随移动的代码:
onLoad () {
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);
//初始时,武器不可见,即为不存在
this.node.active= false;
//根目录
this._rootNode= this.node.getParent().getParent().getParent();
this._rootScript= this._rootNode.getComponent("weapen_scene");
},
start () {
},
update (dt) {
},
_onTouchStart(event) {
MyLog.show("=============拖动开始=============");
// MyLog.show(event);
let pow=event.getLocation();//世界坐标
let local_pow=this.node.convertToNodeSpaceAR(pow);//世界坐标转还为节点坐标
//记录开始的位置
this._start_pos= cc.v2(this.node.x, this.node.y);
},
_onTouchMove(event) {
MyLog.show("=============拖动持续=============");
//MyLog.show(event);
let pow=event.getLocation() ;//世界坐标
//let local_pow=this.node.convertToNodeSpaceAR(pow);//世界坐标转还为节点坐标
//this.node.x= local_pow.x;
//this.node.y= local_pow.y;
//移动物体
let delta=event.getDelta();
this.node.x+=delta.x;
this.node.y+=delta.y;
this.node.opacity= 100;
//检查碰撞
this._checkHitOther();
//回收碰撞
this._recoveryWeapen();
},
_onTouchEnd(event) {
MyLog.show("=============拖动结束=============");
//MyLog.show(event);
let pow=event.getLocation();//世界坐标
let local_pow=this.node.convertToNodeSpaceAR(pow);//世界坐标转还为节点坐标
let bRetStartPos= true;
if (bRetStartPos) {
MyLog.show("物体归位");
this.node.x= this._start_pos.x;
this.node.y= this._start_pos.y;
MyLog.show("this._start_pos: "+ this._start_pos.x+","+this._start_pos.y);
this.node.opacity= 255;
}
},
_onTouchCancel(event) {
MyLog.show("=============拖动取消=============");
let pow=event.getLocation();//世界坐标
let local_pow=this.node.convertToNodeSpaceAR(pow);//世界坐标转还为节点坐标
},
2、在道具的触摸事件中检查移动的道具与其他道具是矩形相交,即简单的碰撞检查功能;
//碰撞检查
_checkHitOther() {
let baseNode= this.node.getParent().getParent();
//MyLog.show("baseNode.children.length= ",baseNode.children.length);
//MyLog.show("baseNode.children: ",baseNode.children);
for (let i = 0, ed= baseNode.children.length; i < ed; i++) {
let wpNode = baseNode.children[i];
//MyLog.show("wpNode.name= ", wpNode.name);
//MyLog.show("this.name= ", this.node.parent.name);
let mv_wp_name= this.node.parent.name;
if (wpNode.name===mv_wp_name)
continue;
//MyLog.show("wpNode: ",wpNode);
let wp= wpNode.getChildByName("wp"); //被碰的
if (!wp || wp.active===false) {
//不可见的武器,无效的位置
MyLog.show("忽略不可见的武器,无效的位置");
continue;
}
//操作状态检查
MyLog.show("操作状态检查:_comb_state=", this.node._comb_state);
if (this.node._comb_state===1) { //|| wpNode._comb_state===1) {
MyLog.show("合成操作中,不再检测碰撞");
break;
}
let wp_box= wp.getBoundingBoxToWorld();
let mv_box= this.node.getBoundingBoxToWorld();
//MyLog.show("wp_box:",wp_box);
//MyLog.show("mv_box:",mv_box);
//let bHit= gameTools.RectIntersectRect(wp_box, mv_box); //这里检测区域太大了,要缩小避免误操作。
let bHit= wp_box.contains(mv_box.center); //用中心点与矩形包含判断
if (bHit) {
MyLog.show("======发生碰撞=====");
MyLog.show("wpNode.name= ", wpNode.name);
MyLog.show("this.name= ", this.node.parent.name);
//wp.active= false;
//检查是否满足合成条件
let hit_wp_lv= wp.getChildByName("lvLabel").getComponent(cc.Label).string; //被碰撞的
let mv_wp_lv= this.node.getChildByName("lvLabel").getComponent(cc.Label).string; //移动的
if (hit_wp_lv===mv_wp_lv) {
MyLog.show("同等级武器,可合成");
cc.tween(wpNode)
.to(0.1, {scale:1.5})
.to(0.1, {scale:1})
.start();
//合成状态锁定
this.node._comb_state= 1;
//wpNode._comb_state= 1;
let wp_index= gameTools.findNumFromString(wpNode.name);
let mv_wp_index= gameTools.findNumFromString(mv_wp_name);
//合成操作
this._combWeapen(mv_wp_index, wp_index);
return;
}
cc.tween(wpNode)
.to(0.1, {scale:1.3})
.to(0.1, {scale:1})
.start();
//检查是否满足换位条件
if (hit_wp_lv!==mv_wp_lv) {
//可以交换
MyLog.show("可以互换");
//break;
}
}else{
//MyLog.show("------未发生碰撞");
//wp.active= true;
}
}
},
3、如果发生碰撞,则判断是否同级道具,如果是则调用方法删除或隐藏移动的道具和被碰撞的道具,生成新道具(高一级道具);
//合成操作
_combWeapen(wp_index, mv_wp_index) {
MyLog.show("合成操作");
if (wp_index>=0 && mv_wp_index>=0) {
let ret= this._rootScript._combWeapen(wp_index-1, mv_wp_index-1 );
if (ret) {
MyLog.show("合成 操作成功");
} else {
MyLog.show("合成 失败或取消");
}
}else{
MyLog.show("合成失败:参数错误,");
MyLog.show("wp_index=,", wp_index);
MyLog.show("mv_wp_index=,", mv_wp_index);
}
//合成状态解锁
this.node._comb_state= 0;
//wpNode._comb_state= 0;
},
主场景中脚本方法(合成实现)
//合成武器
_combWeapen(wpNode_index, nx_wpNode_index) {
MyLog.show("合成武器:wpNode_index=", wpNode_index);
MyLog.show("nx_wpNode_index=", nx_wpNode_index);
//_updateBaseWp(op_type , wpNode_index, wpData_index, nx_wpNode_index, nx_wpData_index)
if (wpNode_index>=0 && nx_wpNode_index>=0) {
let wpData_index= -1;
let nx_wpData_index= -1;
MyLog.show("合成前数据列表, _wpList:", this._wpList);
for(let i=0, ed=this._wpList.length; i=0 && wpData_index>=0)
break;
}
MyLog.show("wpData_index=", wpData_index);
if (wpData_index=this._wpLv_max-1) {
MyLog.show("非法参数,或最大等级,不可再合成");
return false;
}
//更新武器节点
let new_wpData_index= wpData_index + 1; //合成后数据编号
MyLog.show("合成后数据编号 new_wpData_index=", new_wpData_index);
wpNode_index= this._updateBaseWp("comb", wpNode_index, null, nx_wpNode_index, new_wpData_index);
if (wpNode_index<0) {
MyLog.show("合成武器失败:", wpNode_index);
return false;
}
let bSuccess= false;
//从列表中,删除武器
bSuccess= this._del_wpNodeData(wpNode_index);
if (bSuccess) {
MyLog.show("删除数据失败:wpNode_index=",wpNode_index);
}
bSuccess= this._del_wpNodeData(nx_wpNode_index);
if (bSuccess) {
MyLog.show("删除数据失败:nx_wpNode_index=",nx_wpNode_index);
}
//添加合成等级武器数据
MyLog.show("合成的武器: 位置,nx_wpNode_index="+ nx_wpNode_index+", 数据,new_wpData_index=", new_wpData_index);
this._add_wpNodeData(nx_wpNode_index, new_wpData_index);
MyLog.show("合成武器成功: LV=", new_wpData_index);
} else {
MyLog.show("错误的武器节点编号:", wpNode_index);
return false;
}
return true;
},
最后还有回收的实现
(道具脚本)
//回收操作
_recoveryWeapen() {
let btn_decompose= this._rootNode.getChildByName("btn_decompose");
let rv_Box= btn_decompose.getBoundingBoxToWorld();
let mv_box= this.node.getBoundingBoxToWorld();
//let bHit= gameTools.RectIntersectRect(rv_Box, mv_box); //这里检测区域太大了,要缩小避免误操作。
let bHit= rv_Box.contains(mv_box.center); //用中心点与矩形包含判断
//this._recovery_state= 0;
if (bHit && !btn_decompose._recovery_state) {
btn_decompose._recovery_state= 1; //回收状态锁定
MyLog.show("======回收,发生碰撞=====");
cc.tween(btn_decompose)
.to(0.5, {scale:1.5})
.to(0.5, {scale:1})
.start();
let wpName= this.node.parent.name;
let wp_index= gameTools.findNumFromString(wpName);
MyLog.show("wp_index", wp_index);
let ret= this._rootScript._confrimRecoveryWp(wp_index-1);
if (ret) {
MyLog.show("回收操作成功");
} else {
MyLog.show("回收失败或取消");
}
// this._recovery_state= 0;
}else{
// MyLog.show("------回收,未发生碰撞");
}
},
主场景脚本部分
//回收武器
_recoveryWeapen(wpNode_index) {
if (wpNode_index>=0) {
let wpNode= this._wpNodeList[wpNode_index];
if (wpNode) {
//隐藏武器节点
wpNode_index= this._updateBaseWp("del", wpNode_index);
if (wpNode_index<0) {
MyLog.show("删除武器失败:", wpNode_index);
return false;
}
let bSuccess= false;
let wpData_index= -1;
//从列表中,删除武器
for(let i=0, ed=this._wpList.length; i=0) {
let wpData= this.json_weapendata[wpData_index];
//MyLog.show("回收武器,返还蛋壳:",wpData);
let rec_price= - Math.floor(wpData.combList.dkCnt/2);
MyLog.show("回收武器,返还半价的蛋壳:", rec_price);
this.update_dk_show(rec_price);
}
} else {
MyLog.show("无效的武器节点:", wpNode);
return false;
}
} else {
MyLog.show("错误的武器节点编号:", wpNode_index);
return false;
}
return true;
},
交换或移动位置等,大家可以按这思想去实现完善。
上面的拖动合成功能,已经应用到这个小游戏中,但没有做引导。大家可以体验一下:
欢迎做小游戏的朋友一起交流,我的QQ:31911030,添加时备注一下:“小游戏”。
作者:honesthgx