Estoy creando un juego simple con Swift y SpriteKit. Quiero agregar un fondo sin fin (verticalmente), solo encontré respuestas para el fondo con imágenes pero necesito hacerlo sin imagen, solo color de fondo. Pensé en comprobar si el reproductor está en frame.maxY, si es así, para volver al punto de partida, pero me preguntaba si hay una mejor idea.

//Does not matter which ring we chose as all ring's 'y' position is the same.
func moveBackgroundUp(){
    if ((mPlayer.position.y >= self.frame.maxY) || (mRingOne.position.y >= self.frame.maxY)) {
        mPlayer.position.y = 150 //mPlayers original starting point.
        for ring in mRings {
            ring.position.y = 350
        }
    }
}

¡Gracias de antemano!

3
swiftnewbie 14 ene. 2017 a las 19:06
No mueva el fondo hacia arriba, pero cree un código para cuando la cámara esté a punto de ocupar un espacio que su nodo de fondo actual no ocupa, agregue un nuevo sprite de fondo a la escena, donde su origen es donde termina el último. Esto creará una sensación perfecta.
 – 
Pierce
14 ene. 2017 a las 20:04
Usar un sprite también sería bueno. pero la respuesta perforada también es buena
 – 
Fluidity
15 ene. 2017 a las 03:16

1 respuesta

La mejor respuesta

No se limite a mover un fondo hacia arriba en la pantalla, realmente no es la manera de hacerlo. Lo que debes hacer es detectar la posición de la cámara (asumiendo que se mueve con el jugador), y cuando su posición esté a punto de ocupar espacio fuera del espacio ocupado de tu sprite de fondo actual, agrega un nuevo sprite de fondo a la escena donde el el último quedó fuera. Aquí hay un ejemplo de cómo hacer eso con solo un sprite rojo:

Primero agregue una propiedad a la escena para rastrear la posición del nivel:

// To track the y-position of the level
var levelPositionY: CGFloat = 0.0

Ahora crea un método para actualizar tu fondo:

func updateBackground() {
    let cameraPos = camera!.position
    if cameraPos.y > levelPositionY - (size.height * 0.55) {
        createBackground()
    }
}

func createBackground() {

    // Create a new sprite the size of your scene
    let backgroundSprite = SKSpriteNode(color: .red, size: size)
    backgroundSprite.anchorPoint = CGPoint(x: 0.5, y: 0)
    backgroundSprite.position = CGPoint(x: 0, y: levelPositionY)

    // Replace backgroundNode with the name of your backgroundNode to add the sprite to
    backgroundNode.addChild(backgroundSprite)
    levelPositionY += backgroundSprite.size.height
}

Ahora desea llamar a updateBackground dentro de su método update(_:) anulado:

override func update(_ currentTime: TimeInterval) {

    // All your other update code
    updateBackground()

}

Además, asegúrese de crear un fondo inicial cuando cree la escena por primera vez:

override func didMove(to view: SKView) {
    createBackground()
}

¡NOTA! : es importante establecer el punto de ancla personalizado para el objeto de fondo para que este código funcione correctamente. Un ancla de (0.5, 0) permite que el sprite de fondo se ancle en el medio de la escena en el eje x, pero en la parte inferior de la escena en el eje y. Esto le permite apilar fácilmente uno encima del otro.

EDITAR : olvidé mencionar que también es una buena idea conservar recursos y eliminar los nodos de fondo que estén fuera del área visible y no volverán a aparecer (es decir, un juego de desplazamiento continuo en el que puedes no retroceda). Puede hacerlo actualizando su método updateBackground anterior:

func updateBackground() {
    let cameraPos = camera!.position
    if cameraPos.y > levelPositionY - (size.height * 0.55) {
        createBackground()
    }

    // Make sure to change 'backgroundNode' to whatever the name of your backgroundNode is.
    for bgChild in backgroundNode.children {
        // This will convert the node's coordinates to scene's coordinates. See below for this function
        let nodePos = fgNode.convert(fgChild.position, to: self)
        if !isNodeVisible(bgChild, positionY: nodePos.y) {
            // Remove from it's parent node
            bgChild.removeFromParent()
        }
    }
}

func isNodeVisible(_ node: SKNode, positionY: CGFloat) -> Bool {
    if !camera!.contains(node) {
        if positionY < camera!.position.y - size.height * 2.0 {
            return false
        }
    }
    return true
}

Entonces, arriba, simplemente recorre todos los elementos secundarios dentro de su nodo de fondo y detecta si están fuera de la vista, y si es así, elimínelos del elemento primario. Asegúrese de cambiar mi backgroundNode genérico a cualquiera que sea el nombre de su nodo de fondo.

3
Pierce 21 ene. 2017 a las 19:36
- Olvidé mencionar que es una buena idea eliminar también los nodos de su escena una vez que estén fuera de la vista y no regresen. De lo contrario, terminará asignando toda su memoria y su aplicación se cerrará si se ejecuta durante mucho tiempo. Agregaré una actualización a mi respuesta para mostrarte cómo. Es la mejor práctica de programación. Buena suerte :)
 – 
Pierce
21 ene. 2017 a las 19:19
¿Hay algo que deba hacer? Tengo un problema de "encontrado nulo al desenvolver un valor opcional". en la función updateBackground, causada por la línea let cameraPos.
 – 
swiftnewbie
26 ene. 2017 a las 20:00
- Debe asegurarse de que su escena tenga una propiedad de nodo camera. En la parte superior de su clase agregue let cameraNode = SKCameraNode(), luego en didMove(to view:) agregue esto: addChild(cameraNode), luego camera = cameraNode en una nueva línea, y luego camera?.position = CGPoint(x: size.width/2, y: size.height/2) una línea debajo ese. Debería solucionar el problema. Está desenvolviendo un valor opcional del nodo de la cámara de su escena que aparentemente nunca creó una instancia.
 – 
Pierce
26 ene. 2017 a las 20:25