SpriteKit之輕量級瓦片地圖生成工具SDmapNode詳解


SDmapNode簡介


近來,一直研究SpriteKit游戲框架,但是發(fā)現(xiàn)網(wǎng)上的相關(guān)資料并不是太全面,比如瓦片地圖的創(chuàng)建方式,網(wǎng)上只有TML地圖文件的創(chuàng)建方式,想直接直接使用數(shù)組形式創(chuàng)建和txt文件形式創(chuàng)建,網(wǎng)上并沒有比較好的實(shí)現(xiàn)方式,大部分是需要自己封裝,所以,我就封裝了一個瓦片地圖的生成的類SDmapNode,對于上述的三種形式的創(chuàng)建方式SDmapNode都是支持的.并且使用起來比較簡便,只需要根據(jù)提示屬于對應(yīng)的參數(shù)即可,想TML文件創(chuàng)建形式,只需要在工程中導(dǎo)入TML文件,然后在生成方法填寫TML文件名稱生成即可.


SDmapNode使用說明


注意:使用SDmapNode之前需要導(dǎo)入libz.tbd,這是TML文件形式創(chuàng)建所必須的庫.

瓦片地圖的創(chuàng)建形式是由三種的,下面我們就這三種創(chuàng)建形式來逐一說明.


1.數(shù)組形式創(chuàng)建

數(shù)組形式創(chuàng)建形式應(yīng)該是最接近根源的一種形式.在SDmapNode中,使用數(shù)組形式創(chuàng)建瓦片地圖我們需要注意一下幾項(xiàng).

必看????????

1.每一個圖片的大小尺寸必須一致,比如一張圖片是16x16的,那么其他的都要16x16.
2.需要導(dǎo)入紋理集文件.
3.紋理圖片允許png和jpg格式,想要支持其他格式,請聯(lián)系騷棟,或者修改源碼.
4.圖片的名稱必須為單個字母.
5.4中所說圖片的名稱為單字母的緣由是為了數(shù)組做準(zhǔn)備的.
6.數(shù)組中的每一個元素都是一個字符串.

先導(dǎo)入紋理集文件.這里就不多廢話了.

接著,我們看一下,SDmapNode中是如何實(shí)現(xiàn)使用數(shù)組創(chuàng)建瓦片地圖的.我們需要往初始化方式中傳三個參數(shù),分別是紋理集合的名稱,瓦片的大小尺寸和瓦片地圖的矩陣數(shù)組.初始化方式如下.


-(instancetype)initWithAtlasName:(NSString *)atlasName tileSize:(CGSize)tileSize tileCodes:(NSArray*)tileCodes;

接著,我們說一下實(shí)現(xiàn)原理.首先我們先分解我們的數(shù)組,并且拆分每一個字符串,獲取字符串每一個字符所對應(yīng)的瓦片紋理.代碼如下

for (int row = 0; row <tileCodes.count; row ++) {
            
            //獲取到每一行的排列字符串.
            NSString *lineString = tileCodes[row];
            
            for (int col = 0; col <lineString.length; col ++) {
                
                //截取指定的字符
                NSString *tileCodeString = [lineString substringWithRange:NSMakeRange(col, 1)];
                
                //創(chuàng)建瓦片
                SKSpriteNode *tileCode = [self nodeForCode:tileCodeString];
                
                //設(shè)置瓦片位置
                tileCode.position = [self positionWithRow:row col:col];
                
                
                [self addChild:tileCode];
                
            }
               
        }

獲取完成之后,我們需要根據(jù)每一個字符去我們的紋理集中尋找對應(yīng)的紋理.如果找不到,那么就創(chuàng)建一個空的對象,并且大小與瓦片地圖的大小相同.因?yàn)榧y理集中的圖片名名稱是帶有后綴的,所以目前只設(shè)置了判斷png和jpg類型,如果有其他類型,可以自行修改源碼.

