守望者--AIR技术交流

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
热搜: ANE FlasCC 炼金术
查看: 1347|回复: 7

[算法/性能优化] Flash 翻书效果研究

[复制链接]
  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    51691
    钢镚
    1422

    开源英雄守望者

    发表于 2015-1-10 14:28:28 | 显示全部楼层 |阅读模式
    声明:
    由于此文发表时间较早,原文(英文)中提供的效果链接已经失效,所以此处删去了原文提供的无效链接,请网友见谅。如果有类似源文件,请与本站联系,谢谢。
    总论—概念描述
    这个项目的概念是使来到我站点的人有机会用FlashMX设计一本虚拟的书,就象一本真正的书那样,不过它是摆在你的计算机桌面上的。你可以一页一页地阅读。
    注意,这个课程是面向那些对ActionScript有所了解以及知道如何在FlashMX中编码的人。如果你只知道如何创建一个球并让它在桌面上滚动,那么请过几个月再来吧。
    只是开玩笑啦。基本上在这个课程里只有很少的技术。在这个教程中的所有函数是经常使用的。编码非常容易,你需要知道的只是一些基本的三角知识,比如sine(正弦)、cosec(余弦)、hypotenuse(直角三角形的斜边)。这些对于这个教程来说就足够了。所以,放轻松,好好享受吧。
    这是一个正在进行的项目。如果你有任何问题,请给我e-mail。让我们开始吧。
    第一部分—基本计算函数(basic calculation functions)
    在这个根脚本(root script)里,我们有两个基本计算函数。你可以把它们直接拷贝到你的舞台(stage)上,因为我们将会一遍遍用到它们。一个是getDist,另一个是getAngle。它们对你来说很简单,是吧?老实说,我都没兴趣解释这样的东西,这些是高中数学课上该学的。
    第一个函数是获得两点之间的距离。我们需要知道这两点之间的坐标。
    //得到两点之间的距离
    1. function getDist(px1, py1, px2, py2){
    2.   x = px2 - px1;
    3.   y = py2 - py1;
    4.   hyp = Math.sqrt(Math.pow(x,2) + Math.pow(y,2));
    5.   return hyp;
    6. }
    复制代码

    好了,现在你进展已经不错。我们可以试一下更难点的。——怎么获得两点之间的角度。

    //得到两点之间的角度
    1. function getAngle(px1, py1, px2, py2){
    2.   x = px2 - px1;
    3.   y = py2 - py1;
    4.   hyp = Math.sqrt(Math.pow(x,2) + Math.pow(y,2));
    5.   cos = x / hyp;
    6.   rad = Math.acos(cos);
    7.   //如果你看不懂,就去问你的数学老师
    8.   deg = 180/(Math.PI / rad);
    9.   //是的,我们通过cos得到了一个角度“rad”,不过是以弧度为单位的
    10.   //因此,我们需要再进一步把它转换成我们所需要的标准的角度
    11.   if(y <0){
    12.       deg = -deg;
    13.   } else if((y == 0) && (x <0)){
    14.       deg = 180;
    15.   }
    16. return deg;
    17. }
    复制代码


    我不需要做更多解释了吧?

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    51691
    钢镚
    1422

    开源英雄守望者

     楼主| 发表于 2015-3-2 09:34:52 | 显示全部楼层
    翻书原理2

      http://www.blueidea.com/tech/multimedia/2006/3894.asp

    最近要做些电子书,本来准备去网上买现成的鼠标拖拽翻页效果的组件,但一看报价吓一跳,而且执行效率也不高,一个叫AsFlipPage4。0的组件CPU占用率高居70%,喊价1000RMB,真是恐怖。下载了几个开源的程序自己也看不懂。于是一咬牙自己做了一个。
      设置遮罩和阴影之后的最终成品



    Flash演示 大家用鼠标拖拽画面四个角即可看见效果
      主要原理:

    • 将电子书分为3个内容层,叠放顺序如图。第一层为当前页面层,是现在正在显示的页面;第二层是随鼠标拖拽时卷起的页角,第三层是当页角卷起时,露出下一页的层。
    • 设置遮罩:当页边卷起时,层1仅显示四边形FBDE内部分,层2仅显示ABCD部分,层3仅显示BGHD部分。
    • 旋转:层2内的内容要随着鼠标运动而不停变换倾斜角度,其角度始终与AC边斜度一致。
    • 翻页:当页面完全翻过时,层1的当前页数=当前页数+1




      程序的核心在于如何获得四个点ABCD的坐标,我使用的是求垂直平分线的方法,既:点C是鼠标位置,点H是页角位置,BD既为此两点间的垂直平分线。由已知的C,H坐标求出直线BD的一次函数y=kx+b以后再求出其与FG,EH的切点,既得点B,D坐标,点A是点G于直线BD的对称点,通过求点G对BD的对称点既可得点A坐标。
      demo1: 4个顶点的计算




    Flash演示 将鼠标移到黄色热区并拖动即可看见效果
      其他几个要点:
      限制C点范围:当鼠标在下图灰色区域内时,点C的坐标既等于鼠标坐标,当鼠标离开灰色区域时,点C必须停留在区域内。弧KML是以点J为圆心,KJ为半径的圆,弧KNL是以点I为圆心,IK为半径的圆(demo1既未限制C点范围,若鼠标超过弧形区域就会出错。




      响应事件:设置4个热区,分别位于书的4个顶点,分别设置rollOverrollOutreleaseOutsiderelease事件函数。事实上这一部分函数编写极费时间,需要考虑各种各样的可能性和针对性的处理方法。
      鼠标吸附及黏滞:当鼠标进入热区和快速移动时,页角是逐渐黏附向鼠标的,这样可以使动画看上去更流畅。demo4设置了吸附,demo1没有设置。


    Flash演示 大家用鼠标拖拽画面四个角即可看见效果
      阴影:翻页时的阴影须时刻与直线BD的位置保持一致,书的背景阴影要考虑到首页和末页两个特殊情况。
      首页与末页:在翻动到首页与末页时层3遮罩须重新设置为整本书宽的1/2。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 1 反对 0

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    51691
    钢镚
    1422

    开源英雄守望者

     楼主| 发表于 2015-1-10 14:29:30 | 显示全部楼层
    第二部分—舞台(stage)上基本的Movie Clips
    在库(library)中创建4个方块符号(symbol)。它们是你书中的不同的页面。如果你喜欢,你可以根据需要重新设计。我只需要提醒你一件事,就是,把参考点放在每个symbol的左下角,我们需要用它们来找到页面的位置。
    在这个演示例子里,假定我们的书只有4页。如果你想让你的书页数更多,那就请自己加一些新的check situation函数。要确保页面的大小与书本相符。
    把它们拖到你的舞台上,确保它们在不同的层面。
    按照这个顺序:第4页,第1页,第2页,第3页。
    第3页应该在最上面一层。确保将这些movie clip如下图所示放置。
    第3页的具体位置没什么要紧,因为我们将会把它做动态调整。
    2、创建一个符号(symbol)圆,并切割下来(cut)。我们需要在移动鼠标的时候用它来检查不同的位置。
    3、创建一个包含一个点的symbol,你可以用任何风格的点,这取决于你。
    把“点”这个symbol在舞台上放5次,分别命名为D0,D1,D2,D3和D4
    我需要提醒你的是,不要在movie clip Page1和Page4的区域外放置任何movie clip。
    4、我们还会需要一些别的符号(symbol),比如阴影或别的什么,我们可以迟一点再创建它们,别担心。
    现在再数一次,你库(library)里的符号(symbol)有:
    s_circle, s_dot, s_page1, s_page2, s_page3, s_page4
    你舞台(stage)上的符号(symbol)有:
    checkcircle, D0, D1, D2, D3, D4, page1, page2, page3, page4
    把舞台(stage)上所有的movie clip选中,把它们转换(convert)为一个符号(symbol) s_stage。
    把s_stage拖到舞台上,把它命名为movie clip“Stage”。
    确保movie clip D0位于movie clip“Stage”的中心。
    确保movie clip “Stage”的大小是Page 1 加 Page 4。
    这就是为什么当你在转换符号s_stage的时候不要在区域外面放置任何movie clip的原因。
    基本上,建立movie clip D0到D4 的目的是为了清楚找到参考点。当我们完成这个教程的时候,你可以把这些movie clip的透明度设置为0。我这里就是这么做的。
    我们可以在下面的课程中开始编码了。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    51691
    钢镚
    1422

    开源英雄守望者

     楼主| 发表于 2015-1-10 14:31:02 | 显示全部楼层
    第三部分—初始化
    如下图所示初始化所有变量。

    1. // Set the book's width and height. (设置书的宽和高)
    2. stageW = _root.stage._width;
    3. stageH = _root.stage._height;
    4. // Set reference points' position (设置参考点的位置)
    5. pax=_root.stage.d0._x - stageW/2;
    6. pay=_root.stage.d0._y - stageH/2;
    7. pbx=_root.stage.d0._x - stageW/2;
    8. pby=_root.stage.d0._y + stageH/2;
    9. pcx=_root.stage.d0._x;
    10. pcy=_root.stage.d0._y - stageH/2;
    11. pdx=_root.stage.d0._x;
    12. pdy=_root.stage.d0._y + stageH/2;
    13. pex=_root.stage.d0._x + stageW/2;
    14. pey=_root.stage.d0._y - stageH/2;
    15. pfx=_root.stage.d0._x + stageW/2;
    16. pfy=_root.stage.d0._y + stageH/2;
    17. _root.stage.page3._alpha = 0;
    18. // 我们需要在开始的时候显示movie clip Page2,所以先隐藏Page 3
    复制代码


    把这部分代码放入你的第一个根脚本(root frame script)。
    ——怎么找到第一个点?
    第一个点,D1,是你鼠标的位置。(说实在话,在D1的位置上有几种情况。假设你的鼠标离开了movie clip圆,会发生什么?你可以迟一些时候再完成这部分。我已经做好了。这是留给你的作业。)
    在给D1的位置赋值之前,我们首先需要一个主函数。
    1. //主函数
    2. function startSlip(){
    3.   getD1(); //这个函数是我们要在这一课中讨论的
    4.   getD234();
    5.   DrewMask(); //我们将在以后添加这两个函数
    6. }
    复制代码

    现在你可以检查如何设置D1了。
    1. //得到第一点,D1的位置
    2. function getD1(){
    3.   if (_root.stage.checkcircle.hittest(_xmouse, _ymouse, true)) {
    4.     _root.stage.d1._x = _root.stage._xmouse;
    5.     _root.stage.d1._y = _root.stage._ymouse;
    6.   } else {
    7.     //自己完成这部分。基本上,我还要用三个函数来设置 D1的位置
    8.   }
    9. }
    复制代码

    提示:你的鼠标要去四个区域,在每个区域里,D1的位置是不同的。在这个例子里,我们只讨论区域A。我会把所有的代码放在最终文件里,你如果感兴趣的话,可以稍后查看。
    因为要按住鼠标拖动页面,你需要移动的第一个点是在页面右下角的点。
    很好,我们还有三个点要做,耐心一点。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    51691
    钢镚
    1422

    开源英雄守望者

     楼主| 发表于 2015-1-10 14:32:00 | 显示全部楼层
    第四部分—得到所有其他三个点
    同上面一样,你有几种情况要考虑。
    第一种情况比较简单。第3点位于边EF上。在这种情况下,点D4与点D3位于同一位置。
    另一种情况比较难一点。点D3位于边CE上。你需要计算D3和D4。
    或者:
    这里,我们需要一些三角函数来获得所有的数值。嗨,一定有更有效的方式来编码,我真是没兴趣再做一遍。:(
    我只需要提醒你一件事:
    Flash的坐标系开始于左上角,逐渐向下扩展到右边。
    对于一个数学家来说,求得所有的点很可能只需要几分钟,但是我却花了整整一个上午。如果你想做,你可以自己做,或者只需拷贝这些代码。
    1. //用D1和F来找到其他的点
    2. function getD234(){
    3.   len = _root._root.getDist( pfx, pfy, _root.stage.d1._x,_root.stage.d1._y);
    4.   len1 = len/2;
    5.   len2 = (pfx - _root.stage.d1._x)/2;
    6.   _root.stage.d2._x = pfx - len1*len1/len2;
    7.   _root.stage.d2._y = pfy;
    8.   len2 = (pfy - _root.stage.d1._y)/2;
    9.   len3 = len1*len1/len2;
    10.   _root.stage.d3._x = pfx;
    11.   _root.stage.d3._y = pfy - len3;
    12.   // 检查D4是否和D3在同一个位置
    13.   if (_root.stage.d3._y < pey){
    14.     ptx = pex - (pfx - _root.stage.d2._x)*(pey - _root.stage.d3._y)/len3;
    15.     pty = pey;
    16.     len = _root.getDist(_root.stage.d3._x, _root.stage.d3._y, ptx, pty);
    17.     len1 = (pex - ptx)*(pey - _root.stage.d3._y)/len;
    18.     len2 = len1*len1/(pex - ptx);
    19.     _root.stage.d4._x = pex - len2*2;
    20.     len2 = len1*len1/(pey - _root.stage.d3._y);
    21.     _root.stage.d4._y = pey - len2*2;
    22.     _root.stage.d3._x = ptx;
    23.     _root.stage.d3._y = pty;
    24.   } else {
    25.     _root.stage.d4._x = _root.stage.d3._x;
    26.     _root.stage.d4._y = _root.stage.d3._y;
    27.   }
    28. }
    复制代码

    哇,现在我们快完成了,继续!

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    51691
    钢镚
    1422

    开源英雄守望者

     楼主| 发表于 2015-1-10 14:33:39 | 显示全部楼层
    第五部分—绘制mask shape
    你只需要知道两个特别的点。一个点创建一个空的movie clip,并在其中绘制一些东西。另一个点用另一个动画来遮住一个movie clip。
    好了,让我们来编码。
    1. // 创建遮罩movie clip
    2. function drawMask(){
    3.   _root.stage.createEmptyMovieClip ("triangle", 1);
    4.   with (_root.stage.triangle) {
    5.     colors = [ 0xEFEFEF, 0xFFFFFF ];
    6.     alphas = [ 100, 100 ];
    7.     ratios = [ 0, 0xFF ];
    8.     matrix = { a:200, b:0, c:0, d:0, e:200, f:0, g:200, h:200, i:1 };

    9.     beginGradientFill( "linear", colors, alphas, ratios, matrix );

    10.     moveTo (_root.stage.d1._x, _root.stage.d1._y);
    11.     lineTo (_root.stage.d2._x, _root.stage.d2._y);
    12.     lineTo (_root.stage.d3._x, _root.stage.d3._y);
    13.     lineTo (_root.stage.d4._x, _root.stage.d4._y);
    14.     lineTo (_root.stage.d1._x, _root.stage.d1._y);

    15.     endFill();
    16.     //我认为不需要解释这部分。你能在Flash MX的帮助或者参考中找到它们。我是从那里拷贝过来的。
    17.     // Pretty clear, right? (很清楚了吧?)
    18.   }

    19.   setPage3();
    20.   //我们需要在鼠标移动时移动和旋转movie clip Page3。这就是为什么在这里我们需要这个函数

    21.   _root.stage.page3.setMask(_root.stage.triangle);
    22. }
    复制代码


    这是我们还需要知道的一个函数:setMask
    就个人而言,我认为这个 setMask 函数在使用时有些小bug。它不象其他函数那么好用。
    我要提醒你的另一件事是,在同一级脚本里你只能用setMask一次,意思就是,如果你想同时setMask movie clip Page2,你需要创建新的 mask movie clip,并在不同级的脚本中setMask。
    很难理解吗?好吧,在我的例子里,我把下一个setMask放在movie clip Page2里。
    1. // 移动并旋转movie clip Page3
    2. function setPage3(){

    3.   _root.stage.page3._x = _root.stage.d1._x;
    4.   _root.stage.page3._y = _root.stage.d1._y;

    5.   angle = _root.getAngle(_root.stage.stage.d1._x,_root.stage.stage.d1._y, _root.stage.stage.d4._x, _root.stage.stage.d4._y);
    6.   _root.stage.page3._rotation = angle + 90;
    7. //为什么这里加了90度?我不知道。我只是发现加了这个之后数字才能很好地工作

    8. _root.stage.page3._alpha = 100;
    9. //记得我们把movie clip Page3的透明度设置为0了吗?现在我们需要把它变回去。因为movie clip Page2在Page3的下一层。
    10. }
    复制代码

    在这一课程中多加一条编码。
    在movie clip “Stage”中:
    1. onClipEvent (enterFrame) {
    2.   _root.startSlip();
    3. }
    复制代码

    这一段代码使 Flash 一直检查鼠标的位置。

    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    51691
    钢镚
    1422

    开源英雄守望者

     楼主| 发表于 2015-1-10 14:34:32 | 显示全部楼层
    第六部分—在Page2中绘制mask shape
    在movie clip Page2里创建一个新的名为Page2_content的movie clip。
    随便你取什么名都可以。
    把下面的代码加到新的movie clip Page2_content中。
    基本上,就象我们在上一个课程中讨论的那样,在同一级的script中,你只能使用setMask一次。这就是为什么在movie clip Page2里还需要再用一次的原因。
    这些代码是为了显示底部的movie clip Page4。
    1. // 在movie clip Page2_content内部
    2. onClipEvent (enterFrame) {

    3.   _parent.createEmptyMovieClip ("triangle2", 1);
    4.   _root.stage.page2.page2_content.setMask (_parent.triangle2);

    5.   with (_parent.triangle2) {
    6.     colors = [ 0xEFEFEF, 0xFFFFFF ];
    7.     alphas = [ 0, 0 ];
    8.     ratios = [ 0, 0xFF ];
    9.     matrix = { a:200, b:0, c:0, d:0, e:200, f:0, g:200, h:200, i:1 };
    10.     beginGradientFill( "linear", colors, alphas, ratios, matrix );
    11.     moveTo (_root.pdx , _root.pdy - _root.stageH/2);
    12.     lineTo (_root.stage.d2._x, _root.stage.d2._y - _root.stageH/2);
    13.     lineTo (_root.stage.d3._x, _root.stage.d3._y - _root.stageH/2);
    14.     lineTo (_root.pex, _root.pey - _root.stageH/2);
    15.     lineTo (_root.pcx, _root.pcy - _root.stageH/2);
    16.     lineTo (_root.pdx, _root.pdy - _root.stageH/2);

    17.     endFill();
    18.   }
    19. }
    复制代码

    检查一下你现在进展如何了?很酷,对吧?

    总结—你需要添加的其他东西

    现在,我们已经完成得差不多了。但是,当然,我们还需要再做一点什么,使它看起来象一本真正的书。
    我们需要加一些阴影movie clip。我用png文件来做透明效果。并且保证它随着Page3一起移动旋转。那些代码有些相似。角度有些不同,因为现在旋转轴不再是边D1、D4,而是边D2、D3。
    另外:你要添加一个函数来检测页面如何回退和前进。在我最终的版本里,我用了mouse release函数。
    基本上,还会有比较难的一步,就是如何查验第一页和最后一页。如果没有那些,你就不能增加页数。
    现在我又累又饿,剩下的事情就作为你们自己的作业吧。:)
    祝好运!

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-2-24 01:34
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    0

    主题

    38

    帖子

    868

    积分

    上士

    Rank: 5Rank: 5

    威望
    20
    贡献
    0
    金币
    14
    钢镚
    0
    发表于 2017-10-26 01:03:35 | 显示全部楼层
    感谢分享!~
    守望者AIR技术交流社区(www.airmyth.com)
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    
    关闭

    站长推荐上一条 /4 下一条

    QQ|手机版|Archiver|网站地图|小黑屋|守望者 ( 京ICP备14061876号

    GMT+8, 2019-8-18 13:53 , Processed in 0.053716 second(s), 34 queries .

    守望者AIR

    守望者AIR技术交流社区

    本站成立于 2014年12月31日

    快速回复 返回顶部 返回列表