效果演示
达到书页随着鼠标拖动、点击基本自由改变方向和位置,模拟出书本翻页效果。
基本思路
创建两张一左一右节点拼接后显示初始完整页面,在点击后创建出新节点。新节点有三个节点:可移动页面(halfPage)、中缝阴影(shadow)、底部静止页面(staticPage)。三分部均需要套入裁切,只显示裁切后的区域范围。通过实时计算裁切矩形模板的abcd点,动态修改模板形状,进而达到新页面三部分的显示区域动态变化
代码结构
流程
点击热区 ![](https://i-blog.csdnimg.cn/blog_migrate/46b4ded84e0b1504afb614c2f337a53d.png)
计算裁切模板矩形四个点
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
公式: