Cocos Creator拖拽物体去指定区域

573 阅读1分钟

我们要实现的效果是,按住并拖动一个物体,物体跟随手指(鼠标)移动,拖到指定位置放下,如果没有拖到指定位置 就放开则会返回到原始位置。

新建脚本DragItem.ts,挂到要拖动的预制体上

const { ccclass, property } = cc._decorator;
@ccclass
export default class DragItem extends cc.Component {
    @property({type:cc.Node, tooltip:"拖动去的指定区域节点列表"})
    targetOfDragList: cc.Node[] = [];


    @property({tooltip:"是否吸附到中点心"})
    isCenter:boolean = true;

    _onDragComp:Function=null;
    _oldPos = null; // 上一个位置
    _target:cc.Node = null;//所在的槽位;

    start() {
        this._oldPos = this.node.position;
    }

    onEnable() {
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
        this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this);
    }

    onDisable() {
        this.node.off(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
        this.node.off(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this);
    }

    public get target():cc.Node{
        return this._target;
    }

    public set onDragComp(value:Function){
        this._onDragComp = value;
    }

    _onTouchMove(touchEvent) {
        let location = touchEvent.getLocation();
        this.node.position = this.node.parent.convertToNodeSpaceAR(location); // 确定位置
    }

    _onTouchEnd(touchEvent) {
        if (this.targetOfDragList.length === 0) {
            return; // 没有目标位置
        }
        let inTarget = false;
        let offsetX:number = 0;
        let offsetY:number = 0;
        for (const targetNode of this.targetOfDragList) {
            let checkData:{isIn:boolean, offsetX?:number, offsetY?:number} = this._withinTarget(targetNode, touchEvent);
            if (checkData.isIn) {
                this._target = targetNode;
                inTarget = true;
                offsetX = checkData.offsetX;
                offsetY = checkData.offsetY;
                break;
            }
        }
        if (!inTarget) {
            this._target = null;
            this.node.position = this._oldPos; //还回去
        }else{
            if(this.isCenter){
                this.node.position = cc.v3(this.node.x-offsetX, this.node.y-offsetY);//吸咐到中心点上
            }
        }
        if(this._onDragComp){
            this._onDragComp(this.node, this._target);
        }
    }
    
    /**
     * 判断触摸事件是否在槽位里
     * @param targetNode 
     * @param touchEvent 
     * @returns isIn是否在槽位里,offsetX与槽位中心点的偏移量X,offsetY与槽位中心点的偏移量Y
     */
    _withinTarget(targetNode: cc.Node, touchEvent):{isIn:boolean, offsetX?:number, offsetY?:number} {
        let rect = targetNode.getBoundingBox();
        let location = touchEvent.getLocation();
        let point = targetNode.parent.convertToNodeSpaceAR(location);
        let checkData:any = {};
        let isIn:boolean = rect.contains(point);
        checkData.isIn = isIn;
        if(isIn){
            let centerX:number = rect.x + rect.width * 0.5;
            let centerY:number = rect.y + rect.height * 0.5;
            checkData.offsetX = point.x-centerX;
            checkData.offsetY = point.y-centerY;
        }
        return checkData;
    }
}

思路与之前的拖动类似。 在最后TOUCH_END的时候,判断自己是否在目标区域内。 如果不在则返回上一个坐标。 在场景中使用

import DragItem from "./DragItem";
const { ccclass, property } = cc._decorator;
@ccclass
export default class DragDemo extends cc.Component {
    @property(cc.Prefab) dragitem: cc.Prefab = null;
    @property([cc.Node]) dragTargets: cc.Node[] = [];
    start() {
        this.createItem();
    }
    createItem() {
        let d = cc.instantiate(this.dragitem);
        this.node.addChild(d);
        let dragTo = d.getComponent(DragItem);
        dragTo.targetOfDragList = this.dragTargets;// 设置目的地
    }
}