JS实现翻书效果,有大神能提供点思路嘛?有偿也行。

类似下面这样的

2赞

搓了十年了,还在搓:joy:

1赞

那没办法啊,有市场就有需求。

找一下吧,论坛里有

直接搜索搓牌,好几个帖子

23f7179c5687123766f62259ca8a15a1.rar (2.1 MB)

实在是找不到了,,用mask写了一个,,暂时先用着, 效果也还凑合着,,效果在附件里面

2赞

大佬牛逼,求组件代码

视频效果
代码如下:
// Learn cc.Class:
// - https://docs.cocos.com/creator/manual/en/scripting/class.html
// Learn Attribute:
// - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
// - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

var rubType = 0, rubPoints = {}, openedCallback = null, nowPoker = null;

cc.Class({
extends: cc.Component,

properties: {
    imgFlower1: cc.Sprite,
    imgFlower2: cc.Sprite,
    imgNumber1: cc.Sprite,
    imgNumber2: cc.Sprite,
    imgPoker: cc.Sprite,
    maskBackground: cc.Mask,
    maskPoker: cc.Mask,
    maskShadow: cc.Mask,
    nodeShadow: cc.Node
},

start () {
    this.initVars();

    this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
    this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
    this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
},

onTouchStart(event) {
    if (rubType == 0) {
        var point = this.maskBackground.node.convertToNodeSpaceAR(event.touch.getLocation()),
            halfWidth = this.maskPoker.node.width / 2,
            halfHeight = this.maskPoker.node.height / 2;

        rubPoints.a = {
            x: point.x,
            y: point.y
        };

        if (rubPoints.a.x >= -halfWidth - 5 && rubPoints.a.x <= halfWidth + 5 && rubPoints.a.y >= -halfHeight - 5 && rubPoints.a.y <= halfHeight + 5) {
            rubType = 1;

            this.nodeShadow.active = true;

            rubPoints.d = { x: rubPoints.a.x > 0 ? halfWidth : -halfWidth, y: rubPoints.a.y > 0 ? halfHeight : -halfHeight };
        }
    }
},

onTouchMove(event) {
    if (rubType == 1) {
        var point = this.maskBackground.node.convertToNodeSpaceAR(event.touch.getLocation());

        rubPoints.a = {
            x: point.x,
            y: point.y
        };

        this.rubPoker();
    }
},

onTouchEnd(event) {
    if (rubType == 1) {
        if (this.isNeedOpenRub())
            this.openRub();
        else
            this.closeRub();
    }
},

updateRubBackground() {
    var graphics = this.maskBackground._graphics;

    graphics.clear();
    graphics.moveTo(rubPoints.b.x, rubPoints.b.y);
    graphics.lineTo(rubPoints.d.x, rubPoints.d.y);
    graphics.lineTo(rubPoints.c.x, rubPoints.c.y);
    graphics.close();
    graphics.fill();
},

updateRubPoker(angle) {
    var graphics = this.maskPoker._graphics,
        newB = this.convertingPoint(rubPoints.b),
        newC = this.convertingPoint(rubPoints.c),
        newD = this.convertingPoint(rubPoints.d),
        rotatePoint = this.calculateRotatePoint(this.convertingPoint(rubPoints.d), angle);

    this.maskPoker.node.angle = -angle / Math.PI * 180;
    this.maskPoker.node.setPosition(rubPoints.a.x - rotatePoint.x, rubPoints.a.y - rotatePoint.y);

    graphics.clear();
    graphics.moveTo(newB.x, newB.y);
    graphics.lineTo(newD.x, newD.y);
    graphics.lineTo(newC.x, newC.y);
    graphics.close();
    graphics.fill();
},

updateRubShadow(angle) {
    var graphics = this.maskShadow._graphics,
        halfWidth = this.maskPoker.node.width / 2,
        halfHeight = this.maskPoker.node.height / 2,
        a = this.calculateRotatePoint({ x: -halfWidth, y: halfHeight }, angle),
        b = this.calculateRotatePoint({ x: -halfWidth, y: -halfHeight }, angle),
        c = this.calculateRotatePoint({ x: halfWidth, y: -halfHeight }, angle),
        d = this.calculateRotatePoint({ x: halfWidth, y: halfHeight }, angle),
        position = rubPoints.b,
        anchorX = (rubPoints.d.x > 0 && rubPoints.d.y > 0) || (rubPoints.d.x < 0 && rubPoints.d.y < 0) ? 1 : 0;

    if (position.x < -halfWidth || position.x > halfWidth || position.y < -halfHeight || position.y > halfHeight) {
        position = rubPoints.c;
        anchorX = (rubPoints.d.x > 0 && rubPoints.d.y > 0) || (rubPoints.d.x < 0 && rubPoints.d.y < 0) ? 0 : 1;
    }

    this.nodeShadow.angle = (180 + this.maskPoker.node.angle) / 2;
    this.nodeShadow.setPosition(position);
    this.nodeShadow.anchorX = anchorX;

    if (rubPoints.d.y > 0)
        this.nodeShadow.angle += 180;

    graphics.clear();
    graphics.moveTo(a.x + this.maskPoker.node.x, a.y + this.maskPoker.node.y);
    graphics.lineTo(b.x + this.maskPoker.node.x, b.y + this.maskPoker.node.y);
    graphics.lineTo(c.x + this.maskPoker.node.x, c.y + this.maskPoker.node.y);
    graphics.lineTo(d.x + this.maskPoker.node.x, d.y + this.maskPoker.node.y);
    graphics.close();
    graphics.fill();
},

getAngle(point1, point2) {
    var dot = point1.x * point2.x + point1.y * point2.y,
        det = point1.x * point2.y - point1.y * point2.x;

    return Math.atan2(det, dot);
},

convertingPoint(point) {
    return {
        x: -point.x,
        y: point.y
    };
},

calculateRotatePoint(point, degree) {
    return {
        x: point.x * Math.cos(degree) + point.y * Math.sin(degree),
        y: -point.x * Math.sin(degree) + point.y * Math.cos(degree)
    };
},

rubPoker() {
    if (rubPoints.d.y > 0 && rubPoints.a.y >= rubPoints.d.y)
        rubPoints.a.y = rubPoints.d.y - 0.2;
    else if (rubPoints.d.y < 0 && rubPoints.a.y <= rubPoints.d.y)
        rubPoints.a.y = rubPoints.d.y + 0.2;

    if (rubPoints.d.x > 0 && rubPoints.a.x >= rubPoints.d.x)
        rubPoints.a.x = rubPoints.d.x - 0.2;
    else if (rubPoints.d.x < 0 && rubPoints.a.x <= rubPoints.d.x)
        rubPoints.a.x = rubPoints.d.x + 0.2;

    this.initRubPoints();

    var angle = this.getAngle({
        x: rubPoints.a.x - rubPoints.b.x,
        y: rubPoints.a.y - rubPoints.b.y
    }, {
        x: rubPoints.d.x - rubPoints.b.x,
        y: rubPoints.d.y - rubPoints.b.y
    }) + Math.PI;

    this.updateRubBackground();
    this.updateRubPoker(angle);
    this.updateRubShadow(angle);
},

openRub() {
    if (rubType == 1 && rubPoints.a && rubPoints.d) {
        var a = { x: -rubPoints.d.x, y: rubPoints.d.y },
            b = { x: rubPoints.d.x, y: -rubPoints.d.y },
            self = this,
            toA = this.getPointLength(rubPoints.a, a) > this.getPointLength(rubPoints.a, b) ? b : a;

        rubType = 2;

        cc.tween(rubPoints.a).to(0.08, toA, {
            progress: function (start, end, current, t) {
                self.rubPoker();

                return start + (end - start) * t;
            }
        }).call(function () {
            self.rubPoker();

            var currentPoint = toA.x == rubPoints.d.x ? { x: toA.x, y: 0 } : { x: 0, y: toA.y },
                endPoint = toA.x == rubPoints.d.x ? { y: rubPoints.d.y } : { x: rubPoints.d.x },
                rubPoker = function () {
                    var points = [],
                        graphics = self.maskPoker._graphics;

                    if (toA.x == rubPoints.d.x) {
                        self.nodeShadow.y = currentPoint.y;

                        points.push({ x: currentPoint.x, y: -currentPoint.y });
                        points.push({ x: -currentPoint.x, y: -currentPoint.y });
                        points.push({ x: -currentPoint.x, y: rubPoints.d.y });
                        points.push({ x: currentPoint.x, y: rubPoints.d.y });

                        if (Math.abs(currentPoint.y - rubPoints.d.y) < 10)
                            self.nodeShadow.active = false;
                    } else {
                        self.nodeShadow.x = currentPoint.x;

                        points.push({ x: currentPoint.x, y: currentPoint.y });
                        points.push({ x: currentPoint.x, y: -currentPoint.y });
                        points.push({ x: -rubPoints.d.x, y: -currentPoint.y });
                        points.push({ x: -rubPoints.d.x, y: currentPoint.y });

                        if (Math.abs(currentPoint.x - rubPoints.d.x) < 10)
                            self.nodeShadow.active = false;
                    }

                    graphics.clear();
                    graphics.moveTo(points[0].x, points[0].y);
                    for (var i = 1; i < points.length; i++) {
                        graphics.lineTo(points[i].x, points[i].y);
                    }
                    graphics.close();
                    graphics.fill();
                };

            cc.tween(currentPoint).to(0.08, endPoint, {
                progress: function (start, end, current, t) {
                    rubPoker();

                    return start + (end - start) * t;
                }
            }).call(function () {
                rubPoker();

                if (nowPoker.number < 14) {
                    cc.tween(self.imgFlower1.node).set({ opacity: 0, active: true }).to(0.2, { opacity: 255 }).start();
                    cc.tween(self.imgFlower2.node).set({ opacity: 0, active: true }).to(0.2, { opacity: 255 }).start();
                    cc.tween(self.imgNumber1.node).set({ opacity: 0, active: true }).to(0.2, { opacity: 255 }).start();
                    cc.tween(self.imgNumber2.node).set({ opacity: 0, active: true }).to(0.2, { opacity: 255 }).call(function () {
                        if (openedCallback)
                            openedCallback();
                    }).start();
                }

                rubType = 3;
            }).start();
        }).start();
    } else {
        this.closeRub();
    }
},

getPointLength(pointA, pointB) {
    return Math.sqrt(Math.pow(pointA.x - pointB.x, 2) + Math.pow(pointA.y - pointB.y, 2));
},

closeRub() {
    if (rubType == 1 && rubPoints.a && rubPoints.d) {
        var self = this;

        rubType = 2;

        cc.tween(rubPoints.a).to(0.08, rubPoints.d, {
            progress: function (start, end, current, t) {
                self.rubPoker();

                return start + (end - start) * t;
            }
        }).call(function () {
            rubType = 0;

            self.closeRub();
        }).start();
    } else {
        rubType = 0;

        this.maskBackground._graphics.clear();
        this.maskPoker._graphics.clear();
        this.maskShadow._graphics.clear();
    }
},

initRub(poker, callback) {
    this.initVars();

    openedCallback = callback;
    nowPoker = poker;

    var pokerName,
        self = this;

    if (poker.number > 13) {
        pokerName = poker.number == 14 ? "xiaowang" : "dawang";
    } else {
        pokerName = ["fangkuai", "meihua", "hongtao", "heitao"][poker.color] + poker.number;

        cc.loader.loadRes("common_tt2/poker", cc.SpriteAtlas, function (error, spriteAtlas) {
            if (!error && spriteAtlas) {
                self.imgFlower1.spriteFrame = self.imgFlower2.spriteFrame = spriteAtlas.getSpriteFrame("flower_" + poker.color);

                self.imgNumber1.spriteFrame = self.imgNumber2.spriteFrame = spriteAtlas.getSpriteFrame((poker.color == 0 || poker.color == 2 ? "hong_" : "hei_") + poker.number);
            }
        });
    }

    cc.loader.loadRes("common_tt2/singlePokers/" + pokerName, cc.SpriteFrame, function (error, spriteFrame) {
        if (!error && spriteFrame)
            self.imgPoker.spriteFrame = spriteFrame;
    });
},

initVars() {
    rubType = 0;
    rubPoints = {};

    this.nodeShadow.setPosition(-10000, -10000);
    this.maskBackground._graphics.clear();
    this.maskPoker._graphics.clear();
    this.maskShadow._graphics.clear();

    this.imgFlower1.node.active = this.imgFlower2.node.active = this.imgNumber1.node.active = this.imgNumber2.node.active = this.nodeShadow.active = false;
},

initRubPoints() {
    var temp = {
        x: (rubPoints.a.x + rubPoints.d.x) / 2,
        y: (rubPoints.a.y + rubPoints.d.y) / 2
    };

    rubPoints.b = {
        x: temp.x - (rubPoints.d.y - temp.y) * (rubPoints.d.y - temp.y) / (rubPoints.d.x - temp.x),
        y: rubPoints.d.y
    };

    rubPoints.c = {
        x: rubPoints.d.x,
        y: temp.y - (rubPoints.d.x - temp.x) * (rubPoints.d.x - temp.x) / (rubPoints.d.y - temp.y)
    };
},

isNeedOpenRub() {
    return rubPoints.a && rubPoints.d && (Math.abs(rubPoints.a.x - rubPoints.d.x) > this.maskPoker.node.width * 0.66666 || Math.abs(rubPoints.a.y - rubPoints.d.y) >= this.maskPoker.node.height * 0.8 || (Math.abs(rubPoints.a.x - rubPoints.d.x) <= 10 && Math.abs(rubPoints.a.y - rubPoints.d.y) >= this.maskPoker.node.height * 0.45) || (Math.abs(rubPoints.a.y - rubPoints.d.y) <= 10 && Math.abs(rubPoints.a.x - rubPoints.d.x) >= this.maskPoker.node.width * 0.45));
}

// update (dt) {},

});

2赞

代码在楼下

预制件布局如下:

其中,backgroundMask、pokerMask、background、poker都是扑克牌有多大,他的宽高就是多大。
shadowMask、rub、bg则是占整个舞台大小,shadow则是长方形,宽度大于扑克牌的宽度2倍左右,高度自己控制。
flower以及number则是扑克上面的具体花色以及数字,自己调整即可,没要求

太复杂了 不看:3:

复制就可以用的:joy:

大佬有完整demo么?

牛,mark下以后可能会用到。

可以啊,要是代码里加点注释就更好了:joy:

1赞

mark就对了。

大佬有完整demo吗

mark一下