教你一招:四两拔千斤
在游戏中实现节点的可拖动是一个比较常见情况,比如:可以给小朋友做一个将果皮投进垃圾箱的教学练习、角色换装、物品包裹界面等。
在Cocos Creator中实现一个可拖动组件,只需对目标节点拖拽配置就能让节点任意移动,这对策划、美术人员来说是不是很有杀伤力!
1. 创建测试场景
在实现一个组件代码之前最好新建一个测试场景,组件代码在测试场景中通过了基本测试之后再放入正式环境使用。
而且在组件完成后,测试场景最好也不要丢弃了,等我们以后为组件升级或修改BUG时,可用于快速检验修改是否正确。
初始化工程
2. 实现可拖拽组件
我们来看下组件代码非常简单,就算你不会编程,根着注释相信也能明白个大概
const {ccclass, property} = cc._decorator;
@ccclass
export default class Dragable extends cc.Component {
onLoad() {
//注册TOUCH_MOVE事件
this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
}
onTouchMove(touchEvent: cc.Event.EventTouch) {
//获取触摸位移增量
let dt = touchEvent.getDelta();
//设置节点位置
this.node.x += dt.x;
this.node.y += dt.y;
}
}
代码主要是设置节点的触摸监听,在监听事件中修改节点的位置。将组件代码挂载到节点上,其它什么都不用做,运行起来看看效果:
3. 设置移动目标
有了这个组件,可以控制节点任意移动了,但是很多情况下,需要将节点移动到指定位置,比如将果皮投进垃圾箱,我们增强一下组件代码:
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() {
//保存原始父节点
this._oldPosition = this.node.position;
this._oldParent = this.node.parent;
//注册触摸开始
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);
}
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) {
//移动节点
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节点在父容器的包围盒,返回一个矩形对象
let rect = this.target.getBoundingBox();
//使用target容器转换触摸坐标
let location = touchEvent.getLocation();
let point = this.target.parent.convertToNodeSpaceAR(location);
if (rect.contains(point)) {
//在目标矩形内,修改节点坐标
point = this.target.convertToNodeSpaceAR(location);
this.node.position = cc.v3(point);
//修改父节点
this.node.parent = this.target;
return;
}
//不在矩形中,还原节点位置
this.node.position = this._oldPosition;
}
}
代码变复杂了,简单说明一下:
是增加了一个target节点属性,他是节点要移动到的目标 增加TOUCH_END事件,当手指抬起时,检查当前节点是否在目标节点之中 在目标范围,修改节点父子关系 不在目标范围,还原节点位置(提前缓存节点原始坐标)
组件有了锁定目标的功能,现在就可以实现将果皮投进垃圾箱了,当然也可以用来实现给角色换装、物品包裹之类的操作,请看下面的演示:
我给目标节点挂载了一个Layout组件,设置成GRID模式,实现自动网格排列,很像游戏中的物品包裹功能,这个组件真的是物超所值哦!
4. 小结
这次主要运用了节点的触摸事件监听,在触摸事件的touchEvent参数中获取当前触摸坐标点。
同时还需要对坐标点在不同节点坐标系下进行转换,需要理解的是拖动节点的本质是:修改节点在父节点上的位置,需要使用this.node.parent.convertToNodeSpaceAR进行转换。
同时还有使用了最简单的碰撞检测函数rect.contains,检查一个坐标点是否在矩形内。
好了这次的代码有点多非程序员同学要好好消化下,发挥你的想像,可以使用这个组件做出更有趣的东西。
Creator星球教程文章分类导航 天天996,试用期4个月,被公司劝退!开发者太糟心了! 卧槽,爆款了!!!小游戏开发者,公测当日收益过千! 我肝了三个月,这样学Creator,零基础都不怕! CreatorPrimer 30篇教程汇总 盘点Creator星球上的几大开源工具包