cocos实现可拖动节点

直接先上代码吧

//MOUSE_MOVE  当鼠标在目标节点在目标节点区域中移动时,不论是否按下。
//MOUSE_DOWN  当鼠标按下时触发一次。
//MOUSE_UP  MOUSE_ENTER
//MOUSE_LEAVE  当鼠标移出目标节点区域时,不论是否按下。
//TOUCH_CANCEL  当手指在目标节点区域外离开屏幕时。
//TOUCH_END   当手指在目标节点区域内离开屏幕时。
//TOUCH_MOVE  当手指在屏幕上移动时。
//TOUCH_START  当手指触摸到屏幕时。
//cc.Node.EventType
//convertTouchToNodeSpaceAR  先将空间坐标转到其父节点的 这样实现在父节点区域内可移动

//矩阵位置坐标 x,y为矩阵左上角的坐标值
let Rect = function (x, y, height, width) {
    this.x = x;
    this.y = y;
    this.height = height;
    this.width = width;
}

/**
 * @brief 判断两个轴对齐的矩形是否重叠
 * @param rc1 第一个矩阵的位置
 * @param rc2 第二个矩阵的位置
 * @return 两个矩阵是否重叠(边沿重叠,也认为是重叠)
 */
Rect.prototype.isOverlap = function (rectB) {
    if (this.x + this.width > rectB.x &&
        rectB.x + rectB.width > this.x &&
        this.y + this.height > rectB.y &&
        rectB.y + rectB.height > this.y) {
        return true;
    }

    return false;
}

/**
 * @brief 判断两个轴对齐的矩形是否重叠
 * @param rc1 第一个矩阵的位置
 * @param rc2 第二个矩阵的位置
 * @return 两个矩阵是否重叠(边沿重叠,也认为是重叠)
 */
Rect.prototype.isOverlap1 = function (rectB) {
    let x1 = this.x + this.width
    let y1 = this.y - this.height;

    let x2 = rectB.x + rectB.width
    let y2 = rectB.y - rectB.height;

    let olbx = Math.max(this.x, rectB.x);
    let oltx = Math.min(x1, x2);;
    let olby = Math.max(this.y, rectB.y);
    let olty = Math.min(y1, y2);

    return (olbx < oltx) && (olby < olty);
}

Rect.prototype.isOverlap2 = function (rectB) {
    let limitX = [Math.max(this.x, rectB.x), Math.min(this.x + this.width, rectB.x + rectB.width)];
    let limitY = [Math.max(this.y - this.height, rectB.y - rectB.height), Math.min(this.y, rectB.y)];
    if ((limitX[0] < limitX[1]) && limitY[0] < limitY[1]) {
        return true;
    }
    return false;
}

