cocosCreator拖拽组件

import Target, { TOUCH_ID, Z_INDEX } from './Target';

const { ccclass, property } = cc._decorator;

@ccclass
export default class Drag extends cc.Component {
    private static touchId = TOUCH_ID.HIT;

    @property(cc.String)
    param = '';

    @property([cc.Node])
    protected targetArray: cc.Node[] = [];

    @property(cc.Boolean)
    isCopy = false;

    protected lastCheckTime = 0;

    protected leftMax = 0;

    protected rightMax = 0;

    protected topMax = 0;

    protected bottomMax = 0;

    protected readonly diffTime = 100;

    private lastCoverTarget: cc.Node | null = null;

    private initPos: cc.Vec2 = cc.Vec2.ZERO;

    protected override async onLoad() {
        await this.waitFitNode();
        this.init();
        this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    }

    protected waitFitNode(): Promise<void> {
        return new Promise((resolve) => {
            cc.director.once(
                cc.Director.EVENT_AFTER_DRAW,
                () => {
                    resolve();
                },
                this
            );
        });
    }

    private init() {
        this.node.zIndex = Z_INDEX.DRAG;
        this.initPos = this.node.getPosition();
        this.leftMax = -this.node.parent.width / 2 + this.node.width / 2;
        this.rightMax = this.node.parent.width / 2 - this.node.width / 2;
        this.topMax = this.node.parent.height / 2 - this.node.height / 2;
        this.bottomMax = -this.node.parent.height / 2 + this.node.height / 2;
    }

    protected onTouchStart(e: cc.Event.EventTouch) {
        if (Drag.touchId !== TOUCH_ID.HIT) {
            return;
        }
        Drag.touchId = e.getID();
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.onDragBegin();
    }

    protected onTouchMove(e: cc.Event.EventTouch) {
        if (Drag.touchId !== e.touch.getID()) {
            return;
        }
        const tempX = this.node.x + e.getDeltaX();
        const tempY = this.node.y + e.getDeltaY();
        if (
            tempX < this.leftMax ||
            tempX > this.rightMax ||
            tempY < this.bottomMax ||
            tempY > this.topMax
        ) {
            return;
        }
        this.node.x = tempX;
        this.node.y = tempY;

        const time = new Date().getTime();
        if (time - this.lastCheckTime < this.diffTime) {
            return;
        }
        this.onDragCheck();
    }

    protected onTouchEnd(e: cc.Event.EventTouch) {
        if (Drag.touchId !== e.touch.getID()) {
            return;
        }
        Drag.touchId = TOUCH_ID.HIT;
        this.node.off(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.onDragEnd();
    }

    protected copyOne() {
        const node = cc.instantiate(this.node);
        node.parent = this.node.parent;
        node.position = this.node.position;
        node.zIndex = Z_INDEX.DRAG;
        const drag = node.getComponent(Drag);
        drag.isCopy = true;
        drag.param = this.param;
        drag.targetArray = this.targetArray;
    }

    protected onDragBegin() {
        if (this.isCopy && this.node.x === this.initPos.x && this.node.y === this.initPos.y) {
            this.copyOne();
        }
        this.node.zIndex = Z_INDEX.DRAG_FLY;
        this.targetArray.forEach((target) => {
            const targetComponent = target.getComponent(Target);
            targetComponent.showTip();
            targetComponent.delDrag(this.node);
        });
    }

    protected onDragEnd() {
        this.node.zIndex = Z_INDEX.DRAG;
        this.targetArray.forEach((target) => {
            const targetComponent = target.getComponent(Target);
            targetComponent.hideTip();
            targetComponent.hideCover();
        });
        this.lastCoverTarget = null;
        const minCoverTarget = this.getMinCoverTarget();
        if (minCoverTarget) {
            this.onDragHit(minCoverTarget);
        } else {
            this.onDragMiss();
        }
    }

    protected onDragHit(minCoverTarget: cc.Node) {
        minCoverTarget.getComponent(Target).addDrag(this.node);
    }

    protected onDragMiss() {
        this.flyBack();
    }

    protected onDragCheck() {
        if (this.lastCoverTarget) {
            this.lastCoverTarget.getComponent(Target).hideCover();
        }
        const minCoverTarget = this.getMinCoverTarget();
        if (minCoverTarget) {
            this.lastCoverTarget = minCoverTarget;
            minCoverTarget.getComponent(Target).showCover();
        }
    }

    protected getMinCoverTarget(): cc.Node | null {
        let minCoverTarget: cc.Node | null = null;
        let minDistance: number | null = null;
        this.targetArray.forEach((target) => {
            const targetRect = target.getBoundingBox();
            const nodeRect = this.node.getBoundingBox();
            const isCover = targetRect.intersects(nodeRect);
            if (isCover) {
                const distance = cc.Vec2.distance(target.position, this.node.position);
                if (minDistance === null || distance < minDistance) {
                    minCoverTarget = target;
                    minDistance = distance;
                }
            }
        });
        return minCoverTarget;
    }

    flyBack() {
        Drag.touchId = TOUCH_ID.MISS;
        cc.Tween.stopAllByTarget(this.node);
        cc.tween(this.node)
            .to(0.5, { x: this.initPos.x, y: this.initPos.y })
            .call(() => {
                Drag.touchId = TOUCH_ID.HIT;
                if (this.isCopy) {
                    this.node.destroy();
                }
            })
            .start();
    }
}
import Drag from './Drag';
export const enum Z_INDEX {
    TARGET = 5,
    DRAG = 10,
    DRAG_FLY = 11,
}

export const enum TOUCH_ID {
    HIT = -1,
    MISS = 100,
}

const { ccclass, property } = cc._decorator;

@ccclass
export default class Target extends cc.Component {
    @property(cc.Node)
    tipNode: cc.Node = nn<cc.Node>();

