SpriteKit - SKCameraNode 视差效果?

3

我一直在尝试使用SKCameraNode,但是找不到有关如何创建视差效果的任何信息。

假设我在上面的代码中添加一个behindNode,并将其放置在baseNode下方。然后我对我的相机进行动画处理。

let behindNode = SKNode()
addChild(behindNode)

let blueSquare = SKSpriteNode(color: SKColor.blueColor(), size: CGSize(width: 80, height: 80))
blueSquare.position = CGPoint(x: size.width/2+40, y: size.height/2+40)
behindNode.addChild(blueSquare)

let baseNode = SKNode()
addChild(baseNode)

let redSquare = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 80, height: 80))
redSquare.position = CGPoint(x: size.width/2, y: size.height/2)
baseNode.addChild(redSquare)


let cameraNode = SKCameraNode()
camera = cameraNode
addChild(camera!)
camera!.position = redSquare.position

cameraNode.runAction(SKAction.sequence([
    SKAction.waitForDuration(1),
    SKAction.moveBy(CGVector(dx: 100, dy: 100), duration: 3),
    SKAction.moveBy(CGVector(dx: -100, dy: 100), duration: 1),
    SKAction.moveBy(CGVector(dx: 100, dy: -100), duration: 1)
]))

enter image description here

当相机移动时,我希望蓝色正方形的移动速度相对于红色正方形更慢。我期望相机节点有一个相对位置字典或类似的东西,但它没有。

2个回答

4
我创建了一个方案,不涉及秒或帧。
你可以创建SKCameraNode的子类,并使用Swift的didSet()方法,在类变量更改后调用该方法。在我们的情况下,我们要监听相机节点位置变量的更改。
class CameraNodeParallax:SKCameraNode{

override var position : CGPoint {
    didSet {  
       // Move our backgrounds
    }
}

我们还想创建一个包含所有视差背景节点的数组,以及一个包含相应移动速度与摄像机移动速度相关的数组。
var backgroundNodes:[SKNode] = []
var backgroundNodesSpeedFactor:[CGVector] = [] // in relation to camera nodes speed

func addParallaxBackgroundNode(background:SKNode, vector:CGVector) {
    backgroundNodes.append(background)
    backgroundNodesSpeedFactor.append(vector)
}

一个填充新变量的init()函数也可能非常有用。
init(position:CGPoint) {
  super.init()
  self.position = position
}

现在我们可以填写didSet()监听器:
// Move our backgrounds
var i = 0
for node in backgroundNodes {

    let positionChangeX = position.x-oldValue.x
    let positionChangeY = position.y-oldValue.y
    let changeX = positionChangeX*backgroundNodesSpeedFactor[i].dx
    let changeY = positionChangeY*backgroundNodesSpeedFactor[i].dy
    node.position = CGPointMake(node.position.x+changeX,node.position.y+changeY)

    i += 1
}

最终代码如下:

class CameraNodeParallax:SKCameraNode{

    var backgroundNodes:[SKNode] = []
    var backgroundNodesSpeedFactor:[CGVector] = [] // in relation to camera nodes speed

    init(position:CGPoint) {
        super.init()
        self.position = position
    }

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

    override var position : CGPoint {
        didSet {

            // Move your parallax backgrounds
                var i = 0
                for node in backgroundNodes {

                    let positionChangeX = position.x-oldValue.x
                    let positionChangeY = position.y-oldValue.y
                    let changeX = positionChangeX*backgroundNodesSpeedFactor[i].dx
                    let changeY = positionChangeY*backgroundNodesSpeedFactor[i].dy
                    node.position = CGPointMake(node.position.x+changeX,node.position.y+changeY)

                    i += 1
                }
        }
    }

    func addParallaxBackgroundNode(background:SKNode, vector:CGVector) {
        backgroundNodes.append(background)
        backgroundNodesSpeedFactor.append(vector)
    }
}

我创建了一个替代实现,它不继承自SKCameraNode,代码链接在这里https://github.com/gitmalong/lovelySpriteKitHelpers/blob/master/ParallaxBackgroundMover.swift


3

我在我的iOS 9 SpriteKit游戏中使用了视差效果。

基本上你需要在场景的update()函数中添加几行代码,将正方形沿着相机的相反方向移动,但要使用一些缩放因子。

update(){
  let moveXFactor: CGFloat = 3
  let moveYFactor: CGFloat = 2
  camera.position = CGPoint( camera.position.x + moveXFactor, camera.position.y + moveYFactor )

  let redSquareParallaxSpeedFactor: CGFloat = -0.2
  let blueSquareParallaxSpeedFactor: CGFloat = -0.1
  redSquare.position = CGPoint( redSquare.position.x + redSquareParallaxSpeedFactor * moveXFactor, redSquare.position.y + redSquareParallaxSpeedFactor * moveYFactor )
  blueSquare.position = CGPoint( blueSquare.position.x + blueSquareParallaxSpeedFactor * moveXFactor, blueSquare.position.y + blueSquareParallaxSpeedFactor * moveYFactor )
}

这是一个简化的例子。使用一个变量来跟踪fps,并根据恒定的时间比例移动对象,而不是基于设备当前fps一直变快或变慢。
因此,请在场景类文件中定义一些变量。
var lastUpdate: NSTimeInterval
var deltaTime: CGFloat

然后在场景类的init()函数中初始化它们。

lastUpdate = 0
deltaTime = 0.01666

最后,在场景的update()函数中每次刷新时更新它们。
deltaTime = CGFloat( currentTime - lastUpdate )
lastUpdate = currentTime

if deltaTime > 1.0 {
  deltaTime = 0.0166
}

现在这个时钟可以正常工作了,让我们利用它来调整视差效果,使其更加平滑。

update(){
  deltaTime = CGFloat( currentTime - lastUpdate )
  lastUpdate = currentTime

  if deltaTime > 1.0 {
    deltaTime = 0.0166
  }

  let someScale: CGFloat = 0.001

  var moveXFactor: CGFloat = 3 * deltaTime * someScale
  var moveYFactor: CGFloat = 2 * deltaTime * someScale
  camera.position = CGPoint( camera.position.x + moveXFactor, camera.position.y + moveYFactor )

  let redSquareParallaxSpeedFactor: CGFloat = -0.2
  let blueSquareParallaxSpeedFactor: CGFloat = -0.1
  redSquare.position = CGPoint( redSquare.position.x + redSquareParallaxSpeedFactor * moveXFactor, redSquare.position.y + redSquareParallaxSpeedFactor * moveYFactor )
  blueSquare.position = CGPoint( blueSquare.position.x + blueSquareParallaxSpeedFactor * moveXFactor, blueSquare.position.y + blueSquareParallaxSpeedFactor * moveYFactor )
}

1
感谢您提供的所有代码。我有点希望有一种更内置的方法来完成这个任务。SKCameraNode并没有真正为我们节省太多代码。我们可能还是老老实实地用传统的方式移动一堆SKNodes。 - hamobi
这个想法是让你将游戏对象保持在与相机相同的层级上,而所有背景视差对象都使用上述代码。 - jmcmahon443
1
您如何对此 s 中的 z-order 进行排序,以便背景对象永远不会出现在前景对象的前面? - Confused
我理解这个原则..但是我认为在这种情况下使用SKCameraNode真的没有任何优势。如果你要编写所有这些代码来相对于相机以不同的速率移动物体,那么你可能会想用一些传统的方式来滑动一些父级SKNodes。 - hamobi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接