cc.Class({
    extends: cc.Component,
    properties: {
        isVerticalMove: false,
        isHorizontalMove: true,
        moveNode: {
            type: cc.Node,
            default: null,
            tootip: "待控制移动的节点"
        },
        arreaInsulateNode: {
            type: cc.Node,
            default: null,
            tootip: "可在框起来的节点区域移动 anchorX anchorY必须为0.5"
        },
        arreaLimitNode: {
            type: cc.Node,
            default: [],
            tootip: "节点不得进入的节点区域"
        }


    },

    onLoad: function () {
        this.updateTimer = 0;
        this._registerHandler();
    },

    /**
     *
     * *外部预留控制接口
     * @param {*} startTouchCallback  
     * @param {*} touchEndCallback  外部注册触摸结束时回调  原生的需要两个callback都注册
     * @param {*} touchCancelCallback 外部注册触摸取消时回调
     */
    initCallback: function (startTouchCallback, touchEndCallback, touchCancelCallback) {
        this.__startTouchCallback = startTouchCallback;
        this.__touchEndCallback = touchEndCallback;
        this.__touchCancelCallback = touchCancelCallback;
    },

    _registerHandler: function () {
        if (CC_JSB) {
            this.moveNode.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this, true);
            this.moveNode.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this, true);
            this.moveNode.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this, true);
            this.moveNode.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this.true);
        } else {
            this.moveNode.on(cc.Node.EventType.MOUSE_LEAVE, this.onTouchEnd, this, true);
            this.moveNode.on(cc.Node.EventType.MOUSE_ENTER, this.onTouchStart, this,true);
            this.moveNode.on(cc.Node.EventType.MOUSE_MOVE, this.onTouchMove, this, true);
        }

    },

    /**
     *z外部主动调起注册事件的函数
     *
     */
    registerHandler: function () {
        this.unregisterHandler();
        this._registerHandler();
    },

    /**
     * 外部空接口,注销事件,可主动调起,但是需要保证在向反处主动调起注册事件的函数registerHandler
     */
    unregisterHandler: function () {
        if (CC_JSB) {
            this.moveNode.off(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
            this.moveNode.off(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
            this.moveNode.off(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
            this.moveNode.off(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
        } else {
            this.moveNode.off(cc.Node.EventType.MOUSE_MOVE, this.onTouchMove, this);
            this.moveNode.off(cc.Node.EventType.MOUSE_LEAVE, this.onTouchEnd, this);
            this.moveNode.off(cc.Node.EventType.MOUSE_ENTER, this.onTouchStart, this);
        }

    },

    /**
     *此处可以添加当玩家解除待移动节点时,节点变色,变粗等醒目操作
     *
     * @param {*} event
     * @returns
     */
    onTouchStart: function (event) {
        if(!cc.isValid(this.arreaInsulateNode)) return;
        let Vec = this.arreaInsulateNode.convertToWorldSpaceAR(event.getLocation());
        let VecMove = this.arreaInsulateNode.convertToWorldSpaceAR(this.moveNode.getPosition());

        console.log("Vec:",Vec);
        console.log("VecMove:",VecMove);
        this.__startTouchCallback && this.__startTouchCallback(event, this);
    },

    /**
     *
     *让节点回归常态就好啊
     * @param {*} event
     * @returns
     */
    onTouchEnd: function (event) {
        if(!cc.isValid(this.arreaInsulateNode)) return;
        this.__touchEndCallback && this.__touchEndCallback(event, this);
    },

    onTouchCancel: function (event) {
        if(!cc.isValid(this.arreaInsulateNode)) return;
        this.__touchCancelCallback && this.__touchCancelCallback(event, this);

    },

    /**
     *移动节点具体逻辑
     *
     * @param {*} event
     * @returns
     */
    onTouchMove: function (event) {
        if (!cc.isValid(this.arreaInsulateNode)) return;
        // console.log("", this.moveNode.zIndex);
        let heightM = this.moveNode.height;  // 待移动节点的长*宽
        let widthM = this.moveNode.width;
        let heightP = this.arreaInsulateNode.height;//假设可移动区域大小为 heightP*widthP  原点为左下角位置
        let widthP = this.arreaInsulateNode.width;

        let canvasNode = cc.director.getScene().getChildByName('Canvas');
        if (!cc.isValid(canvasNode)) return;
        let arreaLimit = canvasNode.convertToWorldSpaceAR(this.arreaInsulateNode.getPosition());
        let changeX = this.moveNode.x + event.getDeltaX();
        let chageXflag = false;
        if (this.isHorizontalMove) {
            let deltX = arreaLimit.x - widthP / 2;
            let changeLimitX = widthP - (1 - this.moveNode.anchorX) * widthM + deltX;
            let changeLimitXleft = this.moveNode.anchorX * widthM + deltX;

            let newVec2 = this.arreaInsulateNode.convertToWorldSpaceAR(cc.v2(changeX, 0));
            //changeX 属于区间(0,heightP)
            if (newVec2.x > changeLimitXleft && newVec2.x < changeLimitX) {

                chageXflag = true;
            }

        }

        let changeY = this.moveNode.y + event.getDeltaY();
        let changeYFlag = false;
        if (this.isVerticalMove) {
            let deltY = arreaLimit.y - heightP / 2;
            let changeLimitY = heightP - (1 - this.moveNode.anchorY) * heightM + deltY;
            let changeLimitYboom = this.moveNode.anchorY * heightM + deltY;

            let newVec2 = this.arreaInsulateNode.convertToWorldSpaceAR(cc.v2(0, changeY));
            if (newVec2.y >= changeLimitYboom && newVec2.y <= changeLimitY) {

                changeYFlag = true;
            }
        }

        // if (this.isRectLap(changeX, changeY)) {
        //     return;
        // }
        if (chageXflag&&this.isRectLap(changeX, this.moveNode.y)) {//只有需要计算的情况才去计算啦
            chageXflag = false;
        }
        if (changeYFlag&&this.isRectLap(this.moveNode.x, changeY)) {
            changeYFlag = false;
        }
        if (chageXflag) {
            this.moveNode.x = changeX;
        }

        if (changeYFlag) {
            this.moveNode.y = changeY;
        }
        // var a = this.moveNode.parent.convertTouchToNodeSpaceAR(event);
    },

    
    /**
     *判断改变后,移动节点与不可穿越节点是否有重叠
     *
     * @param {*} changeX
     * @param {*} changeY
     * @returns
     */
    isRectLap: function (changeX, changeY) {
        if (!cc.isValid(this.arreaInsulateNode)) return;
        if (this.arreaLimitNode.length <= 0) return;
        let newVec2 = this.arreaInsulateNode.convertToWorldSpaceAR(cc.v2(changeX, changeY));
        let Dx = newVec2.x - this.moveNode.anchorX * this.moveNode.width;
        let Dy = newVec2.y + (1 - this.moveNode.anchorY) * this.moveNode.height;
        let rectA = new Rect(Dx, Dy, this.moveNode.height, this.moveNode.width);
        // console.log("rectA Dx:", Dx, "   Dy", Dy, "   height:", this.moveNode.height, "   width:", this.moveNode.width)
        for (let index = 0; index < this.arreaLimitNode.length; index++) {
            let nodeA = this.arreaLimitNode[index];
            if (cc.isValid(nodeA)) {
                let newVecA = this.arreaInsulateNode.convertToWorldSpaceAR(nodeA.getPosition());
                // console.log("rectb Dxa:",newVecA)
                let Dxa = newVecA.x - nodeA.anchorX * nodeA.width;
                let Dya = newVecA.y + (1 - nodeA.anchorY) * nodeA.height;
                let rectB = new Rect(Dxa, Dya, nodeA.height, nodeA.width);
                // console.log("rectb Dxa:", Dxa, "   Dya", Dya, "   height:", nodeA.height, "   width:", nodeA.width);
                // console.log("index",index,"rectA.isOverlap(rectB)=",rectA.isOverlap(rectB));
                if (rectA.isOverlap2(rectB)) {
                    return true;
                }
            }

        }

        return false;
    },

    onDestroy: function () {
        this.unregisterHandler();
    },

    // //每帧调用一次。根据滚动位置动态更新item的坐标和显示(所以spawnCount可以比totalCount少很多)
    // update: function (dt) {
    //     this.updateTimer += dt;
    //     if (this.updateTimer < this.updateInterval) {
    //         return; // we don't need to do the math every frame
    //     }
    //     this.updateTimer = 0;



    // },
});

文中主要实现是注册 TOUCH_MOVE和MOUSE_MOVE的来监听节点触摸移动。同时对节点的可移动区域进行处理。至于对其他时间监听主要是为了形成完整的接口处理节点的显示等状态。代码还算是逻辑清晰。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值