Starling的性能优化(译文)Part 3
一日不复药,血压归旧高,诚如二弟所言,高血压是一辈子的事。继续完成剩余译文。
扁平化Sprite(Flattened Sprites)
为了追求最小化的状态变更,你已经做了一大堆事以期你的游戏获得性能提升。然而Starling仍然需要遍历你所有的对象,检查它们的状态,并且把它们的数据提交到GPU——这可是在每一帧都发生的事啊!(好恐怖啊!)
别慌,我们下一步就来搞定这个问题。如果在你的游戏中的某个部分的几何图案处于静态,不发生(或者很少发生)变化,可以在这个Sprite上调用flatten方法。Starling将会预处理它和它的子对象数据并提交给GPU。在接下来的帧调用中,它将被正常的绘制,不触发任何CPU处理,也不需要在上传它的数据给GPU。
这是一个非常棒的特性,这潜在地大量减轻了GPU的负担。但是要注意的是即便扁平化的sprite们被从状态变更的苦难中隔离了出来:如果被扁平化的Sprite中包含有不同渲染状态的子对象,它仍然是会被多步骤的绘制的。
QuadBatch类
尽管扁平化的Sprite速度很快很好用,但是仍然存在一些必要的开销:
当你向一个Sprite添加子对象时,它们将会派发ADDED和ADDED_TO_STAGE事件,这可能诱发在它们身上以及其子对象身上的开销。
像所有容器类显示对象一样,你只能将同一个对象向其添加一次。
为了摆脱这些限制,你可以屈尊使用一个Starling用于内部批量处理图像的较低级别的类:QuadBatch,它工作起来是这样的:var quadBatch:QuadBatch = new QuadBatch();
var image:Image = new Image(texture);
quadBatch.addImage(image);
for (var i:int=0; i<100; ++i)
{
image.x += 10;
quadBatch.addImage(image);
}
`
你注意到了吧,你可以把同一个对象想添加多少次,就添加多少次(作为比照,你可以把同一个Image向一个Sprite在不同位置添加N次试试看)!此外,添加它们不会触发任何事件派发。同时,想当然的是它有如下的缺点:所有你添加的这些对象必须具备相同的状态(例如说,来自同一个atlas)。第一个你添加到QuadBatch的图片将会决定它的状态。之后你也不能改变它们的状态,除非完全重置这个QuadBatch
你只能向其添加Image,Quad,QuadBatch类的实例。
这货是个单行线,只能向上面添加对象。想移除对象只能完全重置它。
因此,它只适合在非常特殊的状态下使用(例如说:Bitmap Font现在就是直接采用QuadBatch),在以上提到的办法里面,它是最高效的渲染办法了,没有之一。使用位图字体(Bitmap Font)
TextFields(文本框类)支持两种不同的字体:真类型字体和位图字体(True Type fonts and Bitmap Fonts.)
真类型字体非常易用:通常只要绑定对应的“ttf”文件就可以搞定。对于静态文本框来说尽管它们包含了成百上千的字符,真类型字体处理起来也不是问题。Starling会将文字们渲染成一张位图,然后像显示其他素材一样显示就可以了。但是如果对于频繁变化的短字符来说(比如:分数显示),它就太慢了。如果你的游戏需要显示任何非ASCII的字符(比如说我们天朝汉文或者阿拉伯语)时,真类型字体恐怕是你唯一的选择。位图字体是受限于资源尺寸的(想想吧,作为一个天朝本科生你起码要掌握3000+汉字才能混的下去,你不可能把3000个字以看得清的尺寸排列在一张2048像素见方的位图里的)。
使用位图字体的文本框可以非常快速地创建和更新。它还具备一个优点是它们除了原始字体资源意外的任何内存资源。这使得它们成为在Starling中显示文字的首选方案。我建议在所有可以使用它们的地方使用。弄清楚你是否真的需要Mipmaps
Mipmaps是你资源的序列缩小采样,旨在提升渲染速度和减少图形锯齿效果。
[![](https://archive.writeitdown.site/MipMap_Example_STS101.jpg)](https://archive.writeitdown.site/MipMap_Example_STS101.jpg)在默认情况下,Starling每次都为加载的资源做了这个操作(通过Texture.fromBitmap[Data]方法创建资源时),在很多情况下,这是个不错的选择:它会提升图片被缩放时候的渲染速度,并可以避免恶劣的锯齿效果。 然而在某些情况下,我们需要不让Starling创建Mipmaps:在需要使素材加载得更加迅速时。
无需对图像做模糊处理时。指定得缩放比例会让你得图片看起来比较模糊,如果不使用mipmapping,它们看起来会比较尖锐(另外,可以尝试对这些图像使用TextureSmoothing.TRILINEAR来弥补效果上的不足)
简而言之,禁用mipmaps会使你的游戏在加载资源时速度变快;但是在图像被缩放的时候渲染速度会变慢——要禁用mipmaps,可以使用Texture.fromBitmap[Data]方法的对应属性设置。使用BlendMode.NONE
如果你有一些素材是完全不透明的矩形素材,请禁用它们的混合模式(BlendMode)吧,就当是帮帮GPU君。对大幅的背景图片尤其必要。不要惧怕由此带来的状态变更,它值!` backgroundImage.blendMode = BlendMode.NONE; `
使用stage.color 如果你的背景是纯色的话,请使用设置stage颜色的办法取代添加一个Texture或者画一个有色的Quad上去的办法。Starling需要每一帧都清空并重绘这些附加的对象,然而——如果你只是改变了stage的颜色,这个处理中将不会耗费任何开销在这上面。这简直就像免费的午餐一般啊!` [SWF(backgroundColor="#ff2255")] public class Startup extends Sprite { // ... } `
避免频繁调用“width”和“height” 宽度(width)和高度(height)属性比它们看起来如此直观的名字要高能耗的多,特别是在Sprite上(一个矩阵对象每次都要被计算,然后每个子对象的定点都要和矩阵做乘操作……对不起啊小w和小h我不知道你们一直以来是这么苦) 因此,要尽量避免频繁地调用它们,例如,在一个循环中,某些情况下可以使用一个变量存放它们。` // 翔代码 for (var i:int=0; i<numChildren; ++i) { var child:DisplayObject = getChildAt(i); if (child.x > wall.width) child.removeFromParent(); } // 不错 var wallWidth:Number = wall.width; for (var i:int=0; i<numChildren; ++i) { var child:DisplayObject = getChildAt(i); if (child.x > wallWidth) child.removeFromParent(); } `
将容器设置为不可触摸 当你在界面上移动鼠标/手指时,Starling需要找出你到底捅在哪个对象上了。这是一个非常耗能的操作,因为需要遍历你所有的显示对象然后执行一个hitTest函数。 所以,如果能把一些压根不需要被触摸的对象设置为不可触摸是非常有效的办法。最好把根容器设置为不可触摸,这样Starling就不用总是遍历它所有的子对象了。` // 很好~ for (var i:int=0; i<container.numChildren; ++i) containter.getChildAt(i).touchable = false; // 更好~~ container.touchable = false; `
使用新的事件模型 从Starling1.2版本开始,有了一个派发事件的新办法:` // 老办法 object.dispatchEvent(new Event("type", bubbles)); // 新办法 object.dispatchEventWith("type", bubbles);
新办法好像没什么不同也是派发了一个事件对象出去,但是在这表象背后,它采用的是对象池处理你的事件(一下子高端大气了吧,池啊)。使用这种办法可以帮GC君省去很多工作,所以,它易写又高能,是当前最佳的事件派发办法。(除非你要派发的事件是一个Event类的子类,新办法不适用于这个情况)。
打完收功!!!
资源:
Mipmap