如何使用sprite kit 中文教程制作像切绳子这样的游戏

使用SpriteKit做一个Frvr游戏
招聘信息:
本文为投稿文章,作者:一、游戏怎么玩?好吧,我又回来了,之前利用SpriteKit游戏引擎做过一个十字消除的游戏。对于不会其它引擎的人来说,SpriteKit的优点就是比较简单迅速,快速开发些有趣的小游戏。前些天,玩了一个很好玩的在线游戏Hex Frvr,是使用Html5做的,在AppStore上有可以下载玩到,在线游戏的地址点。玩起来的效果是这样的:Ok,东西就是这么个东东,用SpriteKit来实现吧。二、开始制作游戏之旅。1,素材的准备。好吧,之前做十字消游戏的时候,使用程序生成方块的素材。这次素材是六边形,程序这块本想研究下怎么生成的,不过学习使人进步,我最近研究了下Mac OS下的一个设计神器“Sketch”,然我由此走上了设计师的路(尼玛,老板你怎么不请美工啊)。ok,简单使用下Sketch,画个六边形。如果不想画的哥们,请直接拿Demo工程里面的素材,不谢不谢!Sketch绘制六边形的方法:(1)绘制六边形。a,打开Sketch,新建一个画布(A)图2.1 &插入画布b,插入多边形,默认是5边形,先画一个。在右边检查器里选6,增加一个点,就生成了6变形。注意:按着Shift键拉动,调整成正六边形。图2.2 &插入多边形图2.3 &编辑多变形点个数(2)上颜色加增加立体效果。a.上颜色。在右侧检查器的Fill栏,选择喜欢颜色,然后Blending模式选择Normal。就有基本的底色了。b.增加图像的立体感。(补图,补步骤)增加增加线性渐变:Fill栏里,添加线性渐变,Blending模式选择Overlay。圆形渐变:Fill栏里,添加圆形渐变,Blending模式选择Overlay。效果特效自己可以随便设置,我都是以最上面那个点为渐变起点,最底下的点为渐变终点,强调一下立体的感觉。最终效果如图所示。图2.4 &加入线性渐变和圆形渐变c,导出素材点击export,按照提示到处png格式图片。2,游戏玩法和规则。游戏规则(百度词条):“游戏的主界面是一个大六边形棋盘[2] &,六边形的每一边又由5个小六边形组成,构成共有61格的棋盘空间。玩家拖动系统自动输出的各种六边形组合置于大六边形的空白处,使之排列成完整的一行或多行并且消除得分,而连续消除会有额外Combo加分。直到棋盘上再也无法摆下任意一个六边形组合的时候,游戏就会失败。”OK,归纳成编写程序的输入,我们要实现下面的东东:(1)61个小六边形组成的蜂巢状棋盘。如图2.5的游戏主界面所示,主界面是如游戏名Hex所代表的蜂窝状六边形组合成的棋盘,共有61格,为了显示方便,我都边上了号码。图2.5 &游戏主界面所示(2)24种有4个小六边形组成的不同形状+1个单六边形。如图2.6所示,4个小六边形所排列组合成的不同形状,就是我们要填入到棋盘格子里面的图形和形状。图2.6 所有待填入的图形集合(3)将(2)中的不同形状填入(1)中的棋盘,在横向,左斜方向和右斜方向有占满的六边形格子就消除。(4)每回合有三个(2)中的形状,填入一个补充一个。如果三个形状都无法再填入61格子的棋盘中,游戏结束。其游戏过程可以参见文章开头的动图显示。3.游戏实现数据结构及算法说明。(1)要有方向。一个六边形有六个方向,因此如果要在棋盘中进行比较和消除,必须比较每一个小六边形单元六个方向的情况。很显然,我们将六边形的六个方向做一个编号:LeftTop:0RightTop:1Right:2RightBottom:3LeftBottom:4Left:5其方向示意如图2.7所示:图2.7 & 一个六边形的六个方向编号。程序里枚举类型声明:typedef&enum&:&NSInteger&{
&&&&SUDNone&=&-1,
&&&&SUDTopLeft&=&0,
&&&&SUDTopRight,
&&&&SUDRight,
&&&&SUDBottomRight,
&&&&SUDBottomLeft,
&&&&SUDLeft,
}&ShapeUnitD(2)要有顺序。如何检查2.(2)中的25种形状是否可以放入2.(1)中的棋盘呢?嗯,好了,计算机要一个一个的比较,没有你聪明。不过好在它的速度飞快!但是你要告诉电脑怎么弄。首先比较是有顺序的,对比较的不同的形状,必须规定一个比较顺序。为其中每一个单元的六边形编一个序号,表示比较的顺序。这个顺序要是一个连续的,可达的路径,计算机比较的时候能有来有回。路径可以用上面规定的方向来表示。如图2.8选了两个形状,来说明他们的比较顺序。图2.8 & 两个图形的比较顺序。“一”和“二”的两个图形里每个小六边形都有编号,其编号就是其比较顺序,1非常重要,是比较的起始点。“一”图形里,1是起始比较点,比较1后,就要比较2,2位于1的LeftBottom方位,所以要将LeftBottom记住。3位于2的RightBottom位置,4位于3的RightTop方位。所以按照1到4的顺序,比较路径就是[LeftBottom,RightBottom,RightTop],红色箭头所示。同理,“二”的图形里,比较路径就是[Right,RightBottom,LeftBottom]。注意:这个形状比较顺序非常重要,要理解清楚。(3)要会比较。a,第一种比较是,将图形放置到棋盘上后,看图形里的每一个六边形是否能放置到棋盘上去。在程序里面其实算法很简单,就是遍历图形里每一个小六边形,看其所在位置下的棋盘格子是否是空的,如果全都是空的就可以放上去了。b,每一次成功放置了形状后,都会补充一个新的形状。此时,要判定游戏失败条件,即游戏是否可以进行下去。将现有的没有放进棋盘的三个形状,迭代的对棋盘里的每一个位置进行一下比较,看是否能放得进去。如果三个形状都放不进棋盘,那么游戏结束了。注意,这里的比较,就要使用到刚才定义的比较顺序了,如“一”里面的[LeftBottom,RightBottom,RightTop],因为你知道棋盘格每一个的位置,棋盘六个方向的位置也可以通过数据结构来记录,但是你需要知道放置的图形,它的比较路径和位置信息,才能够很好的便利,所以才会定义比较路径和比较起始点,有了这两个元素,比较才能进行。PS:其实还有别的方法,仅需要图形的起始点,把起始点移到棋盘的每一格,按照比较a里的位置判断方法比较。好了,其实比较简单啦!理解下就好。4,编程实现。SpriteKit的用法和Cocos2dx比较像,也是将实体精灵Sprite以树形结构组织,你来规定Sprite节点的交互和动画,达到游戏的结果。在iOS9系统中加入了很多的新功能,实在值得好好研究,不过这里我们用的比较简单。大家也可以看看我之前写的。里面有SpriteKit的普及和基础知识,我们在这里就不对SpriteKit引擎进行过多的讲解。游戏界面:(1)设计游戏界面布局。第一,由于是蜂巢状的六边形,每一行的个数先是增加,后来又递减,而且位置又不太相同。所以需要记录棋盘每行的单元格个数。计算出横向和纵向的距离,再进行添加。第二,需要记录蜂巢状六边形的六个方向的单元格编号,方便比较的时候搜索。我在这里使用了一个JSON文件,将每一个单元格的信息写入里面,初始化的时候读入,生成相关的信息数据结构。其结构如下,serialNum号就是单元格编号,如图2.5所示。adjacent就是邻接的单元点编号,-1代表该方向没有单元格。"unitInfos"&:&[
&&&&&&"x"&:&0,
&&&&&&"y"&:&0,
&&&&&&"serialNum"&:&0,
&&&&&&"adjacent"&:&"-1&-1&1&6&5&-1"
&&&},添加棋盘的代码参见Demo代码里的GameScene.m的如下代码:-&(void)addPlayground
&&&&//&1&&初始化相关数据结构
&&&&SKSpriteNode&*
&&&&self.unitNodeArray&=&[[NSMutableArray&alloc]&init];
&&&&self.unitTexture&=&[SKTexture&textureWithImageNamed:@"6kuai_gray.png"];
&&&&self.unitWidth&=&self.unitTexture.size.
&&&&self.unitHight=&self.unitTexture.size.
&&&&//2&生成每行的单元格个数,并设置起始点。
&&&&NSArray&*arrayNumber&=&@[@5,@6,@7,@8,@9,@8,@7,@6,@5];
&&&&CGPoint&startPoint&=&CGPointMake(CGRectGetMidX(self.frame)&-2*self.unitWidth,&CGRectGetHeight(self.frame)-150&);
&&//&3&两层循环,摆放棋盘单元格,并填入从JSON中读取的信息,放入userdata字段。
&&&&int&index&=&0;
&&&&int&nodeCount&=&0;
&&&&for&(NSNumber&*lineNumber&in&arrayNumber)&{
&&&&&&&&int&count&=&lineNumber.intV
&&&&&&&&for&(int&i&=&0;&i&<&&i++)&{
&&&&&&&&&&&&//3.1&生成单元格节点
&&&&&&&&&&&&node&=&[SKSpriteNode&spriteNodeWithTexture:self.unitTexture];
&&&&&&&&&&&&//3.2&摆放位置
&&&&&&&&&&&&if&(index&<=&4)&{
&&&&&&&&&&&&&&&&[node&setPosition:CGPointMake(startPoint.x-XDISTANCE*index&+i*self.unitWidth,&startPoint.y-YDISTANCE*index)];
&&&&&&&&&&&&}
&&&&&&&&&&&&else
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&[node&setPosition:CGPointMake(startPoint.x&-&XDISTANCE*((PLAYGROUNDLINE-1)-index)&+&i*self.unitWidth,&startPoint.y&-&YDISTANCE*index)];
&&&&&&&&&&&&}
&&&&&&&&&&&&
&&&&&&&&&&&&//&3.3&读取单元格信息,并填入userData
&&&&&&&&&&&&ShapeUnitInfo&*unitInfo&=&[_unitInfoArray&objectAtIndex:nodeCount];
&&&&&&&&&&&&unitInfo.unitPosition&=&node.
&&&&&&&&&&&&node.userData&=&[[NSMutableDictionary&alloc]&init];
&&&&&&&&&&&&[node.userData&setValue:unitInfo&forKey:@"unitInfo"];
&&&&&&&&&&&&[node&setName:@"unitShape"];
&&&&&&&&&&&&
&&&&&&&&&&&&//&3.4&加入数字标签
&&&&&&&&&&&&SKLabelNode&*label&=&[SKLabelNode&labelNodeWithText:[NSString&stringWithFormat:@"%d",nodeCount]];
&&&&&&&&&&&&label.position&=&CGPointMake(0,&0);
&&&&&&&&&&&&label.fontColor&=&[UIColor&blackColor];
&&&&&&&&&&&&label.fontSize&=&18;
&&&&&&&&&&&&label.zPosition&=&2;
&&&&&&&&&&&&[node&addChild:label];
&&&&&&&&&&&&
&&&&&&&&&&&&//3.5&添加节点入GameScene
&&&&&&&&&&&&[self&addChild:node];
&&&&&&&&&&&&[self.unitNodeArray&addObject:node];
&&&&&&&&&&&&nodeCount++;
&&&&&&&&index++;
}(2)设置游戏相关初始化数据。这里就是读入JSON文件,并将分数置0。-&(void)unitInfoInit
&&&&//&1&初始化信息存入的数据容器,一个NSArray
&&&&if&(_unitNodeArray&!=&nil)&{
&&&&_unitInfoArray&=&[[NSMutableArray&alloc]&init];
&&&&//&2&&读入JSON文件
&&&&NSString&*bundleDir&=&[[NSBundle&mainBundle]&bundlePath];
&&&&NSString&*path&=&[bundleDir&stringByAppendingPathComponent:@"unitInfo.json"];
&&&&NSURL&*url&=&[NSURL&fileURLWithPath:path];
&&&&NSData&*data&=&[NSData&dataWithContentsOfURL:url];
&&&&NSError&*error&=&
&&&&//&3&解析JSON文件,并存入Arrary容器
&&&&NSDictionary&*jsonDic&=&[NSJSONSerialization&JSONObjectWithData:data&options:NSJSONReadingAllowFragments&error:&error];
&&&&NSArray&*unitInfos&=&[jsonDic&objectForKey:@"unitInfos"];
&&&&if&(unitInfos&!=&nil)&{
&&&&&&&&for&(NSDictionary&*unitInfoDic&in&unitInfos)&{
&&&&&&&&&&&&ShapeUnitInfo&*unitInfo&=&[[ShapeUnitInfo&alloc]&init];
&&&&&&&&&&&&int&x&=&((NSNumber&*)[unitInfoDic&objectForKey:@"x"]).intV
&&&&&&&&&&&&int&y&=&((NSNumber&*)[unitInfoDic&objectForKey:@"y"]).intV
&&&&&&&&&&&&int&sn&=&((NSNumber&*)[unitInfoDic&objectForKey:@"serialNum"]).intV
&&&&&&&&&&&&NSString&*adjacentString&=&(NSString&*)[unitInfoDic&objectForKey:@"adjacent"];
&&&&&&&&&&&&NSArray&*adjacents&=&[adjacentString&componentsSeparatedByString:@"&"];
&&&&&&&&&&&&unitInfo.unitLocation&=&CGPointMake(x,&y);
&&&&&&&&&&&&unitInfo.serialNumber&=&
&&&&&&&&&&&&
&&&&&&&&&&&&[unitInfo.adjacentArray&addObjectsFromArray:adjacents];
&&&&&&&&&&&&
&&&&&&&&&&&&[_unitInfoArray&addObject:unitInfo];
}(3)三个备选容器添加.在棋盘下面的位置添加三个备选容器,如图2.5种的2所标示的位置。-&(void)addShapeFrame
&&&//1&初始化存储容器
&&&&SKSpriteNode&*
&&&&_shapePosArray&=&[[NSMutableArray&alloc]&initWithCapacity:3];
&&&&_shapeArray&=&[[NSMutableArray&alloc]&initWithCapacity:3];
&&&//&2&生成被选位置节点,并加入到Scene中去
&&&&for&(int&i&=&0;&i&<&3;&i++)&{
&&&&&&&&node&=&[[SKSpriteNode&alloc]&init];
&&&&&&&&node.size&=&CGSizeMake(100,&100);
&&&&&&&&node.position=&CGPointMake(CGRectGetMidX(self.frame)&+&(i&-&1)*120,&220);
&&&&&&&&node.name&=&[NSString&stringWithFormat:@"shapeFrame_%d",i];
&&&&&&&&[self&addChild:node];
&&&&&&&&[_shapePosArray&addObject:[NSValue&valueWithCGPoint:node.position]];
&&&&//&3&调用生成被选图形的接口,填充入这些位置节点。
&&&&[self&shapeFill];
}(4)随机生成填充形状。上面(3)中代码的最后一步,在GameScene里面调用shapeFill方法来,填充三个备选容器。实际上是调用RandomShapeMgr.h中的RandomShapeMgr的单例对象,生成如图2.6所示的25种不同的待填入形状。重要的是将其编号,和比较队列写好,放入一个队列对象。RandomShapeMgr里的代码里面的posInfoInit方法可以研究下,节点的位置队列和比较队列如何生成好保存。游戏交互实际上SpriteKit里面的交互和iOS应用里的交互一脉相承。由于有点击,拖动图形,放下图形等操作,所以使用如下几个方法:a,-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;b,- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent *)event;c,- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent *)event;分别在点击开始,中途和结束时进行程序处理完成主要核心交互,如下三个功能:(1)点击形状,识别形状,并移动。点击形状,调用方法a。在方法a中,根据节点Name值,判断是否时需要保存处理的形状节点。如是的话,使用 _handleNode来持有。因为屏幕大小限制,平时待选的图形仅仅只有单元格大小的1/2,因此点击持有形状后,会执行动画,将待选形状扩大一倍。处理逻辑:if&([node.name&isEqual:@"shape"])&{
//&&&&&&&&&&&&NSLog(@"shape");
&&&&&&&&&&&&_handleNode&=&
&&&&&&&&&&&&[_handleNode&runAction:[SKAction&scaleTo:2&duration:0.4]&completion:^{
&&&&&&&&&&&&}];
&&&&&&&&&&&&
&&&&&&&&&&&&
&&&&&&&&}移动持有图形,调用方法b,如果_handleNode有值的话,实时更新_handleNode的位置Position值。(2)放置形状,并判断是否能够放置入棋盘。在方法c中,判定是否能够放入棋盘。就是判断图形里的节点是否能否放在它下面的那个单元格中。处理逻辑:if&(_handleNode&!=&nil)&{
&&&&&&&&//&1&获取放入形状的所有小六边形,并获取其颜色纹理texuture
&&&&&&&&NSArray&*handleShapeNodes&=&[_handleNode&children];
&&&&&&&&SKTexture&*texture&=&[(SKSpriteNode&*)[[_handleNode&children]&firstObject]&texture];;
&&&&&&&//&2&遍历所有的小六边形,获取其位置,并察看该位置下是否存在Unit单元格,如果存在单元格,察看是否是被占状态。如果所有的小六边形下,都有未被占用的单元格,那么就可以放置在棋盘上了;反之,返回形状待选区域。
&&&&&&&&NSUInteger&index&=&0;
&&&&&&&&NSUInteger&ocuppiedCount&=&0;
&&&&&&&&NSMutableArray&*tempArray&=&[[NSMutableArray&alloc]&init];
&&&&&&&&//&2.1&遍历小六边形
&&&&&&&&for&(SKSpriteNode&*child&in&handleShapeNodes)&{
&&&&&&&&&&&&index++;
&&&&&&&&&&&&//&2.2&获取小六边形位置
&&&&&&&&&&&&CGPoint&childLocation&=&CGPointMake(child.position.x*2&+_handleNode.position.x,&child.position.y*2+_handleNode.position.y);
&&&&&&&&&&&&//&2.3&获取该位置下的所有节点
&&&&&&&&&&&&NSArray&*shapeNodes&=&[self&nodesAtPoint:childLocation];
&&&&&&&&&&&//&2.4&看该节点下,是否存在违背占用的单元格
&&&&&&&&&&&&for&(SKNode&*shapeNode&in&shapeNodes)&{
&&&&&&&&&&&&&&&&if&([self&isShapeUnit:(SKSpriteNode&*)shapeNode]&&&&![self&isUnitOcuppied:(SKSpriteNode&*)shapeNode])&{
&&&&&&&&&&&&&&&&&&&&ocuppiedCount++;
&&&&&&&&&&&&&&&&&&&&[tempArray&addObject:shapeNode];
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&}
&&&&&&&&//&2.5&如果所有六边形都用空白的Unit可以占,那么就可以放入。
&&&&&&&&if&(&index&==&ocuppiedCount&)&{
&&&&&&&&&&&&//&2.6&执行占用,并调用shapeFill补充shape
&&&&&&&&&&&&for&(SKSpriteNode&*unitNode&in&tempArray)&{
&&&&&&&&&&&&&&&&[unitNode&setTexture:texture];
&&&&&&&&&&&&&&&&ShapeUnitInfo&*unitInfo&=&[unitNode.userData&objectForKey:@"unitInfo"];
&&&&&&&&&&&&&&&&unitInfo.occupy&=&YES;
//&&&&&&&&&&&&&&&&NSLog(@"set&occupy");
&&&&&&&&&&&&}
&&&&&&&&&&&&[_shapeArray&removeObject:_handleNode];
&&&&&&&&&&&&
&&&&&&&&&&&&[_handleNode&removeFromParent];
&&&&&&&&&&&&[self&shapeFill];
&&&&&&&&else&{
&&&&&&&&&&&&//&2.7&&否则就将shape移动回待选区域。
&&&&&&&&&&&&NSUInteger&index&=&[_shapeArray&indexOfObject:_handleNode];
&&&&&&&&&&&&CGPoint&location&=&[(NSValue&*)[_shapePosArray&objectAtIndex:index]&CGPointValue];
&&&&&&&&&&&&SKAction&*scale&=&[SKAction&scaleTo:1&duration:0.3];
&&&&&&&&&&&&SKAction&*move&=&[SKAction&moveTo:location&duration:0.3];
&&&&&&&&&&&&SKAction&*group&=&[SKAction&group:@[scale,move]];
&&&&&&&&&&&&group.timingMode&=&SKActionTimingEaseO
&&&&&&&&&&&&[_handleNode&runAction:group];
&&&&&&&&_handleNode&=&(3)消除判断,消除积分增加。在方法c中,还需要进行消除判断,填入形状后,是否会在横,左斜和右斜方向存在填满一行的情况,如果有就需要进行消除,并积分。&//&检查消除并积分
&[self&resultDealElimination];使用数组记录下Top和Bottom行的单元格编号,并记录每一行开头的单元格编号:&&&&//&1&每一行开头的单元格编号
&&&&NSArray&*compareIndexRow&=&@[@0,@5,@11,@18,@26,@35,@43,@50,@56];
&&&//&2&Top行所有元素的编号
&&&&NSArray&*compareIndexTopSlash&=&@[@0,@1,@2,@3,@4];
&&&&//&3&Bottom行所有元素的编号
&&&&NSArray&*compareIndexBottomSlash&=&@[@56,@57,@58,@59,@60];涉及单元格如图2.9:图2.9 涉及比较消除的单元格比较方向如图2.10所示,1是横向,2是Top斜,3是Bottom斜,比较方向按六边形方向定义比较,具体见代码:图2.10 &涉及比较消除的方向(4)游戏结束判断将三个待填入的图形分别比较放在棋盘里进行遍历比较。看是否存在空隙放入,如果无空隙时,游戏结束。调用如下代码:&//&调用检查是否能Continue
&[self&checkContinue];比较方案如上述所描述,按照填入图形的比较序列,逐个对每个单元格进行比对,如果还存在可以填入的位置,游戏就可以继续,如果不存在,游戏就结束。核心比较代码:-&(BOOL)isOccupByShape:(SKSpriteNode&*)shapeNode&atUnit:(SKSpriteNode&*)unitNode
&&&//&1&获取该形状Shape的比较序列
&&&&NSArray&*comSeqArray&=&(NSArray&*)[shapeNode.userData&objectForKey:@"shapeCompOrder"];
&&&//&2&以读入的单元格为起始比较单元格,按照比较序列进行比较。
&&&&SKSpriteNode&*tempNode&=&unitN
&&&&ShapeUnitInfo&*nodeInfo&=&(ShapeUnitInfo&*)[tempNode.userData&objectForKey:@"unitInfo"];
&&&&if&([nodeInfo&isOccupied])&{
&&&&&&&&return&YES;
&&&&for&(NSNumber&*index&in&comSeqArray)&{
&&&&&&&&NSInteger&nodeIndex&=&[(NSNumber&*)[nodeInfo.adjacentArray&objectAtIndex:[index&unsignedIntegerValue]]&integerValue];
&&&&&&&&if(-1&==&nodeIndex)&{
&&&&&&&&&&&&return&YES;
&&&&&&&&tempNode&=&(SKSpriteNode&*)[_unitNodeArray&objectAtIndex:nodeIndex];
&&&&&&&&nodeInfo&=&(ShapeUnitInfo&*)[tempNode.userData&objectForKey:@"unitInfo"];
&&&&&&&&if&([nodeInfo&isOccupied])&{
&&&&&&&&&&&&return&YES;
&&&&return&NO;
}三、游戏效果,何去何从。好了,从这里下载完整的,在Xcode里面运行打开吧。执行效果如图3.1所示。图3.1 实际游戏效果好了,其实还有很多的功能可以添加和细化。比如添加很多的动画效果,增加积分机制和加入社交化分享,广告条。很多功能可以添加,有兴趣的哥们,就在GitHub的,这个工程里面,好好加油,我顶你哦!
微信扫一扫
订阅每日移动开发及APP推广热点资讯公众号:CocoaChina
您还没有登录!请或
点击量3533点击量3390点击量3040点击量2731点击量2401点击量2364点击量2341点击量2154点击量1978
&2018 Chukong Technologies,Inc.
京公网安备89项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵)。01:中国地图:http://test.sharegis.cn/mapbox/html/3china.html02:德国-德累斯顿市:http://test.sharegis.cn/mapbox/html/6germany.html1.什么是sprite文件sprite文件主要是将一堆小图生成一种大图的方法...
项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵)。01:中国地图:http://test.sharegis.cn/mapbox/html/3china.html02:德国-德累斯顿市:http://test.sharegis.cn/mapbox/html/6germany.html1.什么是sprite文件 sprite 文件主要是将一堆小图生成一种大图的方法,并且将每张小图的位置信息保存下来,方便读取。在网络请求中会减少请求的数量,mapbox借鉴前端中CSS Sprite方法存储图标信息的。sprite.png文件保存图标,sprite.json保存名称及位置信息,下图图展示的是小图标与大图文件的示例。下面我讲一下两种文件互转。 &=互转=&
下面是这次项目实现的功能,包含Sprite大图的合成与分割,也包含对单个图标文件的宽度与高度的调整。2.sprite大图转小图 我们上一节讲到是使用arcgis pro会将.mxd地图配图文件转为mapbox的样式文件,同样会生成sprite.png和sprite.json的图标文件。由于arcgis字体库的限制,生成的图标可能不符合的要求,我们有修改图标的需要,这里我们不仅要替换大图中的小图标而且要记录图标的的位置信息到sprite.json中。下面写了一个从大图文件中生成单个小图标文件的分割功能。 实现思路:首先读取大图图片,然后根据json文件中的位置信息,json中的图标信息如下,xy代表图标的左上角在大图中的位置,width height代表图标的大小,pixelRatio代表像素单位,spriteicon/county为文件名。"spriteicon/county": { "x": 75, "y": 0, "width": 32, "height": 14, "pixelRatio": 1, "sdf": false}读取单个图标文件的像素信息,写到一个新建的Bitmap画布中,实现成果与代码如下: 转换为单个文件
//sprite json文件
string text = ReadFile(textBox3.Text);
JObject obj = JObject.Parse(text);
JToken item = null;
//将json转为对象
List&Param& paramlist = new List&Param&();
for (int i = 0; i & obj.C i++)
if (item == null)
item = obj.F
item = item.N
Param p = new Param();
p.name = item.Path.Substring(2, item.Path.Length - 4).Replace("/", "-").Replace(":", "&");
p.x = (int)item.First["x"];
p.y = (int)item.First["y"];
p.width = (int)item.First["width"];
p.height = (int)item.First["height"];
paramlist.Add(p);
using (Bitmap map = (Bitmap)Image.FromFile(textBox3.Text+@"\sprite.png"))
using (Bitmap editMap = new Bitmap(map, map.Width, map.Height))
foreach (var itemp in paramlist)
//保存图片的画布
Bitmap itemMap = new Bitmap(itemp.width, itemp.height);
for (int i = 0; i & itemp. i++)
for (int j = 0; j & itemp. j++)
//获取像素
Color color = editMap.GetPixel(itemp.x + i, itemp.y + j);
itemMap.SetPixel(i, j, color);
string savepath = System.Environment.CurrentDirectory + @"\spriteicon" + itemp.name+ ".png";
itemMap.Save(savepath);
}3.小图标的调整 对于一些规则的小图标,例如标记路面信息的label,他的宽度由路的属性信息决定,展示我们要对不同长度的文字设置不同大小label这里我们要对多个图标的宽度和高度进行调整,这是只是对lable这样规则的图标进行调整,例如 宽度增加20px实现思路:我们选择规则图形的中心线,宽度调整就是以中心线进行左右拉伸复杂增加宽度,实现代码如下:
DirectoryInfo folder = new DirectoryInfo(System.Environment.CurrentDirectory);
List&string& filenames = new List&string&();
int addnum = Convert.ToInt32(textBox2.Text);
foreach (var NextFolder in folder.GetFiles("*.png"))
if (NextFolder.Name.Contains(textBox1.Text))
filenames.Add(NextFolder.Name);
foreach (var item in filenames)
using (Bitmap map = (Bitmap)Image.FromFile(System.Environment.CurrentDirectory + "/" + item))
using (Bitmap editMap = new Bitmap(map.Width + addnum, map.Height ))
int centernum = map.Width / 2;
for (int i = 0; i & map.W i++)
for (int j = 0; j & map.H j++)
//获取像素
Color color = map.GetPixel(i, j);
if (i == centernum)
editMap.SetPixel(i, j, color);
if (addnum & 0)
for (int m = 0; m & m++)
editMap.SetPixel(i </s
源文地址:https://www.guoxiongfei.cn/cntech/11551.html

我要回帖

更多关于 sprite kit 场景切换 的文章

 

随机推荐