如何将节点放置在地面上?

How to place nodes on the ground?

我正在使用 SpriteKit 创建游戏。背景为png图片,无限移动(视差滚动):

func parallaxScroll(image: String, y: CGFloat, z: CGFloat, duration: Double, needsPhysics: Bool) {
        for i in 0 ... 1 {
            
            // position the first node on the left, and position second on the right
            let node = SKSpriteNode(imageNamed: image)
            node.position = CGPoint(x: 1023 * CGFloat(i), y: y)
            node.zPosition = z
            addChild(node)
            
            if needsPhysics {
                node.physicsBody = SKPhysicsBody(texture: node.texture!, size: node.texture!.size())
                node.physicsBody?.isDynamic = false
                node.physicsBody?.contactTestBitMask = 1
                node.name = "ground"
            }
            
            // make this node move the width of the screen by whatever duration was passed in
            let move = SKAction.moveBy(x: -1024, y: 0, duration: duration)
            
            // make it jump back to the right edge
            let wrap = SKAction.moveBy(x: 1024, y: 0, duration: 0)
            
            // make these two as a sequence that loops forever
            let sequence = SKAction.sequence([move, wrap])
            let forever = SKAction.repeatForever(sequence)
            
            // run the animations
            node.run(forever)
        }
    }

下面的示例函数在随机 y 位置放置一个框:

@objc func createObstacle() {
        let obstacle = SKSpriteNode(imageNamed: "rectangle")
        obstacle.zPosition = -2
        obstacle.position.x = 768
        addChild(obstacle)
        
        obstacle.physicsBody = SKPhysicsBody(texture: obstacle.texture!, size: obstacle.texture!.size())
        obstacle.physicsBody?.isDynamic = false
        obstacle.physicsBody?.contactTestBitMask = 1
        obstacle.name = "obstacle"
        
        let rand = GKRandomDistribution(lowestValue: -200, highestValue: 350)
        obstacle.position.y = CGFloat(rand.nextInt())
        
        // make it move across the screen
        let action = SKAction.moveTo(x: -768, duration: 9)
        obstacle.run(action)
    }
    
    func playerHit(_ node: SKNode) {
        if node.name == "obstacle" {
            player.removeFromParent()
        }
    }
    
    func didBegin(_ contact: SKPhysicsContact) {
        guard let nodeA = contact.bodyA.node else { return }
        guard let nodeB = contact.bodyB.node else { return }
        
        if nodeA == player {
            playerHit(nodeB)
        } else if nodeB == player {
            playerHit(nodeA)
        }
    }

与其随意放置,不如将其放置在“地面”上。下图说明了当前位置和所需位置:

有谁知道如何在不平坦的地面上放置障碍物节点(对象)而不是随机的 y 位置?

您可以在盒子的预期 x 位置从屏幕顶部到底部投射一条光线,当光线击中地面时,将盒子直接放在命中点上方。参见 enumerateBodies(alongRayStart:end:using:)。在你的情况下,你可能想插入 createObstacle 类似的东西:

let topOfScreen = size.height / 2
let bottomOfScreen = -size.height / 2
obstacle.position.x = -768

physicsWorld.enumerateBodies(alongRayStart: CGPoint(x: obstacle.position.x, y: topOfScreen), end: CGPoint(x: obstacle.position.x, y: bottomOfScreen)) { body, point, normal, stop in
  if body.node?.name == "ground" {
    // body is the ground's physics body. point is the point that an object
    // falling from the sky would hit the ground.
    // Assuming the obstacle's anchor point is at its center, its actual position
    // would be slightly above this point
    let positionAboveBody = point + (obstacle.size.height / 2)
    obstacle.position.y = positionAboveBody
  }
}