swift - 如何在场景边缘停止 SKCameraNode

标签 swift sprite-kit

我有一个 SpriteKit 场景,其中背景 (SKSpriteNode) 的大小是场景帧的 2 倍。我添加了一个摄像头,当用户用手指平移和捏合时,它会四处移动。我实现了缩放和平移,但是,我需要相机不移动超过背景节点的边缘。

我尝试过使用物理体和边缘循环,但是没有用(除非我设置错误)。这是我目前拥有的代码和一些有助于传达信息的图像。我应该移动背景节点而不是相机吗?

self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
self.physicsBody!.categoryBitMask = SCENE_EDGE_CAT
self.physicsWorld.contactDelegate = self

mCamera = self.childNode(withName: "camera") as! SKCameraNode
mCamera.physicsBody = SKPhysicsBody(edgeLoopFrom: mCamera.frame)
mCamera.physicsBody?.collisionBitMask = self.SCENE_EDGE_CAT
mCamera.physicsBody!.contactTestBitMask = mCamera.physicsBody!.collisionBitMask

func panForTranslation(_ translation: CGPoint) {
    let position = mCamera.position
    let aNewPosition = CGPoint(x: position.x - translation.x, y: position.y - translation.y)
    mCamera?.position = aNewPosition
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first
    let positionInScene = touch?.location(in:self)
    let previousPosition = touch?.previousLocation(in:self)
    let translation = CGPoint(x: (positionInScene?.x)! - (previousPosition?.x)!, y: (positionInScene?.y)! - (previousPosition?.y)!)

    panForTranslation(translation)
    print(mCamera.position)
}

场景(灰色为背景图,红色为相机) enter image description here

转向这个...

enter image description here

但我需要它停在边缘... enter image description here

最佳答案

有几种方法可以做到这一点。

在 Apple 的示例游戏 DemoBots 中,他们对相机使用约束以跟随玩家。但是,如果玩家靠近屏幕边缘,摄像机就会停止跟随他。

   /// Constrains the camera to follow the PlayerBot without approaching the scene edges.
private func setCameraConstraints() {
    // Don't try to set up camera constraints if we don't yet have a camera.
    guard let camera = camera else { return }

    // Constrain the camera to stay a constant distance of 0 points from the player node.
    let zeroRange = SKRange(constantValue: 0.0)
    let playerNode = playerBot.renderComponent.node
    let playerBotLocationConstraint = SKConstraint.distance(zeroRange, to: playerNode)

    /*
        Also constrain the camera to avoid it moving to the very edges of the scene.
        First, work out the scaled size of the scene. Its scaled height will always be
        the original height of the scene, but its scaled width will vary based on
        the window's current aspect ratio.
    */
    let scaledSize = CGSize(width: size.width * camera.xScale, height: size.height * camera.yScale)

    /*
        Find the root "board" node in the scene (the container node for
        the level's background tiles).
    */
    let boardNode = childNode(withName: WorldLayer.board.nodePath)!

    /*
        Calculate the accumulated frame of this node.
        The accumulated frame of a node is the outer bounds of all of the node's
        child nodes, i.e. the total size of the entire contents of the node.
        This gives us the bounding rectangle for the level's environment.
    */
    let boardContentRect = boardNode.calculateAccumulatedFrame()

    /*
        Work out how far within this rectangle to constrain the camera.
        We want to stop the camera when we get within 100pts of the edge of the screen,
        unless the level is so small that this inset would be outside of the level.
    */
    let xInset = min((scaledSize.width / 2) - 100.0, boardContentRect.width / 2)
    let yInset = min((scaledSize.height / 2) - 100.0, boardContentRect.height / 2)

    // Use these insets to create a smaller inset rectangle within which the camera must stay.
    let insetContentRect = boardContentRect.insetBy(dx: xInset, dy: yInset)

    // Define an `SKRange` for each of the x and y axes to stay within the inset rectangle.
    let xRange = SKRange(lowerLimit: insetContentRect.minX, upperLimit: insetContentRect.maxX)
    let yRange = SKRange(lowerLimit: insetContentRect.minY, upperLimit: insetContentRect.maxY)

    // Constrain the camera within the inset rectangle.
    let levelEdgeConstraint = SKConstraint.positionX(xRange, y: yRange)
    levelEdgeConstraint.referenceNode = boardNode

    /*
        Add both constraints to the camera. The scene edge constraint is added
        second, so that it takes precedence over following the `PlayerBot`.
        The result is that the camera will follow the player, unless this would mean
        moving too close to the edge of the level.
    */
    camera.constraints = [playerBotLocationConstraint, levelEdgeConstraint]
}

如果您不使用约束(您似乎正在这样做),则必须手动添加检查以阻止相机更新。类似于此伪代码的内容

  func panForTranslation(_ translation: CGPoint) {
     guard mCamera.position < ... else { return } // Check your corner position and exit early if camera moved to far

    ...

}

希望对你有帮助

关于swift - 如何在场景边缘停止 SKCameraNode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42707550/

相关文章:

ios - Firebase 将数据附加到节点

android - 在 SpriteKit 上停用物理

swift - 使一个物体跟随另一个物体x位置

ios - SpriteKit : How to animate drawing of a rounded rectangle

ios - 编写这个多条件 If 语句的正确方法是什么?

iphone - Swift 中的同步代码执行

swift - 字典中的值数组

ios - 找不到成员 'setObject' : NSMutableDictionary

sprite-kit - SKLabelNode 在 Sprite 场景中淡出

swift - SpriteKit 通过物理移动节点而不是更新位置