ios - SpriteKit-SKCameraNode Efecto Parallax?
swift sprite-kit (2)
Estoy usando un efecto de paralaje en mi juego iOS 9 SpriteKit.
Básicamente, va a agregar algunas líneas de código a su función de update()
escenas update()
que mueve los cuadrados en la dirección opuesta de la cámara, PERO con algún factor de escala.
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 )
}
Este es un ejemplo simplificado. Utiliza una variable que rastrea los fps con un reloj y mueve los objetos en función de una escala de tiempo constante, en lugar de uno que constantemente avanza más rápido o más lento en función de los fps actuales del dispositivo.
Por lo tanto, defina algunas variables en el archivo de clase de su escena.
var lastUpdate: NSTimeInterval
var deltaTime: CGFloat
Luego inicialícelos en la función init()
de la clase de su escena.
lastUpdate = 0
deltaTime = 0.01666
Y finalmente, actualice cada actualización en la función update()
de su escena.
deltaTime = CGFloat( currentTime - lastUpdate )
lastUpdate = currentTime
if deltaTime > 1.0 {
deltaTime = 0.0166
}
Ahora que este reloj funciona, permitámoslo para escalar el efecto de paralaje para que sea más suave.
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 )
}
He estado experimentando con SKCameraNode, pero no puedo encontrar nada para crear un efecto de paralaje con él.
Digamos que agrego el código anterior y agrego un behindNode
debajo de mi baseNode
. Luego animé mi cámara.
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)
]))
Necesito que el cuadrado azul se mueva a un ritmo más lento en relación con el cuadrado rojo cuando la cámara se mueve ... Esperaría que el cameranode tuviera un diccionario de posiciones relativas o algo así, pero no es así.
Creé una solución que no trata con segundos o marcos.
Puede crear una subclase de SKCameraNode y usar el método didSet () de Swift que se llama después de que se modificó una variable de clase. En nuestro caso, queremos escuchar los cambios de la variable de posición del nodo de la cámara.
class CameraNodeParallax:SKCameraNode{
override var position : CGPoint {
didSet {
// Move our backgrounds
}
}
Además, queremos crear una matriz que contenga todos nuestros nodos de fondo de paralaje y otra que contenga la velocidad de movimiento correspondiente en relación con la velocidad de movimiento de la cámara.
var backgroundNodes:[SKNode] = []
var backgroundNodesSpeedFactor:[CGVector] = [] // in relation to camera nodes speed
func addParallaxBackgroundNode(background:SKNode, vector:CGVector) {
backgroundNodes.append(background)
backgroundNodesSpeedFactor.append(vector)
}
Un init () que llena nuestras nuevas variables puede ser útil también
init(position:CGPoint) {
super.init()
self.position = position
}
Ahora podemos llenar nuestro listener 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
}
El código final se ve así:
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)
}
}
Creé una implementación alternativa que no hereda de SKCameraNode aquí https://github.com/gitmalong/lovelySpriteKitHelpers/blob/master/ParallaxBackgroundMover.swift