2017-03-09 100 views
4

我有一个SpriteKit场景,我有一个背景(SKSpriteNode),它是场景帧大小的两倍。我添加了一个摄像头,随着用户用手指捏住并捏住摄像头。我有捏缩放和平移实现,但是,我需要相机不移过背景节点的边缘。如何停止场景边缘的SKCameraNode

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

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

回答

2

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

在苹果示例游戏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 

    ... 

} 

希望这有助于

+0

我会做第二个选项,但我已经开始尝试,并遇到了一个问题。相机节点没有“大小”属性。所以我可以得到这个位置,但我无法知道左右边缘在哪里,而不知道节点的宽度。有没有解决办法? – TheValyreanGroup

+0

相机将与场景尺寸相同。因此,只需获取场景大小,例如让cameraSize = self.size – crashoverride777

+0

即使我改变相机的比例?这是一个地图视图,所以用户捏合放大,并做到这一点,我改变相机的规模。 – TheValyreanGroup