SpriteKit之轻量级瓦片地图生成工具SDmapNode详解


SDmapNode简介


近来,一直研究SpriteKit游戏框架,但是发现网上的相关资料并不是太全面,比如瓦片地图的创建方式,网上只有TML地图文件的创建方式,想直接直接使用数组形式创建和txt文件形式创建,网上并没有比较好的实现方式,大部分是需要自己封装,所以,我就封装了一个瓦片地图的生成的类SDmapNode,对于上述的三种形式的创建方式SDmapNode都是支持的.并且使用起来比较简便,只需要根据提示属于对应的参数即可,想TML文件创建形式,只需要在工程中导入TML文件,然后在生成方法填写TML文件名称生成即可.


SDmapNode使用说明


注意:使用SDmapNode之前需要导入libz.tbd,这是TML文件形式创建所必须的库.

瓦片地图的创建形式是由三种的,下面我们就这三种创建形式来逐一说明.


1.数组形式创建

数组形式创建形式应该是最接近根源的一种形式.在SDmapNode中,使用数组形式创建瓦片地图我们需要注意一下几项.

必看❗️❗️❗️❗️

1.每一个图片的大小尺寸必须一致,比如一张图片是16x16的,那么其他的都要16x16.
2.需要导入纹理集文件.
3.纹理图片允许png和jpg格式,想要支持其他格式,请联系骚栋,或者修改源码.
4.图片的名称必须为单个字母.
5.4中所说图片的名称为单字母的缘由是为了数组做准备的.
6.数组中的每一个元素都是一个字符串.

先导入纹理集文件.这里就不多废话了.

接着,我们看一下,SDmapNode中是如何实现使用数组创建瓦片地图的.我们需要往初始化方式中传三个参数,分别是纹理集合的名称,瓦片的大小尺寸和瓦片地图的矩阵数组.初始化方式如下.


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

接着,我们说一下实现原理.首先我们先分解我们的数组,并且拆分每一个字符串,获取字符串每一个字符所对应的瓦片纹理.代码如下

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)];
                
                //创建瓦片
                SKSpriteNode *tileCode = [self nodeForCode:tileCodeString];
                
                //设置瓦片位置
                tileCode.position = [self positionWithRow:row col:col];
                
                
                [self addChild:tileCode];
                
            }
               
        }

获取完成之后,我们需要根据每一个字符去我们的纹理集中寻找对应的纹理.如果找不到,那么就创建一个空的对象,并且大小与瓦片地图的大小相同.因为纹理集中的图片名名称是带有后缀的,所以目前只设置了判断png和jpg类型,如果有其他类型,可以自行修改源码.

#pragma mark ---- 获取对应的瓦片 ----

-(SKSpriteNode *)nodeForCode:(NSString *)tileCode{
    
    //如果纹理集合为空,返回空.
    if (nil == self.atlas) {
        
        return nil;
    }
    
    
    // 查看当前的纹理集中是否包含名为tileCode的纹理
    if ([self isIncludeTextureWithTextureName:tileCode]) {
        
        SKSpriteNode *tile = [SKSpriteNode spriteNodeWithTexture:[self.atlas textureNamed:tileCode]];
        
        //设置过滤模式
        tile.texture.filteringMode = SKTextureFilteringNearest;
        
        return tile;
        
        
    }else{
        
        
        SKSpriteNode *tile = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:@""]];
        
        tile.size = self.tileSize;
        
        return tile;
        
        
    }
    
    
}

接着上一块的判断当前的纹理集中是否包含该纹理

#pragma mark ---- 查看当前的纹理集中是否包含名为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;

}

上面的创建单元完成之后,接下来我们就需要根据瓦片的大小以及init中遍历的下标来对单元的position信息进行设置,代码如下

#pragma mark --- 根据数组下标返回瓦片的位置信息 ----

-(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);

}

那么我们看一下我们在场景如何调用的,首先我们导入SDmapNode.h头文件,只需要一个设置一个数组,即可.

#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];

}
//地图的二维数组
-(NSArray *)tileCodesArray{

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

效果图



2.txt文本形式创建

txt文本创建形式和数组创建形式的原理是一样的,不同的就是txt文本形式创建是把瓦片地图所有的创建信息放在一个txt文件中.初始化方式如下.

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

必看❗️❗️❗️❗️

1.txt文本形式创建中txt文本形式必须严格按照txt模板进行.
2.要先导入纹理集文件夹.

首先我们在工程中创建一个txt文本.command +N ,然后选择Other选项,创建Empty.如图所示.

完成之后,我们就按照规范的txt文档形式填入瓦片地图的相关信息.规范如下.

接下来,我们就说一下txt文本形式创建的原理,首先,我们在代码中获取到txt文件的路径信息,然后获取到txt文本中的信息字符串,然后拆分成数组.接下来的如同数组的创建的步骤,创建瓦片地图.获取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文本内容错误");
        
        return nil;
        
    }
    
    //分割txtContents字符串成数组
    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)];
   

接下来创建txt形式的瓦片地图.参数只有一个,只需要输入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地图文件形式创建.

关于如何TML文件的创建点击这里
TML地图文件形式创建比较也是比较简单,输入tml文件名称即可,初始化方式如下.

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

必看❗️❗️❗️❗️

  1. TML地图文件形式创建需要导入的文件有两个,一个是tml文件,另外一个是TexturePacker生成的纹理集图片.不是纹理集文件夹!!!!
    2.使用TML地图文件形式创建地图之前,我们需要先导入libz.tbd这个库

因为JSTileMap做的TML的瓦片地图比较成熟,所以我就在此基础上直接封装了一层,接下来看一下我们使用TML地图文件形式创建瓦片地图的代码.

#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相关使用详解就说到这了,如果有疑问,可以联系骚栋,谢谢.最后附上SDmapNode的下载.

SDmapNode的github传送门💾.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容