在Cocos2d中拖动组件并吸附到节点
最近在学习制作小游戏,要实现一个拖动吸附效果,这里简单实现一下
![](https://jaydenchang.gitee.io/images/images/0x002C-1.png)
代码实现
定义节点和函数功能
在properties
里新建一个对象,用来接收目标区域的节点
properties:{
sense: {
defaule: null,
type: cc.Node,
}
}
然后在小车节点里绑定这个脚本,将要测试的目标节点拖动到属性检查器的sense
这里用小车来表示要移动的组件,先在onload()
内定义小车组件,设置位置,以及定义三个触摸事件函数
onload() {
this.carPos = cc.v2(0, 0);
// 定义一个触摸移动控件
this.node.setPosition(this.carPos.x, this.carPos.y);
this.origin = this.node.convertToWorldSpace(cc.v2(0, 0));
// 获取小车移动前的坐标
// 对当前节点设置位置
this.node.on("touchstart", this.touchStart, this);
this.node.on("touchmove", this.touchMove, this);
this.node.on("touchend", this.touchEnd, this);
// 定义三个触摸事件函数
}
然后就是对三个触摸事件定义
touchStart(event) {
let touchPos = event.getLocation();
// 获取当前触摸位置
let posInNode = this.worldConvertLocalPoint(this.node, touchPos);
// 将当前触摸位置坐标转换为世界坐标
let target = this.node.getContentSize();
// 获得当前触摸组件的大小
let rect = cc.rect(0, 0, target.width, target.height);
// 对触摸对象组件创建一个矩形对象
if (rect.contains(posInNode)) {
// 判断触摸的位置是否在矩形内
this.touchTile = this.node;
// 获取被触摸的对象
}
console.log(posInNode.x + " " + posInNode.y);
// 测试,打印当前触摸位置
},
touchMove(event) {
if (this.touchTile) {
this.touchTile.setPosition(this.touchTile.x + event.getDelta().x ,
this.touchTile.y + event.getDelta().y);
// 根据小车组件移动距离重新给小车定位
}
},
touchEnd(event) {
let touchPos = this.touchTile.convertToWorldSpaceAR(cc.v2(0, 0));
let posInNode = this.worldConvertLocalPoint(this.sense1, touchPos);
let target = this.sense1.getContentSize();
// 定义坐标修正值
let correctValue = cc.v2(this.sense.width / 2 - this.origin.x - this.node.width / 2, this.sense.height / 2 - this.origin.y - this.node.height / 2);
// 获取要置放的区域的大小
let rect = cc.rect(0, 0, target.width, target.height);
if (rect.contains(posInNode)) {
// 判断小车是否落在目标区域的矩形内
console.log("---endPos");
// 设置触摸结束后小车的落位坐标
let targetPos = this.sense1.convertToWorldSpace(cc.v2(correctValue));
// 获取目标区域的中心坐标
let action = cc.moveTo(0.3, targetPos);
// 新建一个位移动作,动画持续时间为0.3s
this.touchTile.runAction(action);
// 小车组件执行动作
} else {
console.log("----go back");
let action = cc.moveTo(0.3, this.carPos);
// 组件回到小车初始位置
this.touchTile.runAction(action);
}
this.touchTile = null;
// 重置触摸组件为空
},
worldConvertLocalPoint(node, worldPoint) {
if (node) {
return node.convertToNodeSpace(worldPoint);
}
return null;
}
最终效果
拖入目标区域
![](https://jaydenchang.gitee.io/images/images/0x002C_drag_accept.gif)
没拖到指定区域
![](https://jaydenchang.gitee.io/images/images/0x002C_drag_refuse.gif)
修正
这里要把小车放到目标区域的正中心,需要对坐标进行修正。在cocos creator里,有节点坐标和世界坐标这两个概念
![](https://jaydenchang.gitee.io/images/images/0x002C_xOy.png)
而在属性检查器里,我们所设置的position
,也就是锚点的位置,是相对于父节点的,例如图中我把position
设为0和0,就是相对于父节点,该组件定位在父节点的几何中心。
![](https://jaydenchang.gitee.io/images/images/0x002C_xOy_detail.png)
那么,哪些坐标值和最终放置的位置坐标有关联呢?
- 小车初始坐标值
- 小车组件的长宽
- 目标区域的长宽
在没有修正之前,把targetPos
的值设为this.sense.convertToWorldSpace(cc.v2(0, 0))
,拖动后的效果如下图
![](https://jaydenchang.gitee.io/images/images/0x002C_without_correct.gif)
并且log打印目标位置的坐标,水平值离屏幕宽度一半还有一定的差距,这时我又打印了拖动结束后小车的坐标值,好家伙,我轻点小车没有拖动,控制台输出的坐标值为(0,0)
,而图中很明显,小车的位置不在世界坐标的原点上,即此时小车的坐标参照点为小车的初始位置
那问题来了,怎么修正?
只需在onload()
中定义一个变量储存小车的世界坐标值
this.origin = this.node.convertToWorldSpace(cc.v2(0, 0))
,然后在touchEnd()
中新定义一个向量值correctValue
,新建一个向量cc.v2(-this.origin.x, -this.origin.y)
,并返回给correctValue
,再将correctValue
转化为世界坐标赋给targetPos
,此时小车会自动吸附到目标区域左下角,展现的效果如下
![](https://jaydenchang.gitee.io/images/images/0x002C_correct.gif)
如果要把小车定位到目标区域的正中央,还需要考虑小车组件和目标区域的长宽,相应地,correctValue
应该设为cc.v2(this.sense.width / 2 - this.node.width / 2 - this.origin.x, this.sense.height / 2 - this.node.height / 2 - this.origin.y)
参考链接
(61条消息) CocosCreator的拖动小游戏主要逻辑_天才派大星 !的博客-CSDN博客_cocos creator 拖动