#pragma mark ---- 獲取對應(yīng)的瓦片 ----

-(SKSpriteNode *)nodeForCode:(NSString *)tileCode{
    
    //如果紋理集合為空,返回空.
    if (nil == self.atlas) {
        
        return nil;
    }
    
    
    // 查看當(dāng)前的紋理集中是否包含名為tileCode的紋理
    if ([self isIncludeTextureWithTextureName:tileCode]) {
        
        SKSpriteNode *tile = [SKSpriteNode spriteNodeWithTexture:[self.atlas textureNamed:tileCode]];
        
        //設(shè)置過濾模式
        tile.texture.filteringMode = SKTextureFilteringNearest;
        
        return tile;
        
        
    }else{
        
        
        SKSpriteNode *tile = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:@""]];
        
        tile.size = self.tileSize;
        
        return tile;
        
        
    }
    
    
}

接著上一塊的判斷當(dāng)前的紋理集中是否包含該紋理

#pragma mark ---- 查看當(dāng)前的紋理集中是否包含名為textureName的紋理 ----
-(BOOL)isIncludeTextureWithTextureName:(NSString *)textureName{

    for (NSString *anyName in self.atlas.textureNames) {

        if ([anyName isEqualToString:[NSString stringWithFormat:@"%@.jpg",textureName]]) {
            
            return YES;
        }
        
        
        if ([anyName isEqualToString:[NSString stringWithFormat:@"%@.png",textureName]]) {
            
            return YES;
        }
  
    }

    return NO;

}

上面的創(chuàng)建單元完成之后,接下來我們就需要根據(jù)瓦片的大小以及init中遍歷的下標(biāo)來對單元的position信息進(jìn)行設(shè)置,代碼如下

#pragma mark --- 根據(jù)數(shù)組下標(biāo)返回瓦片的位置信息 ----

-(CGPoint )positionWithRow:(int)row col:(int)col{

    CGFloat x = col *_tileSize.width + _tileSize.width/2;
    
    CGFloat y = row *_tileSize.height + _tileSize.height/2;
    
    return CGPointMake(x, y);

}

那么我們看一下我們在場景如何調(diào)用的,首先我們導(dǎo)入SDmapNode.h頭文件,只需要一個設(shè)置一個數(shù)組,即可.

#import "GameScene.h"

#import "SDmapNode.h"

@implementation GameScene

-(void)didMoveToView:(SKView *)view{

    [super didMoveToView:view];
    
    SDmapNode *mapNode = [[SDmapNode alloc]initWithAtlasName:@"map" tileSize:CGSizeMake(16, 16) tileCodes:[self tileCodesArray]];
    
    mapNode.position = CGPointMake(self.size.width/2, self.size.height/2);

    [self addChild:mapNode];

}
//地圖的二維數(shù)組
-(NSArray *)tileCodesArray{

    return @[
             @"xwxxx",
             @"xqqqx",
             @"xooox",
             @"xooox",
             @"xooox"
             ];
}

效果圖



2.txt文本形式創(chuàng)建

txt文本創(chuàng)建形式和數(shù)組創(chuàng)建形式的原理是一樣的,不同的就是txt文本形式創(chuàng)建是把瓦片地圖所有的創(chuàng)建信息放在一個txt文件中.初始化方式如下.

-(instancetype)initWithTextFileName:(NSString *)fileName;

必看????????

1.txt文本形式創(chuàng)建中txt文本形式必須嚴(yán)格按照txt模板進(jìn)行.
2.要先導(dǎo)入紋理集文件夾.

首先我們在工程中創(chuàng)建一個txt文本.command +N ,然后選擇Other選項(xiàng),創(chuàng)建Empty.如圖所示.

完成之后,我們就按照規(guī)范的txt文檔形式填入瓦片地圖的相關(guān)信息.規(guī)范如下.

