当前位置: 首页 > 科技观察

TileMaps(Part2),SpriteKit在iOS10平台上的新特性

时间:2023-03-12 03:15:38 科技观察

使用邻接组邻接组可以定义绘制瓦片时应该绘制什么样的边缘图像。例如,如果您正在创建一个小岛,您可以将草地作为中心图块,而边缘图块将是延伸到海洋中的海滩。中间的草方块会随着您的绘画而展开,而边缘部分会自动围绕它们展开。有两种平铺边缘瓷砖的方法。您可以使用从一个表面过渡到另一个表面的单色瓷砖,请参见kenney.nl网站上的下图:另一种方法是使用透明边缘,如下图所示的这组:如果要使用透明边缘,您必须对tilemap节点进行分层。这样,通过透明度显示背景。早些时候,你画了水背景。现在,我们要添加另一个陆地层。返回文件Tiles.sks以编辑您的图块集合。按住Ctrl键的同时单击GroundTiles,然后从菜单中选择New\8-WayAdjacencyGroup。将新的图块组重命名为Grass。当您选择Grass瓷砖组时,您会看到一个充满瓷砖的网格。当然,这些东西对于刚开始的新手来说可能看起来有点混乱,但是过一段时间后这一切就会变得清晰起来。现在,使用草过滤媒体库,您会看到屏幕上显示所有与草相关的图块图像。将图块拖动到网格上的相关位置。我根据每个图像在网格中的位置命名了它。将三个变体添加到中心背景,就像您之前所做的那样。这一次,选择GrassCenter1变体并将PlacementWeight参数更改为10。这样您在绘制时可以得到更多的普通瓷砖。当您将图像拖到目标位置时,您可能会出错。我自己经常混淆角落和边缘瓷砖。不过,不要太担心。只需将正确的图像拖到错误的图像上,然后从弹出菜单中选择“替换图块变体纹理”命令。请注意,如果您选择其他选项,则可以通过这种方式添加相应瓷砖的变体。完成后,记得按Command+S保存图块集。您的最终网格应该如上图所示。现在,在项目导航器中打开文件GameScene.sks。[注意]如果出于某种原因你想用刚刚添加的新瓷砖更改背景水瓷砖,那么很遗憾:目前不支持此类更改;所以,你需要完全重新粉刷它们。您可以删除瓦片地图节点并添加一个新的瓦片地图节点,或者创建另一个瓦片集,然后将节点的瓦片集更改为原始瓦片集。接下来,将一个新的瓦片地图节点拖到场景中并将节点的名称更改为landBackground。您将需要此数据,因为稍后您将在代码中引用该节点。现在,将地图的大小更改为32列乘24行。另外,确保该位置的X和Y坐标都设置为0,X和Y缩放都设置为1。现在,双击场景编辑器以编辑瓦片地图。单击工具栏中的“选择图块”命令。新的Grass瓷砖组将与其他两个瓷砖组一起出现在下拉列表框中。选择最右边的瓦片组Grass,点击工具栏上的画笔工具开始绘画。您将看到边缘如何神奇地环绕您所画的内容!还记得Tiles.sks中令人困惑的网格吗?以下是瓷砖的绘制方式:确定,点击完成命令,并取消选中属性检查器中的启用自动映射项。双击场景编辑器中的landBackground节点,再次编辑瓦片地图。当您单击下拉菜单中的“选择拼贴”命令时,将显示所有可用的拼贴。您现在可以使用您选择的图块在网格中绘制单个正方形。绘制完成后单击“完成”命令。现在,构建并运行您的应用程序以享受您新创建的背景。新的SpriteKit瓦片类除了使用场景编辑器可视化创建瓦片地图外,您还可以在代码中创建瓦片地图。所以,您可能会想:“既然可以使用场景编辑器,为什么还要使用它呢?”如果你需要识别特定的瓷砖,比如水瓷砖怎么办?在本教程中,汽车速度的降低Slowness是由水砖引起的。你可以用代码来实现这个判断!另一个原因是随机性。在本教程中,玩家将收集鸭子和煤气罐。如果你用编辑器绘制这些东西,它们将在每次游戏中保持不变。如果你在代码中添加它们,你可以随机控制它们的位置。回顾一下您到目前为止所做的事情,您创建的每个项目实际上都有一个对应的新SpriteKit类。在文件GameScene.sks中,它们是:SKTileMapNode:对应于您放置在场景编辑器中的节点。SKTileSet:对应于您在属性检查器中分配给瓦片地图节点的瓦片集。打开文件Tiles.sks,您在该文件中使用了:SKTileSet:树结构顶部的项目,在本教程中名为GroundTiles。SKTileGroup:瓦片集中的瓦片组。在本教程中,它们对应于WaterTile、GrassTile和Grass。SKTileGroupRule:定义每个瓦片的邻接规则。例如,左上图块、中心图块或右边缘图块。现在,单击草组并选择中心规则。SKTileDefinition:每个规则都有一组图块定义。这些都是瓷砖的变体。例如,中心图块具有三个SKTileDefinition变体,它们在绘制时随机使用。然后,选择屏幕底部的中间变体之一。因此,在属性检查器中,您将看到每个SKTileDefinition变体的所有可用属性。如果您创建动画图块,您将看到逐帧信息,并且您可以控制帧速率。想象一下你的水砖拍打你的草砖。每个变体对应的属性检查器也是您可以为这些变体提供用户数据的地方。稍后当您想要确定一个对象是鸭子还是煤气罐时,这将很有用。要以编程方式控制图块,我们需要编写一些代码。汽车在水砖上行驶时,速度应明显减慢。有两种方法可以实现这一点。您可以将布尔值userdataisWater添加到所有水块,然后检查代码中的用户数据。或者,由于水是在单独的层上创建的,您可以使用landBackground瓦片地图节点中的透明度来测试汽车位置下方的瓦片是否为空。打开文件GameScene.swift并将landBackground属性添加到GameScene:varlandBackground:SKTileMapNode!接下来,将以下代码添加到方法loadSceneNodes中:guardletlandBackground=childNode(withName:"landBackground")as?SKTileMapNodese{fatalError("Backgroundnodenotloaded")}self.landBackground=landBackground在这里,我们将瓦片地图节点加载到landBackground属性中。现在,在方法update(_:)中添加以下代码:;这是检测小车位置的好地方。在这里,您将汽车的位置数据转换为行和列数据。这就是提取瓦片地图中实际瓦片数据的方式。接下来,将以下代码添加到方法update(_:)中:lettile=landBackground.tileDefinition(atColumn:column,row:row)tile现在包含指定行和列位置的tile的SKTileDefinition信息。***,在方法update(_:)后面添加如下代码:iftile==nil{maxSpeed=waterMaxSpeedprint("water")}else{maxSpeed=landMaxSpeedprint("grass")}car的最大速度将降低到一个合适的值。您可以使用landBackground的透明度属性来确定此值。在这个游戏中,透明的方块被认为是水。***,重新编译运行程序,结果如下:小车的最高速度会比在水中时降低很多。当然,你可以通过控制台输出进一步证实这个结论。集合对象现在,让我们使用之前为汽车集合创建的对象创建一个平铺地图。首先,我们用橡皮鸭和油箱随机填充整个瓦片地图。只需要注意一件事:鸭子自然放在水砖上,气罐放在草砖上。接下来,为对象创建一个新的图块集。运行命令“File\New\File”并选择“iOS\Resource\SpriteKitTileSet”模板,然后单击“Next”按钮。将图块集命名为ObjectTiles并单击命令“创建”。打开文件ObjectTiles.sks并将图块集名称更改为ObjectTiles。接下来,将“新图块组”更改为Duck,然后将rubberduck图像从媒体库拖到图块上。现在,选择鸭子瓷砖,注意相应的瓷砖在底部。在属性检查器中,单击用户数据下的+(您可能需要在检查器上向下滚动一点)。然后,双击userData1将其更改为duck。它是什么类型并不重要,因为我们只是检查该值是否存在,所以我们可以将其保留为整数类型。接下来,按住Ctrl键,同时单击tileset列表中的“ObjectTiles”,然后选择“New\SingleTileGroup”。将这个组重命名为“GasCan”并将图像gascan拖到图块上。然后,选择气罐图块,像以前一样添加用户数据,并将用户数据命名为gascan。[注意]一开始,我想在代码中创建tilemap节点并用命名的tileset填充它,但在撰写本文时,我无法检索名称为initializer的SKTileSet。所以,现在,只需在场景编辑器中使用tileset名称创建一个空的tilemap节点。现在,打开文件GameScene.sks并向场景添加一个瓦片地图节点。然后在属性检查器中将其命名为objects,并将其X和Y坐标设置为0,并将MapSize设置为32X24。对于图块集,从下拉菜单中选择“对象图块”,您会注意到图块大小将自动设置,请参见下图。接下来,打开文件GameScene.swift并添加以下新属性:varobjectsTileMap:SKTileMapNode!然后,在方法loadSceneNodes()中添加以下代码:通过Objectstileset。接下来在方法loadSceneNodes()之后添加一个新的方法,如下:funcsetupObjects(){//1lettileSet=objectsTileMap.tileSet//2lettileGroups=tileSet.tileGroups//3guardletduckTile=tileGroups.first(where:{$0.name=="Duck"})else{fatalError("NoDucktiledefinitionfound")}guardletgascanTile=tileGroups.first(where:{$0.name=="GasCan"})else{fatalError("NoGasCantiledefinitionfound")}//4letnumberOfObjects=64letcolumns=UInt32(objectsTileMap.numberOfColumns)letrows=UInt32(objectsTileMap.numberOfRows)}到目前为止,您已经设置了随机放置对象所需的所有属性。大致思路如下:1.从场景编辑器的瓦片地图节点中获取瓦片集。2.从瓦片集中检索瓦片组列表。3.从tilegroup数组中的tiles中检索tile定义。其中,tileGroups.first(where:)是Swift3中提供的新方法,用于查找对象数组中的第一个出现。4.创建在地图上放置对象所需的常量。这里,numberOfObjects的值可以修改为合适的值。现在,在上面同样的方法中,继续添加如下代码://5for_in1...numberOfObjects{//6letcolumn=Int(arc4random_uniform(columns))letrow=Int(arc4random_uniform(rows))letgroundTile=landBackground.tileDefinition(atColumn:column,row:row)//7lettile=groundTile==nil?duckTile:gascanTile//8objectsTileMap.setTileGroup(tile,forColumn:column,row:row)}这段代码的大致逻辑如下:5.放置64以循环的方式对象。6.随机选择一列和一行。7、如果选择的瓷砖是单色的,则选择气槽;否则,选择鸭子。这将确保鸭子在水中,气罐在草地上。8.将鸭子或气罐放在瓷砖上,并将它们放在选定的行中。现在,在didMove(to:)方法的顶部调用以下新方法:setupObjects()现在,重建并运行项目。你会注意到背景中的水里全是鸭子,草地上还有煤气罐。请参考下图。***一件事是写代码把所有的鸭子都捡起来放到推车上。这类似于您之前编写的用于检测您是否在水面上的代码,当然不包括您使用用户数据来控制鸭子和气体的部分。回到GameScene.swift文件,在GameScene的顶部添加两个属性:"Gas.wav",waitForCompletion:false)}()在这里,您创建了两个在收集对象时播放声音的动作。这些声音数据也包含在示例项目中。现在,将以下代码添加到方法update(_:)的***中:letobjectTile=objectsTileMap.tileDefinition(atColumn:column,row:row)iflet_=objectTile?.userData?.value(forKey:"gascan"){run(gascanSound)objectsTileMap.setTileGroup(nil,forColumn:column,row:row)}iflet_=objectTile?.userData?.value(forKey:"duck"){run(duckSound)objectsTileMap.setTileGroup(nil,forColumn:column,row:row)}在这里,我们检查用户数据,看看它是否包含gascan或duck。然后,播放适当的声音并将图块组设置为零。这将从视图中删除图块。再次构建并运行应用程序,尝试收集煤气罐和鸭子!这比实现精灵碰撞要容易得多!总结通过本文,您应该已经了解了如何使用TileMapEditor。这确实是对SpriteKit工具系列的一个很好的补充。本文游戏最新版下载地址为https://cdn1.raywenderlich.com/wp-content/uploads/2016/06/RDRescue-Finished.zip。想要了解更多详情,不妨观看苹果WWDC2016大会的相关视频(https://developer.apple.com/videos/play/wwdc2016/610/)。