    @property(cc.Node)
    coverNode: cc.Node = nn<cc.Node>();

    @property(cc.Node)
    pitNodes: cc.Node = nn<cc.Node>();

    drags: Array<cc.Node> = [];

    private list: Array<{ drag: cc.Node | null; pit: cc.Node }> = [];

    protected override onLoad(): void {
        this.initNode();
        this.hideTip();
        this.hideCover();
    }

    getDragsParam(): string[] {
        return this.drags.map((drag) => {
            return drag.getComponent(Drag).param;
        });
    }

    protected initNode() {
        this.node.zIndex = Z_INDEX.TARGET;
        if (!this.pitNodes) {
            this.pitNodes = new cc.Node();
            this.pitNodes.setPosition(0, 0);
            this.node.addChild(this.pitNodes);
        }
        if (this.pitNodes.children.length === 0) {
            const pit = new cc.Node();
            pit.setPosition(0, 0);
            this.pitNodes.addChild(pit);
        }
        this.pitNodes.children.forEach((pitNode) => {
            const param = {
                drag: null,
                pit: pitNode,
            };
            this.list.push(param);
        });
    }

    delDrag(drag: cc.Node) {
        this.drags = this.drags.filter((item) => {
            return item.uuid !== drag.uuid;
        });
        this.list.forEach((item) => {
            if (item.drag?.uuid === drag.uuid) {
                item.drag = null;
            }
        });
    }

    addDrag(drag: cc.Node) {
        let emptyPit = this.list.find((item) => {
            return !item.drag;
        });
        if (!emptyPit) {
            emptyPit = this.list[this.list.length - 1];
            emptyPit.drag?.getComponent(Drag)?.flyBack();
            emptyPit.drag = null;
        }
        this.drags.push(drag);
        emptyPit.drag = drag;
        const pitNode = emptyPit.pit;
        const dragNodePos = drag.parent.convertToNodeSpaceAR(
            pitNode.parent.convertToWorldSpaceAR(pitNode.getPosition())
        );
        drag.setPosition(dragNodePos);
    }

    showTip() {
        if (this.tipNode) {
            this.tipNode.active = true;
        }
    }

    hideTip() {
        if (this.tipNode) {
            this.tipNode.active = false;
        }
    }

    showCover() {
        if (this.coverNode) {
            this.coverNode.active = true;
        }
    }

    hideCover() {
        if (this.coverNode) {
            this.coverNode.active = false;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值