在Xcode 8中为SKTileMapNode的tile提供物理

MJ1*_*986 5 xcode sprite-kit skphysicsbody swift sktilemapnode

我正在学习Swift,作为一个项目,我正在开发一个类似于超级马里奥的基于平铺的2D游戏,我的角色会走路并跳上瓷砖.

最新版本的Xcode和Sprite Kit可以直接在Xcode中创建Tile Map.

在新的Xcode和Sprite工具包的演示中,这个人展示了一个类似于我正在做的游戏.

https://developer.apple.com/videos/play/wwdc2016/610/ (大约20分钟).

他提到我给Tiles用户数据属性,并且在代码中我们搜索具有该用户数据的所有tile并给它们一些物理属性,以便角色可以碰撞或与它们交互(在我的情况下,我的角色不会掉落)或者穿过瓷砖).

所以基本上,这个想法是给那些瓦片一个物理体,但这不能用SKphysicsBody来完成.所以必须有另一种方式,因为我是Swift的新手,我很想念它.

如果有人知道这一点,我将非常感谢帮助.

如果问题不清楚,请告诉我,因为我也是堆栈溢出的新手.

pea*_*ype 5

Apple 工作人员 Bobjt在这里说,“正确的方法”是将用户数据添加到您的SKTileDefinition对象中,并使用它来识别物理实体并将其添加到您的磁贴中。

因此,您可以通过编程方式或在编辑器中将用户数据值添加到磁贴定义中,如下所示:

在此处输入图片说明

然后在代码中,您将检查每个图块定义以查看它是否具有用户数据值。如果是这样,那么您需要计算图块的位置并在新节点上添加一个物理体,将其作为您的图块地图的父项。这是 Bobjt 称之为“正确方法”的代码:

self.tileMap = self.childNode(withName: "Tile Map") as? SKTileMapNode  
guard let tileMap = self.tileMap else { fatalError("Missing tile map for the level") }  

let tileSize = tileMap.tileSize  
let halfWidth = CGFloat(tileMap.numberOfColumns) / 2.0 * tileSize.width  
let halfHeight = CGFloat(tileMap.numberOfRows) / 2.0 * tileSize.height  

for col in 0..<tileMap.numberOfColumns {  
    for row in 0..<tileMap.numberOfRows {  
        let tileDefinition = tileMap.tileDefinition(atColumn: col, row: row)  
        let isEdgeTile = tileDefinition?.userData?["edgeTile"] as? Bool  
        if (isEdgeTile ?? false) {  
            let x = CGFloat(col) * tileSize.width - halfWidth  
            let y = CGFloat(row) * tileSize.height - halfHeight  
            let rect = CGRect(x: 0, y: 0, width: tileSize.width, height: tileSize.height)  
            let tileNode = SKShapeNode(rect: rect)  
            tileNode.position = CGPoint(x: x, y: y)  
            tileNode.physicsBody = SKPhysicsBody.init(rectangleOf: tileSize, center: CGPoint(x: tileSize.width / 2.0, y: tileSize.height / 2.0))  
            tileNode.physicsBody?.isDynamic = false  
            tileNode.physicsBody?.collisionBitMask = playerCollisionMask | wallCollisionMask  
            tileNode.physicsBody?.categoryBitMask = wallCollisionMask  
            tileMap.addChild(tileNode)  
        }  
    }  
}  
Run Code Online (Sandbox Code Playgroud)

就个人而言,我认为这种方法太挑剔了。我将在我的游戏中尝试不同的方法,如果有效,我会在这里发布。我真正想要的是让 Apple 增强 tile map API,以便我们可以将物理实体直接添加到单个 tile。或许在这个过程中,他们可以优化引擎,让各个瓦片上的物理体自动合并,形成更大、更优化的形状,以提高系统性能。

更新:我向Apple提出了关于这个问题的请求无论它有什么好处


Con*_*sed 2

我不确定是否有一种万无一失的方法可以做到这一点......但这里有两种方法来思考如何尝试将物理应用到图块地图。

选项 1:将 SKNode 应用到地图上每个图块的每个位置,并根据该图块的内容和状态将适当的物理体应用到该 SKNode。

选项 2:使用每个图块的位置信息将物理体数组添加到 SKTileMapNode,并相应地定位每个图块。

我正在想象一个重力向下、马里奥风格的平台游戏,这种地形需要物理体作为地面:

在此输入图像描述

摘自 Apple WWDC 关于图块和物理的文字记录:

你会注意到我正在与这里的瓷砖发生碰撞。

我通过利用可以放在每个图块上的自定义用户数据来实现这一目标。

在这里,我将向您展示我们的瓷砖套装。

在此处选择其中一种变体。

您可以看到我们这里有一些用户数据。

我只有一个名为 edgeTile 的值,它是一个布尔值,我设置为 1。

因此,在代码中,我将在此处浏览平台演示中的图块地图,并且正在寻找所有这些边缘图块。

每当我找到一个时,我都会创建一些物理数据以允许玩家与其发生碰撞。

由于它就在我们的瓷砖地图中,假设我想翻过这里的这堵大墙。

当我运行游戏时,你会发现我的家伙实际上无法跳得足够高来克服它。

他真的很想这么做,因为那边的红色按钮看起来真的很诱人。

我真的很想推动那件事。

因此,由于我们只是从图块和用户数据生成物理数据,所以我们所能做的就是到这里并删除这些图块并再次构建并运行我们的游戏。

现在瓷砖已经消失了,我们现在可以穿过那里了。

我们不需要更改代码或任何东西。

我们只是使用从图块地图中提取的数据来设置图块。

就是这么简单。


听起来很简单,但需要比我更大的头脑才能弄清楚正在做什么以及如何完成。