我正在使用SpriteKit在Swift中制作一个平台游戏,其中包含一个跳跃的主角。但是,一旦水平加载,玩家立即跌落地面。 You can see it in action here.
我正在使用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 :(得分:0)
EDIT。 我认为ERROR这里没有使用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)
}
}
}