2017-05-26 95 views
0

我正在Swift中制作一个平台游戏,SpriteKit涉及跳转的主角。然而,等级加载后,玩家立即落地。 You can see it in action here.Swift SKPhysicsBody通过匹配位掩码的静态SKPhysicsBody坠落

我正在使用SKTilemapNode创建地面,并在水平加载时通过瓦片循环以在瓦片地图的子节点上创建SKPhysicsBody。这与2016年WWDC的“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的物理身体是动态的,它的工作原理。这就是我在这之前让游戏工作的原因,但是,这会造成很多地面上的抖动,因为玩家正在移动它。所以,感谢您阅读这个至少,并且任何建议将不胜感激。

+0

您是否尝试将body.isDynamic切换为true? – sicvayne

+0

正如我所看到的,玩家与第一帧上的瓦片相交,在这种情况下,没有任何碰撞。你能否试着将玩家移动到瓦片之上?也许它会工作。 –

+0

@PéterKovács感谢您的回答,但不幸的是,我的角色仍然通过@sicvayne来了,是的,这对我来说是过去的工作,我只是觉得它没有任何意义,因为它停止工作'body.isDynamic = false '。我最终设置了'body.isDynamic = false; body.mass = CGFloat(Int.max)'来解决这个问题。 – TempixTL

回答

0

编辑。 我认为错误在这里没有使用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) 
     } 
    } 
} 
+0

感谢您的回答,我试过这个,但它不工作不幸。我尝试使用枚举,而没有任何运气。由于我找不到任何逻辑原因,我决定只是将瓷砖贴图的物理体设置为动态,并将其设置为“CGFloat(Int.max)”,这对我来说已经足够了。 – TempixTL

+0

我有一个可用的物理接触系统。使用枚举与:UInt32。让我编辑我的答案 –

+0

请看看我的编辑。请记住使用UInt32。这一点很重要。再加上我的动态,但它的工作。这应该肯定有效。如果你想要更多的位掩码,它会去4 8 16 32等 –