cocos2dx-lua 裁切实现类3d翻页效果

 效果演示

        达到书页随着鼠标拖动、点击基本自由改变方向和位置,模拟出书本翻页效果。

基本思路

        创建两张一左一右节点拼接后显示初始完整页面,在点击后创建出新节点。新节点有三个节点:可移动页面(halfPage)、中缝阴影(shadow)、底部静止页面(staticPage)。三分部均需要套入裁切,只显示裁切后的区域范围。通过实时计算裁切矩形模板的abcd点,动态修改模板形状,进而达到新页面三部分的显示区域动态变化

代码结构

流程

   点击热区        

 计算裁切模板矩形四个点

    1.c点

       c点为鼠标拖动坐标。       

        但是cPoint需要在一定限制范围之内不然会出现穿帮,x坐标需要在图片宽度之内,而y轴限制的范围需要计算。控制页面上半圆与下半圆之内(y坐标的极限范围),其中半圆计算需要根据点击的热区分为两种情况。

         红色为c点在下半圆的y轴极限区域

         蓝色为c点在上半圆的y轴极限区域

1)点击热区为左下或者右下:

        上半圆的半径为图片宽度的一半其圆心为图片底部中心E如图蓝色显示

         下半圆的半径为图片高度与图片宽度一半的勾股定理所得,其圆心F是页面顶部中心如图红色显示

if mouse_Y < 0 then
            --如果鼠标在书的下边的下方
            cPointY = -math.sqrt(self.rDown * self.rDown - (self.cPoint.x - self.pageWidth / 2) * (self.cPoint.x - self.pageWidth / 2)) + self.pageHeight
            
            if cPointY > mouse_Y then
                --如果在半圆外
                self.cPoint.y = cPointY
            else
                --如果在半圆内
                self.cPoint.y = mouse_Y
            end
        else
            --如果鼠标在书的下边的上方
            cPointY = math.sqrt(self.rUp * self.rUp - (self.cPoint.x - self.pageWidth / 2) * (self.cPoint.x - self.pageWidth / 2)) + 0
            
            if cPointY < mouse_Y then
                --如果在半圆外
                self.cPoint.y = cPointY
            else
                --如果在半圆内
                self.cPoint.y = mouse_Y
            end
        end

2)点击热区为左上或者右上:

        上半圆的半径为图片宽度一半与图片高度一半的三角斜边j圆心为底部中心F如图蓝色显示

        下半圆的半径图片宽度一半k圆心为顶部中心点E如图红色显示

if mouse_Y < self.pageHeight then
            --如果鼠标在书的上边的下方
            cPointY = -math.sqrt(self.rUp * self.rUp - (self.cPoint.x - self.pageWidth / 2) * (self.cPoint.x - self.pageWidth / 2)) + self.pageHeight
            
            if cPointY > mouse_Y then
                --如果在半圆外
                self.cPoint.y = cPointY
            else
                --如果在半圆内
                self.cPoint.y = mouse_Y
            end
        else
            --如果鼠标在书的上边的上方
            cPointY = math.sqrt(self.rDown * self.rDown - (self.cPoint.x - self.pageWidth / 2) * (self.cPoint.x - self.pageWidth / 2)) + 0
            
            if cPointY < mouse_Y then
                --如果在半圆外
                self.cPoint.y = cPointY
            else
                --如果在半圆内
                self.cPoint.y = mouse_Y
            end
        end

公式:

个性化:

拖拽效果可以是完全跟手拖动和不跟手拖动两种,在传入值前做不同赋值就能达到不同效果。 

        2.d点

         首先计算出c点与起点页脚D的中点m1,就能计算c点和起点连线垂直平分线的斜率k0,这样就能知道一条直线的一个点和斜率k,并且d点的y轴为0就能求出d点x轴       

        3.b点

            使用求出的c点和起点连线垂直平分线的斜率k0与中点且已知b点y轴坐标为页面高度就能求出b点x轴坐标

             b点计算时有可能会出现2种可能性

             1)b点横坐标超出画面宽度

             超出页面宽度将x赋值为页面宽度 计算y轴且a点坐标不存在赋空

             2)b点横坐标在画面宽度内

              d点正常计算且存在a点

         4.a点

                已知与a点相邻的起点边上的起角点C,aC直线平行cD直线所以斜率为-1/k0,就可以计算获得a点与其起角点C的中点m2(其中中点计算是解二元一次方程,已知两条直线相交求交集点,详细代码与数学推导见附件)相当于,已知中点m2、终点C就能求起始点a

 计算拖动与x轴相交角度

                已知c点与起角点的中点,以及起角点就能使用math.atan2 返回从传入两点的线段与x轴正方向之间的平面角度(弧度值)就能获得旋转角度

