【问题标题】:Swift SKPhysicsBody falling through static SKPhysicsBody with matching bitmasksSwift SKPhysicsBody 落入具有匹配位掩码的静态 SKPhysicsBody
【发布时间】:2017-05-26 18:33:50
【问题描述】:

我正在使用 SpriteKit 在 Swift 中制作一个平台游戏,其中包含一个跳跃的主角。但是,一旦关卡加载,玩家就会立即从地面坠落。 You can see it in action here.

我正在使用 SKTilemapNode 创建地面,并在加载关卡时循环通过瓷砖以在瓷砖地图的子节点上创建 SKPhysicsBody。这与 WWDC 2016 的“SpriteKit 中的新功能”视频中演示的内容非常相似:

所以,我们在这里建立了一个小平台。一个可以跑来跑去的小家伙。你可以看到我在后台进行了视差滚动。你会注意到我在这里与瓷砖碰撞。我通过利用我们可以放在每个图块上的自定义用户数据来实现这一点。在这里,我将在我们的瓷砖组中向您展示。在此处选择一种变体。 你可以看到我们这里有一些用户数据。我只有一个名为 edgeTile 的值,它是一个布尔值,我设置为 1。 所以,在代码中,我在这里浏览了我们平台演示中的瓦片图,我正在寻找所有这些边缘瓦片。 每当我找到它时,我都会创建一些物理数据来让玩家与之碰撞。

我基于 SKTilemapNode 创建物理体的功能如下:

extension SKTileMapNode {

//In order for this to work, edge tile definitions must have the "edge" property in user data
func createPhysicsBody() -> SKPhysicsBody {
    var physicsBodies = [SKPhysicsBody]()

    for row in 0 ..< self.numberOfRows {
        for column in 0 ..< self.numberOfColumns {
            if self.tileDefinition(atColumn: column, row: row)?.userData?["edge"] != nil {
                physicsBodies.append(SKPhysicsBody(rectangleOf: self.tileSize, center: self.centerOfTile(atColumn: column, row: row)))
            }

        }
    }

    let body = SKPhysicsBody(bodies: physicsBodies)
    body.affectedByGravity = false
    body.isDynamic = false
    body.allowsRotation = false
    body.pinned = true
    body.restitution = 0
    body.collisionBitMask = 0b1111
    body.categoryBitMask = 0b1111
    body.contactTestBitMask = 0b1000

    return body
}

func initializePhysicsBody() {
    let node = SKNode()
    node.name = "Tilemap"
    node.physicsBody = createPhysicsBody()

    addChild(node)
}

}

所以,在我的场景设置中,我所要做的就是调用 tileMap.initializePhysicsBody() 来做我需要的一切。

我的播放器的 SKPhysicsBody 如下:

let rect = CGSize(width: 16 * xScale, height: 24 * yScale)
let physics = SKPhysicsBody(rectangleOf: rect)
physics.isDynamic = true
physics.allowsRotation = false
physics.pinned = false
physics.affectedByGravity = true
physics.friction = 0
physics.restitution = 0
physics.linearDamping = 0
physics.angularDamping = 0
physics.density = 100
physics.categoryBitMask = 0b0001
physics.collisionBitMask = 0b0001
physics.contactTestBitMask = 0b0011
physics.usesPreciseCollisionDetection = true

physicsBody = physics

我不确定问题出在哪里,但是如果我将 SKTilemapNode 的物理主体设置为动态的,它就可以工作。这就是我让游戏一直运行到现在的方式,但是,这会在地面上产生很多抖动,因为玩家击中它会导致地面移动。所以,至少感谢您阅读本文,任何建议都将不胜感激。

【问题讨论】:

  • 您是否尝试过将 body.isDynamic 切换为 true?
  • 如我所见,玩家与第一帧上的瓷砖相交,在这种情况下没有任何碰撞。你能试着把玩家移动到瓷砖上方吗?也许它会起作用。
  • @PéterKovács 感谢您的回答,但不幸的是我的角色仍然失败了@sicvayne 是的,这在过去对我有用,我只是认为它停止工作没有任何意义一次body.isDynamic = false。我最终设置了body.isDynamic = false; body.mass = CGFloat(Int.max) 来解决这个问题。
  • 哎呀,对不起大家,我的意思是 body.isDynamic = true; body.mass = CGFloat(Int.max) 让它工作

标签: ios swift sprite-kit


【解决方案1】:

编辑。 我认为这里的错误没有使用 UInt 32

body.categoryBitMask: UInt32 = 2
body.collisionBitMask: UInt32 = 1
body.contactTestBitMask: UInt32 = 1

和播放器

physics.categoryBitMask: UInt32 = 1
physics.collisionBitMask: UInt32 = 2
physics.contactTestBitMask: UInt32 = 2

这绝对可以工作

也可以为 tileMapNode(如下所示)尝试这种方式,而不是创建扩展。这是 dontangg 在苹果开发者论坛上给出的

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)  
        }  
    }  
} 

【讨论】:

  • 感谢您的回答,我试过这个,但不幸的是它没有工作。我也尝试使用枚举,但没有任何运气。由于我找不到这背后的任何逻辑原因,我决定将瓦片贴图的物理主体设置为动态的,并将其质量设置为 CGFloat(Int.max),这对我来说足够好。
  • 我有一个有效的物理联系系统。使用枚举:UInt32。让我编辑我的答案
  • 请看我的编辑。记得使用 UInt32。这一点很重要。加上我的不是动态的,但它有效。这绝对应该有效。如果您想要更多位掩码,则可以使用 4 8 16 32 等。
  • 这不会为我编译,我在每行的冒号处收到“预期表达式”错误。即使将其格式化为每行的body.categoryBitMask = UInt32(2) 仍然对我不起作用。谁知道呢。
  • 我做了一些研究,我认为这里的问题在于您创建和扩展 TileMapNode。我也观看了一些视频(似乎他们使用 bool 来检测边缘。我认为该解决方案已在此处的论坛forums.developer.apple.com/thread/50043 中提到。我还在答案中复制了上面的代码以便于参考。Goodluck :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多