SpriteKit導(dǎo)入TexturePacker導(dǎo)出的紋理集

1、為什么要使用紋理集?

紋理集是將多張小圖合成一張大圖,使用紋理集有以下優(yōu)點(diǎn):
1、減少內(nèi)存占用,減少磁盤占用;
2、減少磁盤讀取次數(shù),一次性讀取一張大圖比多次讀取多張小圖速度更快;
3、減少OpenGL繪制次數(shù);
可以參照這里的講解https://blog.csdn.net/tonny_guan/article/details/26232685

2、SpriteKit自帶的紋理集工具SKTextureAtlas

SKTextureAtlas的用法比較簡單,接口也很簡單。將紋理圖片放入文件夾,并將文件夾命名為xxx.atlas,然后導(dǎo)入工程,項(xiàng)目中就可以使用方法:

+ (instancetype)atlasNamed:(NSString *)name;

創(chuàng)建紋理集,之后使用方法

- (SKTexture *)textureNamed:(NSString *)name;

獲取紋理集中的紋理。

3、TexturePacker

實(shí)際上大多數(shù)的游戲開發(fā)者都會(huì)用TexturePacker工具來打包紋理集,TexturePacker可以將一系列的小圖整合成一張大的.png圖片,外加一個(gè)描述文件,描述文件可以是.plist格式或者其他格式。描述文件的作用是描述每張小圖在大圖中的位置,旋轉(zhuǎn)等信息。TexturePacker支持市面上流行的Unity,Cocos等游戲引擎,在導(dǎo)出的時(shí)候可以選擇導(dǎo)出不同的游戲引擎。
遺憾的是SKTextureAtlas不支持TexturePacker導(dǎo)出的格式,而.atlas的文件夾的形式也不適合圖片從服務(wù)器端加載的情況。因此我想自己寫一個(gè)工具,支持讀取TexturePacker導(dǎo)出的支持Cocos格式的.plist文件,如果需要支持其他引擎,可以分析相應(yīng)的描述文件做相應(yīng)的調(diào)整。

4、TexturePacker導(dǎo)出的Cocos格式的.plist描述文件分析

.plist文件是一個(gè)字典,主要分為兩部分:
1、metadata:主要包含格式,png圖片大小,png圖片的名稱等信息

image.png

2、frames:這一部分就是原來的各個(gè)小圖片在合成到一張大圖片中之后的控制信息,這是一個(gè)數(shù)組。每個(gè)數(shù)組的數(shù)據(jù)如下:
aliases:不懂,不重要
spriteOffset:TexturePacker在合圖的時(shí)候可以選擇修剪模式(自動(dòng)裁減掉原圖的透明部分),表示裁剪之后的圖中心相對(duì)于原圖中心的偏移量
spriteSize:合圖之后的大小,這個(gè)值會(huì)小于或等于原圖大小
spriteSourceSize:原圖的大小
textureRect:這張圖在整張大圖里面的位置(要注意這個(gè)坐標(biāo)是以左上角為原點(diǎn)的)
textureRotated:是否順時(shí)針旋轉(zhuǎn)90度,合圖的時(shí)候可以勾選rotated,有的小圖有可能會(huì)被旋轉(zhuǎn)以最大限度利用空余部分
更詳細(xì)的介紹可以參考https://www.codeandweb.com/blog/2016/01/29/cocos2d-plist-format-explained
image.png

5、WPTeatureAtlas和WPTexture

我寫的WPTeatureAtlas主要負(fù)責(zé)解析.plist文件,存儲(chǔ)解析出的紋理,提供便捷方法訪問紋理

@interface WPTextureAtlas : NSObject

@property(nonatomic, strong, readonly) NSString *plistFile;
@property(nonatomic, strong, readonly) NSString *imageFile;
@property(nonatomic, strong, readonly) SKTexture *totalTexture;
@property(nonatomic, strong, readonly) NSMutableDictionary<NSString *, WPTexture *> *texturesDict;
@property(nonatomic, strong, readonly) NSArray<WPTexture *> *sortTexturesArr;

- (instancetype)initWithPlistFile:(NSString *)plistFile
                        imageFile:(NSString *)imageFile;

- (WPTexture *)textureWithName:(NSString *)name;

@end

WPTexture繼承自SKTexture,并添加前面描述的.plist文件中的屬性

@interface WPTexture : SKTexture

// 裁剪后圖片的中心相對(duì)于裁剪前圖片的中心偏移量
@property(nonatomic, assign, readonly) CGPoint spriteOffset;
// 裁剪之后的大小
@property(nonatomic, assign, readonly) CGSize spriteSize;
// 裁剪之前的大小
@property(nonatomic, assign, readonly) CGSize spriteSourceSize;
// 是否順時(shí)針旋轉(zhuǎn)90度
@property(nonatomic, assign, readonly) BOOL textureRotated;

+ (instancetype)textureWithDict:(NSDictionary *)dict
                   totalTexture:(SKTexture *)totalTexture;

@end

下面是解析代碼,這里面主要用到了SKTexture的textureWithRect:inTexture:方法;這里對(duì)textureRect做了轉(zhuǎn)換,因?yàn)樵贠penGL里面紋理坐標(biāo)是左下角為原點(diǎn),寬和高都是1,textureWithRect:inTexture:方法里面的rect參數(shù)就是紋理坐標(biāo)下面的rect。這個(gè)方法返回的texture就是一整張大圖中的一部分,達(dá)到我們截取一部分紋理的目的。