接下來,我們就說一下txt文本形式創(chuàng)建的原理,首先,我們在代碼中獲取到txt文件的路徑信息,然后獲取到txt文本中的信息字符串,然后拆分成數(shù)組.接下來的如同數(shù)組的創(chuàng)建的步驟,創(chuàng)建瓦片地圖.獲取txt文本信息的代碼如下.

    //獲取txt的文件路徑字符串
    NSString *txtPath =[[NSBundle mainBundle] pathForResource:fileName ofType:nil];
    
    //如果不存在路徑
    if (nil == txtPath || [txtPath isEqualToString:@""]) {
        
        NSLog(@"txt文件路徑不存在!");
        
        return nil;
    }
    
    NSError *error = nil;
    
    //獲取文本中的字符串
    NSString *txtContents = [NSString stringWithContentsOfFile:txtPath encoding:NSUTF8StringEncoding error:&error];
    
    
    if (error != nil && txtContents ==nil) {
        
        NSLog(@"獲取txt文本內(nèi)容錯誤");
        
        return nil;
        
    }
    
    //分割txtContents字符串成數(shù)組
    NSArray *txtContentArray = [txtContents componentsSeparatedByString:@"\n"];
    
    //獲取紋理集的名稱
    NSString *atlasName = txtContentArray[0];
    
    //獲取每一個紋理的寬度和高度
    NSArray *tileSizeArray = [txtContentArray[1] componentsSeparatedByString:@"*"];
    
    int tileWidth = [tileSizeArray[0] intValue];
    
    int tileHeight = [tileSizeArray.lastObject intValue];
    
    CGSize tileSize =CGSizeMake(tileWidth, tileHeight);
    
    //獲取瓦片地圖排列組合
    NSArray *tileCodes = [txtContentArray subarrayWithRange:NSMakeRange(2, txtContentArray.count-2)];
   

接下來創(chuàng)建txt形式的瓦片地圖.參數(shù)只有一個,只需要輸入txt文件名即可.

#import "GameScene.h"

#import "SDmapNode.h"

@implementation GameScene

-(void)didMoveToView:(SKView *)view{

    [super didMoveToView:view];
    
    SDmapNode *mapNode = [[SDmapNode   alloc]initWithTextFileName:@"background"];

    mapNode.position = CGPointMake(self.size.width/2, self.size.height/2);
    
    [self addChild:mapNode];

}

效果圖



3.TML地圖文件形式創(chuàng)建.

關(guān)于如何TML文件的創(chuàng)建點(diǎn)擊這里
TML地圖文件形式創(chuàng)建比較也是比較簡單,輸入tml文件名稱即可,初始化方式如下.

-(instancetype)initWithTMLFileName:(NSString *)TMLFileName;

必看????????

  1. TML地圖文件形式創(chuàng)建需要導(dǎo)入的文件有兩個,一個是tml文件,另外一個是TexturePacker生成的紋理集圖片.不是紋理集文件夾!!!!
    2.使用TML地圖文件形式創(chuàng)建地圖之前,我們需要先導(dǎo)入libz.tbd這個庫

因?yàn)镴STileMap做的TML的瓦片地圖比較成熟,所以我就在此基礎(chǔ)上直接封裝了一層,接下來看一下我們使用TML地圖文件形式創(chuàng)建瓦片地圖的代碼.

#import "GameScene.h"

#import "SDmapNode.h"

@implementation GameScene

-(void)didMoveToView:(SKView *)view{

    [super didMoveToView:view];

    SDmapNode *mapNode = [[SDmapNode alloc]initWithTMLFileName:@"map.tmx"];
    
 
    mapNode.position = CGPointMake(self.size.width/2, self.size.height/2);
    
    [self addChild:mapNode];

}

效果圖如下所示.



SDmapNode相關(guān)使用詳解就說到這了,如果有疑問,可以聯(lián)系騷棟,謝謝.最后附上SDmapNode的下載.

SDmapNode的github傳送門??.

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

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

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