SpriteSheet精靈動畫引擎


動畫渲染性能對比Flash中動畫制作方式有多種,如矢量動畫、位圖幀動畫、精靈序列圖等等。針對不同的制作方式,對同一個角色動畫進行如下測試:一個角色在屏幕上顯示5個實例,對應呼吸、施法、行走、受傷、普攻狀態。

測試運行的環境:

l Release version of Flash Player 12.0.159.1

l AMD Phenom(tm) II X4 830 Processor(2800 Mhz)

l Microsoft Windows 7 專業版 (32位)

得出測試結果如下表所示,為了節約大小資源中所用位圖均為png8。

表1:不同動畫渲染效率對比(具體測試數據與所使用資源有關)

渲染方式
描述
CPU
內存(KB)
文件大小(KB)
時間軸
矢量
12
6m
24
矢量+cacheAsBitmap
12
6.2m
24
位圖
2
6.8m
534
位圖+導出類
2
13m
537
位圖渲染
SpriteSheet精靈序列圖
1
11m
220 png + 31 json/xml
從上表可以得出,精靈序列圖消耗CPU最少,並且文件大小適中,但內存消耗較大。對於游戲來說,CPU銷毀越小,幀頻可以越大,游戲越流暢。

clip_image002

圖1:精靈序列圖動畫效果及幀頻、內存信息

可以看出使用精靈序列圖幀頻和內存都非常穩定,內存沒有頻繁的gc,gc非常消耗cpu會造成游戲卡頓現象。反觀其它渲染方式,會發現內存不穩定,這對游戲性能是一個風險。

clip_image004

圖2:矢量動畫

clip_image006

圖3:矢量+cacheAsBitmap動畫

clip_image008

圖4:位圖動畫

clip_image010

圖5:位圖+導出類

下面詳細介紹下精靈序列圖的原理及注意事項。

精靈序列圖SpriteSheet精靈序列圖是一種大的網格式位圖,其中每一格都對應着一個動畫截屏,每一動畫截屏對應動畫的一幀。精靈序列圖通常采用PNG格式,這樣可以使用Alpha通道。

clip_image011

圖6:角色受傷動畫序列圖

除了大位圖之后,還必須有一個對應的數據描述文件,常用的格式有json、json-array、xml。數據描述文件,用來指定每幀動畫在大圖中的位置(偏移位置、寬、高等等),如json格式如下:

JSON格式描述數據:{"frames": {

"呼吸0000":{

          "frame": {"x":0,"y":0,"w":110,"h":110}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":110,"h":110}, "sourceSize": {"w":110,"h":110}

},
"呼吸0001":
{

          "frame": {"x":110,"y":0,"w":110,"h":110}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":110,"h":110}, "sourceSize": {"w":110,"h":110}

},

},
"meta": {

          "app": "Adobe Flash CS6", "version": "12.0.0.481", "image": "jsonformat.png", "format": "RGB8", "size": {"w":1024,"h":1024}, "scale": "1"

}
}
其中:

Key-"呼吸0000":表示幀的名字/對應圖片文件名(json-array格式中,使用filename字段表示);

frame: 圖片在大圖中的偏移位置(左上角為原點)和大小(未旋轉前) 需要注意這里的圖片大小是圖片未旋轉前的大小;

rotated: 是否旋轉(順時針方向);

trimmed: 是否有去掉周圍多余的透明部分;

spriteSourceSize: x,y表示圖片未去掉周圍透明部分的偏移量,這是如果需要還原圖片原先的大小要用的;

sourceSize: 圖片的原始大小,包含透明部分;

渲染機制精靈序列圖使用位塊圖像傳輸(bit-blitting,blit = Bit-Block Image Transfer)技術,它涉及到使用位圖來渲染最終的顯示效果。 將需要顯示的效果,像素會繪制到一個已添加到舞台上的位圖中。為了表現動畫效果,會在一個循環中更新位圖的像素。關鍵步驟如下:

1) 加載動畫中需要的Sprite Sheet位圖數據(.png文件)

2) 在displayList中添加一個BitmapData目標位圖數據(畫布)

3) 向畫布復制或者擦除游戲(copyPixel vs draw)

4) 根據游戲顯示層次順序將Sprite Sheet復制到畫布

5) 在游戲循環中重復第3、4步

copyPixel的效率比draw高,所以一般情況下,使用copyPixel復制圖像到畫布。

內存占用在所有動畫渲染方式中,精靈序列圖對幀頻的影響是最小的。因為精靈序列圖會預先被緩存到BitmapData實例中,這就可以使渲染速度變得更快。一定要隨時注意內存的占用,仔細把控,詳盡規划。精靈序列圖之所以效率高,是由於位圖序列都緩存在內存中從而可被快速調取。但這樣也可能會導致巨大的內存開銷。

注意:一張圖片占用多少內存只取決於圖像的尺寸,而與圖像文件的類型和圖像壓縮無關。

