ios - Swift SKPhysicsBody 通过具有匹配位掩码的静态 SKPhysicsBody

标签 ios swift sprite-kit

我正在 Swift 中使用 SpriteKit 制作一款平台游戏,其中涉及一个跳跃的主角。然而,一旦关卡加载,玩家就会立即掉到地上。 You can see it in action here.

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

So, here we've got a little platform that I built. A little guy that can run around. And you can see that I got the parallax scrolling going on in the background. And you'll note that I'm colliding with the tiles here. And I achieve this by leveraging custom user data that we can put on each of our tiles. Here, I'll show you in our tile set. Select one of the variants here. And you can see that we have some user data over here. And I just have a value called edgeTile which is a Boolean, and I set to 1. So, in code, I'm going through the tile map in our platform demo here, and I'm looking for all of these edge tiles. And whenever I find one, I create some physics data to allow the player to collide with it.

我基于 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 的物理体设置为动态,它就可以工作。到目前为止,这就是我让游戏运行的方式,但是,这会在地面上产生很多抖动,因为它会因玩家击中它而移动。所以,至少感谢您阅读到这里,如有任何建议,我们将不胜感激。

最佳答案

编辑。 我认为这里的错误不是使用 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)  
        }  
    }  
} 

关于ios - Swift SKPhysicsBody 通过具有匹配位掩码的静态 SKPhysicsBody,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44208131/

相关文章:

ios - 关闭 SKScene 后,内存仍然很高

xcode - SpriteKit 可以使用什么类型的游戏 map ?

ios - 结束异步进程的正确方法

ios - 可重复使用的自定义单元格

swift - 使用按位异或运算符将 hashValue 添加在一起或简单地将它们添加在一起

ios - 如何为服务器上的表格 View 单元格中的每个帖子更新类似按钮

ios - 在 iOS 库类中的现有属性上添加属性观察器

ios - 快速添加图像图标到 UITableViewController

ios - 使用 SkyDrive api ios 获取文件的缩略图(第一页)

swift - 为什么要在 Swift 中使用类型转换?