+ (instancetype)textureWithDict:(NSDictionary *)dict
                   totalTexture:(SKTexture *)totalTexture
{
    BOOL textureRotated = [dict[@"textureRotated"] boolValue];
    
    CGRect rect = CGRectFromString(dict[@"textureRect"]);
    // TexturePacker中獲取的rect是原點(diǎn)在左上角點(diǎn),但是SpriteKit、OpenGL默認(rèn)加載的紋理坐標(biāo)是原點(diǎn)在左下角點(diǎn)
    CGFloat x, y, w, h;
    if (textureRotated) { // 如果順時(shí)針旋轉(zhuǎn)了90度,那么width和heigth調(diào)換了
        x = rect.origin.x / totalTexture.size.width;
        y = (totalTexture.size.height - rect.origin.y - rect.size.width) / totalTexture.size.height;
        w = rect.size.height / totalTexture.size.width;
        h = rect.size.width / totalTexture.size.height;
    } else {
        x = rect.origin.x / totalTexture.size.width;
        y = (totalTexture.size.height - rect.origin.y - rect.size.height) / totalTexture.size.height;
        w = rect.size.width / totalTexture.size.width;
        h = rect.size.height / totalTexture.size.height;
    }
    
    WPTexture *texture = [WPTexture textureWithRect:CGRectMake(x, y, w, h) inTexture:totalTexture];
    
    texture.spriteOffset = CGPointFromString(dict[@"spriteOffset"]);
    texture.spriteSize = CGSizeFromString(dict[@"spriteSize"]);
    texture.spriteSourceSize = CGSizeFromString(dict[@"spriteSourceSize"]);
    texture.textureRotated = textureRotated;
    
    return texture;
}

6、支持紋理的裁剪和旋轉(zhuǎn)

TexturePacker在合成圖片的時(shí)候是支持裁剪和旋轉(zhuǎn)的,裁剪可以裁剪掉透明像素,而旋轉(zhuǎn)則可以更大限度利用空間。但是前面的SKTexture創(chuàng)建的紋理僅僅是截取大圖中的一部分,如果這個(gè)圖被裁剪,或者旋轉(zhuǎn)了,那么我們直接在SKSpriteNode中使用SKTexture會(huì)導(dǎo)致貼圖的位置或方向不正確,這個(gè)時(shí)候我們需要對(duì)SKSpriteNode做幾何變換才能達(dá)到正確的效果。我寫了個(gè)WPSpriteNode來處理這種情況:

@interface WPSpriteNode : SKSpriteNode

+ (instancetype)spriteNodeWithWPTexture:(WPTexture *)texture;
- (instancetype)initWithWPTexture:(WPTexture *)texture;

@end

@implementation WPSpriteNode

+ (instancetype)spriteNodeWithWPTexture:(WPTexture *)texture
{
    return [[WPSpriteNode alloc] initWithWPTexture:texture];
}

- (instancetype)initWithWPTexture:(WPTexture *)texture
{
    if (self = [super initWithTexture:texture]) {
        if (texture.textureRotated) {
            // 順時(shí)針轉(zhuǎn)了90度之后,原來的Y轉(zhuǎn)成與X軸同向,而原來的X變成與-Y同向
            self.anchorPoint = CGPointMake(0.5 - texture.spriteOffset.y / texture.spriteSize.height, 0.5 + texture.spriteOffset.x / texture.spriteSize.width);
            // 逆時(shí)針轉(zhuǎn)回90度
            self.zRotation = M_PI_2;
        } else {
            // 根據(jù)偏移量將裁剪后的圖反向移回原圖的中心
            self.anchorPoint = CGPointMake(0.5 - texture.spriteOffset.x / texture.spriteSize.width, 0.5 - texture.spriteOffset.y / texture.spriteSize.height);
        }
    }
    
    return self;
}

@end

demo工程在這里

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Cocoa利用TexturePacker創(chuàng)建的紋理圖集實(shí)現(xiàn)角色的幀動(dòng)畫 by 大熊貓侯佩 什么是TexturePa...
    hopy閱讀 3,349評(píng)論 0 5
  • DragonBones舊版本動(dòng)畫文件轉(zhuǎn)新版動(dòng)畫 DragonBones(簡稱:DB)2.2版本的骨骼動(dòng)畫是早期Co...
    丶忒閱讀 4,866評(píng)論 1 1
  • 推開沾滿灰塵的鏤榥 陽光 透過指縫照在我滿是胡茬的臉上 微風(fēng) 偷偷吹散你殘留的味道 回憶的沙漏 又倒轉(zhuǎn)了 果然 還...
    CHITYzz首肯閱讀 821評(píng)論 0 0
  • 最美戶外瑜伽行前段時(shí)間已結(jié)束,現(xiàn)在整理各地圖片,看著真心喜歡,曬曬圖,看看瑜伽男神女神們是如何積極向上生活的哈!
    二月份的天閱讀 252評(píng)論 0 0
  • 田華20171130(第79天) 【一個(gè)目標(biāo)】三個(gè)月店里完成純收入10萬元【與此相關(guān)的好種子】 (1)格西老師智庫...
    竹林千頃田華閱讀 413評(píng)論 0 1

友情鏈接更多精彩內(nèi)容