位圖所占內存(字節)= 位圖寬度 x 位圖高度 x 4

假設一幀的圖片的大小為200x400像素,占用內存312.5KB。如果一個動畫18幀,則占用內存約5.5M。如果一個角色包含4個方向或4個動作的動畫,則占用內存約22M。同屏在線10個角色,則占用內存約220M。

SpriteSheet工具現在Flash cs6已經集成了將動畫導出為SpriteSheet,如下圖所示:

clip_image012

圖7:Flash cs6導出SpriteSheet設置

TexturePacker也可以打包圖片為SpriteSheet格式。

精靈序列圖引擎前面介紹了精靈序列圖的原理及注意事項,下面實現一個精靈序列圖動畫的引擎,支持Flash Cs6/TexturePacker導出的JSON、JSON-Array、Starling(XML)3種數據格式。

clip_image014

圖8:精靈序列圖引擎類圖

SpriteSheet類clip_image015

圖9:SpriteSheet類

SpriteSheet繼承自flash.display.Sprite,包含一個bitmap成員用作畫布。使用定時器Timer來驅動動畫循環。

SpriteSheet使用類似Movieclip,提供play()、stop()、gotoAndPlay()、gotoAndStop()接口,並支持鼠標事件。

mAnimation成員(Animation實例)用於描述SpriteSheet當前表示的動作,如游戲中一個角色包含呼吸、行走、施法、受傷動作。

mTextureAltas成員(TexureAtlas實例)用於維護整個精靈序列圖數據,並負責將特定幀位圖復制到畫布顯示。

TexureAtlas類TexureAtlas類保存了整個精靈序列圖數據,並根據SpriteSheet的當前動作,生成構成動畫的所有幀在精靈序列圖中的偏移和大小。

Animation類Animation動畫信息類。

l seqName表示動畫序列名(e.g. "walk")

l delay表示幀間隔

l loop表示動畫是否循環播放

l arFrames:Vector.<SpriteFrame>;// 幀信息數據

SpriteFrame類SpriteFrame類表示圖片在大圖中的偏移位置(左上角為原點)和大小(未旋轉前)等等信息,根據數據描述文件生成。

clip_image016

圖10:SpriteFra示意

JsonFormat、JsonArrayFormat、XmlFormat類SpriteSheet序列圖數據解析類,分別解析對應格式的描述數據。

Demo實例SpriteSheet使用非常簡單,與原生Movieclip差異不大。下面的例子分別加載JSON、JSON-Array、XML格式的數據及對應的PNG資源,然后創建SpriteSheet實例。

Demo:
package
{

       import com.as3game.asset.AssetManager; import com.as3game.spritesheet.SpriteSheet; import com.as3game.spritesheet.vos.DataFormat; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.MouseEvent; import flash.filters.ColorMatrixFilter; import flash.text.TextField; /** * ... * @author Tylerzhu */ public class TestSpriteSheet extends Sprite { public function TestSpriteSheet() { SWFProfiler.init(stage, this); AssetManager.getInstance().getGroupAssets("spritesheets-json", ["data/json/jsonformat.json", "data/json/jsonformat.png"], onAnimLoaded); AssetManager.getInstance().getGroupAssets("spritesheets-xml", ["data/xml/xmlformat.xml", "data/xml/xmlformat.png"], onAnimLoadedXML); AssetManager.getInstance().getGroupAssets("spritesheets-jsonarray", ["data/json-array/jsonarrayformat.json", "data/json-array/jsonarrayformat.png"], onAnimLoadedJsonArray); } private function onAnimLoaded():void { var bitmapData:BitmapData = AssetManager.getInstance().bulkLoader.getBitmapData("data/json/jsonformat.png"); var sheets:* = AssetManager.getInstance().getContent("data/json/jsonformat.json"); var sp:SpriteSheet = new SpriteSheet(bitmapData, sheets, DataFormat.FORMAT_JSON); sp.setAction("呼吸", 14); sp.play(); addChild(sp); } private function onAnimLoadedXML():void { var bitmapData:BitmapData = AssetManager.getInstance().bulkLoader.getBitmapData("data/xml/xmlformat.png"); var sheets:* = AssetManager.getInstance().getContent("data/xml/xmlformat.xml"); var sp:SpriteSheet = new SpriteSheet(bitmapData, sheets, DataFormat.FORMAT_XML); sp.setAction("呼吸", 15); sp.play(); sp.y = 150; addChild(sp); } private function onAnimLoadedJsonArray():void { var bitmapData:BitmapData = AssetManager.getInstance().bulkLoader.getBitmapData("data/json-array/jsonarrayformat.png"); var sheets:* = AssetManager.getInstance().getContent("data/json-array/jsonarrayformat.json"); var sp:SpriteSheet = new SpriteSheet(bitmapData, sheets, DataFormat.FORMAT_JSON_ARRAY); sp.setAction("呼吸", 15); sp.play(); sp.y = 300; addChild(sp); } }

}
原文來自:技術之家


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM