Loading

在Cocos2d中拖动组件并吸附到节点

最近在学习制作小游戏,要实现一个拖动吸附效果,这里简单实现一下

代码实现

定义节点和函数功能

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;
}
最终效果

拖入目标区域

没拖到指定区域

修正

这里要把小车放到目标区域的正中心,需要对坐标进行修正。在cocos creator里,有节点坐标和世界坐标这两个概念

而在属性检查器里,我们所设置的position,也就是锚点的位置,是相对于父节点的,例如图中我把position设为0和0,就是相对于父节点,该组件定位在父节点的几何中心。

那么,哪些坐标值和最终放置的位置坐标有关联呢?

  • 小车初始坐标值
  • 小车组件的长宽
  • 目标区域的长宽

在没有修正之前,把targetPos的值设为this.sense.convertToWorldSpace(cc.v2(0, 0)),拖动后的效果如下图

并且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,此时小车会自动吸附到目标区域左下角,展现的效果如下

如果要把小车定位到目标区域的正中央,还需要考虑小车组件和目标区域的长宽,相应地,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 拖动

原文出处:cocos2d拖动组件吸附效果 | Jayden's Blog (jaydenchang.top)

posted @ 2022-02-19 15:33  JaydenChang  阅读(255)  评论(0编辑  收藏  举报