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

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

问题描述

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





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



解决方案

这样的应用正是 SKConstraint 适用于。



你可以看到这个确切功能的演示 - 约束一个摄像机,使其跟随播放器,但不会在关卡边缘显示太多空白空间 - 在WWDC15中sion 使用DemoBots深入了解GameplayKit 。*(链接那里应该在讨论此功能的讨论中跳到大约7:27。)



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


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

      //约束相机与播放器节点保持0点的恒定距离。 
    let zeroRange = SKRange(constantValue:0.0)
    let playerBotLocationConstraint = SKConstraint.distance(zeroRange,toNode:playerNode)


  2. 使用位置约束将相机保持在关卡边缘的某个范围内。通过获取关卡的框架并按照相机应该保持距离关卡边缘的距离来计算该范围。

      //通过`scaleMode = .AspectFill`获取场景大小
    让scaledSize = CGSize(width:size.width * camera.xScale,height:size.height * camera.yScale)

    //获取整个级别内容的帧
    let boardNode = childNodeWithName(WorldLayer.Board.nodePath)!
    let boardContentRect = boardNode.calculateAccumulatedFrame()

    //从$ sc $ b //插入的边缘插入那个框架`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)
    let insetContentRect = boardContentRect.insetBy(dx:xInset,dy:yInset)

    //使用inset的角作为位置约束的X和Y范围
    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] 


如需深入了解,下载Apple的DemoBots示例代码项目,其中包含大量评论和支持代码,我从上面的代码片段中删除了以防止此帖子过度长。相机约束的所有内容都在 func setCameraConstraints() in LevelScene.swift



*尽管有会话名称,但它不仅仅是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天全站免登陆