在 SpriteKit 中将相机夹在场景的背景周围 [英] Clamping camera around the background of a scene in SpriteKit

查看:11
本文介绍了在 SpriteKit 中将相机夹在场景的背景周围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

解决方案

像这样的应用程序正是 SKConstraint 是为了.

您可以在 WWDC15 会议中看到这个确切功能的演示 - 约束相机使其跟随玩家,但不会在关卡边缘显示太多空白空间 - 在 WWDC15 会话中 使用 DemoBots 深入了解 GameplayKit.*(那里的链接应该跳转到 7:27 左右开始讨论此功能的谈话.)

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

  1. 使用 distance 约束来保持相机以播放器为中心(自动,无需在每次 update()).

    //约束相机与玩家节点保持 0 点的恒定距离.让 zeroRange = SKRange(constantValue: 0.0)让 playerBotLocationConstraint = SKConstraint.distance(zeroRange, toNode: playerNode)

  2. 使用位置约束将相机保持在关卡边缘的一定范围内.通过获取关卡的框架并将该矩形插入相机应与关卡边缘保持的距离来计算该范围.

    //获取由 `scaleMode = .AspectFill` 缩放的场景大小让 scaledSize = CGSize(width: size.width * camera.xScale, height: size.height * camera.yScale)//获取整个关卡内容的框架让 boardNode = childNodeWithName(WorldLayer.Board.nodePath)!让 boardContentRect = boardNode.calculateAccumulatedFrame()//从关卡的边缘插入该帧//插入 `scaledSize/2 - 100` 以在关卡周围显示 100 pt 的黑色//(如果你想要零填充,则不需要 `- 100`)//使用 min() 确保如果级别很小,我们不会插入太远让 xInset = min((scaledSize.width/2) - 100.0, boardContentRect.width/2)让 yInset = min((scaledSize.height/2) - 100.0, boardContentRect.height/2)让 insetContentRect = boardContentRect.insetBy(dx: xInset, dy: yInset)//使用插图的角作为位置约束的 X 和 Y 范围让 xRange = SKRange(lowerLimit: insetContentRect.minX, upperLimit: insetContentRect.maxX)让 yRange = SKRange(lowerLimit: insetContentRect.minY, upperLimit: insetContentRect.maxY)让 levelEdgeConstraint = SKConstraint.positionX(xRange, y: yRange)levelEdgeConstraint.referenceNode = boardNode

  3. 将这两个约束应用到您的 SKCameraNode.

    camera.constraints = [playerBotLocationConstraint, levelEdgeConstraint]

要深入了解,下载 Apple 的 DemoBots 示例代码项目,其中有很多评论和支持代码,我从上面的代码片段中删减了这些代码,以防止这篇文章变得过长.相机约束的所有内容都在 LevelScene.swift 中的 func setCameraConstraints() 中.

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

so I have a base game setup that can be found at the bitbucket link below:

Game link

I'm currently having a hard time understanding how to translate the camera node in relation to the scene's layout.

The goal is to have the camera follow the player up until hitting a corner boundary defined by the size of the scene. In this particular test scenario setup, the scene is 1000x1000 in size with a camera scale of 1.

The code below is used to modify the position of the camera when a new position is set to follow the character:

    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)))
        }

    }

There are hardcore value that currently fit the required scene size, and I'm unsure how to get those results via the scale. The scale by default is:

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

Without the knowledge of knowing there's a translation in scale, by default, I would expect the boundaries to be largestSceneDimensionXValue - cameraSize.width/2 largestSceneDimensionYValue - cameraSize.height/2

As a high level example. Would anyone be able to assist me in getting this translation?

Overall the scene should look like the following in all corners:

VS having the black background overflow in the camera as such:

解决方案

Applications like this are exactly what SKConstraint is for.

You can see a demo of this exact feature — constraining a camera so that it follows the player, but doesn't show too much empty space around the edge of the level — in the WWDC15 session Deeper into GameplayKit with DemoBots.* (The link there should jump to about 7:27 in the talk where discussion of this feature begins.)

The gist of what's in the video, with some snippets from the DemoBots sample code:

  1. Use a distance constraint to keep the camera centered on the player (automatically, without having to set camera.position directly on every 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. Use a position constraint to keep the camera within a certain range of the edge of the level. Calculate that range by taking the frame of the level and insetting that rect by the distance the camera should keep from the edge of the level.

    // 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. Apply both constraints to your SKCameraNode.

    camera.constraints = [playerBotLocationConstraint, levelEdgeConstraint]
    

For a deeper look, download Apple's DemoBots sample code project, which has a lot of comments and supporting code that I trimmed from the above snippets to keep this post from getting excessively long. Everything for the camera constraint is in func setCameraConstraints() in LevelScene.swift.

* Despite the session name, it's about a lot more than just GameplayKit... it shows how to leverage many the technologies introduced in iOS 8 / OS X 10.11 / Xcode 7 to build something resembling a full-scale game: App Thinning, new SpriteKit features, ReplayKit, and a lot more.

这篇关于在 SpriteKit 中将相机夹在场景的背景周围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