function M:getK0(cPoint, pointCorner)
    local disX = pointCorner.x - cPoint.x
    local disY = pointCorner.y - cPoint.y
    
    if disX == 0 then
        disX = 0.0001
    end
    
    local k = disY / disX -- c点和起点连线的斜率
    
    if k == 0 then
        k = 0.0001
    end
    
    self.lineAngle = math.atan2(pointCorner.y - cPoint.y, pointCorner.x - cPoint.x) * 180 / math.pi
    return -1 * 1 / k
end

图片加载

        拖拽的图片就加载在halfPage节点,节点根据拖动时获取到的c点以及上面获取的角度,赋值节点的角度和坐标,以及根据不同点击热区设置不同的锚点。

halfPage节点角度和坐标设置

        因为图片旋转角度与计算实时角度相反所以需要*-1,而左侧点击热区的k值相差右侧点击热区k值180度所以左侧旋转角度需要减去180度

function M:onDrag(cPoint, angle, dir)
    if dir == FLIP_LEFT_UP then
        self.halfPage:p(cPoint)
        self.halfPage:rotation(-angle - 180)
    elseif dir == FLIP_LEFT_DOWN then
        self.halfPage:p(cPoint)
        self.halfPage:rotation(-angle - 180)
    elseif dir == FLIP_RIGHT_UP then
        self.halfPage:p(cPoint)
        self.halfPage:rotation(-angle)
    elseif dir == FLIP_RIGHT_DOWN then
        self.halfPage:p(cPoint)
        self.halfPage:rotation(-angle)
    end
end

 halfPage节点锚点设置

if dir == FLIP_RIGHT_UP then
        self.page3:anchor(cc.p(0, 1))
    elseif dir == FLIP_RIGHT_DOWN then
        self.page3:anchor(cc.p(0, 0))
    elseif dir == FLIP_LEFT_UP then
        self.page3:anchor(cc.p(1, 1))
    elseif dir == FLIP_LEFT_DOWN then
        self.page3:anchor(cc.p(1, 0))
    end

        分为4种情况

        1.右下角热区

            操控点是图片左下角所以动态绘制的时候需要设置锚点为(0,0)

        2.左下角热区

                操控点是图片右下角所以动态绘制的时候需要设置锚点为(1,0)

        3.右上角热区 

                 操控点是图片右上角所以动态绘制的时候需要设置锚点为(0,1) 

        4.左上角热区 

                 操控点是图片左上角所以动态绘制的时候需要设置锚点为(1,1) 

数学推导

        1.a点计算代码

                使用点击右下热区作为例子

local cx  -- a点(和起点在同一个书边的角的中点)的横坐标
local cy  -- a点(和起点在同一个书边的角的中点)的纵坐标
local pointBCS_X  -- c点和起点的中点的横坐标
local pointBCS_Y  -- c点和起点的中点的纵坐标
local k  -- 垂直于c点和起点连线的直线的斜率
-- 计算a点坐标
cx = (self.pageWidth + self.pageHeight * k - k * pointBCS_Y + k * k *pointBCS_X) / (1 + k * k)
cy = k * (cx - pointBCS_X) + pointBCS_Y
self.aPoint.x = 2 * cx - self.pageWidth
self.aPoint.y = 2 * cy - self.pageHeight
-- 计算b点坐标
self.bPoint.y = self.pageHeight
self.bPoint.x = (self.pageHeight - pointBCS_Y) / k + pointBCS_X

公式: 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值