读Strarling有感
什么是Starling?我们是否应该选择Starling来开发Flash游戏?
简单来说,Statling就是一个ActionScript库。模拟传统Flash的显示列表机制,但渲染是通过Stage3D进行的,利用GPU加速实现高效的渲染。
事件冒泡:在主应用中不必为每个移动着的图片侦听事件,只需要对舞台对象侦听事件就够了。
//Starling 是一个基于Stage3D所开发的一个能够使用GPU来加速的2D Flash应用程序的ActionScript3框架。
Starling主要是为游戏开发而设计的, 但是它的用途不仅限于此。
Starling最大的好处在于你可以很快地写出使用GPU加速的应用程序而不必接触那些复杂的底层Stage3D API。
对于是否应该选择Starling,必须清楚两个问题:
1,项目是应用还是游戏?
2,目标平台是PC还是移动设备?
除了Starling,还有Genome2D,ND2D,ARE2D等可供选择。
底层Stage3D API要接触的概念
vertices buffer(顶点缓冲),perspective matrices(视角矩阵),shader programs(着色器编程), assembly bytecode(字节码装配)
Starling的特点
1、直观
2、轻量级 :它的类数量不多(也就80K左右的代码量);
3、免费
Starling的构造函数
public function Starling
(
rootClass:Class,
stage:flash.display.Stage,
viewPort:Rectangle=null,
stage3D:Stage3D=null,
renderMode:String="auto",
profile:String="baselineConstrained"
)
PS: rootClass 参数传入的是一个继承自starling.display.Sprite的类引用(不是对象),这个类引用将作为Starling的入口类,即Starling中的文档类
stage 参数传入的是原生Flash的舞台,由Starling创建的Stage3D对象将位于此stage对象的下一层。
viewPort 参数表给Starling的场景定义一个矩形的可见区域(默认情况下由stageWidth和stageHeight决定)
stage3D 参数默认取的是stage.stage3Ds[0],即第一个Stage3D实例
renderMode 参数表示渲染方式(CPU渲染 和 GPU渲染)
profile 参数表示驱动模式(默认为约束模式 Context3DProfile.BASELINE_CONSTRAINED ,但在滤镜和遮罩的时候只能在baseline模式下运行,即 Context3DProfile.BASELINE)
什么是约束模式?
约束模式是指在Starling中强制限制显示内容始终在舞台的边界以内,否则报错:Error #3723: Invalid Context3D bounds。
设置Starling使用软件渲染(CPU渲染)
mStarling = new Starling(rootClass , stage, null, null, Context3DRenderMode.SOFTWARE); // AUTO为GPU渲染,默认
若想让一个嵌入在网页中的swf用上Stage3D来进行GPU加速的话,你就必须修改html源代码,使wmode = direct
判断是否使用硬件加速渲染(GPU渲染)
var isHW:Boolean = Starling.context.driverInfo.toLowerCase().indexOf("software") == -1; // return true/false
Starling的事件
Starling被实例化之后,可以得到两个事件:context3DCreate和rootCreated,前者代表context3D实例被创建,后者代表RootClass的实例被创建。
Starling处理交互事件是在传统Flash的Stage层进行侦听的,通过点击坐标,显示区域 和 遮挡关系 判断,确定点击的是哪个显示对象。
PS:在Starling的显示对象中没有Mouse事件,只有Touch事件,这一点跟Flash本身的事件机制不一样。
Starling的跑道机制
跑道机制是指,根据帧的设定频率,Flash可以在每一秒执行若干次的渲染,来保持画面的更新。而每一帧Flash都会派发EnterFrame事件。
Starling也在侦听Flash的EnterFrame事件,通过 advanceTime(当前时间和上一帧的时间差) 来调用nextFrame方法。
Starling其它对象的API和方法
enableErrorChecking : 设置是否启用错误检测功能,默认为false
isStarted : 判断start方法是否被执行过
juggler: juggler 是一个用于存储一系列实现了IAnimatable 接口的对象的对象,你可以通过调用juggler 对象的 advanceTime 方法来让它调度其保存的那些实现IAnimatable 接口的对象每一帧的行为。当一个动画播放完毕后,juggler 会将其剔除。
知识扩展:
位移(向左:<< 向右:>> ) (向左位移相乘,向右位移相除)
n >> 1 : 向右位移一位操作(>>1)等价于n除以2,只不过速度要更快一些。
Q:用最有效率的方法算出2乘以8等於几?
A : 2 << 3 显示列表
事件
* Event.ADDED : 当显示对象被添加到一个容器中抛出
* Event.ADDED_TO_STAGE : 当显示对象被添加到一个已存在于舞台上的容器中时,也就是其变得可见时抛出
* Event.REMOVED : 当显示对象被从一个容器中移除时抛出 * Event.REMOVED_FROM_STAGE : 当显示对象被从一个已存在于舞台上的容器中移除时,也就是其变得不可见时抛出
Starling中DisplayObject类提供的方法
* removeFromParent : 从父对象中移除,如果它有父对象的话
* getBounds : 得到一个以某个坐标系为参考系的能包含该显示对象的最小矩形。
* hitTestPoint : 返回当前坐标系中某个点位置下层次最高(挡在最前面)的显示对象
* globalToLocal : 将一个点由舞台坐标转换为当前坐标系坐标
* localToGlobal : 将一个点由当前坐标系坐标转换为舞台坐标
* transformationMatrix : 当前显示对象位置与其父容器的转换
Texture(纹理)
Texture是用来储存展示图像的信息,但它不能直接被添加到显示列表。
Mip映射:是指将一个纹理保存多个缩小版本的方式。(一般是除以二,直到不能再除。PS:对于一个128*128的图片,它的全部Mip映射等级为:64*64,32*32,16*16,8*8,4*4,2*2以及1*1)
在Starling中创建Texture的时候,默认是开启mipmap的,这样可以优化纹理缩放时的显示效果和执行效率,代价就是需要更多的内存。如果需要关闭mipmap映射,您可以在调用Texture.fromBitmapData或Texture.fromBitmap的时候,设置第二个参数generateMipMaps为false。也可以用mipmapping属性。
PS:若是你不用Starling框架的话,那你就得通过使用BitmapData.draw这个API并使用一个缩小一倍的Matrix作为参数来手动地生成全部的映射等级。
mipmapping 属性: 设置某个Texture对是否使用Mip映射。
知识回顾:Bitmap 和 BitmapData
1、Bitmap是DisplayObject的子类,可以直接addChild()到舞台当中。
2、Bitmap构造函数: Bitmap(bitmapData:BitmapData = null, pixelSnapping:String="auto", smoothing:Boolean=false),pixelSnapping是自动紧贴,smoothing是平滑处理
3、BitmapData对象并不是DisplayObject,而是直接继承自Object。
4、Bitmap对象只是把BitmapData对象记录的像素ARGB值提交给Flash Player渲染引擎,然后一个位图就在舞台上渲染出来了。
PS:测试一下事件的target及currentTarget属性,我们会发现currentTarget对象始终是Stage对象,而target属性则是所点击到的某个具体对象。
Q:Starling中纹理占用的内存如何估算?
A:Flash中位图和纹理存储方式为32位4字节RGBA方式,也就是说,一个像素需要占用4个字节。一张1024像素的图片要占4M内存,So ,你懂的。
碰撞检测
检测两个简单的圆形碰撞时,依靠对两圆心间距离是否小于两圆半价之和来判断就够了。
其他的一些情况下,一般用判断两个物体的矩形边框是否交汇的方法可以做简单的碰撞检测。
在Starling中,BitmapData对象提供的hitTest这个API来做到像素级碰撞检测。
hitTest 方法
public function hitTest(
firstPoint:Point,
firstAlphaThreshold:uint,
secondObject:Object,
secondBitmapDataPoint:Point = null,
secondAlphaThreshold:uint = 1):Boolean
绘图API
Starling中没有提供flash.display.Graphics对象一样的绘图API。但是可以通过BitmapData的draw方法来把绘制好的原生显示对象画到一个BitmapData对象中,
之后用此对象作为Texture的数据源。
Flat Sprites
Starling中提供的一个非常强大的特性。
将全部子对象的顶点着色器及索引缓冲区(vertex and index buffer)集成为一个大的并由它来接管全局的渲染工作(包括容器及其子对象),
且只需要调用一次绘制方法即可完成渲染的工作,就跟完成一个简单的纹理的渲染一样。
而不是
每个显示对象都用专属的顶点着色器及索引缓冲区来进行各自的渲染工作。
PS:所有子对象都有属于自己的顶点着色器及索引缓冲区,当Sprite被flat了之后,只需调用一次绘制方法即可完成全局的渲染工作(只在一个顶点着色器和索引缓冲区中)
Flat 与 cacheAsBitmap 的区别:在原生Flash中,显示对象一旦被设置了cacheAsBitmap为true之后,只要该显示对象或者其子对象发生了改变,Flash会自动生成新的位图缓存,保证显示正确的图形 ,但是flat sprites不会自动生成新的。因此你必须再次调用flatten方法来手动地重新生成一次才能看到改变。
扩展阅读 :
MovieClip
Stage3D框架都有着其自规定的最大尺寸,对于Starling来说最大尺寸为2048*2048。
public function MovieClip(textures:Vector.<Texture>, fps:Number)
Starling中MovieClip常用API
currentFrame : 指示当前帧序号
fps : 默认情况下的帧频,即每秒播放的帧数
isPlaying : 判断当前影片剪辑是否正在播放
loop : 判断当前影片剪辑是否会循环播放
numFrames : 当前影片剪辑包含的总帧数
totalTime : 播完一次影片所需时间,单位为秒
addFrame : 为影片剪辑增加一帧至时间轴末尾
addFrameAt : 添加一帧到指定位置
getFrameDuration : 获取某一帧的持续时间
getFrameSound : 获取某一帧播放的声音
getFrameTexture : 获取某一帧所用纹理
pause : 暂停影片播放
play : 开始播放影片. 不过在此之前你需要确保影片对象被添加到了一个Juggler对象中
removeFrameAt : 移出指定位置处的帧
setFrameDuration : 设置某一帧的持续时间(单位为秒)
setFrameSound : 设置某一帧播放的声音
setFrameTexture : 设置某一帧所用纹理
Juggler
Juggler类允许我们控制所有实现了IAnimatable接口的对象的动画播放。
MovieClip类实现了该接口,你也可以自定义一个动画类在Starling中播放,你所要做的,仅仅是让你的自定义类实现IAnimatable接口,然后重载advanceTime方法。
常用API
add : 添加一个动画对象到juggler
advanceTime(先行时间) : 需要手动调控Juggler的主循环逻辑时调用。
PS:当游戏暂停的时候,会弹出一个菜单面板到你暂停着的游戏面板之上,此时你就需要另一个Juggler来负责管理该菜单面板中的动画了,即调用其advanceTime方法。
Starling.current.stop() 停止所有Juggler对象,前提是每个独立的模块或窗口都是一个Juggler对象。
delayCall : 延迟调用某个对象的某个方法
elapsedTime : 指示一个juggler对象的完整生命周期时间
isComplete : 指示一个Juggler的状态,默认情况下它总是返回flase
purge : 一次性移除全部子对象
remove : 从juggler中移除一个对象
removeTweens : 移除全部类型为Tween的且存在指定目标的对象
Quad类
Starling的设计思路,即认为一切显示对象都是四边形,其它的显示对象都可以由四边形扩展而来。
QuadBatch
QuadBatch定义了两个方法:addQuad(),和addImage()。
在Starling内部,RenderSupport类负责管理和维护QuadBatch。当遍历显示列表的时候,RenderSupport就会将所有的四边形,划分到若干个批次里面,这样渲染的时候,每个QuadBatch内部的四边形会被集中处理,只提交一次。
Stage 调用 render() 方法,交由RenderSupport处理,RenderSupport会创建一个QuadBatch对象,(第一个加入的对象,将决定了这个QuadBatch的状态),然后判断下面要加入的对象是否符合这个状态,否则要再新建一个QuadBatch。
TextField
Starling会使用CPU创建了一个原生的Flash TextField对象,然后转换成传至GPU进行渲染。
PS:我们所看到的不是并不是真正的TextField,而是一个TextField的快照被绘制在一个Bitmap之后封装在texture中上传至GPU的产物。
常用API
alpha : 文本透明度
autoScale : 是否让文本自动缩放以适应TextField的区域,这个很给力。
bold : 指定文本是否以粗体显示
border : 允许显示textfield的边框图像
bounds : textfield所占区域
color : 文本颜色
fontName : 文本字体名
fontSize : 文本大小
hAlign : 文本水平排列方式
italic : 指定文本是否以斜体显示
kerning : 当你在使用位图字体时(前提是存在可用的位图字体),允许你设置字符间距。此属性默认值为YES
text : 显示的文本
textBounds : textfield中实际文本所占区域
underline : 指定文本是否显示下划线
vAlign : 文本垂直排列方式
嵌入外部字体:先从外部加载一个字体文件,然后实例化该字体类并将其的字体名fontName作为参数传至TextField构造函数即可。
[Embed(source='字体路径', embedAsCFF='false', fontName='Abduction')] //引入下载好的字体文件
回顾:
Flash显示层的关系是(从下到上): StageVideo(可以直接在设备硬件上处理视频) -> Stage3D -> Stage 。
原生Flash显示列表采用CPU进行渲染,在最上层;Stage3D显示列表采用GPU进行渲染,在原生显示列表之下。
Starling的 nativeOverlay 属性,可以在Starling对象中访问原生Flash显示列表 ,并向其中添加常用的原生Flash显示对象,它们将会覆盖于Stage3D舞台之上。
PS:任何时候都可以通过Starling对象的 nativeStage 属性来访问原生Flash的舞台对象(flash.display.Stage)。
位图字体
为了获得最佳的视觉体验,降低资源加载量和垃圾回收量,我们可以在TextField对象中用上位图字体。
制作位图字体工具 :
Mac : GlyphDesigne(71 squared出品,收费)
Windows : Bitmap Font Generator(Angel Code出品,免费)
RenderTexture
RenderTexture允许开发者在Starling中实现无损绘画功能 。类似于(原生Flash中的BitmapData对象)
RenderTexture对象可以作为一张“画布”,满足你在一个Texture纹理对象中进行绘画的愿望,而且每次绘画时不会抹除上一次绘画的结果。
处理屏幕尺寸改变
改变屏幕尺寸的方法 :1、Event.RESIZE事件
2、更改 stage.stageWidth 及 stage.stageHeight 属性
3、ResizeEvent.RESIZE事件 (Starling中)
Starling对象的dispose方法作用是什么?是否有效?
不同对象的dispose方法的作用不同,对于纹理来讲,这会销毁纹理数据,释放内存空间。而对于MovieClip等对象来说,dispose的作用只是删除事件侦听,并不会销毁附加的纹理,这一点需要注意,纹理需要您手动销毁。
Starling应用中如何尽量节省内存?
这是一个很纠结的问题,我们必须找到一个平衡点。为了提高应用的渲染效率,响应速度,我们需要尽量提前将大批次的纹理提交给GPU,而且尽量不销毁,这样在下次使用的时候就可以非常快速的切换,但这样就会消耗更多内存。现在我们只能是 销毁掉不会马上调用的纹理,来降低内存占用。
Starling应用能否和普通Flash显示内容协作?
可以,但要注意性能。在PC上,性能问题不明显。
PS:《愤怒的小鸟》 就是采用Starling渲染,操作控制则是传统的Flash显示对象实现的。
Starling中nativeOverlay的作用
传统Flash显示对象,无法添加到Starling的显示列表中,但可以通过Starling.curren.nativeOverlay属性获取这个处于传统显示层面的Sprite引用,然后把显示对象添加进去。
Starling性能优化
Starling使用Stage3D来渲染所有的可见对象,这就意味着所有的绘制都是GPU完成的。GPU希望能得到大量的数据,然后在一次调用中绘制所有的对象。
PS:如果可以用一种尽可能减少状态变化的方式创建场景,那么渲染性能将会受益无穷。
可以优化的情况:
1、用半透明的方式绘制。
2、用不同颜色绘制。
原理:在未着色的对象和着色的对象之间切换时,将会导致一次状态变更。
优化方案:根对象(root object)的透明度为“0.999”或一个近似的值。由于这个透明度会向下影响到子元件的渲染,Starling会将任何对象都按照“着色”对象来对待,这样就不会触发过多的状态的变更了。
3、避免重复调用width和height (获取宽度和高度属性是一个的性能开销,特别是对于Sprite容器)
PS:这一点就跟循环一样,我们先用一个变量接收Array或List的长度,而不是在循环体中实时统计。
4、让容器不可点击(当光标/手指在屏幕上移动的时候,Starling就会寻找哪一个对象被点击了。这可能是一项奢侈昂贵的操作,因为它需要遍历所有的显示对象,并调用hitTest方法。因此,如果一个对象不需要被触碰,可以把它设置成 container.touchable = false)
5、使用新的事件模型 ,用对象池来缓存事件对象 object.dispatchEventWith("type", bubbles);
6、访问数组或向量数组元素 (当对象索引是一个计算结果的时候,请转换为int类型。)var element:Object = array[int(10*x)];
7、代码优化 (Code ReView)