在SpriteKit中围绕场景背景夹紧相机

时间:2016-02-01 18:19:27

标签: ios swift sprite-kit

所以我有一个基础游戏设置,可以在下面的bitbucket链接找到:

Game link

我目前很难理解如何翻译相对于场景布局的相机节点。

目标是让相机跟随播放器,直到达到由场景大小定义的角落边界。在此特定测试场景设置中,场景大小为1000x1000,相机比例为1.

以下代码用于在新位置设置为跟随角色时修改摄像机的位置:

    var cameraPosition: CGPoint {

        get {
            return CGPoint(x: camera!.position.x, y: camera!.position.y)
        }

        set {

            let cameraScale = CGFloat(1)
            let sceneScale = CGFloat(1)//CGFloat(1 - 0.44  + 0.05 /*possible rounding error adjustment*/)
//            let viewAspectRatio = CGRectGetWidth(view!.frame)/CGRectGetHeight(view!.frame)
            let newPositionValue = double2(x: Double(newValue.x * sceneScale), y: Double(newValue.y * sceneScale))

            let scaledSceneSize = CGSize(width: size.width * sceneScale , height: size.height * sceneScale)
////            scaledSceneSize.height = scaledSceneSize.height / viewAspectRatio

            let cameraSize = view!.bounds.size
            let scaledCameraSize = CGSize(width: cameraSize.width * cameraScale, height: cameraSize.height * cameraScale)


            let minX = 0//-scaledSceneSize.width * anchorPoint.x + scaledCameraSize.width / 2
            let minY = -219//-scaledSceneSize.height * anchorPoint.y + scaledCameraSize.height / 2

            let minValues = double2(x: Double(minX), y: Double(minY))

            let maxX = 0//(scaledSceneSize.width * anchorPoint.x - scaledCameraSize.width / 2) //size.width - cameraSize.width / 2
            let maxY = 219//(scaledSceneSize.height * anchorPoint.y - scaledCameraSize.height / 2) //- cameraSize.height / 2

            let maxValues = double2(x: Double(maxX), y: Double(maxY))

            let clampedPosition = clamp(newPositionValue, min: minValues, max: maxValues)


            camera!.position = CGPoint(x: (clampedPosition.x / Double(sceneScale)), y: (clampedPosition.y / Double(sceneScale)))
        }

    }

目前有适合所需场景大小的硬核值,我不确定如何通过比例获得这些结果。默认情况下,比例为:

/* Set the scale mode to scale to fit the window */
            scene.scaleMode = .AspectFill

如果不知道在规模上有翻译,默认情况下,我会期望边界 largestSceneDimensionXValue - cameraSize.width / 2 largestSceneDimensionYValue - cameraSize.height / 2

作为一个高级别的例子。有人能帮助我获得这个翻译吗?

整体而言,场景在所有角落应如下所示: goal

VS在相机中出现黑色背景溢出:

anti goal

2 个答案:

答案 0 :(得分:3)

这样的应用正是SKConstraint的用途。

你可以看到这个确切功能的演示 - 限制一个摄像机,使其跟随播放器,但在水平边缘周围没有显示太多空白空间 - 在WWDC15会话中Deeper into GameplayKit with DemoBots 。*(关于此功能的讨论开始时,应该跳到大约7:27的链接。)

视频内容的要点,以及DemoBots示例代码中的一些片段:

  1. 使用距离约束使相机在播放器上居中(自动,无需在每个camera.position上直接设置update()。)

    // Constrain the camera to stay a constant distance of 0 points from the player node.
    let zeroRange = SKRange(constantValue: 0.0)
    let playerBotLocationConstraint = SKConstraint.distance(zeroRange, toNode: playerNode)
    
  2. 使用位置约束将相机保持在关卡边缘的某个范围内。通过获取关卡的框架并按照相机应该保持距离关卡边缘的距离来计算该范围。

    // get the scene size as scaled by `scaleMode = .AspectFill`
    let scaledSize = CGSize(width: size.width * camera.xScale, height: size.height * camera.yScale)
    
    // get the frame of the entire level contents
    let boardNode = childNodeWithName(WorldLayer.Board.nodePath)!
    let boardContentRect = boardNode.calculateAccumulatedFrame()
    
    // inset that frame from the edges of the level
    // inset by `scaledSize / 2 - 100` to show 100 pt of black around the level
    // (no need for `- 100` if you want zero padding)
    // use min() to make sure we don't inset too far if the level is small
    let xInset = min((scaledSize.width / 2) - 100.0, boardContentRect.width / 2)
    let yInset = min((scaledSize.height / 2) - 100.0, boardContentRect.height / 2)
    let insetContentRect = boardContentRect.insetBy(dx: xInset, dy: yInset)
    
    // use the corners of the inset as the X and Y range of a position constraint
    let xRange = SKRange(lowerLimit: insetContentRect.minX, upperLimit: insetContentRect.maxX)
    let yRange = SKRange(lowerLimit: insetContentRect.minY, upperLimit: insetContentRect.maxY)
    let levelEdgeConstraint = SKConstraint.positionX(xRange, y: yRange)
    levelEdgeConstraint.referenceNode = boardNode
    
  3. 将两个约束应用于SKCameraNode

    camera.constraints = [playerBotLocationConstraint, levelEdgeConstraint]
    
  4. 更深入一点,download Apple's DemoBots sample code project,它有很多评论和支持代码,我从上面的代码片段中删除,以防止这篇文章变得过长。相机约束的所有内容都在func setCameraConstraints()的{​​{1}}中。

    *尽管有会话名称,但它不仅仅是GameplayKit ......它还展示了如何利用iOS 8 / OS X 10.11 / Xcode 7中引入的许多技术来构建类似的东西一个全面的游戏:App Thinning,新的SpriteKit功能,ReplayKit等等。

答案 1 :(得分:1)

我没有使用你的代码。我做了一个示例项目,并使其工作。

enter image description here

继承我的代码

import SpriteKit

class GameScene: SKScene {

    let world = SKSpriteNode(imageNamed: "world.jpg")
    let player = SKSpriteNode(color: SKColor.greenColor(), size: CGSizeMake(10, 10))

    var cam: SKCameraNode!

    override init(size: CGSize) {
        super.init(size: size)
        print(world.size)
        addChild(world)
        addChild(player)

        world.zPosition = 1
        player.zPosition = 2

        cam = SKCameraNode()
        self.camera = cam
        addChild(cam)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        for touch: AnyObject in touches {
            let location = touch.locationInNode(self)

            player.position = location
        }
    }

    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        for touch: AnyObject in touches {
            let location = touch.locationInNode(self)

            player.position = location
        }
    }

    func clampCamera(){

        func clamp(inout input: CGFloat, num1: CGFloat, num2: CGFloat) {
            if input < num1 {
                input = num1
            }
            else if input > num2 {
                input = num2
            }
        }

        let lBoundary = -world.size.width/2 + size.width/2
        let rBoundary = world.size.width/2 - size.width/2
        let bBoundary = -world.size.height/2 + size.height/2
        let tBoundary = world.size.height/2 - size.height/2

        clamp(&camera!.position.x, num1: lBoundary, num2: rBoundary)
        clamp(&camera!.position.y, num1: bBoundary, num2: tBoundary)

    }

    override func update(currentTime: NSTimeInterval) {
        camera!.position = player.position
        clampCamera()
    }
}

这是我用作我的&#34;世界&#34; http://i.imgur.com/XhZbh8q.jpg