首页 > 其他分享 >Starling实现的硬皮翻书效果

Starling实现的硬皮翻书效果

时间:2023-01-10 12:32:01浏览次数:50  
标签:function flipingPageLocation 硬皮 private Starling 翻书 var import pn

Starling实现的硬皮翻书效果


作者:郭少瑞

———————————————————————————————————————–

在今年的最后一天,这个效果终于更新为软纸翻页的版本(封面和封底仍然是硬纸)​

​​

硬纸到软纸的最大困难,在于拖拽中的几何算法和纹理拼接(因为Starling还未提供遮罩,所以不能按照遮罩的思路做,只能根据顶点拼接纹理)。几何算法是从天地会的这篇帖子中获取的,感谢这位作者。拼接则相对简单,显示中如果遇到五边形,则用一个三角形和一个四边形拼接。通过合理控制每个多边形的顶点坐标和纹理UV坐标,可以模拟实现原来遮罩才能做的效果。

———————————————————————————————————————–

Flash的翻书效果想必大家都看到过很多,不过基于Stage3D的版本似乎还很难找到(也可能是我孤陋寡闻了,如果您知道的话欢迎补充)。现在很多项目已经开始使用Stage3D(或基于Stage3D的衍生框架比如Starling)来制作了,有时候也需要将原有传统Flash的效果移植到Stage3D层面来实现,这样融合更方便,性能上也可能更强大一些。

​​

下面是一个基于Starling的翻书效果实现,当然还很简陋,只实现了硬皮翻页,软纸翻页还没有实现。不过我觉得在这个例子上进行一下扩展,用图片纹理坐标和顶点控制的方式,是可以实现出原来遮罩才能实现的效果的(传统Flash翻书效果大都使用遮罩),所以这个例子权作抛砖引玉,期待能有更为完善的例子出来。

效果演示

您可以点击下面的地址,查看这个Demo的实现效果:
​http://www.todoair.com/demo/book/StarlingBook.html

Sorry,因为没写Loading,文件尺寸较大,需要您耐心等待一会儿。

实现过程

为了尽可能利用Starling的批处理优势来提升性能,所以素材采用了TextureAtlas的方式,将所有页的图片集中到一张大图上(当然这个地方也有缺点,如果一张图放不下的话,就要分几张图存放,并修改获取素材的方式,以便从不同的源中获得纹理)。在渲染处理上,使用QuadBatch来代替普通的显示对象叠加,来尽量提升性能。在笔者的电脑上,这个例子可以稳定在60FPS运行。

核心是PageFlipContainer这个类,这个类使用一个QuadBatch实例来更新显示,并侦听Touch事件来启动翻页过程。具体代码如下:


package test.pf
{
import flash.display.Bitmap;
import flash.geom.Point;

import starling.display.Image;
import starling.display.QuadBatch;
import starling.display.Sprite;
import starling.events.Event;
import starling.events.Touch;
import starling.events.TouchEvent;
import starling.events.TouchPhase;
import starling.textures.Texture;
import starling.textures.TextureAtlas;

import test.TrangleImage;

/**
* 基于Starling的翻页组件
* @author shaorui
*/
public class PageFlipContainer extends Sprite
{
/**包含内页的图集*/
private var altas:TextureAtlas;
/**书的宽度*/
private var bookWidth: Number ;
/**书的高度*/
private var bookHeight: Number ;
/**书的总页数*/
private var bookCount: Number ;
/**批处理显示*/
private var quadBatch:QuadBatch;
/**左侧显示页面页码*/
private var leftPageNum: int = - 1 ;
/**右侧显示页面页码*/
private var rightPageNum: int = 0 ;
/**翻动中的页面编码(正面,反面为+1)*/
private var flipingPageNum: int = - 1 ;
/**正在翻页的位置(-1到1),由程序控制,外部无须调用*/
public var flipingPageLocation: Number = - 1 ;
/**是否需要更新*/
private var needUpdate: Boolean = true ;

/**@private*/
public function PageFlipContainer(altas:TextureAtlas,bookWidth: Number ,bookHeight: Number ,bookCount: Number )
{
super ();
this .altas = altas;
this .bookWidth = bookWidth;
this .bookHeight = bookHeight;
this .bookCount = bookCount;
initPage();
}
/**初始化页*/
private function initPage(): void
{
quadBatch = new QuadBatch();
addChild(quadBatch);
textures = altas.getTextures();
cacheImage = new Image(textures[ 0 ]);
flipImage = new ImagePage(textures[ 0 ]);
addEventListener(Event.ENTER_FRAME,enterFrameHandler);
addEventListener(Event.ADDED_TO_STAGE,firstFrameInit);
addEventListener(TouchEvent.TOUCH,onTouchHandler);
}
/**显示的时候初始化第一个画面*/
private function firstFrameInit(): void
{
removeEventListener(Event.ADDED_TO_STAGE,firstFrameInit);
enterFrameHandler();
needUpdate = false ;
}
/**用于缓存纹理的图片*/
private var cacheImage:Image;
/**翻动的图片*/
private var flipImage:ImagePage;
/**缓存的纹理数组*/
private var textures:Vector.;
/**每帧调用*/
private function enterFrameHandler(event:Event= null ): void
{
if (stage == null || !needUpdate)
return ;
quadBatch.reset();
if (flipingPageNum >= 0 )
{
leftPageNum = flipingPageNum - 1 ;
rightPageNum = flipingPageNum + 2 ;
}
//选择左侧的页面
if (validatePageNumber(leftPageNum))
{
cacheImage.x = 0 ;
cacheImage.texture = textures[leftPageNum];
quadBatch.addImage(cacheImage);
}
//渲染右侧的页面
if (validatePageNumber(rightPageNum))
{
cacheImage.x = bookWidth/ 2 ;
cacheImage.texture = textures[rightPageNum];
quadBatch.addImage(cacheImage);
}
//渲染正在翻转的页面
if (validatePageNumber(flipingPageNum))
{
if (flipingPageLocation>= 0 )
flipImage = new ImagePage(textures[flipingPageNum]);
else
flipImage = new ImagePage(textures[flipingPageNum+ 1 ]);
flipImage.setLocation(flipingPageLocation);
quadBatch.addImage(flipImage);
flipImage.dispose();
}
}
/**是否处于拖动状态*/
private var isDraging: Boolean = false ;
/**触碰处理*/
private function onTouchHandler(event:TouchEvent): void
{
var touch:Touch = event.getTouch( this );
if (touch != null && (touch.phase == TouchPhase.BEGAN || touch.phase == TouchPhase.MOVED || touch.phase == TouchPhase.ENDED))
{
var point:Point = touch.getLocation( this );
var imgWidth: Number = bookWidth/ 2 ;
if (touch.phase == TouchPhase.BEGAN)
{
isDraging = true ;
if (point.x >= imgWidth)
{
if (validatePageNumber(rightPageNum))
{
flipingPageNum = rightPageNum;
}
}
else
{
if (validatePageNumber(leftPageNum))
{
flipingPageNum = leftPageNum- 1 ;
}
}
}
else if (touch.phase == TouchPhase.MOVED)
{
if (isDraging)
{
flipingPageLocation = (point.x-imgWidth)/imgWidth;
if (flipingPageLocation > 1 )
flipingPageLocation = 1 ;
if (flipingPageLocation < - 1 ) flipingPageLocation = - 1 ; validateNow(); } } else { isDraging = false ; finishTouchByMotion(point.x); } } else { needUpdate = false ; } } /**触控结束后,完成翻页过程*/ private function finishTouchByMotion(endX: Number ): void { var imgWidth: Number = bookWidth/ 2 ; needUpdate = true ; touchable = false ; addEventListener(Event.ENTER_FRAME,executeMotion); function executeMotion(event:Event): void { if (endX >= imgWidth)
{
flipingPageLocation += 0.04 ;
if (flipingPageLocation >= 1 )
{
flipingPageLocation = 1 ;
removeEventListener(Event.ENTER_FRAME,executeMotion);
tweenCompleteHandler();
}
}
else
{
flipingPageLocation -= 0.04 ;
if (flipingPageLocation = 0 && pageNum < bookCount) return true ; else return false ; } /**当前页码*/ public function get pageNumber(): int { if (leftPageNum >= 0 )
return leftPageNum;
else
return rightPageNum;
}
/**强制更新一次显示*/
public function validateNow(): void
{
needUpdate = true ;
enterFrameHandler();
needUpdate = false ;
}
/**跳页*/
public function gotoPage(pn: int ): void
{
if (pn < 0 ) pn = 0 ; if (pn >= bookCount)
pn = bookCount- 1 ;
if (pn == 0 )
{
leftPageNum = - 1 ;
rightPageNum = 0 ;
}
else if (pn == bookCount- 1 )
{
leftPageNum = pn;
rightPageNum = - 1 ;
}
else
{
if (pn% 2 == 0 )
pn = pn - 1 ;
leftPageNum = pn;
rightPageNum = pn+ 1 ;
}
flipingPageNum = - 1 ;
validateNow();
}
}
}



使用方式:

/**初始化*/
private function initGame(event:Event): void
{
/*----------------------翻页组件-----------------------*/
//把图片合集到一起,减少DRW值
var bookImgs:Bitmap = new bookImgClass();
var xml:XML = XML( new booXml());
//这个工具可以给图片加上阴影,提升显示效果
ShadowUtil.addShadow(bookImgs,xml);
var texture:Texture = Texture.fromBitmap(bookImgs);
var atlas:TextureAtlas = new TextureAtlas(texture,xml);
//创建一个翻页容器,设置纹理,书的尺寸和总页数
pageFlipContainer = new PageFlipContainer(atlas, 800 , 480 , 8 );
pageFlipContainer.x = 100 ;
pageFlipContainer.y = 100 ;
addChild(pageFlipContainer);
//创建一个按钮控制翻页
var btn:Button = new Button(Texture.fromBitmap( new btnImgClass() as Bitmap), "下一页" );
btn.x = 100 ;
btn.y = 600 ;
btn.addEventListener(TouchEvent.TOUCH,btnTouchHandler);
addChild(btn);
}
/**翻页*/
private function btnTouchHandler(event:TouchEvent): void
{
var touch:Touch = event.getTouch(event.target as DisplayObject);
if (touch != null && touch.phase == TouchPhase.ENDED)
{
var pn: int = pageFlipContainer.pageNumber+ 1 ;
if ( pn% 2 == 0 )
pn+= 1 ;
if ( pn >= 8 )
pn = 0 ;
pageFlipContainer.gotoPage(pn);
}
}

标签:function,flipingPageLocation,硬皮,private,Starling,翻书,var,import,pn
From: https://blog.51cto.com/kenkao/6000192

相关文章

  • Starling GodRay 效果实现
    ​​Starling‘GodRay’Filter​​Whilecruisingtheinternettodaylookingforinterestingthingstotryout,Iranacrossthisfunlittle​​GPUGem​​​......
  • Starling常见问题解决办法
    ​​Starling常见问题解决办法​​来自:​​智慧+毅力=无所不能​​ 1、Android设备上阻止用户按下后退后的行为侦听按键事件//阻止后退行为view.stage.addEventL......
  • Starling浅尝
      starling笔记:基于Stage3Dg开发出来的一个可以使用GPU加速2D应用程序的框架。是一个渲染框架!特色:直观,轻量,免费。Starling与Sparrow框架很相近。驱动关系:GPU-->OpenGL/E......
  • Starling使用总结
    1.Starling应用能否和普通Flash显示内容协作?      可以,但要注意性能。在PC上,性能问题不明显。PS:《愤怒的小鸟》就是采用Starling渲染,操作控制则是传统的Flas......
  • Js 之turn.js翻书中添加视频、链接
    注意:视频在翻页后没有做关闭功能。代码在百度网盘中一、前端效果图 二、后端数据配置效果图  ......