TexturePacker是一個常用的制作sprite sheet的工具,它提供了很多實用的功能。
一般我們制作sprite sheet都是使用他的gui版本,純手工操作,就像下面這張圖示的一樣。
剛開始我們的項目也是使用這種方式,但后來發現這種方式在開發中有很大的問題。隨着圖片的增多,sprite sheet會越來越多,為了生成這些sprite sheet需要做很多重復的手工勞動,再考慮到給Android平台打包的sprite sheet配置和iOS的不同,還有包括圖片變更,配置優化等情況,算下來光打包sprite sheet就需要巨大的工作量,這還不考慮由於手工誤操作造成的各種問題。
於是我就考慮,如何盡可能地減少打包sprite sheet的工作量,提高開發的效率。后來通過搜索,看到raywenderlich上一篇關於使用TexturePacker的文章,里面比較詳細地介紹了TexturePacker的用法,特別還提到了它的命令行工具的使用以及這個工具和xcode的集成,這給了我想要的答案。
接下來講一下我在項目中如何使用這個TexturePacker的命令行工具以及實用它的一些經驗。
---------------------------------------正式開始的分割線-----------------------------------------
具體下載和安裝TexturePacker以及它命令行工具的方法就不說了,上面提到的那篇文章里有較詳細的說明。一些准備就緒后,我們可以在命令行里執行texturepacker命令,正常情況下你將會看到texturepacker的各種參數以及使用方法的說明,如下圖:
接下來為了方便說明,我們新建一個測試工程foo,這里以quick-cocos2d-x-2.2.1-rc引擎創建的工程為例,創建好后目錄結構如下圖:
我們需要一個目錄去保存所有原始的(未打到sprite sheet里的)圖片,這里我們新建個目錄叫originalImages,然后找些圖片,丟進這個目錄,並將他們分類到不同的文件夾,接着我們再創建一個目錄,用來存放我們打包sprite sheet的腳本工具,我們起名叫tools,然后,我們再創建一個目錄spriteSheets,用於存放打好的圖片,最后,一般我們會將工程用到的圖片存放到res/images目錄里面,所以為了清楚,再創建一個這個文件夾,最終目錄結構如下圖所示:
接下來我說一下思路,我們的腳本工具存放在tools文件夾中,運行之后會去遍歷originalImages這個目錄下的所有文件夾,然后將每個文件夾中的圖片打包為一個sprite sheet,這個sprite sheet名字與該文件夾的名字相同,接着將打包后的sprite sheet文件復制兩份,一份存入spriteSheets目錄中,另一份拷貝到我們程序使用圖片的目錄。
舉例來說,當我運行腳本,會生成三份sprite sheet,分別是button.png,button.plist,checkBox.png,checkBox.plist,common.png,common.plist,他們分別會存放入spriteSheets目錄和res目錄下的images目錄中(一般res目錄下的images目錄用來存放程序中用到的圖片)。
---------------------------------------漸入佳境的分割線------------------------------------------
好的,一切准備就緒,我們開始說說這個腳本究竟要如何編寫。
首先我們需要大概了解一下texturepacker的一些常用參數。
--format
指定sprite sheet的格式,默認是cocos2d,做cocos2d-x項目的話,就選cocos2d就行。可選的選項如下:
--texture-format
非常重要的一個屬性,指定texture的格式。如果我們做iOS上的游戲,一般都會使用PVR,因為這個format的texture是專門為蘋果iPhone和iPad的圖形處理器優化的,而Android因為設備硬件多種多樣,所以我們一般可能會選用png格式的,感興趣的朋友可以自己搜索一下相關內容。這個參數如果不指定值的話texturepacker會嘗試去根據sprite sheet的命名來自動選擇一個合適的format。具體的選項如下:
--data
指定data文件的名字,也就是plist文件的名字
--sheet
sprite sheet文件的名字
--enable-rotation
是否開啟旋轉。一般我們會開啟,為了更有效率的將散圖打在一起。
--scale
在創建sprite sheet之前為所有散圖做一個調整scale的操作,比如,如果是0.5,那么就把原始圖都壓縮一般大小,再存入sprite sheet中
--shape-padding
設置每個圖片在sprite sheet中的間隔,默認是2
--max-size
sprite sheet的最大尺寸,你不可能將所有圖片都打入到一張sprite sheet里,因為沒有設備能支持這樣的sprite sheet,於是需要限定大小:)。
--opt
這個是很重要的一個屬性,決定了sprite sheet的像素格式,這個屬性可以很大程序改變sprite sheet所占的內存。常用的選項如下:
--trim
為了能在一張sprite sheet加入更多的圖片,裁減掉原始圖片的空白像素,但是使用的時候還是按照圖片的原始尺寸來使用。
--smart-update
智能更新,為了避免重復生成相同內容的sprite sheet,texturepacker會檢查現存的sprite sheet和將要生成的sprite sheet內容是否相同,如果不同再生成新的,如果相同則不生成。
---------------------------------------激動人心的分割線------------------------------------------
好了,最后激動人心的時刻到了,我們上腳本!(腳本寫的一般,多包涵)
1 #! /bin/bash 2 3 CURRENT_DIR=`dirname $0` 4 5 # input paths 6 IMAGE_DIR=$CURRENT_DIR/../originalImages 7 8 # path that game proj use 9 GAME_IMAGE_PATH=$CURRENT_DIR/../res/images 10 11 # temporary path to place the sprite sheets 12 OUTPUT_PATH=$CURRENT_DIR/../spriteSheets 13 OUTPUT_PATH_PVR=$OUTPUT_PATH/packagedPVR 14 OUTPUT_PATH_PNG=$OUTPUT_PATH/packagedPNG 15 16 # path of the texture packer command line tool 17 TP=/usr/local/bin/TexturePacker 18 19 # $1: Source Directory where the assets are located 20 # $2: Output File Name without extension 21 # $3: RGB Quality factor 22 # $4: Scale factor 23 # $5: Max-Size factor 24 # $6: Texture Type (PNG, PVR.CCZ) 25 # $7: Texture format 26 pack_textures() { 27 28 ${TP} --smart-update \ 29 --texture-format $7 \ 30 --format cocos2d \ 31 --data "$2".plist \ 32 --sheet "$2".$6 \ 33 --maxrects-heuristics best \ 34 --enable-rotation \ 35 --scale $4 \ 36 --shape-padding 1 \ 37 --max-size $5 \ 38 --opt "$3" \ 39 --trim \ 40 $1/*.png 41 42 } 43 44 # check the output path 45 46 if [ -d $OUTPUT_PATH ];then 47 : 48 else 49 mkdir $OUTPUT_PATH 50 fi 51 52 if [ -d $OUTPUT_PATH_PVR ] 53 then 54 : 55 else 56 mkdir $OUTPUT_PATH_PVR 57 fi 58 59 if [ -d $OUTPUT_PATH_PNG ] 60 then 61 : 62 else 63 mkdir $OUTPUT_PATH_PNG 64 fi 65 66 # do the job 67 for i in $IMAGE_DIR/* 68 do 69 if [ -d $i ] 70 then 71 spriteSheetName=`basename $i` 72 pack_textures $i $OUTPUT_PATH_PNG/$spriteSheetName 'RGBA8888' 1 2048 'png' "png" 73 pack_textures $i $OUTPUT_PATH_PVR/$spriteSheetName 'RGBA8888' 1 2048 'pvr.ccz' "pvr2ccz" 74 fi 75 done 76 77 # cp them to the game proj image path 78 79 cp -f $OUTPUT_PATH_PVR/* $GAME_IMAGE_PATH
將腳本的內容保存到一個文件中,命名后把后綴改為command,比如我是這個樣子的:
然后記得在命令行里改一下腳本的權限,最后雙擊一下腳本,新鮮的sprite sheets就打包出來了,如果有什么圖片的改動,只需要修改originalImages這個目錄下的圖片,然后雙擊一下腳本,新的sprite sheet就生成好了,再也沒有了無聊煩人的手工勞動,向TP的GUI說再見吧!是不是很爽?:)
----------------------------------------最后的分割線-----------------------------------------
最后簡單說一下在腳本里我們做的事情:
在腳本中我們針對originalImages里面每一個文件夾中的圖,生成了兩份sprite sheet,這兩份唯一的區別是一份是pvr2ccz格式的,一份是png格式的,其他的屬性都相同:像素格式RGBA8888,scale為1,最大尺寸為2048*2048。在生成完成后,將所有的sprite sheet拷貝到了spriteSheets這個文件夾,並把其中pvr格式的sprite sheet拷貝到了我們工程使用的圖片目錄里。
OK,大概就是這樣子,那個腳本可以根據項目具體需求去改,我寫的很簡單,也沒加什么log,這個其實完全可以寫得更智能話寫,這就留給各位去發揮了。
----------------------------------一些更新和補充----------------------------------------
最近有園子里的朋友和我交流了幾個問題,我覺得其中有2個挺不錯的,具體交流的內容在本文的留言里面有,不過為了方便大家查閱,我把它們整理(其實主要是截圖,我是有多懶=。=)了一下,整合到這個篇文章中:
問題1:來自園友 tanyongdahaoren
“
”
答案:
“
”
這個問題回答的比較明確,我就不過多解釋了:)
(這里忍不住吐槽一下博客園的插入代碼功能,在回復里面沒有bash的選項不說,在文章中bash的代碼明顯沒有按照bash的腳本着色,“/*”竟然按照注釋理解了,真心汗一個)
問題2:來自園友sousou123
“
”
這個園友主要的想法是考慮如何用TexturePacker把單張的png圖片轉換成pvr格式的圖片。我一開始建議它用蘋果官方的工具texturetool,但后來我意識到,這個texturetool相對TexturePacker有很多不方便的地方,比如它對原始圖片的格式有硬性要求,必須至少滿足:
- Height and width must be at least 8.
- Height and width must be a power of 2.
- Must be square (height==width)
而TexturePacker雖然可以做png到pvr轉換的事情,但是畢竟設計目的是打包sprite sheet用的。
不過經過和他的討論,最終我給出了TexturePacker的解決方案:
“
”
這段腳本所做的事情是遍歷images這個文件夾下的所有png圖片,然后對每一張小圖片都做一次打包操作,打包后的圖片格式為pvr,這就相當於對每一張圖片做了一次格式的轉換:從png到pvr。這個做法雖然不同於TexturePacker的設計初衷,但畢竟是可行的,而且很方便。
這里要注意一點,我們相對於之前打包的腳本多增加了一個參數:--size-constraints
這個參數非常關鍵,它決定了最終生成的sprite sheet的尺寸是否會受POT(Power Of Two)格式的限制。一般情況下我們生成sprite sheet的尺寸都是寬高相等,並且都是2的N次方。而對我們現在這個轉換圖片格式的需求,這個限制就多余了,因為我們肯定希望原始圖片多大尺寸,最終轉換得到的圖片就是多大尺寸,所以這里我們設置這個參數的值為AnySize。
--size-constraints AnySize
不得不說TexturePacker這個工具的功能真的很強大,作者考慮問題非常得全面~
這個參數在GUI里面在這里:
還有一點小問題是,對於每一個sprite sheet,都會需要生成一個data文件,這里我們不需要這個data文件,所以在參數里面我們就隨便叫了一個dummy.plist:)其他的參數你們可以按需修改。
好了,更新部分就是這么多,最后感謝一下園友sousou123和tanyongdahaoren,通過解決他們的問題也讓我學到了新的東西:)
感謝大家的收看~ 如果有問題可以留言或者私信我,我會盡量回覆大家。
最近剛開始專門寫博客,如果表達的不好,或者有其他方面問題,也請大家多提寶貴意見:)
最最后,原創文章,轉載請注明出處,謝謝:)